From 291c70a20cda14542e6253ff4a6910d40967aca7 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 17 Nov 2021 08:16:34 +0100 Subject: [PATCH 01/28] - modularized `dotnet.js` - By using emcc options `MODULARIZE` and `EXPORT_ES6`, depending on `WasmEnableES6` to produce ES6 or CommonJS modules respectively. - `WasmEnableES6` enables `WasmBuildNative` because `dotnet.js` need to be re-linked - CommonJS version is able to be loaded into global namespace and behaves as before this change. - Added new `modularize-dotnet.*.js` files which are included in `dotnet.js` creation. - it exports `createDotnetRuntime` method instead of global `Module` - `createDotnetRuntime` takes function which creates `Module`-like config `(exports) => EmscriptenModuleConfig` . - `createDotnetRuntime` returns `Promise<{MONO, INTERNAL, BINDING, Module}>` exports. - Added `browser-es6` sample app, which uses `WasmEnableES6=true` to compile `dotnet.js` as ES6 module. - Added `browser-legacy` sample, which uses `dotnet.js` CommonJS module and loads it into global namespace. - Attempt to fix In-Tree `_WasmSelectRuntimeComponentsForLinking` when `WasmBuildNative` - feedback from Radek & Kate & Ankit - rebased --- eng/testing/tests.wasm.targets | 1 + .../Directory.Build.props | 12 +- .../{pal_random.js => pal_random.lib.js} | 0 src/mono/sample/wasm/browser-es6/Program.cs | 22 +++ .../browser-es6/Wasm.Browser.Sample.csproj | 20 +++ src/mono/sample/wasm/browser-es6/index.html | 20 +++ src/mono/sample/wasm/browser-es6/main.js | 27 ++++ .../sample/wasm/browser-legacy/Program.cs | 22 +++ .../Wasm.Browser.LegacySample.csproj | 21 +++ .../sample/wasm/browser-legacy/index.html | 44 ++++++ src/mono/sample/wasm/browser-legacy/main.js | 18 +++ src/mono/sample/wasm/browser/index.html | 4 +- src/mono/sample/wasm/browser/main.js | 7 +- src/mono/wasm/Makefile | 4 +- src/mono/wasm/build/README.md | 2 + src/mono/wasm/build/WasmApp.InTree.targets | 15 ++ src/mono/wasm/build/WasmApp.Native.targets | 36 +++-- .../debugger/DebuggerTestSuite/ArrayTests.cs | 2 +- .../DebuggerTestSuite/DebuggerTestBase.cs | 2 +- src/mono/wasm/runtime/.eslintrc.js | 7 +- src/mono/wasm/runtime/CMakeLists.txt | 4 +- .../{library-dotnet.js => dotnet.lib.js} | 8 +- src/mono/wasm/runtime/exports.ts | 21 ++- src/mono/wasm/runtime/imports.ts | 2 +- .../runtime/modularize-cjs/dotnet.extpost.js | 4 + .../runtime/modularize-cjs/dotnet.post.js | 3 + .../wasm/runtime/modularize-cjs/dotnet.pre.js | 23 +++ src/mono/wasm/runtime/modularize-dotnet.md | 94 ++++++++++++ .../runtime/modularize-es6/dotnet.post.js | 3 + .../wasm/runtime/modularize-es6/dotnet.pre.js | 15 ++ src/mono/wasm/runtime/rollup.config.js | 33 ++-- src/mono/wasm/runtime/startup.ts | 25 ++- src/mono/wasm/runtime/types.ts | 25 ++- src/mono/wasm/runtime/types/emscripten.d.ts | 1 + src/mono/wasm/test-main.js | 142 +++++++++--------- src/mono/wasm/wasm.proj | 33 +++- 36 files changed, 594 insertions(+), 128 deletions(-) rename src/libraries/Native/Unix/System.Native/{pal_random.js => pal_random.lib.js} (100%) create mode 100644 src/mono/sample/wasm/browser-es6/Program.cs create mode 100644 src/mono/sample/wasm/browser-es6/Wasm.Browser.Sample.csproj create mode 100644 src/mono/sample/wasm/browser-es6/index.html create mode 100644 src/mono/sample/wasm/browser-es6/main.js create mode 100644 src/mono/sample/wasm/browser-legacy/Program.cs create mode 100644 src/mono/sample/wasm/browser-legacy/Wasm.Browser.LegacySample.csproj create mode 100644 src/mono/sample/wasm/browser-legacy/index.html create mode 100644 src/mono/sample/wasm/browser-legacy/main.js rename src/mono/wasm/runtime/{library-dotnet.js => dotnet.lib.js} (85%) create mode 100644 src/mono/wasm/runtime/modularize-cjs/dotnet.extpost.js create mode 100644 src/mono/wasm/runtime/modularize-cjs/dotnet.post.js create mode 100644 src/mono/wasm/runtime/modularize-cjs/dotnet.pre.js create mode 100644 src/mono/wasm/runtime/modularize-dotnet.md create mode 100644 src/mono/wasm/runtime/modularize-es6/dotnet.post.js create mode 100644 src/mono/wasm/runtime/modularize-es6/dotnet.pre.js diff --git a/eng/testing/tests.wasm.targets b/eng/testing/tests.wasm.targets index 0286959859cc1..ca2d51ad1a6e4 100644 --- a/eng/testing/tests.wasm.targets +++ b/eng/testing/tests.wasm.targets @@ -138,6 +138,7 @@ <_WasmPropertyNames Include="WasmDedup" /> <_WasmPropertyNames Include="WasmLinkIcalls" /> <_WasmPropertyNames Include="WasmNativeStrip" /> + <_WasmPropertyNames Include="WasmEnableES6" /> <_WasmPropertyNames Include="_WasmDevel" /> <_WasmPropertiesToPass 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 61f2942b48c90..ed4da6f875aea 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props @@ -218,10 +218,16 @@ - - - + + + + + + + + + diff --git a/src/libraries/Native/Unix/System.Native/pal_random.js b/src/libraries/Native/Unix/System.Native/pal_random.lib.js similarity index 100% rename from src/libraries/Native/Unix/System.Native/pal_random.js rename to src/libraries/Native/Unix/System.Native/pal_random.lib.js diff --git a/src/mono/sample/wasm/browser-es6/Program.cs b/src/mono/sample/wasm/browser-es6/Program.cs new file mode 100644 index 0000000000000..743f481896fcb --- /dev/null +++ b/src/mono/sample/wasm/browser-es6/Program.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; + +namespace Sample +{ + public class Test + { + public static void Main(string[] args) + { + Console.WriteLine ("Hello, World!"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static int TestMeaning() + { + return 42; + } + } +} diff --git a/src/mono/sample/wasm/browser-es6/Wasm.Browser.Sample.csproj b/src/mono/sample/wasm/browser-es6/Wasm.Browser.Sample.csproj new file mode 100644 index 0000000000000..8ae5482f8bb7e --- /dev/null +++ b/src/mono/sample/wasm/browser-es6/Wasm.Browser.Sample.csproj @@ -0,0 +1,20 @@ + + + Debug + true + main.js + true + embedded + 1 + true + + + + + + + + <_SampleProject>Wasm.Browser.Sample.csproj + + + diff --git a/src/mono/sample/wasm/browser-es6/index.html b/src/mono/sample/wasm/browser-es6/index.html new file mode 100644 index 0000000000000..44fc8ff2bde9b --- /dev/null +++ b/src/mono/sample/wasm/browser-es6/index.html @@ -0,0 +1,20 @@ + + + + + + + Sample ES6 + + + + + + + + + Result from Sample.Test.TestMeaning: + + + + \ No newline at end of file diff --git a/src/mono/sample/wasm/browser-es6/main.js b/src/mono/sample/wasm/browser-es6/main.js new file mode 100644 index 0000000000000..ec88e870212e5 --- /dev/null +++ b/src/mono/sample/wasm/browser-es6/main.js @@ -0,0 +1,27 @@ +import createDotnetRuntime from './dotnet.js' + +const { MONO, BINDING, Module } = await createDotnetRuntime(() => ({ + disableDotNet6Compatibility: true, + configSrc: "./mono-config.json", + onAbort: () => { + wasm_exit(1); + }, +})); + +const App = { + init: function () { + const testMeaning = BINDING.bind_static_method("[Wasm.Browser.Sample] Sample.Test:TestMeaning"); + const ret = testMeaning(); + document.getElementById("out").innerHTML = ret; + + console.debug(`ret: ${ret}`); + let exit_code = ret == 42 ? 0 : 1; + wasm_exit(exit_code); + }, +}; + +App.init(); + +function wasm_exit(exit_code) { + console.log(`WASM EXIT ${exit_code}`); +} \ No newline at end of file diff --git a/src/mono/sample/wasm/browser-legacy/Program.cs b/src/mono/sample/wasm/browser-legacy/Program.cs new file mode 100644 index 0000000000000..743f481896fcb --- /dev/null +++ b/src/mono/sample/wasm/browser-legacy/Program.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; + +namespace Sample +{ + public class Test + { + public static void Main(string[] args) + { + Console.WriteLine ("Hello, World!"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static int TestMeaning() + { + return 42; + } + } +} diff --git a/src/mono/sample/wasm/browser-legacy/Wasm.Browser.LegacySample.csproj b/src/mono/sample/wasm/browser-legacy/Wasm.Browser.LegacySample.csproj new file mode 100644 index 0000000000000..c03897e467d94 --- /dev/null +++ b/src/mono/sample/wasm/browser-legacy/Wasm.Browser.LegacySample.csproj @@ -0,0 +1,21 @@ + + + Debug + true + main.js + true + embedded + 1 + true + + + + + + + + <_SampleProject>Wasm.Browser.LegacySample.csproj + + + + diff --git a/src/mono/sample/wasm/browser-legacy/index.html b/src/mono/sample/wasm/browser-legacy/index.html new file mode 100644 index 0000000000000..a2e7322aecf0e --- /dev/null +++ b/src/mono/sample/wasm/browser-legacy/index.html @@ -0,0 +1,44 @@ + + + + + + + Legacy global module sample + + + + + + + Result from Sample.Test.TestMeaning: + + + + + + + + \ No newline at end of file diff --git a/src/mono/sample/wasm/browser-legacy/main.js b/src/mono/sample/wasm/browser-legacy/main.js new file mode 100644 index 0000000000000..bcec2e80e2418 --- /dev/null +++ b/src/mono/sample/wasm/browser-legacy/main.js @@ -0,0 +1,18 @@ +// 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", + onDotNetReady: () => { + try { + App.init(); + } catch (error) { + set_exit_code(1, error); + throw (error); + } + }, + onAbort: (error) => { + set_exit_code(1, error); + }, +}; diff --git a/src/mono/sample/wasm/browser/index.html b/src/mono/sample/wasm/browser/index.html index 2fa08c756cbf2..340b67d645a75 100644 --- a/src/mono/sample/wasm/browser/index.html +++ b/src/mono/sample/wasm/browser/index.html @@ -24,7 +24,7 @@ }; const App = { - init: () => { + init: ({ MONO, BINDING, Module }) => { const testMeaning = BINDING.bind_static_method("[Wasm.Browser.Sample] Sample.Test:TestMeaning"); const ret = testMeaning(); document.getElementById("out").innerHTML = ret; @@ -35,8 +35,8 @@ }, }; + - diff --git a/src/mono/sample/wasm/browser/main.js b/src/mono/sample/wasm/browser/main.js index 9e347d4d346cd..032946ae7418e 100644 --- a/src/mono/sample/wasm/browser/main.js +++ b/src/mono/sample/wasm/browser/main.js @@ -3,11 +3,12 @@ "use strict"; -var Module = { +createDotnetRuntime(({ MONO, BINDING, Module }) => ({ + disableDotNet6Compatibility: true, configSrc: "./mono-config.json", onDotNetReady: () => { try { - App.init(); + App.init({ MONO, BINDING, Module }); } catch (error) { set_exit_code(1, error); throw (error); @@ -16,4 +17,4 @@ var Module = { onAbort: (error) => { set_exit_code(1, error); }, -}; \ No newline at end of file +})); diff --git a/src/mono/wasm/Makefile b/src/mono/wasm/Makefile index f8355fe857e6b..9739030ebaeb9 100644 --- a/src/mono/wasm/Makefile +++ b/src/mono/wasm/Makefile @@ -93,7 +93,7 @@ $(NATIVE_BIN_DIR)/include/wasm: $(BUILDS_OBJ_DIR): mkdir -p $$@ -$(NATIVE_BIN_DIR)/dotnet.js: runtime/driver.c runtime/pinvoke.c runtime/pinvoke.h runtime/corebindings.c $(NATIVE_BIN_DIR)/src/runtime.iffe.js runtime/library-dotnet.js $(SYSTEM_NATIVE_LIBDIR)/pal_random.js $(MONO_LIBS) $(EMCC_DEFAULT_RSP) | $(NATIVE_BIN_DIR) +$(NATIVE_BIN_DIR)/dotnet.js: runtime/driver.c runtime/pinvoke.c runtime/pinvoke.h runtime/corebindings.c $(NATIVE_BIN_DIR)/src/runtime.iffe.js runtime/dotnet.lib.js $(SYSTEM_NATIVE_LIBDIR)/pal_random.lib.js $(MONO_LIBS) $(EMCC_DEFAULT_RSP) | $(NATIVE_BIN_DIR) $(DOTNET) build $(CURDIR)/wasm.proj $(_MSBUILD_WASM_BUILD_ARGS) /t:BuildWasmRuntimes $(MSBUILD_ARGS) $(EMCC_DEFAULT_RSP): $(CURDIR)/wasm.proj | $(NATIVE_BIN_DIR)/src Makefile @@ -113,7 +113,7 @@ clean: icu-files: $(wildcard $(ICU_LIBDIR)/*.dat) $(ICU_LIBDIR)/libicuuc.a $(ICU_LIBDIR)/libicui18n.a | $(NATIVE_BIN_DIR) cp $^ $(NATIVE_BIN_DIR) -source-files: runtime/driver.c runtime/pinvoke.c runtime/corebindings.c runtime/library-dotnet.js $(SYSTEM_NATIVE_LIBDIR)/pal_random.js | $(NATIVE_BIN_DIR)/src +source-files: runtime/driver.c runtime/pinvoke.c runtime/corebindings.c runtime/dotnet.lib.js $(SYSTEM_NATIVE_LIBDIR)/pal_random.lib.js | $(NATIVE_BIN_DIR)/src cp $^ $(NATIVE_BIN_DIR)/src header-files: runtime/pinvoke.h | $(NATIVE_BIN_DIR)/include/wasm diff --git a/src/mono/wasm/build/README.md b/src/mono/wasm/build/README.md index 79b9ef30f46dd..323704aab2a74 100644 --- a/src/mono/wasm/build/README.md +++ b/src/mono/wasm/build/README.md @@ -32,6 +32,8 @@ Implementation: - *after* any of the wasm build targets, use `AfterTargets="WasmBuildApp"` on that target - Avoid depending on this target, because it is available only when the workload is installed. Use `$(WasmNativeWorkload)` to check if it is installed. +- `WasmEnableES6` will cause native re-link and produce `dotnet.js` as ES6 module. When `Module.disableDotNet6Compatibility` is set it would not pollute global namespace. Currently debugger doesn't work in that pure mode. + ## `Publish` Implementation: diff --git a/src/mono/wasm/build/WasmApp.InTree.targets b/src/mono/wasm/build/WasmApp.InTree.targets index b4f2af25b0afd..d5c0764f1726f 100644 --- a/src/mono/wasm/build/WasmApp.InTree.targets +++ b/src/mono/wasm/build/WasmApp.InTree.targets @@ -51,4 +51,19 @@ + + + + <_MonoRuntimeComponentDontLink Include="libmono-component-diagnostics_tracing-static.a"/> + + + <_MonoRuntimeComponentDontLink Include="libmono-component-hot_reload-static.a"/> + <_MonoRuntimeComponentDontLink Include="libmono-component-debugger-static.a"/> + + + <_MonoRuntimeComponentDontLink Include="libmono-component-hot_reload-stub-static.a"/> + <_MonoRuntimeComponentDontLink Include="libmono-component-debugger-stub-static.a"/> + + + diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets index bfac812dadd9b..1f0ace7dec788 100644 --- a/src/mono/wasm/build/WasmApp.Native.targets +++ b/src/mono/wasm/build/WasmApp.Native.targets @@ -106,6 +106,9 @@ true true + + true + false @@ -114,6 +117,8 @@ true true + + true false @@ -181,6 +186,7 @@ <_EmccCommonFlags Include="$(_DefaultEmccFlags)" /> <_EmccCommonFlags Include="$(EmccFlags)" /> <_EmccCommonFlags Include="-s DISABLE_EXCEPTION_CATCHING=0" /> + <_EmccCommonFlags Include="-s EXPORT_ES6=1" Condition="'$(WasmEnableES6)' == 'true'" /> <_EmccCommonFlags Include="-g" Condition="'$(WasmNativeStrip)' == 'false'" /> <_EmccCommonFlags Include="-v" Condition="'$(EmccVerbose)' != 'false'" /> @@ -222,8 +228,18 @@ <_WasmRuntimePackSrcFile ObjectFile="$(_WasmIntermediateOutputPath)%(FileName).o" /> - <_DotnetJSSrcFile Include="$(_WasmRuntimePackSrcDir)\*.js" Exclude="$(_WasmRuntimePackSrcDir)\*.iffe.js"/> - <_WasmExtraJSFile Include="$(_WasmRuntimePackSrcDir)\*.iffe.js" Kind="extern-pre-js" /> + + + + + + + + + <_WasmExtraJSFile Include="$(_WasmRuntimePackSrcDir)\*.%(JSFileType.Identity)" Kind="%(JSFileType.Kind)" /> + <_WasmExtraJSFile Include="$(_WasmRuntimePackSrcDir)\cjs\*.%(JSFileType.Identity)" Kind="%(JSFileType.Kind)" Condition="'$(WasmEnableES6)' != 'true'" /> + <_WasmExtraJSFile Include="$(_WasmRuntimePackSrcDir)\es6\*.%(JSFileType.Identity)" Kind="%(JSFileType.Kind)" Condition="'$(WasmEnableES6)' == 'true'" /> + <_WasmNativeFileForLinking Include="@(NativeFileReference)" /> @@ -270,8 +286,9 @@ - - + + + <_EmBuilder Condition="$([MSBuild]::IsOSPlatform('WINDOWS'))">embuilder.bat @@ -351,14 +368,9 @@ <_WasmExtraJSFile Include="@(Content)" Condition="'%(Content.Extension)' == '.js'" /> <_EmccLinkStepArgs Include="@(_EmccLDFlags)" /> - <_EmccLinkStepArgs Include="--js-library "%(_DotnetJSSrcFile.Identity)"" /> - <_WasmLinkDependencies Include="@(_DotnetJSSrcFile)" /> - - <_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' or '%(_WasmExtraJSFile.Kind)' == 'extern-post-js'" /> + + <_EmccLinkStepArgs Include="--%(_WasmExtraJSFile.Kind) "%(_WasmExtraJSFile.Identity)"" Condition="'%(_WasmExtraJSFile.Kind)' != ''" /> + <_WasmLinkDependencies Include="@(_WasmExtraJSFile)" /> <_EmccLinkStepArgs Include=""%(_WasmNativeFileForLinking.Identity)"" /> <_WasmLinkDependencies Include="@(_WasmNativeFileForLinking)" /> diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs index 3d7cdf93ae541..b708352ac8657 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs @@ -574,7 +574,7 @@ public async Task InvalidArrayId() => await CheckInspectLocalsAtBreakpointSite( // Trying to access object as an array if (!DotnetObjectId.TryParse(c_obj_id, out var id) || id.Scheme != "object") - Assert.True(false, "Unexpected object id format. Maybe this test is out of sync with the object id format in library-dotnet.js?"); + Assert.True(false, "Unexpected object id format. Maybe this test is out of sync with the object id format in dotnet.lib.js?"); if (!int.TryParse(id.Value, out var idNum)) Assert.True(false, "Expected a numeric value part of the object id: {c_obj_id}"); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs index c908343d9ef82..60ede3a0a9423 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs @@ -808,7 +808,7 @@ internal async Task GetProperties(string id, JToken fn_args = null, bool return null; var locals = frame_props.Value["result"]; - // FIXME: Should be done when generating the list in library-dotnet.js, but not sure yet + // FIXME: Should be done when generating the list in dotnet.lib.js, but not sure yet // whether to remove it, and how to do it correctly. if (locals is JArray) { diff --git a/src/mono/wasm/runtime/.eslintrc.js b/src/mono/wasm/runtime/.eslintrc.js index 43876b2a90aca..8aacf17304191 100644 --- a/src/mono/wasm/runtime/.eslintrc.js +++ b/src/mono/wasm/runtime/.eslintrc.js @@ -16,7 +16,12 @@ module.exports = { "plugins": [ "@typescript-eslint" ], - "ignorePatterns": ["node_modules/**/*.*", "bin/**/*.*"], + "ignorePatterns": [ + "node_modules/**/*.*", + "bin/**/*.*", + "modularize-cjs/*.js", + "modularize-es6/*.js", + ], "rules": { "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-non-null-assertion": "off", diff --git a/src/mono/wasm/runtime/CMakeLists.txt b/src/mono/wasm/runtime/CMakeLists.txt index 4a67bcfe1a816..5592d3f37c0d9 100644 --- a/src/mono/wasm/runtime/CMakeLists.txt +++ b/src/mono/wasm/runtime/CMakeLists.txt @@ -24,8 +24,8 @@ target_link_libraries(dotnet ${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/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 --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" + LINK_DEPENDS "${NATIVE_BIN_DIR}/src/emcc-default.rsp;${NATIVE_BIN_DIR}/src/cjs/dotnet.pre.js;${NATIVE_BIN_DIR}/src/cjs/runtime.iffe.js;${NATIVE_BIN_DIR}/src/dotnet.lib.js;${NATIVE_BIN_DIR}/src/pal_random.lib.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.post.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.extpost.js;" + LINK_FLAGS "@${NATIVE_BIN_DIR}/src/emcc-default.rsp ${CONFIGURATION_LINK_FLAGS} -DENABLE_NETCORE=1 --extern-pre-js ${NATIVE_BIN_DIR}/src/cjs/runtime.iffe.js --pre-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.pre.js --js-library ${NATIVE_BIN_DIR}/src/dotnet.lib.js --js-library ${NATIVE_BIN_DIR}/src/pal_random.lib.js --post-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.post.js --extern-post-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.extpost.js " RUNTIME_OUTPUT_DIRECTORY "${NATIVE_BIN_DIR}") if(CMAKE_BUILD_TYPE STREQUAL "Release") diff --git a/src/mono/wasm/runtime/library-dotnet.js b/src/mono/wasm/runtime/dotnet.lib.js similarity index 85% rename from src/mono/wasm/runtime/library-dotnet.js rename to src/mono/wasm/runtime/dotnet.lib.js index 49f3bf5878778..8aaf51b8f1f3f 100644 --- a/src/mono/wasm/runtime/library-dotnet.js +++ b/src/mono/wasm/runtime/dotnet.lib.js @@ -6,11 +6,8 @@ const DotNetSupportLib = { $DOTNET: {}, - $MONO: {}, - $BINDING: {}, - $INTERNAL: {}, // 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});", + $DOTNET__postset: "__dotnet_runtime.__initializeImportsAndExports({isGlobal:ENVIRONMENT_IS_GLOBAL, 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 @@ -66,7 +63,4 @@ for (let linked_function of linked_functions) { } autoAddDeps(DotNetSupportLib, "$DOTNET"); -autoAddDeps(DotNetSupportLib, "$MONO"); -autoAddDeps(DotNetSupportLib, "$BINDING"); -autoAddDeps(DotNetSupportLib, "$INTERNAL"); mergeInto(LibraryManager.library, DotNetSupportLib); diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index ca6994dba709c..96976867e8d71 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -28,7 +28,8 @@ import { mono_wasm_load_data_archive, mono_wasm_asm_loaded, mono_wasm_set_main_args, mono_wasm_pre_init, - mono_wasm_on_runtime_initialized + mono_wasm_on_runtime_initialized, + mono_wasm_runtime_is_initialized } from "./startup"; import { mono_set_timeout, schedule_background_exec } from "./scheduling"; import { mono_wasm_load_icu_data, mono_wasm_get_icudt_name } from "./icu"; @@ -149,6 +150,9 @@ function initializeImportsAndExports( // this could be overriden on Module if (!module.onRuntimeInitialized) { module.onRuntimeInitialized = mono_wasm_on_runtime_initialized; + module.ready = module.ready.then(() => { + return mono_wasm_runtime_is_initialized; + }); } if (!module.print) { module.print = console.log; @@ -156,6 +160,20 @@ function initializeImportsAndExports( if (!module.printErr) { module.printErr = console.error; } + if (!module.imports) { + module.imports = {}; + } + if (!module.imports.require) { + module.imports.require = globalThis.require; + } + if (!module.imports.require) { + module.imports.require = (name) => { + const resolve = (module.imports)[name]; + if (!resolve) + throw new Error(`Please provide Module.imports.${name}`); + return resolve; + }; + } if (imports.isGlobal || !module.disableDotNet6Compatibility) { Object.assign(module, api); @@ -341,6 +359,7 @@ interface BINDING { call_assembly_entry_point: typeof mono_call_assembly_entry_point, unbox_mono_obj: typeof unbox_mono_obj } + export interface DotNetPublicAPI { MONO: MONO, BINDING: BINDING, diff --git a/src/mono/wasm/runtime/imports.ts b/src/mono/wasm/runtime/imports.ts index be89b335731c9..5a1918e9c27c9 100644 --- a/src/mono/wasm/runtime/imports.ts +++ b/src/mono/wasm/runtime/imports.ts @@ -24,7 +24,7 @@ export let locateFile: Function; export function setImportsAndExports( imports: { isGlobal: boolean, isNode: boolean, isShell: boolean, isWeb: boolean, locateFile: Function }, exports: { mono: any, binding: any, internal: any, module: any }, -) { +): void { MONO = exports.mono; BINDING = exports.binding; INTERNAL = exports.internal; diff --git a/src/mono/wasm/runtime/modularize-cjs/dotnet.extpost.js b/src/mono/wasm/runtime/modularize-cjs/dotnet.extpost.js new file mode 100644 index 0000000000000..7e1523b6d38be --- /dev/null +++ b/src/mono/wasm/runtime/modularize-cjs/dotnet.extpost.js @@ -0,0 +1,4 @@ + +if (typeof globalThis.Module === "object") { + createDotnetRuntime(() => { return globalThis.Module; }).then((exports) => exports); +} \ No newline at end of file diff --git a/src/mono/wasm/runtime/modularize-cjs/dotnet.post.js b/src/mono/wasm/runtime/modularize-cjs/dotnet.post.js new file mode 100644 index 0000000000000..e025a6fe7a933 --- /dev/null +++ b/src/mono/wasm/runtime/modularize-cjs/dotnet.post.js @@ -0,0 +1,3 @@ +createDotnetRuntime.ready = createDotnetRuntime.ready.then(() => { + return { MONO, BINDING, INTERNAL, Module }; +}) diff --git a/src/mono/wasm/runtime/modularize-cjs/dotnet.pre.js b/src/mono/wasm/runtime/modularize-cjs/dotnet.pre.js new file mode 100644 index 0000000000000..b98da867a3cb0 --- /dev/null +++ b/src/mono/wasm/runtime/modularize-cjs/dotnet.pre.js @@ -0,0 +1,23 @@ +const MONO = {}, BINDING = {}, INTERNAL = {}; +let ENVIRONMENT_IS_GLOBAL = typeof globalThis.Module === "object"; +if (ENVIRONMENT_IS_GLOBAL) { + if (globalThis.Module.ready) { + throw new Error("MONO_WASM: Module.ready couldn't be redefined.") + } + globalThis.Module.ready = Module.ready; + Module = createDotnetRuntime = globalThis.Module; +} +else if (typeof createDotnetRuntime === "function") { + ENVIRONMENT_IS_GLOBAL = false; + Module = { ready: Module.ready }; + const extension = createDotnetRuntime({ MONO, BINDING, INTERNAL, Module }) + if (extension.ready) { + throw new Error("MONO_WASM: Module.ready couldn't be redefined.") + } + Object.assign(Module, extension); + createDotnetRuntime = Module; +} +else { + throw new Error("MONO_WASM: Can't locate global Module object or moduleFactory callback of createDotnetRuntime function.") +} +let require = (name) => { return Module.imports.require(name) }; \ No newline at end of file diff --git a/src/mono/wasm/runtime/modularize-dotnet.md b/src/mono/wasm/runtime/modularize-dotnet.md new file mode 100644 index 0000000000000..55b7692f7b6a0 --- /dev/null +++ b/src/mono/wasm/runtime/modularize-dotnet.md @@ -0,0 +1,94 @@ +# Linked javascript files +They are emcc way how to extend the dotnet.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`. +In `src\mono\wasm\build\WasmApp.Native.targets` we apply them by file naming convention as: `*.extpre.js`,`*.pre.js`, `*.post.js`, `*.extpost.js` +- For ES6 with `WasmEnableES6 == true` from `src/es6`folder +- For CommonJS with `WasmEnableES6 == false` from `src/cjs`folder + +In `src\mono\wasm\runtime\CMakeLists.txt` which links only in-tree, we use same mapping explicitly. Right now CommonJS is default. + +# cjs/modularize-dotnet.extpost.js +- Is at the end of file but is executed first (1) +- Applied only when linking CommonJS +- If `globalThis.Module` exist it takes it and start runtime with it. +- Otherwise user could still use the `createDotnetRuntime` export or `globalThis.createDotnetRuntime` if it was loaded into global namespace. + +# cjs/modularize-dotnet.pre.js +- Executed second (2) +- Applied only when linking CommonJS +- Will try to see if it was executed with `globalThis.Module` and if so, it would use it's instance as `Module`. It would preserve emscriptens `Module.ready` +- Otherwise it would load it would assume it was called via `createDotnetRuntime` export same as described for `modularize-dotnet.prees6.js` below. + +# es6/modularize-dotnet.pre.js +- Executed second (2) +- Applied only when linking ES6 +- Will check that it was passed `moduleFactory` callback. Because of emscripten reasons it has confusing `createDotnetRuntime` name here. +- Will validate `Module.ready` is left un-overriden. + +# runtime.iffe.js +- Executed third (3) +- this is produced from `*.ts` files in this directory by rollupJS. + +# modularize-dotnet.post.js +- Executed last (4) +- When `onRuntimeInitialized` is overriden it would wait for emscriptens `Module.ready` +- Otherwise it would wait for for MonoVM to load all assets and assemblies. +- It would pass on the API exports + +# About new API +The signature is +``` +function createDotnetRuntime(moduleFactory: (api: DotNetExports) => EmscriptenModuleConfig): Promise +``` + +Simplest intended usage looks like this in ES6: +``` +import createDotnetRuntime from './dotnet.js' + +await createDotnetRuntime(() => ({ + configSrc: "./mono-config.json", +})); +``` + +More complex scenario with using APIs, commented +``` +import createDotnetRuntime from './dotnet.js' + +export const { MONO, BINDING } = await createDotnetRuntime(({ MONO, BINDING, Module }) => +// this is callback with no statement, the APIs are only empty shells here and are populated later. +({ + disableDotNet6Compatibility: true, + configSrc: "./mono-config.json", + onConfigLoaded: () => { + // This is called during emscripten `preInit` event, after we fetched config. + + // Module.config is loaded and could be tweaked before application + Module.config.environment_variables["MONO_LOG_LEVEL"]="debug" + + // here we could use API passed into this callback + // call some early available functions + MONO.mono_wasm_setenv("HELLO", "WORLD); + } + onDotNetReady: () => { + // Only when there is no `onRuntimeInitialized` override. + // This is called after all assets are loaded , mapping to legacy `config.loaded_cb`. + // It happens during emscripten `onRuntimeInitialized` after monoVm init + globalization + assemblies. + // This also matches when the top level promise is resolved. + // The original emscripten `Module.ready` promise is replaced this this. + + // at this point both emscripten and monoVM are fully initialized. + Module.FS.chdir(processedArguments.working_dir); + }, + onAbort: (error) => { + set_exit_code(1, error); + }, +})); + +// at this point both emscripten and monoVM are fully initialized. +// we could use the APIs returned and resolved from createDotnetRuntime promise +// both API exports are receiving the same API object instances, i.e. same `MONO` instance. +const run_all = BINDING.bind_static_method ("[debugger-test] DebuggerTest:run_all"); +run_all(); +``` diff --git a/src/mono/wasm/runtime/modularize-es6/dotnet.post.js b/src/mono/wasm/runtime/modularize-es6/dotnet.post.js new file mode 100644 index 0000000000000..e025a6fe7a933 --- /dev/null +++ b/src/mono/wasm/runtime/modularize-es6/dotnet.post.js @@ -0,0 +1,3 @@ +createDotnetRuntime.ready = createDotnetRuntime.ready.then(() => { + return { MONO, BINDING, INTERNAL, Module }; +}) diff --git a/src/mono/wasm/runtime/modularize-es6/dotnet.pre.js b/src/mono/wasm/runtime/modularize-es6/dotnet.pre.js new file mode 100644 index 0000000000000..1400c3558e9d2 --- /dev/null +++ b/src/mono/wasm/runtime/modularize-es6/dotnet.pre.js @@ -0,0 +1,15 @@ +const MONO = {}, BINDING = {}, INTERNAL = {}; +let ENVIRONMENT_IS_GLOBAL = false; +if (typeof createDotnetRuntime === "function") { + Module = { ready: Module.ready }; + const extension = createDotnetRuntime({ MONO, BINDING, INTERNAL, Module }) + if (extension.ready) { + throw new Error("MONO_WASM: Module.ready couldn't be redefined.") + } + Object.assign(Module, extension); + createDotnetRuntime = Module; +} +else { + throw new Error("MONO_WASM: Can't use moduleFactory callback of createDotnetRuntime function.") +} +let require = (name) => { return Module.imports.require(name) }; \ No newline at end of file diff --git a/src/mono/wasm/runtime/rollup.config.js b/src/mono/wasm/runtime/rollup.config.js index 33bbb20e44845..4a80c72a233a4 100644 --- a/src/mono/wasm/runtime/rollup.config.js +++ b/src/mono/wasm/runtime/rollup.config.js @@ -42,16 +42,28 @@ const format = "iife"; const name = "__dotnet_runtime"; export default defineConfig([ + { treeshake: !isDebug, input: "exports.ts", - output: [{ - file: nativeBinDir + "/src/" + outputFileName, - name, - banner, - format, - plugins, - }], + output: [ + // cjs/runtime.iffe.js + { + file: nativeBinDir + "/src/cjs/" + outputFileName, + name, + banner, + format, + plugins, + }, + // es6/runtime.iffe.js + { + file: nativeBinDir + "/src/es6/" + outputFileName, + name, + banner, + format, + plugins, + } + ], plugins: [typescript()] }, { @@ -91,8 +103,11 @@ async function writeWhenChanged(options, bundle) { isOutputChanged = oldHash !== newHash; } if (isOutputChanged) { - if (!await checkFileExists(hashFileName)) { - await mkdir(nativeBinDir + "/src", { recursive: true }); + if (!await checkFileExists(nativeBinDir + "/src/cjs")) { + await mkdir(nativeBinDir + "/src/cjs", { recursive: true }); + } + if (!await checkFileExists(nativeBinDir + "/src/es6")) { + await mkdir(nativeBinDir + "/src/es6", { recursive: true }); } await writeFile(hashFileName, newHash); } else { diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index 1f1059135ef4c..a91f3961d48f1 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -47,12 +47,22 @@ export async function mono_wasm_pre_init(): Promise { } } -export function mono_wasm_on_runtime_initialized(): void { - const moduleExt = Module as EmscriptenModuleMono; - if (!moduleExt.config || moduleExt.config.isError) { +export async function mono_wasm_on_runtime_initialized(): Promise { + /* TODO + if (ENVIRONMENT_IS_NODE) { + const importFn = new Function("module", "name", "return (async () => { if (!module.imports[name]) try { module.imports[name] = await import(name); } catch (err) { } })();"); + await importFn(Module, "fs"); + await importFn(Module, "path"); + await importFn(Module, "fetch"); + await importFn(Module, "crypto"); + await importFn(Module, "ws"); + await importFn(Module, "url"); + }*/ + + if (!Module.config || Module.config.isError) { return; } - mono_load_runtime_and_bcl_args(moduleExt.config); + await mono_load_runtime_and_bcl_args(Module.config); } // Set environment variable NAME to VALUE @@ -347,7 +357,12 @@ export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise< _apply_configuration_from_args(args); - const local_fetch = typeof (args.fetch_file_cb) === "function" ? args.fetch_file_cb : _fetch_asset; + // TODO move polyfills out into separate module + const local_fetch = typeof (Module.imports.fetch) === "function" + ? Module.imports.fetch + : typeof (args.fetch_file_cb) === "function" + ? args.fetch_file_cb + : _fetch_asset; const load_asset = async (asset: AllAssetEntryTypes): Promise => { //TODO we could do module.addRunDependency(asset.name) and delay emscripten run() after all assets are loaded diff --git a/src/mono/wasm/runtime/types.ts b/src/mono/wasm/runtime/types.ts index d452649c96b2e..f265af0ff4047 100644 --- a/src/mono/wasm/runtime/types.ts +++ b/src/mono/wasm/runtime/types.ts @@ -78,7 +78,7 @@ export type MonoConfig = { assets: AllAssetEntryTypes[], // a list of assets to load along with the runtime. each asset is a dictionary-style Object with the following properties: debug_level?: number, // Either this or the next one needs to be set enable_debugging?: number, // Either this or the previous one needs to be set - fetch_file_cb?: Request, // a function (string) invoked to fetch a given file. If no callback is provided a default implementation appropriate for the current environment will be selected (readFileSync in node, fetch elsewhere). If no default implementation is available this call will fail. + fetch_file_cb?: Function, // a function (string) invoked to fetch a given file. If no callback is provided a default implementation appropriate for the current environment will be selected (readFileSync in node, fetch elsewhere). If no default implementation is available this call will fail. globalization_mode: GlobalizationMode, // configures the runtime's globalization mode diagnostic_tracing?: boolean // enables diagnostic log messages during startup remote_sources?: string[], // additional search locations for assets. Sources will be checked in sequential order until the asset is found. The string "./" indicates to load from the application directory (as with the files in assembly_list), and a fully-qualified URL like "https://example.com/" indicates that asset loads can be attempted from a remote server. Sources must end with a "/". @@ -190,8 +190,23 @@ export type EmscriptenModuleConfig = { onConfigLoaded?: () => void; onDotNetReady?: () => void; - /** - * @deprecated DEPRECATED! backward compatibility https://github.com/search?q=mono_bind_static_method&type=Code - */ - mono_bind_static_method: (fqn: string, signature: string) => Function, + imports: { + require: (name: string) => any; + fetch: (url: string) => Promise; + fs: { + promises: { + readFile: (path: string) => Promise, + readFileSync: (path: string, options: string | undefined) => string, + } + }; + crypto: { + randomBytes: (size: number) => Buffer + }; + ws: WebSocket & { Server: any }; + path: { + normalize: (path: string) => string, + dirname: (path: string) => string, + }; + url: any; + } } diff --git a/src/mono/wasm/runtime/types/emscripten.d.ts b/src/mono/wasm/runtime/types/emscripten.d.ts index 51dbcbe364cfe..234c512558618 100644 --- a/src/mono/wasm/runtime/types/emscripten.d.ts +++ b/src/mono/wasm/runtime/types/emscripten.d.ts @@ -52,6 +52,7 @@ declare interface EmscriptenModule { removeRunDependency(id: string): void; addRunDependency(id: string): void; + ready: Promise; preInit?: (() => Promise)[]; onRuntimeInitialized?: () => void; } diff --git a/src/mono/wasm/test-main.js b/src/mono/wasm/test-main.js index 8ef7f699b10ea..aa89ea164c276 100644 --- a/src/mono/wasm/test-main.js +++ b/src/mono/wasm/test-main.js @@ -67,33 +67,34 @@ for (let m of methods) { } } -function proxyJson(func) { - for (let m of ["log", ...methods]) - console[m] = proxyMethod(`console.${m}`, func, true); -} - let consoleWebSocket; if (is_browser) { const consoleUrl = `${window.location.origin}/console`.replace('http://', 'ws://'); consoleWebSocket = new WebSocket(consoleUrl); - // redirect output so that when emscripten starts it's already redirected - proxyJson(function (msg) { + consoleWebSocket.onopen = function (event) { + originalConsole.log("browser: Console websocket connected."); + }; + consoleWebSocket.onerror = function (event) { + originalConsole.error(`websocket error: ${event}`); + }; + consoleWebSocket.onclose = function (event) { + originalConsole.error(`websocket closed: ${event}`); + }; + + const send = (msg) => { if (consoleWebSocket.readyState === WebSocket.OPEN) { consoleWebSocket.send(msg); } else { originalConsole.log(msg); } - }); + } - consoleWebSocket.onopen = function (event) { - originalConsole.log("browser: Console websocket connected."); - }; - consoleWebSocket.onerror = function (event) { - originalConsole.error(`websocket error: ${event}`); - }; + // redirect output early, so that when emscripten starts it's already redirected + for (let m of ["log", ...methods]) + console[m] = proxyMethod(`console.${m}`, send, true); } if (typeof globalThis.crypto === 'undefined') { @@ -121,48 +122,56 @@ if (typeof globalThis.performance === 'undefined') { } } } -var Module = { - config: null, - configSrc: "./mono-config.json", - onConfigLoaded: () => { - if (!Module.config) { - 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) { - Module.config.environment_variables[variable] = processedArguments.setenv[variable]; - } - - if (!processedArguments.enable_gc) { - INTERNAL.mono_wasm_enable_on_demand_gc(0); - } - }, - onDotNetReady: () => { - let wds = Module.FS.stat(processedArguments.working_dir); - if (wds === undefined || !Module.FS.isDir(wds.mode)) { - set_exit_code(1, `Could not find working directory ${processedArguments.working_dir}`); - return; - } - - Module.FS.chdir(processedArguments.working_dir); +loadDotnet("./dotnet.js").then((createDotnetRuntime) => { + return createDotnetRuntime(({ MONO, INTERNAL, BINDING, Module }) => ({ + disableDotNet6Compatibility: true, + config: null, + configSrc: "./mono-config.json", + onConfigLoaded: () => { + if (!Module.config) { + 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) { + Module.config.environment_variables[variable] = processedArguments.setenv[variable]; + } - App.init(); - }, - onAbort: (error) => { - console.log("ABORT: " + error); - const err = new Error(); - console.log("Stacktrace: \n"); - console.error(err.stack); - set_exit_code(1, error); - }, -}; + if (!processedArguments.enable_gc) { + INTERNAL.mono_wasm_enable_on_demand_gc(0); + } + }, + onDotNetReady: () => { + let wds = Module.FS.stat(processedArguments.working_dir); + if (wds === undefined || !Module.FS.isDir(wds.mode)) { + set_exit_code(1, `Could not find working directory ${processedArguments.working_dir}`); + return; + } + Module.FS.chdir(processedArguments.working_dir); + + App.init({ MONO, INTERNAL, BINDING, Module }); + }, + onAbort: (error) => { + console.log("ABORT: " + error); + const err = new Error(); + console.log("Stacktrace: \n"); + console.error(err.stack); + set_exit_code(1, error); + }, + })) +}).catch(function (err) { + console.error(err); + set_exit_code(1, "failed to load the dotnet.js file"); + throw err; +}); const App = { - init: async function () { + init: async function ({ MONO, INTERNAL, BINDING, Module }) { console.info("Initializing....."); + Object.assign(App, { MONO, INTERNAL, BINDING, Module }); + for (let i = 0; i < processedArguments.profilers.length; ++i) { const init = Module.cwrap('mono_wasm_load_profiler_' + processedArguments.profilers[i], 'void', ['string']); init(""); @@ -228,7 +237,7 @@ const App = { const fqn = "[System.Private.Runtime.InteropServices.JavaScript.Tests]System.Runtime.InteropServices.JavaScript.Tests.HelperMarshal:" + method_name; try { - return INTERNAL.call_static_method(fqn, args || [], signature); + return App.INTERNAL.call_static_method(fqn, args || [], signature); } catch (exc) { console.error("exception thrown in", fqn); throw exc; @@ -244,12 +253,15 @@ function set_exit_code(exit_code, reason) { 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} isXmlDoneCheck=${isXmlDoneCheck} WS.bufferedAmount=${consoleWebSocket.bufferedAmount} ${stack}.`; + // 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} isXmlDoneCheck=${isXmlDoneCheck} WS.bufferedAmount=${consoleWebSocket.bufferedAmount} ${stack}.`; - // Notify the selenium script - Module.exit_code = exit_code; + if (App.Module) { + // Notify the selenium script + App.Module.exit_code = exit_code; + } //Tell xharness WasmBrowserTestRunner what was the exit code const tests_done_elem = document.createElement("label"); @@ -257,8 +269,8 @@ function set_exit_code(exit_code, reason) { tests_done_elem.innerHTML = exit_code.toString(); document.body.appendChild(tests_done_elem); - console.log('WS: ' + messsage); - originalConsole.log('CDP: ' + messsage); + // console.log('WS: ' + messsage); + // originalConsole.log('CDP: ' + messsage); const stop_when_ws_buffer_empty = () => { if (consoleWebSocket.bufferedAmount == 0) { // tell xharness WasmTestMessagesProcessor we are done. @@ -354,7 +366,7 @@ async function loadDotnet(file) { if (typeof WScript !== "undefined") { // Chakra loadScript = function (file) { WScript.LoadScriptFile(file); - return globalThis.Module; + return globalThis.createDotnetRuntime; }; } else if (is_node) { // NodeJS loadScript = async function (file) { @@ -368,8 +380,8 @@ async function loadDotnet(file) { let timeout = 100; // bysy spin waiting for script to load into global namespace while (timeout > 0) { - if (globalThis.Module) { - return globalThis.Module; + if (globalThis.createDotnetRuntime) { + return globalThis.createDotnetRuntime; } // delay 10ms await new Promise(resolve => setTimeout(resolve, 10)); @@ -381,7 +393,7 @@ async function loadDotnet(file) { else if (typeof globalThis.load !== 'undefined') { loadScript = async function (file) { globalThis.load(file) - return globalThis.Module; + return globalThis.createDotnetRuntime; } } else { @@ -390,9 +402,3 @@ async function loadDotnet(file) { return loadScript(file); } - -loadDotnet("./dotnet.js").catch(function (err) { - console.error(err); - set_exit_code(1, "failed to load the dotnet.js file"); - throw err; -}); \ No newline at end of file diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index 68482d708962c..5e305bd72b8e2 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -71,8 +71,9 @@ <_EmccCommonFlags Include="--source-map-base http://example.com" /> <_EmccCommonFlags Include="-s STRICT_JS=1" /> - <_EmccCommonFlags Include="-s MODULARIZE=1" Condition="'$(WasmEnableES6)' != 'false'" /> - <_EmccCommonFlags Include="-s EXPORT_ES6=1" Condition="'$(WasmEnableES6)' != 'false'" /> + <_EmccCommonFlags Include="-s EXPORT_NAME="'createDotnetRuntime'"" /> + <_EmccCommonFlags Include="-s MODULARIZE=1"/> + <_EmccCommonFlags Include="-s EXPORT_ES6=1" Condition="'$(WasmEnableES6)' == 'true'" /> @@ -152,7 +153,8 @@ $(CMakeConfigurationEmccFlags) -O2 -DEMSDK_PATH="$(EMSDK_PATH.TrimEnd('\/'))" - emcmake cmake $(MSBuildThisFileDirectory)runtime -DCMAKE_BUILD_TYPE=$(Configuration) -DCONFIGURATION_EMCC_FLAGS="$(CMakeConfigurationEmccFlags)" -DCONFIGURATION_LINK_FLAGS="$(CMakeConfigurationLinkFlags)" -DMONO_INCLUDES="$(MonoArtifactsPath)include/mono-2.0" -DMONO_OBJ_INCLUDES="$(MonoObjDir.TrimEnd('\/'))" -DICU_LIB_DIR="$(ICULibDir.TrimEnd('\/'))" -DMONO_ARTIFACTS_DIR="$(MonoArtifactsPath.TrimEnd('\/'))" -DNATIVE_BIN_DIR="$(NativeBinDir.TrimEnd('\/'))" -DSYSTEM_NATIVE_DIR="$(RepoRoot)src/libraries/Native/Unix/System.Native" -DSOURCE_DIR="$(MSBuildThisFileDirectory.TrimEnd('\/'))/runtime"$(CMakeConfigurationEmsdkPath) + emcmake cmake $(MSBuildThisFileDirectory)runtime -DCMAKE_BUILD_TYPE=$(Configuration) -DCONFIGURATION_EMCC_FLAGS="$(CMakeConfigurationEmccFlags)" -DCONFIGURATION_LINK_FLAGS="$(CMakeConfigurationLinkFlags)" -DMONO_INCLUDES="$(MonoArtifactsPath)include/mono-2.0" -DMONO_OBJ_INCLUDES="$(MonoObjDir.TrimEnd('\/'))" -DICU_LIB_DIR="$(ICULibDir.TrimEnd('\/'))" -DMONO_ARTIFACTS_DIR="$(MonoArtifactsPath.TrimEnd('\/'))" -DNATIVE_BIN_DIR="$(NativeBinDir.TrimEnd('\/'))" + emcmake cmake $(MSBuildThisFileDirectory)runtime -DCMAKE_BUILD_TYPE=$(Configuration) -DCONFIGURATION_EMCC_FLAGS="$(CMakeConfigurationEmccFlags)" -DCONFIGURATION_LINK_FLAGS="$(CMakeConfigurationLinkFlags)" -DMONO_INCLUDES="$(MonoArtifactsPath)include/mono-2.0" -DMONO_OBJ_INCLUDES="$(MonoObjDir.TrimEnd('\/'))" -DICU_LIB_DIR="$(ICULibDir.TrimEnd('\/'))" -DMONO_ARTIFACTS_DIR="$(MonoArtifactsPath.TrimEnd('\/'))" -DNATIVE_BIN_DIR="$(NativeBinDir.TrimEnd('\/'))" $(CMakeConfigurationEmsdkPath) call "$(RepositoryEngineeringDir)native\init-vs-env.cmd" && call "$([MSBuild]::NormalizePath('$(EMSDK_PATH)', 'emsdk_env.bat'))" && $(CMakeBuildRuntimeConfigureCmd) bash -c 'source $(EMSDK_PATH)/emsdk_env.sh 2>&1 && $(CMakeBuildRuntimeConfigureCmd)' @@ -181,11 +183,22 @@ + + + + @@ -203,6 +216,8 @@ $(NativeBinDir)src\*.js; $(_EmccDefaultsRspPath); $(NativeBinDir)src\emcc-props.json" /> + + @@ -221,6 +236,14 @@ DestinationFolder="$(MicrosoftNetCoreAppRuntimePackNativeDir)src" SkipUnchangedFiles="true" /> + + + + From 5c3a3130f752eada16e5518555b98f28dfffac62 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 24 Nov 2021 10:22:33 +0100 Subject: [PATCH 02/28] return back the hack for _MonoSelectRuntimeComponents --- src/mono/wasm/build/WasmApp.InTree.targets | 14 -------------- src/mono/wasm/build/WasmApp.Native.targets | 21 +++++++++++++++++---- src/mono/wasm/test-main.js | 4 ++-- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/mono/wasm/build/WasmApp.InTree.targets b/src/mono/wasm/build/WasmApp.InTree.targets index d5c0764f1726f..3e122f8007ae9 100644 --- a/src/mono/wasm/build/WasmApp.InTree.targets +++ b/src/mono/wasm/build/WasmApp.InTree.targets @@ -52,18 +52,4 @@ - - - <_MonoRuntimeComponentDontLink Include="libmono-component-diagnostics_tracing-static.a"/> - - - <_MonoRuntimeComponentDontLink Include="libmono-component-hot_reload-static.a"/> - <_MonoRuntimeComponentDontLink Include="libmono-component-debugger-static.a"/> - - - <_MonoRuntimeComponentDontLink Include="libmono-component-hot_reload-stub-static.a"/> - <_MonoRuntimeComponentDontLink Include="libmono-component-debugger-stub-static.a"/> - - - diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets index 1f0ace7dec788..b02fd347bc868 100644 --- a/src/mono/wasm/build/WasmApp.Native.targets +++ b/src/mono/wasm/build/WasmApp.Native.targets @@ -286,9 +286,22 @@ - - - + + + + + <_MonoRuntimeComponentDontLink Include="libmono-component-diagnostics_tracing-static.a"/> + + + <_MonoRuntimeComponentDontLink Include="libmono-component-hot_reload-static.a"/> + <_MonoRuntimeComponentDontLink Include="libmono-component-debugger-static.a"/> + + + <_MonoRuntimeComponentDontLink Include="libmono-component-hot_reload-stub-static.a"/> + <_MonoRuntimeComponentDontLink Include="libmono-component-debugger-stub-static.a"/> + + + <_EmBuilder Condition="$([MSBuild]::IsOSPlatform('WINDOWS'))">embuilder.bat @@ -390,7 +403,7 @@ diff --git a/src/mono/wasm/test-main.js b/src/mono/wasm/test-main.js index aa89ea164c276..f31b253ec3c45 100644 --- a/src/mono/wasm/test-main.js +++ b/src/mono/wasm/test-main.js @@ -283,8 +283,8 @@ function set_exit_code(exit_code, reason) { }; stop_when_ws_buffer_empty(); - } else if (INTERNAL) { - INTERNAL.mono_wasm_exit(exit_code); + } else if (App && App.INTERNAL) { + App.INTERNAL.mono_wasm_exit(exit_code); } } From 83998762e495e58a118387d78511c85167094983 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 24 Nov 2021 17:39:16 +0100 Subject: [PATCH 03/28] folders in nupkg are hard --- eng/liveBuilds.targets | 11 +++++++++++ .../Microsoft.NETCore.App/Directory.Build.props | 14 +++++++------- src/mono/wasm/Makefile | 2 +- src/mono/wasm/runtime/CMakeLists.txt | 4 ++-- .../{dotnet.extpost.js => dotnet.cjs.extpost.js} | 0 .../{dotnet.post.js => dotnet.cjs.post.js} | 0 .../{dotnet.pre.js => dotnet.cjs.pre.js} | 0 src/mono/wasm/runtime/modularize-dotnet.md | 10 +++++----- .../{dotnet.post.js => dotnet.es6.post.js} | 0 .../{dotnet.pre.js => dotnet.es6.pre.js} | 0 src/mono/wasm/runtime/rollup.config.js | 12 +++++------- src/mono/wasm/wasm.proj | 10 +++++----- 12 files changed, 36 insertions(+), 27 deletions(-) rename src/mono/wasm/runtime/modularize-cjs/{dotnet.extpost.js => dotnet.cjs.extpost.js} (100%) rename src/mono/wasm/runtime/modularize-cjs/{dotnet.post.js => dotnet.cjs.post.js} (100%) rename src/mono/wasm/runtime/modularize-cjs/{dotnet.pre.js => dotnet.cjs.pre.js} (100%) rename src/mono/wasm/runtime/modularize-es6/{dotnet.post.js => dotnet.es6.post.js} (100%) rename src/mono/wasm/runtime/modularize-es6/{dotnet.pre.js => dotnet.es6.pre.js} (100%) diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets index 1cd7a1d81a2aa..6722d39f337ad 100644 --- a/eng/liveBuilds.targets +++ b/eng/liveBuilds.targets @@ -184,10 +184,21 @@ Include=" $(LibrariesNativeArtifactsPath)src\*.c; $(LibrariesNativeArtifactsPath)src\*.js; + $(LibrariesNativeArtifactsPath)src\*.ts; $(LibrariesNativeArtifactsPath)src\emcc-default.rsp; $(LibrariesNativeArtifactsPath)src\emcc-props.json;" NativeSubDirectory="src" IsNative="true" /> + + - - - - - - - + + + + + + + diff --git a/src/mono/wasm/Makefile b/src/mono/wasm/Makefile index 9739030ebaeb9..1afe3b8b75b6a 100644 --- a/src/mono/wasm/Makefile +++ b/src/mono/wasm/Makefile @@ -93,7 +93,7 @@ $(NATIVE_BIN_DIR)/include/wasm: $(BUILDS_OBJ_DIR): mkdir -p $$@ -$(NATIVE_BIN_DIR)/dotnet.js: runtime/driver.c runtime/pinvoke.c runtime/pinvoke.h runtime/corebindings.c $(NATIVE_BIN_DIR)/src/runtime.iffe.js runtime/dotnet.lib.js $(SYSTEM_NATIVE_LIBDIR)/pal_random.lib.js $(MONO_LIBS) $(EMCC_DEFAULT_RSP) | $(NATIVE_BIN_DIR) +$(NATIVE_BIN_DIR)/dotnet.js: runtime/driver.c runtime/pinvoke.c runtime/pinvoke.h runtime/corebindings.c $(NATIVE_BIN_DIR)/src/cjs/runtime.cjs.iffe.js runtime/dotnet.lib.js $(SYSTEM_NATIVE_LIBDIR)/pal_random.lib.js $(MONO_LIBS) $(EMCC_DEFAULT_RSP) | $(NATIVE_BIN_DIR) $(DOTNET) build $(CURDIR)/wasm.proj $(_MSBUILD_WASM_BUILD_ARGS) /t:BuildWasmRuntimes $(MSBUILD_ARGS) $(EMCC_DEFAULT_RSP): $(CURDIR)/wasm.proj | $(NATIVE_BIN_DIR)/src Makefile diff --git a/src/mono/wasm/runtime/CMakeLists.txt b/src/mono/wasm/runtime/CMakeLists.txt index 5592d3f37c0d9..4deaf16360c6e 100644 --- a/src/mono/wasm/runtime/CMakeLists.txt +++ b/src/mono/wasm/runtime/CMakeLists.txt @@ -24,8 +24,8 @@ target_link_libraries(dotnet ${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/cjs/dotnet.pre.js;${NATIVE_BIN_DIR}/src/cjs/runtime.iffe.js;${NATIVE_BIN_DIR}/src/dotnet.lib.js;${NATIVE_BIN_DIR}/src/pal_random.lib.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.post.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.extpost.js;" - LINK_FLAGS "@${NATIVE_BIN_DIR}/src/emcc-default.rsp ${CONFIGURATION_LINK_FLAGS} -DENABLE_NETCORE=1 --extern-pre-js ${NATIVE_BIN_DIR}/src/cjs/runtime.iffe.js --pre-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.pre.js --js-library ${NATIVE_BIN_DIR}/src/dotnet.lib.js --js-library ${NATIVE_BIN_DIR}/src/pal_random.lib.js --post-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.post.js --extern-post-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.extpost.js " + LINK_DEPENDS "${NATIVE_BIN_DIR}/src/emcc-default.rsp;${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.pre.js;${NATIVE_BIN_DIR}/src/cjs/runtime.cjs.iffe.js;${NATIVE_BIN_DIR}/src/dotnet.lib.js;${NATIVE_BIN_DIR}/src/pal_random.lib.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.post.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.extpost.js;" + LINK_FLAGS "@${NATIVE_BIN_DIR}/src/emcc-default.rsp ${CONFIGURATION_LINK_FLAGS} -DENABLE_NETCORE=1 --extern-pre-js ${NATIVE_BIN_DIR}/src/cjs/runtime.cjs.iffe.js --pre-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.pre.js --js-library ${NATIVE_BIN_DIR}/src/dotnet.lib.js --js-library ${NATIVE_BIN_DIR}/src/pal_random.lib.js --post-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.post.js --extern-post-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.extpost.js " RUNTIME_OUTPUT_DIRECTORY "${NATIVE_BIN_DIR}") if(CMAKE_BUILD_TYPE STREQUAL "Release") diff --git a/src/mono/wasm/runtime/modularize-cjs/dotnet.extpost.js b/src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.extpost.js similarity index 100% rename from src/mono/wasm/runtime/modularize-cjs/dotnet.extpost.js rename to src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.extpost.js diff --git a/src/mono/wasm/runtime/modularize-cjs/dotnet.post.js b/src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.post.js similarity index 100% rename from src/mono/wasm/runtime/modularize-cjs/dotnet.post.js rename to src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.post.js diff --git a/src/mono/wasm/runtime/modularize-cjs/dotnet.pre.js b/src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.pre.js similarity index 100% rename from src/mono/wasm/runtime/modularize-cjs/dotnet.pre.js rename to src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.pre.js diff --git a/src/mono/wasm/runtime/modularize-dotnet.md b/src/mono/wasm/runtime/modularize-dotnet.md index 55b7692f7b6a0..d85526ea09650 100644 --- a/src/mono/wasm/runtime/modularize-dotnet.md +++ b/src/mono/wasm/runtime/modularize-dotnet.md @@ -9,29 +9,29 @@ In `src\mono\wasm\build\WasmApp.Native.targets` we apply them by file naming con In `src\mono\wasm\runtime\CMakeLists.txt` which links only in-tree, we use same mapping explicitly. Right now CommonJS is default. -# cjs/modularize-dotnet.extpost.js +# dotnet.cjs.extpost.js - Is at the end of file but is executed first (1) - Applied only when linking CommonJS - If `globalThis.Module` exist it takes it and start runtime with it. - Otherwise user could still use the `createDotnetRuntime` export or `globalThis.createDotnetRuntime` if it was loaded into global namespace. -# cjs/modularize-dotnet.pre.js +# dotnet.cjs.pre.js - Executed second (2) - Applied only when linking CommonJS - Will try to see if it was executed with `globalThis.Module` and if so, it would use it's instance as `Module`. It would preserve emscriptens `Module.ready` - Otherwise it would load it would assume it was called via `createDotnetRuntime` export same as described for `modularize-dotnet.prees6.js` below. -# es6/modularize-dotnet.pre.js +# dotnet.es6.pre.js - Executed second (2) - Applied only when linking ES6 - Will check that it was passed `moduleFactory` callback. Because of emscripten reasons it has confusing `createDotnetRuntime` name here. - Will validate `Module.ready` is left un-overriden. -# runtime.iffe.js +# runtime.*.iffe.js - Executed third (3) - this is produced from `*.ts` files in this directory by rollupJS. -# modularize-dotnet.post.js +# dotnet.*.post.js - Executed last (4) - When `onRuntimeInitialized` is overriden it would wait for emscriptens `Module.ready` - Otherwise it would wait for for MonoVM to load all assets and assemblies. diff --git a/src/mono/wasm/runtime/modularize-es6/dotnet.post.js b/src/mono/wasm/runtime/modularize-es6/dotnet.es6.post.js similarity index 100% rename from src/mono/wasm/runtime/modularize-es6/dotnet.post.js rename to src/mono/wasm/runtime/modularize-es6/dotnet.es6.post.js diff --git a/src/mono/wasm/runtime/modularize-es6/dotnet.pre.js b/src/mono/wasm/runtime/modularize-es6/dotnet.es6.pre.js similarity index 100% rename from src/mono/wasm/runtime/modularize-es6/dotnet.pre.js rename to src/mono/wasm/runtime/modularize-es6/dotnet.es6.pre.js diff --git a/src/mono/wasm/runtime/rollup.config.js b/src/mono/wasm/runtime/rollup.config.js index 4a80c72a233a4..4133bf0ab6336 100644 --- a/src/mono/wasm/runtime/rollup.config.js +++ b/src/mono/wasm/runtime/rollup.config.js @@ -6,7 +6,6 @@ import * as fs from "fs"; import { createHash } from "crypto"; import dts from "rollup-plugin-dts"; -const outputFileName = "runtime.iffe.js"; const isDebug = process.env.Configuration !== "Release"; const nativeBinDir = process.env.NativeBinDir ? process.env.NativeBinDir.replace(/"/g, "") : "bin"; const terserConfig = { @@ -47,17 +46,15 @@ export default defineConfig([ treeshake: !isDebug, input: "exports.ts", output: [ - // cjs/runtime.iffe.js { - file: nativeBinDir + "/src/cjs/" + outputFileName, + file: nativeBinDir + "/src/cjs/runtime.cjs.iffe.js", name, banner, format, plugins, }, - // es6/runtime.iffe.js { - file: nativeBinDir + "/src/es6/" + outputFileName, + file: nativeBinDir + "/src/es6/runtime.es6.iffe.js", name, banner, format, @@ -89,7 +86,8 @@ function writeOnChangePlugin() { async function writeWhenChanged(options, bundle) { try { - const asset = bundle[outputFileName]; + const name = Object.keys(bundle)[0]; + const asset = bundle[name]; const code = asset.code; const hashFileName = options.file + ".sha256"; const oldHashExists = await checkFileExists(hashFileName); @@ -112,7 +110,7 @@ async function writeWhenChanged(options, bundle) { await writeFile(hashFileName, newHash); } else { // this.warn('No change in ' + options.file) - delete bundle[outputFileName]; + delete bundle[name]; } } catch (ex) { this.warn(ex.toString()); diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index 5e305bd72b8e2..7eb6c6caabd68 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -188,14 +188,14 @@ DestinationFolder="$(NativeBinDir)src" SkipUnchangedFiles="true" /> - - From e25050d9a02f15cfeaccb6599867057b720c6eb9 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 25 Nov 2021 09:05:29 +0100 Subject: [PATCH 04/28] feedback --- ...asm.Browser.Sample.csproj => Wasm.Browser.ES6.Sample.csproj} | 2 +- src/mono/sample/wasm/browser-es6/main.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/mono/sample/wasm/browser-es6/{Wasm.Browser.Sample.csproj => Wasm.Browser.ES6.Sample.csproj} (90%) diff --git a/src/mono/sample/wasm/browser-es6/Wasm.Browser.Sample.csproj b/src/mono/sample/wasm/browser-es6/Wasm.Browser.ES6.Sample.csproj similarity index 90% rename from src/mono/sample/wasm/browser-es6/Wasm.Browser.Sample.csproj rename to src/mono/sample/wasm/browser-es6/Wasm.Browser.ES6.Sample.csproj index 8ae5482f8bb7e..a617dd85614f2 100644 --- a/src/mono/sample/wasm/browser-es6/Wasm.Browser.Sample.csproj +++ b/src/mono/sample/wasm/browser-es6/Wasm.Browser.ES6.Sample.csproj @@ -14,7 +14,7 @@ - <_SampleProject>Wasm.Browser.Sample.csproj + <_SampleProject>Wasm.Browser.ES6.Sample.csproj diff --git a/src/mono/sample/wasm/browser-es6/main.js b/src/mono/sample/wasm/browser-es6/main.js index ec88e870212e5..5bf06e2171125 100644 --- a/src/mono/sample/wasm/browser-es6/main.js +++ b/src/mono/sample/wasm/browser-es6/main.js @@ -10,7 +10,7 @@ const { MONO, BINDING, Module } = await createDotnetRuntime(() => ({ const App = { init: function () { - const testMeaning = BINDING.bind_static_method("[Wasm.Browser.Sample] Sample.Test:TestMeaning"); + const testMeaning = BINDING.bind_static_method("[Wasm.Browser.ES6.Sample] Sample.Test:TestMeaning"); const ret = testMeaning(); document.getElementById("out").innerHTML = ret; From 5a3f6b15583f0999b0db5e07155a3b1175f76136 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Thu, 25 Nov 2021 15:10:22 +0100 Subject: [PATCH 05/28] minor fixes --- src/mono/wasm/build/WasmApp.InTree.targets | 1 - src/mono/wasm/runtime/startup.ts | 5 +++-- src/mono/wasm/runtime/types.ts | 2 -- src/mono/wasm/wasm.proj | 4 ++-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/mono/wasm/build/WasmApp.InTree.targets b/src/mono/wasm/build/WasmApp.InTree.targets index 3e122f8007ae9..b4f2af25b0afd 100644 --- a/src/mono/wasm/build/WasmApp.InTree.targets +++ b/src/mono/wasm/build/WasmApp.InTree.targets @@ -51,5 +51,4 @@ - diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index a91f3961d48f1..65e7b6bb3ec95 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -360,8 +360,9 @@ export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise< // TODO move polyfills out into separate module const local_fetch = typeof (Module.imports.fetch) === "function" ? Module.imports.fetch - : typeof (args.fetch_file_cb) === "function" - ? args.fetch_file_cb + // legacy fallback + : typeof ((args).fetch_file_cb) === "function" + ? (args).fetch_file_cb : _fetch_asset; const load_asset = async (asset: AllAssetEntryTypes): Promise => { diff --git a/src/mono/wasm/runtime/types.ts b/src/mono/wasm/runtime/types.ts index f265af0ff4047..47898395eddc9 100644 --- a/src/mono/wasm/runtime/types.ts +++ b/src/mono/wasm/runtime/types.ts @@ -78,7 +78,6 @@ export type MonoConfig = { assets: AllAssetEntryTypes[], // a list of assets to load along with the runtime. each asset is a dictionary-style Object with the following properties: debug_level?: number, // Either this or the next one needs to be set enable_debugging?: number, // Either this or the previous one needs to be set - fetch_file_cb?: Function, // a function (string) invoked to fetch a given file. If no callback is provided a default implementation appropriate for the current environment will be selected (readFileSync in node, fetch elsewhere). If no default implementation is available this call will fail. globalization_mode: GlobalizationMode, // configures the runtime's globalization mode diagnostic_tracing?: boolean // enables diagnostic log messages during startup remote_sources?: string[], // additional search locations for assets. Sources will be checked in sequential order until the asset is found. The string "./" indicates to load from the application directory (as with the files in assembly_list), and a fully-qualified URL like "https://example.com/" indicates that asset loads can be attempted from a remote server. Sources must end with a "/". @@ -184,7 +183,6 @@ export type EmscriptenModuleMono = EmscriptenModule & EmscriptenModuleConfig; export type EmscriptenModuleConfig = { disableDotNet6Compatibility?: boolean, - // backward compatibility config?: MonoConfig | MonoConfigError, configSrc?: string, onConfigLoaded?: () => void; diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index 825bfca17ab07..a0b24929f9712 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -153,8 +153,8 @@ $(CMakeConfigurationEmccFlags) -O2 -DEMSDK_PATH="$(EMSDK_PATH.TrimEnd('\/'))" - emcmake cmake $(MSBuildThisFileDirectory)runtime -DCMAKE_BUILD_TYPE=$(Configuration) -DCONFIGURATION_EMCC_FLAGS="$(CMakeConfigurationEmccFlags)" -DCONFIGURATION_LINK_FLAGS="$(CMakeConfigurationLinkFlags)" -DMONO_INCLUDES="$(MonoArtifactsPath)include/mono-2.0" -DMONO_OBJ_INCLUDES="$(MonoObjDir.TrimEnd('\/'))" -DICU_LIB_DIR="$(ICULibDir.TrimEnd('\/'))" -DMONO_ARTIFACTS_DIR="$(MonoArtifactsPath.TrimEnd('\/'))" -DNATIVE_BIN_DIR="$(NativeBinDir.TrimEnd('\/'))" -DSYSTEM_NATIVE_DIR="$(RepoRoot)src/native/libs/System.Native" -DSOURCE_DIR="$(MSBuildThisFileDirectory.TrimEnd('\/'))/runtime" $(CMakeConfigurationEmsdkPath) - call "$(RepositoryEngineeringDir)native\init-vs-env.cmd" && call "$([MSBuild]::NormalizePath('$(EMSDK_PATH)', 'emsdk_env.bat'))" && $(CMakeBuildRuntimeConfigureCmd) + emcmake cmake $(MSBuildThisFileDirectory)runtime -DCMAKE_BUILD_TYPE=$(Configuration) -DCONFIGURATION_EMCC_FLAGS="$(CMakeConfigurationEmccFlags)" -DCONFIGURATION_LINK_FLAGS="$(CMakeConfigurationLinkFlags)" -DMONO_INCLUDES="$(MonoArtifactsPath)include/mono-2.0" -DMONO_OBJ_INCLUDES="$(MonoObjDir.TrimEnd('\/'))" -DICU_LIB_DIR="$(ICULibDir.TrimEnd('\/'))" -DMONO_ARTIFACTS_DIR="$(MonoArtifactsPath.TrimEnd('\/'))" -DNATIVE_BIN_DIR="$(NativeBinDir.TrimEnd('\/'))" -DSYSTEM_NATIVE_DIR="$(RepoRoot)src/native/libs/System.Native" -DSOURCE_DIR="$(MSBuildThisFileDirectory.TrimEnd('\/'))/runtime"$(CMakeConfigurationEmsdkPath) + call "$(RepositoryEngineeringDir)native\init-vs-env.cmd" && call "$([MSBuild]::NormalizePath('$(EMSDK_PATH)', 'emsdk_env.bat'))" &&$(CMakeBuildRuntimeConfigureCmd) bash -c 'source $(EMSDK_PATH)/emsdk_env.sh 2>&1 && $(CMakeBuildRuntimeConfigureCmd)' cmake --build . --config $(Configuration) From 864073e10cd9b419704578687eb1a54bd300c19b Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 25 Nov 2021 20:46:57 +0100 Subject: [PATCH 06/28] - move dotnet.d.ts one level up - add package.json to nuget package - unify naming case DotNet to Dotnet - unify emscripten type definitions - export same instance of __dotnet_exportedAPI on all places - write dotnet.d.ts to version control, so that we could observe when it changes --- eng/liveBuilds.targets | 3 +- .../Directory.Build.props | 1 + src/mono/sample/mbr/browser/main.js | 2 +- src/mono/sample/wasm/Directory.Build.targets | 3 + src/mono/sample/wasm/browser-bench/main.js | 2 +- src/mono/sample/wasm/browser-es6/index.html | 4 +- src/mono/sample/wasm/browser-es6/main.js | 6 +- src/mono/sample/wasm/browser-legacy/main.js | 2 +- src/mono/sample/wasm/browser-profile/main.js | 2 +- src/mono/sample/wasm/browser/main.js | 4 +- src/mono/wasm/build/README.md | 2 +- src/mono/wasm/runtime/buffers.ts | 3 +- src/mono/wasm/runtime/cancelable-promise.ts | 3 +- src/mono/wasm/runtime/cs-to-js.ts | 3 +- src/mono/wasm/runtime/cwraps.ts | 4 +- src/mono/wasm/runtime/debug.ts | 2 +- src/mono/wasm/runtime/dist-types/dotnet.d.ts | 272 ++++++++++++++++++ .../runtime/dist-types/dotnet.d.ts.sha256 | 1 + src/mono/wasm/runtime/dotnet.lib.js | 10 +- src/mono/wasm/runtime/export-types.ts | 13 +- src/mono/wasm/runtime/exports.ts | 31 +- src/mono/wasm/runtime/icu.ts | 3 +- src/mono/wasm/runtime/imports.ts | 6 +- src/mono/wasm/runtime/js-to-cs.ts | 3 +- src/mono/wasm/runtime/memory.ts | 1 + src/mono/wasm/runtime/method-binding.ts | 3 +- src/mono/wasm/runtime/method-calls.ts | 5 +- .../runtime/modularize-cjs/dotnet.cjs.post.js | 2 +- src/mono/wasm/runtime/modularize-dotnet.md | 6 +- .../runtime/modularize-es6/dotnet.es6.post.js | 2 +- src/mono/wasm/runtime/package.json | 1 + src/mono/wasm/runtime/rollup.config.js | 90 +++--- src/mono/wasm/runtime/roots.ts | 2 +- src/mono/wasm/runtime/startup.ts | 15 +- src/mono/wasm/runtime/strings.ts | 3 +- src/mono/wasm/runtime/types.ts | 77 ++--- .../types/{emscripten.d.ts => emscripten.ts} | 16 +- src/mono/wasm/runtime/web-socket.ts | 3 +- src/mono/wasm/test-main.js | 4 +- src/mono/wasm/wasm.proj | 7 +- 40 files changed, 453 insertions(+), 169 deletions(-) create mode 100644 src/mono/wasm/runtime/dist-types/dotnet.d.ts create mode 100644 src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 rename src/mono/wasm/runtime/types/{emscripten.d.ts => emscripten.ts} (78%) diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets index 6722d39f337ad..82931609803a2 100644 --- a/eng/liveBuilds.targets +++ b/eng/liveBuilds.targets @@ -176,6 +176,8 @@ + diff --git a/src/mono/sample/mbr/browser/main.js b/src/mono/sample/mbr/browser/main.js index 6294d62187e37..c1ce2f45024c3 100644 --- a/src/mono/sample/mbr/browser/main.js +++ b/src/mono/sample/mbr/browser/main.js @@ -7,7 +7,7 @@ var Module = { onConfigLoaded: function () { MONO.config.environment_variables["DOTNET_MODIFIABLE_ASSEMBLIES"] = "debug"; }, - onDotNetReady: function () { + onDotnetReady: function () { App.init(); }, }; diff --git a/src/mono/sample/wasm/Directory.Build.targets b/src/mono/sample/wasm/Directory.Build.targets index 95415ef67fb16..f3ee714290d2a 100644 --- a/src/mono/sample/wasm/Directory.Build.targets +++ b/src/mono/sample/wasm/Directory.Build.targets @@ -16,6 +16,9 @@ + + + diff --git a/src/mono/sample/wasm/browser-bench/main.js b/src/mono/sample/wasm/browser-bench/main.js index 40c3e7f673219..c62fb564e218b 100644 --- a/src/mono/sample/wasm/browser-bench/main.js +++ b/src/mono/sample/wasm/browser-bench/main.js @@ -4,7 +4,7 @@ "use strict"; var Module = { configSrc: "./mono-config.json", - onDotNetReady: () => { + onDotnetReady: () => { try { App.init(); } catch (error) { diff --git a/src/mono/sample/wasm/browser-es6/index.html b/src/mono/sample/wasm/browser-es6/index.html index 44fc8ff2bde9b..6dd3faeb7bd7a 100644 --- a/src/mono/sample/wasm/browser-es6/index.html +++ b/src/mono/sample/wasm/browser-es6/index.html @@ -12,8 +12,8 @@ - - Result from Sample.Test.TestMeaning: + + Answer to the Ultimate Question of Life, the Universe, and Everything is : diff --git a/src/mono/sample/wasm/browser-es6/main.js b/src/mono/sample/wasm/browser-es6/main.js index 5bf06e2171125..53fc1dc572609 100644 --- a/src/mono/sample/wasm/browser-es6/main.js +++ b/src/mono/sample/wasm/browser-es6/main.js @@ -1,7 +1,7 @@ import createDotnetRuntime from './dotnet.js' -const { MONO, BINDING, Module } = await createDotnetRuntime(() => ({ - disableDotNet6Compatibility: true, +const { MONO, BINDING, Module, RuntimeBuildInfo } = await createDotnetRuntime((api) => ({ + disableDotnet6Compatibility: true, configSrc: "./mono-config.json", onAbort: () => { wasm_exit(1); @@ -12,7 +12,7 @@ const App = { init: function () { const testMeaning = BINDING.bind_static_method("[Wasm.Browser.ES6.Sample] Sample.Test:TestMeaning"); const ret = testMeaning(); - document.getElementById("out").innerHTML = ret; + document.getElementById("out").innerHTML = `${ret} as computed on dotnet ver ${RuntimeBuildInfo.ProductVersion}`; console.debug(`ret: ${ret}`); let exit_code = ret == 42 ? 0 : 1; diff --git a/src/mono/sample/wasm/browser-legacy/main.js b/src/mono/sample/wasm/browser-legacy/main.js index bcec2e80e2418..1aff8d489a12d 100644 --- a/src/mono/sample/wasm/browser-legacy/main.js +++ b/src/mono/sample/wasm/browser-legacy/main.js @@ -4,7 +4,7 @@ "use strict"; var Module = { configSrc: "./mono-config.json", - onDotNetReady: () => { + onDotnetReady: () => { try { App.init(); } catch (error) { diff --git a/src/mono/sample/wasm/browser-profile/main.js b/src/mono/sample/wasm/browser-profile/main.js index 4f9abe18afd65..ed726e4e02640 100644 --- a/src/mono/sample/wasm/browser-profile/main.js +++ b/src/mono/sample/wasm/browser-profile/main.js @@ -12,7 +12,7 @@ var Module = { } } }, - onDotNetReady: () => { + onDotnetReady: () => { try { Module.init(); } catch (error) { diff --git a/src/mono/sample/wasm/browser/main.js b/src/mono/sample/wasm/browser/main.js index 032946ae7418e..0c865b3f02719 100644 --- a/src/mono/sample/wasm/browser/main.js +++ b/src/mono/sample/wasm/browser/main.js @@ -4,9 +4,9 @@ "use strict"; createDotnetRuntime(({ MONO, BINDING, Module }) => ({ - disableDotNet6Compatibility: true, + disableDotnet6Compatibility: true, configSrc: "./mono-config.json", - onDotNetReady: () => { + onDotnetReady: () => { try { App.init({ MONO, BINDING, Module }); } catch (error) { diff --git a/src/mono/wasm/build/README.md b/src/mono/wasm/build/README.md index 323704aab2a74..faed3d05827f6 100644 --- a/src/mono/wasm/build/README.md +++ b/src/mono/wasm/build/README.md @@ -32,7 +32,7 @@ Implementation: - *after* any of the wasm build targets, use `AfterTargets="WasmBuildApp"` on that target - Avoid depending on this target, because it is available only when the workload is installed. Use `$(WasmNativeWorkload)` to check if it is installed. -- `WasmEnableES6` will cause native re-link and produce `dotnet.js` as ES6 module. When `Module.disableDotNet6Compatibility` is set it would not pollute global namespace. Currently debugger doesn't work in that pure mode. +- `WasmEnableES6` will cause native re-link and produce `dotnet.js` as ES6 module. When `Module.disableDotnet6Compatibility` is set it would not pollute global namespace. Currently debugger doesn't work in that pure mode. ## `Publish` diff --git a/src/mono/wasm/runtime/buffers.ts b/src/mono/wasm/runtime/buffers.ts index 727ac3e8b5908..b0437231ccb8b 100644 --- a/src/mono/wasm/runtime/buffers.ts +++ b/src/mono/wasm/runtime/buffers.ts @@ -1,11 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { Int32Ptr, JSHandle, MonoArray, MonoObject, MonoString, VoidPtr } from "./types"; +import { JSHandle, MonoArray, MonoObject, MonoString } from "./types"; 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"; +import { Int32Ptr, TypedArray, VoidPtr } from "./types/emscripten"; // Creates a new typed array from pinned array address from pinned_array allocated on the heap to the typed array. // adress of managed pinned array -> copy from heap -> typed array memory diff --git a/src/mono/wasm/runtime/cancelable-promise.ts b/src/mono/wasm/runtime/cancelable-promise.ts index 15da16fc595a2..8b749498354d7 100644 --- a/src/mono/wasm/runtime/cancelable-promise.ts +++ b/src/mono/wasm/runtime/cancelable-promise.ts @@ -3,7 +3,8 @@ import { mono_wasm_get_jsobj_from_js_handle } from "./gc-handles"; import { wrap_error } from "./method-calls"; -import { Int32Ptr, JSHandle, MonoString } from "./types"; +import { JSHandle, MonoString } from "./types"; +import { Int32Ptr } from "./types/emscripten"; export const _are_promises_supported = ((typeof Promise === "object") || (typeof Promise === "function")) && (typeof Promise.resolve === "function"); const promise_control_symbol = Symbol.for("wasm promise_control"); diff --git a/src/mono/wasm/runtime/cs-to-js.ts b/src/mono/wasm/runtime/cs-to-js.ts index a0883815aa831..2a7646d85973f 100644 --- a/src/mono/wasm/runtime/cs-to-js.ts +++ b/src/mono/wasm/runtime/cs-to-js.ts @@ -3,7 +3,7 @@ import { mono_wasm_new_root, WasmRoot } from "./roots"; import { - GCHandle, Int32Ptr, JSHandleDisposed, MonoArray, + GCHandle, JSHandleDisposed, MonoArray, MonoArrayNull, MonoObject, MonoObjectNull, MonoString, MonoType, MonoTypeNull } from "./types"; @@ -16,6 +16,7 @@ import { mono_method_get_call_signature, call_method, wrap_error } from "./metho import { _js_to_mono_obj } from "./js-to-cs"; import { _are_promises_supported, _create_cancelable_promise } from "./cancelable-promise"; import { getU32, getI32, getF32, getF64 } from "./memory"; +import { Int32Ptr, VoidPtr } from "./types/emscripten"; // see src/mono/wasm/driver.c MARSHAL_TYPE_xxx and Runtime.cs MarshalType export enum MarshalType { diff --git a/src/mono/wasm/runtime/cwraps.ts b/src/mono/wasm/runtime/cwraps.ts index e991bab9a72c3..b8e5ca141e206 100644 --- a/src/mono/wasm/runtime/cwraps.ts +++ b/src/mono/wasm/runtime/cwraps.ts @@ -2,12 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. import { - CharPtr, CharPtrPtr, Int32Ptr, MonoArray, MonoAssembly, MonoClass, MonoMethod, MonoObject, MonoString, - MonoType, VoidPtr + MonoType } from "./types"; import { Module } from "./imports"; +import { VoidPtr, CharPtrPtr, Int32Ptr, CharPtr } from "./types/emscripten"; 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 229003a95477c..8eb60b46e5478 100644 --- a/src/mono/wasm/runtime/debug.ts +++ b/src/mono/wasm/runtime/debug.ts @@ -4,7 +4,7 @@ import { INTERNAL, Module, MONO, runtimeHelpers } from "./imports"; import { toBase64StringImpl } from "./base64"; import cwraps from "./cwraps"; -import { VoidPtr } from "./types"; +import { VoidPtr, CharPtr } from "./types/emscripten"; let commands_received: CommandResponse; let _call_function_res_cache: any = {}; diff --git a/src/mono/wasm/runtime/dist-types/dotnet.d.ts b/src/mono/wasm/runtime/dist-types/dotnet.d.ts new file mode 100644 index 0000000000000..97cc500f3122c --- /dev/null +++ b/src/mono/wasm/runtime/dist-types/dotnet.d.ts @@ -0,0 +1,272 @@ +//! Licensed to the .NET Foundation under one or more agreements. +//! The .NET Foundation licenses this file to you under the MIT license. +//! +//! This is generated file, see src/mono/wasm/runtime/rollup.config.js + +declare interface ManagedPointer { + __brandManagedPointer: "ManagedPointer"; +} +declare interface NativePointer { + __brandNativePointer: "NativePointer"; +} +declare interface VoidPtr extends NativePointer { + __brand: "VoidPtr"; +} + +/** + * Allocates a block of memory that can safely contain pointers into the managed heap. + * The result object has get(index) and set(index, value) methods that can be used to retrieve and store managed pointers. + * Once you are done using the root buffer, you must call its release() method. + * For small numbers of roots, it is preferable to use the mono_wasm_new_root and mono_wasm_new_roots APIs instead. + */ +declare function mono_wasm_new_root_buffer(capacity: number, name?: string): WasmRootBuffer; +/** + * Allocates temporary storage for a pointer into the managed heap. + * Pointers stored here will be visible to the GC, ensuring that the object they point to aren't moved or collected. + * If you already have a managed pointer you can pass it as an argument to initialize the temporary storage. + * The result object has get() and set(value) methods, along with a .value property. + * When you are done using the root you must call its .release() method. + */ +declare function mono_wasm_new_root(value?: T | undefined): WasmRoot; +/** + * Releases 1 or more root or root buffer objects. + * Multiple objects may be passed on the argument list. + * 'undefined' may be passed as an argument so it is safe to call this method from finally blocks + * even if you are not sure all of your roots have been created yet. + * @param {... WasmRoot} roots + */ +declare function mono_wasm_release_roots(...args: WasmRoot[]): void; +declare class WasmRootBuffer { + private __count; + private length; + private __offset; + private __offset32; + private __handle; + private __ownsAllocation; + constructor(offset: VoidPtr, capacity: number, ownsAllocation: boolean, name?: string); + _throw_index_out_of_range(): void; + _check_in_range(index: number): void; + get_address(index: number): NativePointer; + get_address_32(index: number): number; + get(index: number): ManagedPointer; + set(index: number, value: ManagedPointer): ManagedPointer; + _unsafe_get(index: number): number; + _unsafe_set(index: number, value: ManagedPointer | NativePointer): void; + clear(): void; + release(): void; + toString(): string; +} +declare class WasmRoot { + private __buffer; + private __index; + constructor(buffer: WasmRootBuffer, index: number); + get_address(): NativePointer; + get_address_32(): number; + get(): T; + set(value: T): T; + get value(): T; + set value(value: T); + valueOf(): T; + clear(): void; + release(): void; + toString(): string; +} + +declare function mono_wasm_runtime_ready(): void; + +declare const enum ArgsMarshal { + Int32 = "i", + Int32Enum = "j", + Int64 = "l", + Int64Enum = "k", + Float32 = "f", + Float64 = "d", + String = "s", + Char = "s", + JSObj = "o", + MONOObj = "m" +} +declare type _ExtraArgsMarshalOperators = "!" | ""; +declare type ArgsMarshalString = "" | `${ArgsMarshal}${_ExtraArgsMarshalOperators}` | `${ArgsMarshal}${ArgsMarshal}${_ExtraArgsMarshalOperators}` | `${ArgsMarshal}${ArgsMarshal}${ArgsMarshal}${_ExtraArgsMarshalOperators}` | `${ArgsMarshal}${ArgsMarshal}${ArgsMarshal}${ArgsMarshal}${_ExtraArgsMarshalOperators}`; + +interface MonoObject extends ManagedPointer { + __brandMonoObject: "MonoObject"; +} +interface MonoString extends MonoObject { + __brand: "MonoString"; +} +interface MonoArray extends MonoObject { + __brand: "MonoArray"; +} +declare type MonoConfig = { + isError: false; + assembly_root: string; + assets: AllAssetEntryTypes[]; + debug_level?: number; + enable_debugging?: number; + globalization_mode: GlobalizationMode; + diagnostic_tracing?: boolean; + remote_sources?: string[]; + environment_variables?: { + [i: string]: string; + }; + runtime_options?: string[]; + aot_profiler_options?: AOTProfilerOptions; + coverage_profiler_options?: CoverageProfilerOptions; + ignore_pdb_load_errors?: boolean; +}; +declare type MonoConfigError = { + isError: true; + message: string; + error: any; +}; +declare type AllAssetEntryTypes = AssetEntry | AssemblyEntry | SatelliteAssemblyEntry | VfsEntry | IcuData; +declare type AssetEntry = { + name: string; + behavior: AssetBehaviours; + virtual_path?: string; + culture?: string; + load_remote?: boolean; + is_optional?: boolean; +}; +interface AssemblyEntry extends AssetEntry { + name: "assembly"; +} +interface SatelliteAssemblyEntry extends AssetEntry { + name: "resource"; + culture: string; +} +interface VfsEntry extends AssetEntry { + name: "vfs"; + virtual_path: string; +} +interface IcuData extends AssetEntry { + name: "icu"; + load_remote: boolean; +} +declare const enum AssetBehaviours { + Resource = "resource", + Assembly = "assembly", + Heap = "heap", + ICU = "icu", + VFS = "vfs" +} +declare const enum GlobalizationMode { + ICU = "icu", + INVARIANT = "invariant", + AUTO = "auto" +} +declare type AOTProfilerOptions = { + write_at?: string; + send_to?: string; +}; +declare type CoverageProfilerOptions = { + write_at?: string; + send_to?: string; +}; +declare type DotnetModuleConfigImports = { + require: (name: string) => any; + fetch: (url: string) => Promise; + fs: { + promises: { + readFile: (path: string) => Promise; + readFileSync: (path: string, options: string | undefined) => string; + }; + }; + crypto: { + randomBytes: (size: number) => Buffer; + }; + ws: WebSocket & { + Server: any; + }; + path: { + normalize: (path: string) => string; + dirname: (path: string) => string; + }; + url: any; +}; +declare type DotnetModuleConfig = { + disableDotnet6Compatibility?: boolean; + config?: MonoConfig | MonoConfigError; + configSrc?: string; + onConfigLoaded?: () => void; + onDotnetReady?: () => void; + imports?: DotnetModuleConfigImports; +}; + +declare function mono_wasm_setenv(name: string, value: string): void; +declare function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise; +declare function mono_wasm_load_data_archive(data: Uint8Array, prefix: string): boolean; +/** + * 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 + */ +declare function mono_wasm_load_config(configFilePath: string): Promise; + +declare function mono_wasm_load_icu_data(offset: VoidPtr): boolean; + +declare function conv_string(mono_obj: MonoString): string | null; +declare function js_string_to_mono_string(string: string): MonoString | null; + +declare function js_to_mono_obj(js_obj: any): MonoObject; +declare function js_typed_array_to_array(js_obj: any): MonoArray; + +declare function unbox_mono_obj(mono_obj: MonoObject): any; +declare function mono_array_to_js_array(mono_array: MonoArray): any[] | null; + +declare function mono_bind_static_method(fqn: string, signature?: ArgsMarshalString): Function; +declare function mono_call_assembly_entry_point(assembly: string, args: any[], signature: ArgsMarshalString): any; + +declare function mono_wasm_load_bytes_into_heap(bytes: Uint8Array): VoidPtr; + +declare const MONO: 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; + mono_wasm_load_bytes_into_heap: typeof mono_wasm_load_bytes_into_heap; + mono_wasm_load_icu_data: typeof mono_wasm_load_icu_data; + mono_wasm_load_config: typeof mono_wasm_load_config; + mono_load_runtime_and_bcl_args: typeof mono_load_runtime_and_bcl_args; + mono_wasm_new_root_buffer: typeof mono_wasm_new_root_buffer; + mono_wasm_new_root: typeof mono_wasm_new_root; + mono_wasm_release_roots: typeof mono_wasm_release_roots; + 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; +} +declare const BINDING: 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; + js_typed_array_to_array: typeof js_typed_array_to_array; + js_to_mono_obj: typeof js_to_mono_obj; + mono_array_to_js_array: typeof mono_array_to_js_array; + conv_string: typeof conv_string; + 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; +} +interface DotnetPublicAPI { + MONO: MONO; + BINDING: BINDING; + Module: any; + RuntimeId: number; + RuntimeBuildInfo: { + ProductVersion: string; + Configuration: string; + }; +} + +declare type createDotnetRuntimeType = (moduleFactory: (api: DotnetPublicAPI) => DotnetModuleConfig) => Promise; +declare global { + function getDotnetRuntime(runtimeId: number): DotnetPublicAPI | undefined; +} +declare const createDotnetRuntime: createDotnetRuntimeType; + +export { createDotnetRuntimeType, createDotnetRuntime as default }; diff --git a/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 b/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 new file mode 100644 index 0000000000000..3cae997cee2f7 --- /dev/null +++ b/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 @@ -0,0 +1 @@ +9340ce4866a6f66e64650178de10f37ad5c29c7c548a3c9beb6595581b34db74 \ No newline at end of file diff --git a/src/mono/wasm/runtime/dotnet.lib.js b/src/mono/wasm/runtime/dotnet.lib.js index 609078527e059..69f6428d7ff44 100644 --- a/src/mono/wasm/runtime/dotnet.lib.js +++ b/src/mono/wasm/runtime/dotnet.lib.js @@ -4,10 +4,10 @@ "use strict"; -const DotNetSupportLib = { +const DotnetSupportLib = { $DOTNET: {}, // this line will be executed early on runtime, passing import and export objects into __dotnet_runtime IFFE - $DOTNET__postset: "let api = __dotnet_runtime.__initializeImportsAndExports({isGlobal:ENVIRONMENT_IS_GLOBAL, isNode:ENVIRONMENT_IS_NODE, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, locateFile}, {mono:MONO, binding:BINDING, internal:INTERNAL, module:Module});", + $DOTNET__postset: "let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports({isGlobal:ENVIRONMENT_IS_GLOBAL, 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 @@ -62,8 +62,8 @@ const linked_functions = [ // 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.__linker_exports.${linked_function}.apply(__dotnet_runtime, arguments)`; - DotNetSupportLib[linked_function] = new Function(fn_template); + DotnetSupportLib[linked_function] = new Function(fn_template); } -autoAddDeps(DotNetSupportLib, "$DOTNET"); -mergeInto(LibraryManager.library, DotNetSupportLib); +autoAddDeps(DotnetSupportLib, "$DOTNET"); +mergeInto(LibraryManager.library, DotnetSupportLib); diff --git a/src/mono/wasm/runtime/export-types.ts b/src/mono/wasm/runtime/export-types.ts index 281e9fa80aa0b..335beb19ab20a 100644 --- a/src/mono/wasm/runtime/export-types.ts +++ b/src/mono/wasm/runtime/export-types.ts @@ -1,18 +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 { DotNetPublicAPI } from "./exports"; -import { EmscriptenModuleConfig } from "./types"; +import { DotnetPublicAPI } from "./exports"; +import { DotnetModuleConfig } from "./types"; // ----------------------------------------------------------- // this files has all public exports from the dotnet.js module // ----------------------------------------------------------- -declare function createDotnetRuntime(moduleFactory: (api: DotNetPublicAPI) => EmscriptenModuleConfig): Promise; +export type createDotnetRuntimeType = (moduleFactory: (api: DotnetPublicAPI) => DotnetModuleConfig) => Promise; // Here, declare things that go in the global namespace, or augment existing declarations in the global namespace declare global { - function getDotnetRuntime(runtimeId: number): DotNetPublicAPI | undefined; + function getDotnetRuntime(runtimeId: number): DotnetPublicAPI | undefined; } -export default createDotnetRuntime; \ No newline at end of file +declare const createDotnetRuntime: createDotnetRuntimeType; +export default createDotnetRuntime; + + diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index f9a2dda74f811..c93781c2e9cda 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -26,7 +26,7 @@ import { mono_wasm_add_dbg_command_received, } from "./debug"; import { runtimeHelpers, setImportsAndExports } from "./imports"; -import { EmscriptenModuleMono, MonoArray, MonoConfig, MonoConfigError, MonoObject } from "./types"; +import { DotnetModuleConfigImports, DotnetModuleMono, MonoArray, MonoConfig, MonoConfigError, MonoObject } from "./types"; import { mono_load_runtime_and_bcl_args, mono_wasm_load_config, mono_wasm_setenv, mono_wasm_set_runtime_options, @@ -69,6 +69,7 @@ import { getU8, getU16, getU32, getF32, getF64, } from "./memory"; import { create_weak_ref } from "./weak-ref"; +import { VoidPtr } from "./types/emscripten"; const MONO: MONO = { // current "public" MONO API @@ -119,7 +120,7 @@ const BINDING: BINDING = { _teardown_after_call, }; -let api: DotNetPublicAPI; +let exportedAPI: DotnetPublicAPI; // this is executed early during load of emscripten runtime // it exports methods to global objects MONO, BINDING and Module in backward compatible way @@ -127,8 +128,8 @@ let api: DotNetPublicAPI; function initializeImportsAndExports( imports: { isGlobal: boolean, isNode: boolean, isShell: boolean, isWeb: boolean, locateFile: Function }, exports: { mono: any, binding: any, internal: any, module: any }, -): DotNetPublicAPI { - const module = exports.module as EmscriptenModuleMono; +): DotnetPublicAPI { + const module = exports.module as DotnetModuleMono; const globalThisAny = globalThis as any; // we want to have same instance of MONO, BINDING and Module in dotnet iffe @@ -139,7 +140,7 @@ function initializeImportsAndExports( Object.assign(exports.binding, BINDING); Object.assign(exports.internal, INTERNAL); - api = { + exportedAPI = { MONO: exports.mono, BINDING: exports.binding, INTERNAL: exports.internal, @@ -172,9 +173,7 @@ function initializeImportsAndExports( if (!module.printErr) { module.printErr = console.error; } - if (!module.imports) { - module.imports = {}; - } + module.imports = module.imports || {}; if (!module.imports.require) { module.imports.require = globalThis.require; } @@ -187,8 +186,8 @@ function initializeImportsAndExports( }; } - if (imports.isGlobal || !module.disableDotNet6Compatibility) { - Object.assign(module, api); + if (imports.isGlobal || !module.disableDotnet6Compatibility) { + Object.assign(module, exportedAPI); // backward compatibility // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -237,9 +236,9 @@ function initializeImportsAndExports( else { list = globalThisAny.getDotnetRuntime.__list; } - list.registerRuntime(api); + list.registerRuntime(exportedAPI); - return api; + return exportedAPI; } export const __initializeImportsAndExports: any = initializeImportsAndExports; // don't want to export the type @@ -382,7 +381,7 @@ interface BINDING { unbox_mono_obj: typeof unbox_mono_obj } -export interface DotNetPublicAPI { +export interface DotnetPublicAPI { MONO: MONO, BINDING: BINDING, Module: any, @@ -394,15 +393,15 @@ export interface DotNetPublicAPI { } class RuntimeList { - private list: { [runtimeId: number]: WeakRef } = {}; + private list: { [runtimeId: number]: WeakRef } = {}; - public registerRuntime(api: DotNetPublicAPI): number { + public registerRuntime(api: DotnetPublicAPI): number { api.RuntimeId = Object.keys(this.list).length; this.list[api.RuntimeId] = create_weak_ref(api); return api.RuntimeId; } - public getRuntime(runtimeId: number): DotNetPublicAPI | undefined { + public getRuntime(runtimeId: number): DotnetPublicAPI | undefined { const wr = this.list[runtimeId]; return wr ? wr.deref() : undefined; } diff --git a/src/mono/wasm/runtime/icu.ts b/src/mono/wasm/runtime/icu.ts index a2c247d9a9cbb..05ea504cbffde 100644 --- a/src/mono/wasm/runtime/icu.ts +++ b/src/mono/wasm/runtime/icu.ts @@ -2,7 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. import cwraps from "./cwraps"; -import { GlobalizationMode, VoidPtr } from "./types"; +import { GlobalizationMode } from "./types"; +import { VoidPtr } from "./types/emscripten"; let num_icu_assets_loaded_successfully = 0; diff --git a/src/mono/wasm/runtime/imports.ts b/src/mono/wasm/runtime/imports.ts index 5a1918e9c27c9..ec9cf8075bc47 100644 --- a/src/mono/wasm/runtime/imports.ts +++ b/src/mono/wasm/runtime/imports.ts @@ -2,13 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. /* eslint-disable @typescript-eslint/triple-slash-reference */ -/// /// -import { EmscriptenModuleMono, MonoConfig, RuntimeHelpers } from "./types"; +import { DotnetModuleMono, MonoConfig, RuntimeHelpers } from "./types"; +import { EmscriptenModule } from "./types/emscripten"; // these are our public API (except internal) -export let Module: EmscriptenModule & EmscriptenModuleMono; +export let Module: EmscriptenModule & DotnetModuleMono; export let MONO: any; export let BINDING: any; export let INTERNAL: any; diff --git a/src/mono/wasm/runtime/js-to-cs.ts b/src/mono/wasm/runtime/js-to-cs.ts index 01be716a7b701..8bafaec669cd8 100644 --- a/src/mono/wasm/runtime/js-to-cs.ts +++ b/src/mono/wasm/runtime/js-to-cs.ts @@ -14,8 +14,9 @@ import { wrap_error } from "./method-calls"; import { js_string_to_mono_string, js_string_to_mono_string_interned } from "./strings"; import { isThenable } from "./cancelable-promise"; import { has_backing_array_buffer } from "./buffers"; -import { Int32Ptr, JSHandle, MonoArray, MonoMethod, MonoObject, MonoObjectNull, MonoString, wasm_type_symbol } from "./types"; +import { JSHandle, MonoArray, MonoMethod, MonoObject, MonoObjectNull, MonoString, wasm_type_symbol } from "./types"; import { setI32, setU32, setF64 } from "./memory"; +import { Int32Ptr, TypedArray } from "./types/emscripten"; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function _js_to_mono_uri(should_add_in_flight: boolean, js_obj: any): MonoObject { diff --git a/src/mono/wasm/runtime/memory.ts b/src/mono/wasm/runtime/memory.ts index 55a322637b90f..e8a89bd11a574 100644 --- a/src/mono/wasm/runtime/memory.ts +++ b/src/mono/wasm/runtime/memory.ts @@ -1,4 +1,5 @@ import { Module } from "./imports"; +import { VoidPtr, NativePointer } from "./types/emscripten"; const _temp_mallocs: Array | null> = []; diff --git a/src/mono/wasm/runtime/method-binding.ts b/src/mono/wasm/runtime/method-binding.ts index 1cd070ae944ad..9b4adbd2b6547 100644 --- a/src/mono/wasm/runtime/method-binding.ts +++ b/src/mono/wasm/runtime/method-binding.ts @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import { WasmRoot, WasmRootBuffer, mono_wasm_new_root } from "./roots"; -import { MonoClass, MonoMethod, MonoObject, coerceNull, VoidPtrNull, VoidPtr, MonoType } from "./types"; +import { MonoClass, MonoMethod, MonoObject, coerceNull, VoidPtrNull, MonoType } from "./types"; 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"; @@ -17,6 +17,7 @@ import { _handle_exception_for_call, _teardown_after_call } from "./method-calls"; import cwraps from "./cwraps"; +import { VoidPtr } from "./types/emscripten"; const primitiveConverters = new Map(); const _signature_converters = new Map(); diff --git a/src/mono/wasm/runtime/method-calls.ts b/src/mono/wasm/runtime/method-calls.ts index 8d7174e8b488b..64d4d06eb8dcb 100644 --- a/src/mono/wasm/runtime/method-calls.ts +++ b/src/mono/wasm/runtime/method-calls.ts @@ -5,7 +5,7 @@ import { mono_wasm_new_root, mono_wasm_new_root_buffer, WasmRoot, WasmRootBuffer import { JSHandle, MonoArray, MonoMethod, MonoObject, MonoObjectNull, MonoString, coerceNull as coerceNull, - VoidPtr, VoidPtrNull, Int32Ptr, MonoStringNull + VoidPtrNull, MonoStringNull } from "./types"; import { BINDING, INTERNAL, Module, MONO, runtimeHelpers } from "./imports"; import { _mono_array_root_to_js_array, _unbox_mono_obj_root } from "./cs-to-js"; @@ -21,6 +21,7 @@ import { conv_string, js_string_to_mono_string } from "./strings"; import cwraps from "./cwraps"; import { bindings_lazy_init } from "./startup"; import { _create_temp_frame, _release_temp_frame } from "./memory"; +import { VoidPtr, Int32Ptr, EmscriptenModule } from "./types/emscripten"; function _verify_args_for_method_call(args_marshal: ArgsMarshalString, args: any) { const has_args = args && (typeof args === "object") && args.length > 0; @@ -249,7 +250,7 @@ export function call_static_method(fqn: string, args: any[], signature: ArgsMars return call_method(method, undefined, signature, args); } -export function mono_bind_static_method(fqn: string, signature: ArgsMarshalString): Function { +export function mono_bind_static_method(fqn: string, signature?: ArgsMarshalString): Function { bindings_lazy_init();// TODO remove this once Blazor does better startup const method = mono_method_resolve(fqn); diff --git a/src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.post.js b/src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.post.js index e025a6fe7a933..84493951a5b79 100644 --- a/src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.post.js +++ b/src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.post.js @@ -1,3 +1,3 @@ createDotnetRuntime.ready = createDotnetRuntime.ready.then(() => { - return { MONO, BINDING, INTERNAL, Module }; + return __dotnet_exportedAPI; }) diff --git a/src/mono/wasm/runtime/modularize-dotnet.md b/src/mono/wasm/runtime/modularize-dotnet.md index d85526ea09650..ab0d31e4265e9 100644 --- a/src/mono/wasm/runtime/modularize-dotnet.md +++ b/src/mono/wasm/runtime/modularize-dotnet.md @@ -40,7 +40,7 @@ In `src\mono\wasm\runtime\CMakeLists.txt` which links only in-tree, we use same # About new API The signature is ``` -function createDotnetRuntime(moduleFactory: (api: DotNetExports) => EmscriptenModuleConfig): Promise +function createDotnetRuntime(moduleFactory: (api: DotnetPublicAPI) => DotnetModuleConfig): Promise ``` Simplest intended usage looks like this in ES6: @@ -59,7 +59,7 @@ import createDotnetRuntime from './dotnet.js' export const { MONO, BINDING } = await createDotnetRuntime(({ MONO, BINDING, Module }) => // this is callback with no statement, the APIs are only empty shells here and are populated later. ({ - disableDotNet6Compatibility: true, + disableDotnet6Compatibility: true, configSrc: "./mono-config.json", onConfigLoaded: () => { // This is called during emscripten `preInit` event, after we fetched config. @@ -71,7 +71,7 @@ export const { MONO, BINDING } = await createDotnetRuntime(({ MONO, BINDING, Mod // call some early available functions MONO.mono_wasm_setenv("HELLO", "WORLD); } - onDotNetReady: () => { + onDotnetReady: () => { // Only when there is no `onRuntimeInitialized` override. // This is called after all assets are loaded , mapping to legacy `config.loaded_cb`. // It happens during emscripten `onRuntimeInitialized` after monoVm init + globalization + assemblies. diff --git a/src/mono/wasm/runtime/modularize-es6/dotnet.es6.post.js b/src/mono/wasm/runtime/modularize-es6/dotnet.es6.post.js index e025a6fe7a933..84493951a5b79 100644 --- a/src/mono/wasm/runtime/modularize-es6/dotnet.es6.post.js +++ b/src/mono/wasm/runtime/modularize-es6/dotnet.es6.post.js @@ -1,3 +1,3 @@ createDotnetRuntime.ready = createDotnetRuntime.ready.then(() => { - return { MONO, BINDING, INTERNAL, Module }; + return __dotnet_exportedAPI; }) diff --git a/src/mono/wasm/runtime/package.json b/src/mono/wasm/runtime/package.json index b332bf1141e0e..c582daf3eae90 100644 --- a/src/mono/wasm/runtime/package.json +++ b/src/mono/wasm/runtime/package.json @@ -6,6 +6,7 @@ "url": "git@github.com:dotnet/runtime.git" }, "version": "1.0.0", + "main": "dotnet.js", "scripts": { "rollup": "rollup -c", "lint": "eslint --no-color --max-warnings=0 ./**/*.ts ./*.js" diff --git a/src/mono/wasm/runtime/rollup.config.js b/src/mono/wasm/runtime/rollup.config.js index e9ccd5775098a..dcdbff8f12bee 100644 --- a/src/mono/wasm/runtime/rollup.config.js +++ b/src/mono/wasm/runtime/rollup.config.js @@ -3,6 +3,7 @@ import typescript from "@rollup/plugin-typescript"; import { terser } from "rollup-plugin-terser"; import { readFile, writeFile, mkdir } from "fs/promises"; import * as fs from "fs"; +import * as path from "path"; import { createHash } from "crypto"; import dts from "rollup-plugin-dts"; import consts from "rollup-plugin-consts"; @@ -39,44 +40,59 @@ const terserConfig = { }; 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_generated = banner + "//! \n//! This is generated file, see src/mono/wasm/runtime/rollup.config.js \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([ +const iffeConfig = { + treeshake: !isDebug, + input: "exports.ts", + output: [ + { + file: nativeBinDir + "/src/cjs/runtime.cjs.iffe.js", + name, + banner, + format, + plugins, + }, + { + file: nativeBinDir + "/src/es6/runtime.es6.iffe.js", + name, + banner, + format, + plugins, + } + ], + plugins: [consts({ productVersion, configuration }), typescript()] +}; +const typesConfig = { + input: "./export-types.ts", + output: [ + { + format: "es", + file: nativeBinDir + "/dotnet.d.ts", + banner: banner_generated, + plugins: [writeOnChangePlugin()], + } + ], + plugins: [dts()], +}; - { - treeshake: !isDebug, - input: "exports.ts", - output: [ - { - file: nativeBinDir + "/src/cjs/runtime.cjs.iffe.js", - name, - banner, - format, - plugins, - }, - { - file: nativeBinDir + "/src/es6/runtime.es6.iffe.js", - name, - banner, - format, - plugins, - } - ], - plugins: [consts({ productVersion, configuration }), typescript()] - }, - { - input: "./export-types.ts", - output: [ - // dotnet.d.ts - { - format: "es", - file: nativeBinDir + "/src/" + "dotnet.d.ts", - } - ], - plugins: [dts()], - } +if (isDebug) { + // export types also into the source code and commit to git + // so that we could notice that the API changed and review it + typesConfig.output.push({ + format: "es", + file: "./dist-types/dotnet.d.ts", + banner: banner_generated, + plugins: [writeOnChangePlugin()], + }); +} + +export default defineConfig([ + iffeConfig, + typesConfig ]); // 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. @@ -104,11 +120,9 @@ async function writeWhenChanged(options, bundle) { isOutputChanged = oldHash !== newHash; } if (isOutputChanged) { - if (!await checkFileExists(nativeBinDir + "/src/cjs")) { - await mkdir(nativeBinDir + "/src/cjs", { recursive: true }); - } - if (!await checkFileExists(nativeBinDir + "/src/es6")) { - await mkdir(nativeBinDir + "/src/es6", { recursive: true }); + const dir = path.dirname(options.file); + if (!await checkFileExists(dir)) { + await mkdir(dir, { recursive: true }); } await writeFile(hashFileName, newHash); } else { diff --git a/src/mono/wasm/runtime/roots.ts b/src/mono/wasm/runtime/roots.ts index 1eb88b3d7dc7f..010732c23a894 100644 --- a/src/mono/wasm/runtime/roots.ts +++ b/src/mono/wasm/runtime/roots.ts @@ -3,7 +3,7 @@ import cwraps from "./cwraps"; import { Module } from "./imports"; -import { VoidPtr, ManagedPointer, NativePointer } from "./types"; +import { VoidPtr, ManagedPointer, NativePointer } from "./types/emscripten"; const maxScratchRoots = 8192; let _scratch_root_buffer: WasmRootBuffer | null = null; diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index c7e139dc78445..d586e25adcdc6 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.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 { AllAssetEntryTypes, AssetEntry, CharPtr, CharPtrNull, EmscriptenModuleMono, GlobalizationMode, MonoConfig, VoidPtr, wasm_type_symbol } from "./types"; +import { AllAssetEntryTypes, AssetEntry, CharPtrNull, DotnetModuleMono, GlobalizationMode, MonoConfig, 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"; @@ -11,6 +11,7 @@ import { mono_wasm_init_aot_profiler, mono_wasm_init_coverage_profiler } from ". 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"; +import { VoidPtr, CharPtr } from "./types/emscripten"; export let runtime_is_initialized_resolve: Function; export let runtime_is_initialized_reject: Function; @@ -21,7 +22,7 @@ export const mono_wasm_runtime_is_initialized = new Promise((resolve, reject) => export async function mono_wasm_pre_init(): Promise { - const moduleExt = Module as EmscriptenModuleMono; + const moduleExt = Module as DotnetModuleMono; if (moduleExt.configSrc) { try { // sets MONO.config implicitly @@ -207,7 +208,7 @@ function _apply_configuration_from_args(args: MonoConfig) { } function _finalize_startup(args: MonoConfig, ctx: MonoInitContext) { - const moduleExt = Module as EmscriptenModuleMono; + const moduleExt = Module as DotnetModuleMono; ctx.loaded_files.forEach(value => MONO.loaded_files.push(value.url)); if (ctx.tracing) { @@ -261,12 +262,12 @@ function _finalize_startup(args: MonoConfig, ctx: MonoInitContext) { } } - if (moduleExt.onDotNetReady) { + if (moduleExt.onDotnetReady) { try { - moduleExt.onDotNetReady(); + moduleExt.onDotnetReady(); } catch (err: any) { - Module.printErr("MONO_WASM: onDotNetReady () failed: " + err); + Module.printErr("MONO_WASM: onDotnetReady () failed: " + err); Module.printErr("MONO_WASM: Stacktrace: \n"); Module.printErr(err.stack); runtime_is_initialized_reject(err); @@ -358,7 +359,7 @@ export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise< _apply_configuration_from_args(args); // TODO move polyfills out into separate module - const local_fetch = typeof (Module.imports.fetch) === "function" + const local_fetch = Module.imports && typeof (Module.imports.fetch) === "function" ? Module.imports.fetch // legacy fallback : typeof ((args).fetch_file_cb) === "function" diff --git a/src/mono/wasm/runtime/strings.ts b/src/mono/wasm/runtime/strings.ts index 215b73f6c67b6..2ac05a90e4d92 100644 --- a/src/mono/wasm/runtime/strings.ts +++ b/src/mono/wasm/runtime/strings.ts @@ -2,11 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. import { mono_wasm_new_root_buffer, WasmRootBuffer } from "./roots"; -import { CharPtr, MonoString, MonoStringNull, NativePointer } from "./types"; +import { MonoString, MonoStringNull, } from "./types"; import { Module } from "./imports"; import cwraps from "./cwraps"; import { mono_wasm_new_root } from "./roots"; import { getI32 } from "./memory"; +import { NativePointer, CharPtr } from "./types/emscripten"; export class StringDecoder { diff --git a/src/mono/wasm/runtime/types.ts b/src/mono/wasm/runtime/types.ts index 47898395eddc9..e4cf2b3c2fc0d 100644 --- a/src/mono/wasm/runtime/types.ts +++ b/src/mono/wasm/runtime/types.ts @@ -2,32 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import { bind_runtime_method } from "./method-binding"; - -export type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array; - -export interface ManagedPointer { - __brandManagedPointer: "ManagedPointer" -} - -export interface NativePointer { - __brandNativePointer: "NativePointer" -} - -export interface VoidPtr extends NativePointer { - __brand: "VoidPtr" -} - -export interface CharPtr extends NativePointer { - __brand: "CharPtr" -} - -export interface Int32Ptr extends NativePointer { - __brand: "Int32Ptr" -} - -export interface CharPtrPtr extends NativePointer { - __brand: "CharPtrPtr" -} +import { CharPtr, EmscriptenModule, ManagedPointer, NativePointer, VoidPtr } from "./types/emscripten"; export type GCHandle = { __brand: "GCHandle" @@ -178,33 +153,33 @@ export type CoverageProfilerOptions = { } // how we extended emscripten Module -export type EmscriptenModuleMono = EmscriptenModule & EmscriptenModuleConfig; - -export type EmscriptenModuleConfig = { - disableDotNet6Compatibility?: boolean, +export type DotnetModuleMono = EmscriptenModule & DotnetModuleConfig; +export type DotnetModuleConfigImports = { + require: (name: string) => any; + fetch: (url: string) => Promise; + fs: { + promises: { + readFile: (path: string) => Promise, + readFileSync: (path: string, options: string | undefined) => string, + } + }; + crypto: { + randomBytes: (size: number) => Buffer + }; + ws: WebSocket & { Server: any }; + path: { + normalize: (path: string) => string, + dirname: (path: string) => string, + }; + url: any; +} +export type DotnetModuleConfig = { + disableDotnet6Compatibility?: boolean, config?: MonoConfig | MonoConfigError, configSrc?: string, onConfigLoaded?: () => void; - onDotNetReady?: () => void; - - imports: { - require: (name: string) => any; - fetch: (url: string) => Promise; - fs: { - promises: { - readFile: (path: string) => Promise, - readFileSync: (path: string, options: string | undefined) => string, - } - }; - crypto: { - randomBytes: (size: number) => Buffer - }; - ws: WebSocket & { Server: any }; - path: { - normalize: (path: string) => string, - dirname: (path: string) => string, - }; - url: any; - } + onDotnetReady?: () => void; + + imports?: DotnetModuleConfigImports; } diff --git a/src/mono/wasm/runtime/types/emscripten.d.ts b/src/mono/wasm/runtime/types/emscripten.ts similarity index 78% rename from src/mono/wasm/runtime/types/emscripten.d.ts rename to src/mono/wasm/runtime/types/emscripten.ts index 234c512558618..534fbf935a7c3 100644 --- a/src/mono/wasm/runtime/types/emscripten.d.ts +++ b/src/mono/wasm/runtime/types/emscripten.ts @@ -1,28 +1,28 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -declare interface ManagedPointer { +export declare interface ManagedPointer { __brandManagedPointer: "ManagedPointer" } -declare interface NativePointer { +export declare interface NativePointer { __brandNativePointer: "NativePointer" } -declare interface VoidPtr extends NativePointer { +export declare interface VoidPtr extends NativePointer { __brand: "VoidPtr" } -declare interface CharPtr extends NativePointer { +export declare interface CharPtr extends NativePointer { __brand: "CharPtr" } -declare interface Int32Ptr extends NativePointer { +export declare interface Int32Ptr extends NativePointer { __brand: "Int32Ptr" } -declare interface CharPtrPtr extends NativePointer { +export declare interface CharPtrPtr extends NativePointer { __brand: "CharPtrPtr" } -declare interface EmscriptenModule { +export declare interface EmscriptenModule { HEAP8: Int8Array, HEAP16: Int16Array; HEAP32: Int32Array; @@ -57,4 +57,4 @@ declare interface EmscriptenModule { onRuntimeInitialized?: () => void; } -declare type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array; \ No newline at end of file +export declare type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array; \ No newline at end of file diff --git a/src/mono/wasm/runtime/web-socket.ts b/src/mono/wasm/runtime/web-socket.ts index 319af2f465045..3a6753b4f7fc9 100644 --- a/src/mono/wasm/runtime/web-socket.ts +++ b/src/mono/wasm/runtime/web-socket.ts @@ -10,8 +10,9 @@ import { mono_wasm_get_jsobj_from_js_handle, mono_wasm_get_js_handle } from "./g 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 { JSHandle, MonoArray, MonoObject, MonoObjectNull, MonoString } from "./types"; import { Module } from "./imports"; +import { Int32Ptr } from "./types/emscripten"; 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/test-main.js b/src/mono/wasm/test-main.js index f31b253ec3c45..f378547b34f0d 100644 --- a/src/mono/wasm/test-main.js +++ b/src/mono/wasm/test-main.js @@ -124,7 +124,7 @@ if (typeof globalThis.performance === 'undefined') { } loadDotnet("./dotnet.js").then((createDotnetRuntime) => { return createDotnetRuntime(({ MONO, INTERNAL, BINDING, Module }) => ({ - disableDotNet6Compatibility: true, + disableDotnet6Compatibility: true, config: null, configSrc: "./mono-config.json", onConfigLoaded: () => { @@ -142,7 +142,7 @@ loadDotnet("./dotnet.js").then((createDotnetRuntime) => { INTERNAL.mono_wasm_enable_on_demand_gc(0); } }, - onDotNetReady: () => { + onDotnetReady: () => { let wds = Module.FS.stat(processedArguments.working_dir); if (wds === undefined || !Module.FS.isDir(wds.mode)) { set_exit_code(1, `Could not find working directory ${processedArguments.working_dir}`); diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index 59a889b940254..4f045a0c7c0a5 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -201,7 +201,9 @@ DestinationFolder="$(NativeBinDir)include\wasm" SkipUnchangedFiles="true" /> - @@ -220,7 +222,8 @@ Date: Thu, 25 Nov 2021 20:55:49 +0100 Subject: [PATCH 07/28] fix merge --- src/mono/wasm/wasm.proj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index 4f045a0c7c0a5..8b4afed96ef30 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -153,7 +153,7 @@ $(CMakeConfigurationEmccFlags) -O2 -DEMSDK_PATH="$(EMSDK_PATH.TrimEnd('\/'))" - emcmake cmake $(MSBuildThisFileDirectory)runtime -DCMAKE_BUILD_TYPE=$(Configuration) -DCONFIGURATION_EMCC_FLAGS="$(CMakeConfigurationEmccFlags)" -DCONFIGURATION_LINK_FLAGS="$(CMakeConfigurationLinkFlags)" -DMONO_INCLUDES="$(MonoArtifactsPath)include/mono-2.0" -DMONO_OBJ_INCLUDES="$(MonoObjDir.TrimEnd('\/'))" -DICU_LIB_DIR="$(ICULibDir.TrimEnd('\/'))" -DMONO_ARTIFACTS_DIR="$(MonoArtifactsPath.TrimEnd('\/'))" -DNATIVE_BIN_DIR="$(NativeBinDir.TrimEnd('\/'))" -DSYSTEM_NATIVE_DIR="$(RepoRoot)src/native/libs/System.Native" -DSOURCE_DIR="$(MSBuildThisFileDirectory.TrimEnd('\/'))/runtime"$(CMakeConfigurationEmsdkPath) + emcmake cmake $(MSBuildThisFileDirectory)runtime -DCMAKE_BUILD_TYPE=$(Configuration) -DCONFIGURATION_EMCC_FLAGS="$(CMakeConfigurationEmccFlags)" -DCONFIGURATION_LINK_FLAGS="$(CMakeConfigurationLinkFlags)" -DMONO_INCLUDES="$(MonoArtifactsPath)include/mono-2.0" -DMONO_OBJ_INCLUDES="$(MonoObjDir.TrimEnd('\/'))" -DICU_LIB_DIR="$(ICULibDir.TrimEnd('\/'))" -DMONO_ARTIFACTS_DIR="$(MonoArtifactsPath.TrimEnd('\/'))" -DNATIVE_BIN_DIR="$(NativeBinDir.TrimEnd('\/'))" $(CMakeConfigurationEmsdkPath) call "$(RepositoryEngineeringDir)native\init-vs-env.cmd" && call "$([MSBuild]::NormalizePath('$(EMSDK_PATH)', 'emsdk_env.bat'))" && $(CMakeBuildRuntimeConfigureCmd) bash -c 'source $(EMSDK_PATH)/emsdk_env.sh 2>&1 && $(CMakeBuildRuntimeConfigureCmd)' From 6514dd8ff87e4d0d78df3c5f4179cc3d54a7703e Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 26 Nov 2021 01:13:38 +0100 Subject: [PATCH 08/28] NodeJS work in progress --- src/mono/sample/wasm/console-ts/Program.cs | 15 +++++ .../Wasm.Console.TypeScript.Sample.csproj | 34 ++++++++++ src/mono/sample/wasm/console-ts/main.ts | 30 +++++++++ .../sample/wasm/console-ts/package-lock.json | 23 +++++++ src/mono/sample/wasm/console-ts/package.json | 24 +++++++ src/mono/sample/wasm/console-ts/tsconfig.json | 9 +++ src/mono/wasm/runtime/dist-types/dotnet.d.ts | 28 +++++---- .../runtime/dist-types/dotnet.d.ts.sha256 | 2 +- src/mono/wasm/runtime/dotnet.lib.js | 37 ++++++++++- src/mono/wasm/runtime/exports.ts | 18 ++++++ src/mono/wasm/runtime/imports.ts | 1 + .../runtime/modularize-es6/dotnet.es6.post.js | 2 +- .../runtime/modularize-es6/dotnet.es6.pre.js | 3 +- src/mono/wasm/runtime/polyfills.ts | 50 +++++++++++++++ src/mono/wasm/runtime/startup.ts | 63 ++----------------- src/mono/wasm/runtime/types.ts | 28 +++++---- src/mono/wasm/test-main.js | 2 +- 17 files changed, 280 insertions(+), 89 deletions(-) create mode 100644 src/mono/sample/wasm/console-ts/Program.cs create mode 100644 src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj create mode 100644 src/mono/sample/wasm/console-ts/main.ts create mode 100644 src/mono/sample/wasm/console-ts/package-lock.json create mode 100644 src/mono/sample/wasm/console-ts/package.json create mode 100644 src/mono/sample/wasm/console-ts/tsconfig.json create mode 100644 src/mono/wasm/runtime/polyfills.ts diff --git a/src/mono/sample/wasm/console-ts/Program.cs b/src/mono/sample/wasm/console-ts/Program.cs new file mode 100644 index 0000000000000..166202aea3b42 --- /dev/null +++ b/src/mono/sample/wasm/console-ts/Program.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Threading.Tasks; + +public class Test +{ + public static async Task Main(string[] args) + { + await Task.Delay(1); + Console.WriteLine("Hello NodeJS!"); + return args.Length; + } +} diff --git a/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj b/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj new file mode 100644 index 0000000000000..70838099c9c93 --- /dev/null +++ b/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj @@ -0,0 +1,34 @@ + + + + + bin/main.js + true + Debug + true + true + embedded + 1 + true + + CompileTypeScript; + $(WasmBuildAppDependsOn) + + + + + + + + + <_SampleProject>Wasm.Console.TypeScript.Sample.csproj + <_SampleAssembly>Wasm.Console.TypeScript.Sample.dll + + + + + + + + + diff --git a/src/mono/sample/wasm/console-ts/main.ts b/src/mono/sample/wasm/console-ts/main.ts new file mode 100644 index 0000000000000..1cb5b800da370 --- /dev/null +++ b/src/mono/sample/wasm/console-ts/main.ts @@ -0,0 +1,30 @@ +import { createRequire } from 'module'; +import createDotnetRuntime from 'dotnet' +import { dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const { MONO, BINDING, INTERNAL, Module, RuntimeBuildInfo } = await createDotnetRuntime(() => ({ + imports: { + require: createRequire(import.meta.url) + }, + scriptDirectory: dirname(fileURLToPath(import.meta.url)) + '/', + disableDotnet6Compatibility: true, + configSrc: "./mono-config.json", + onAbort: (err: any) => { + console.log("WASM ABORT " + err); + }, +})); + +try { + + const main_assembly_name = "Wasm.Console.TypeScript.Sample.dll"; + const app_args = process.argv.slice(4); + INTERNAL.mono_wasm_set_main_args(main_assembly_name, app_args); + + // Automatic signature isn't working correctly + const result = await BINDING.call_assembly_entry_point(main_assembly_name, [app_args], "m"); + + console.log("WASM EXIT " + result); +} catch (error) { + console.log("WASM ERROR " + error); +} diff --git a/src/mono/sample/wasm/console-ts/package-lock.json b/src/mono/sample/wasm/console-ts/package-lock.json new file mode 100644 index 0000000000000..da5df8ba099ca --- /dev/null +++ b/src/mono/sample/wasm/console-ts/package-lock.json @@ -0,0 +1,23 @@ +{ + "name": "console-ts", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/node": { + "version": "16.11.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.10.tgz", + "integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==", + "dev": true + }, + "dotnet": { + "version": "file:../../../../../artifacts/bin/native/net7.0-Browser-Debug-wasm" + }, + "typescript": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", + "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "dev": true + } + } +} diff --git a/src/mono/sample/wasm/console-ts/package.json b/src/mono/sample/wasm/console-ts/package.json new file mode 100644 index 0000000000000..fd9d559feec81 --- /dev/null +++ b/src/mono/sample/wasm/console-ts/package.json @@ -0,0 +1,24 @@ +{ + "name": "console-ts", + "version": "1.0.0", + "description": "TypeScript sample for dotnet in WASM", + "main": "bin/main.js", + "type": "module", + "repository": { + "type": "git", + "url": "git@github.com:dotnet/runtime.git" + }, + "scripts": { + "build": "tsc -p .", + "start": "node bin/Debug/AppBundle/main.js" + }, + "author": "Microsoft", + "license": "MIT", + "dependencies": { + "dotnet": "file://../../../../../artifacts/bin/native/net7.0-Browser-Debug-wasm/" + }, + "devDependencies": { + "@types/node": "16.11.10", + "typescript": "4.5.2" + } +} diff --git a/src/mono/sample/wasm/console-ts/tsconfig.json b/src/mono/sample/wasm/console-ts/tsconfig.json new file mode 100644 index 0000000000000..05a3b61afa31c --- /dev/null +++ b/src/mono/sample/wasm/console-ts/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "moduleResolution": "Node", + "target": "ESNext", + "module": "ESNext", + "strict": true, + "outDir": "bin" + } +} \ No newline at end of file diff --git a/src/mono/wasm/runtime/dist-types/dotnet.d.ts b/src/mono/wasm/runtime/dist-types/dotnet.d.ts index 97cc500f3122c..cb85aa9fe8430 100644 --- a/src/mono/wasm/runtime/dist-types/dotnet.d.ts +++ b/src/mono/wasm/runtime/dist-types/dotnet.d.ts @@ -165,30 +165,31 @@ declare type CoverageProfilerOptions = { send_to?: string; }; declare type DotnetModuleConfigImports = { - require: (name: string) => any; - fetch: (url: string) => Promise; - fs: { - promises: { - readFile: (path: string) => Promise; - readFileSync: (path: string, options: string | undefined) => string; + require?: (name: string) => any; + fetch?: (url: string) => Promise; + fs?: { + promises?: { + readFile?: (path: string) => Promise; }; + readFileSync?: (path: string, options: any | undefined) => string; }; - crypto: { - randomBytes: (size: number) => Buffer; + crypto?: { + randomBytes?: (size: number) => Buffer; }; - ws: WebSocket & { + ws?: WebSocket & { Server: any; }; - path: { - normalize: (path: string) => string; - dirname: (path: string) => string; + path?: { + normalize?: (path: string) => string; + dirname?: (path: string) => string; }; - url: any; + url?: any; }; declare type DotnetModuleConfig = { disableDotnet6Compatibility?: boolean; config?: MonoConfig | MonoConfigError; configSrc?: string; + scriptDirectory?: string; onConfigLoaded?: () => void; onDotnetReady?: () => void; imports?: DotnetModuleConfigImports; @@ -255,6 +256,7 @@ interface BINDING { interface DotnetPublicAPI { MONO: MONO; BINDING: BINDING; + INTERNAL: any; Module: any; RuntimeId: number; RuntimeBuildInfo: { diff --git a/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 b/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 index 3cae997cee2f7..08361689d1d1f 100644 --- a/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 +++ b/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 @@ -1 +1 @@ -9340ce4866a6f66e64650178de10f37ad5c29c7c548a3c9beb6595581b34db74 \ No newline at end of file +78af21a88e11709faf2e97c7f4eab76ef277d0262af881eb3001b8d2f385ebdd \ No newline at end of file diff --git a/src/mono/wasm/runtime/dotnet.lib.js b/src/mono/wasm/runtime/dotnet.lib.js index 69f6428d7ff44..e4d9d4f6815f3 100644 --- a/src/mono/wasm/runtime/dotnet.lib.js +++ b/src/mono/wasm/runtime/dotnet.lib.js @@ -7,7 +7,42 @@ const DotnetSupportLib = { $DOTNET: {}, // this line will be executed early on runtime, passing import and export objects into __dotnet_runtime IFFE - $DOTNET__postset: "let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports({isGlobal:ENVIRONMENT_IS_GLOBAL, isNode:ENVIRONMENT_IS_NODE, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, locateFile}, {mono:MONO, binding:BINDING, internal:INTERNAL, module:Module});", + $DOTNET__postset: ` + let __dotnet_replacements = {scriptDirectory, readAsync, fetch: globalThis.fetch}; + let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports( + { isGlobal:ENVIRONMENT_IS_GLOBAL, isNode:ENVIRONMENT_IS_NODE, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, locateFile }, + { mono:MONO, binding:BINDING, internal:INTERNAL, module:Module }, + __dotnet_replacements); + + // here we replace things which are broken on NodeJS for ES6 + if (ENVIRONMENT_IS_NODE) { + __dirname = scriptDirectory = __dotnet_replacements.scriptDirectory; + readAsync = __dotnet_replacements.readAsync; + var fetch = __dotnet_replacements.fetch; + getBinaryPromise = async () => { + if (!wasmBinary) { + try { + if (typeof fetch === 'function' && !isFileURI(wasmBinaryFile)) { + const response = await fetch(wasmBinaryFile, { credentials: 'same-origin' }); + if (!response['ok']) { + throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; + } + return response['arrayBuffer'](); + } + else if (readAsync) { + return await new Promise(function (resolve, reject) { + readAsync(wasmBinaryFile, function (response) { resolve(new Uint8Array(/** @type{!ArrayBuffer} */(response))) }, reject) + }); + } + + } + catch (err) { + return getBinary(wasmBinaryFile); + } + } + return getBinary(wasmBinaryFile); + } + }`, }; // the methods would be visible to EMCC linker diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index c93781c2e9cda..704753d7a9b55 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -70,6 +70,7 @@ import { } from "./memory"; import { create_weak_ref } from "./weak-ref"; import { VoidPtr } from "./types/emscripten"; +import { fetch_like, readAsync_like } from "./polyfills"; const MONO: MONO = { // current "public" MONO API @@ -128,9 +129,14 @@ let exportedAPI: DotnetPublicAPI; function initializeImportsAndExports( imports: { isGlobal: boolean, isNode: boolean, isShell: boolean, isWeb: boolean, locateFile: Function }, exports: { mono: any, binding: any, internal: any, module: any }, + replacements: { scriptDirectory: any, fetch: any, readAsync: any }, ): DotnetPublicAPI { const module = exports.module as DotnetModuleMono; const globalThisAny = globalThis as any; + if (module.scriptDirectory) { + replacements.scriptDirectory = module.scriptDirectory; + } + // we want to have same instance of MONO, BINDING and Module in dotnet iffe setImportsAndExports(imports, exports); @@ -186,6 +192,17 @@ function initializeImportsAndExports( }; } + if (module.imports.fetch) { + runtimeHelpers.fetch = module.imports.fetch; + } else if (globalThisAny.fetch) { + runtimeHelpers.fetch = globalThisAny.fetch; + } + else { + runtimeHelpers.fetch = fetch_like; + } + replacements.fetch = runtimeHelpers.fetch; + replacements.readAsync = readAsync_like; + if (imports.isGlobal || !module.disableDotnet6Compatibility) { Object.assign(module, exportedAPI); @@ -384,6 +401,7 @@ interface BINDING { export interface DotnetPublicAPI { MONO: MONO, BINDING: BINDING, + INTERNAL: any, Module: any, RuntimeId: number, RuntimeBuildInfo: { diff --git a/src/mono/wasm/runtime/imports.ts b/src/mono/wasm/runtime/imports.ts index ec9cf8075bc47..3f659d588ea66 100644 --- a/src/mono/wasm/runtime/imports.ts +++ b/src/mono/wasm/runtime/imports.ts @@ -57,4 +57,5 @@ export const runtimeHelpers: RuntimeHelpers = { MONO.config = value; Module.config = value; }, + fetch: null }; diff --git a/src/mono/wasm/runtime/modularize-es6/dotnet.es6.post.js b/src/mono/wasm/runtime/modularize-es6/dotnet.es6.post.js index 84493951a5b79..841182df7eec4 100644 --- a/src/mono/wasm/runtime/modularize-es6/dotnet.es6.post.js +++ b/src/mono/wasm/runtime/modularize-es6/dotnet.es6.post.js @@ -1,3 +1,3 @@ createDotnetRuntime.ready = createDotnetRuntime.ready.then(() => { return __dotnet_exportedAPI; -}) +}); \ No newline at end of file diff --git a/src/mono/wasm/runtime/modularize-es6/dotnet.es6.pre.js b/src/mono/wasm/runtime/modularize-es6/dotnet.es6.pre.js index 1400c3558e9d2..02d8cffb48185 100644 --- a/src/mono/wasm/runtime/modularize-es6/dotnet.es6.pre.js +++ b/src/mono/wasm/runtime/modularize-es6/dotnet.es6.pre.js @@ -12,4 +12,5 @@ if (typeof createDotnetRuntime === "function") { else { throw new Error("MONO_WASM: Can't use moduleFactory callback of createDotnetRuntime function.") } -let require = (name) => { return Module.imports.require(name) }; \ No newline at end of file +let require = (name) => { return Module.imports.require(name) }; +var __dirname = ''; \ No newline at end of file diff --git a/src/mono/wasm/runtime/polyfills.ts b/src/mono/wasm/runtime/polyfills.ts new file mode 100644 index 0000000000000..01d4d2ded9bc9 --- /dev/null +++ b/src/mono/wasm/runtime/polyfills.ts @@ -0,0 +1,50 @@ +import { ENVIRONMENT_IS_NODE, Module } from "./imports"; + +export async function fetch_like(url: string): Promise { + try { + if (typeof (globalThis.fetch) === "function") { + return globalThis.fetch(url, { credentials: "same-origin" }); + } + else if (ENVIRONMENT_IS_NODE) { + const node_fs = Module.imports!.require!("fs"); + const node_url = Module.imports!.require!("url"); + if (url.startsWith("file://")) { + url = node_url.fileURLToPath(url); + } + + const arrayBuffer = await node_fs.promises.readFile(url); + return { + ok: true, + url, + arrayBuffer: () => arrayBuffer, + json: () => JSON.parse(arrayBuffer) + }; + } + else if (typeof (read) === "function") { + 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, + arrayBuffer: () => { throw e; }, + json: () => { throw e; } + }; + } + throw new Error("No fetch implementation available"); +} + +export function readAsync_like(url: string, onload: Function, onerror: Function): void { + fetch_like(url).then((res: Response) => { + onload(res.arrayBuffer()); + }).catch((err) => { + onerror(err); + }); +} \ No newline at end of file diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index d586e25adcdc6..bc56672ddad46 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -49,17 +49,6 @@ export async function mono_wasm_pre_init(): Promise { } export async function mono_wasm_on_runtime_initialized(): Promise { - /* TODO - if (ENVIRONMENT_IS_NODE) { - const importFn = new Function("module", "name", "return (async () => { if (!module.imports[name]) try { module.imports[name] = await import(name); } catch (err) { } })();"); - await importFn(Module, "fs"); - await importFn(Module, "path"); - await importFn(Module, "fetch"); - await importFn(Module, "crypto"); - await importFn(Module, "ws"); - await importFn(Module, "url"); - }*/ - if (!Module.config || Module.config.isError) { return; } @@ -82,44 +71,6 @@ export function mono_wasm_set_runtime_options(options: string[]): void { cwraps.mono_wasm_parse_runtime_options(options.length, argv); } -async function _fetch_asset(url: string): Promise { - try { - if (typeof (fetch) === "function") { - 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 { - ok: true, - url, - arrayBuffer: () => arrayBuffer, - json: () => JSON.parse(arrayBuffer) - }; - } - else if (typeof (read) === "function") { - 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, - arrayBuffer: () => { throw e; }, - json: () => { throw e; } - }; - } - throw new Error("No fetch implementation available"); -} - function _handle_fetched_asset(ctx: MonoInitContext, asset: AssetEntry, url: string, blob: ArrayBuffer) { const bytes = new Uint8Array(blob); if (ctx.tracing) @@ -358,13 +309,9 @@ export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise< _apply_configuration_from_args(args); - // TODO move polyfills out into separate module - const local_fetch = Module.imports && typeof (Module.imports.fetch) === "function" - ? Module.imports.fetch - // legacy fallback - : typeof ((args).fetch_file_cb) === "function" - ? (args).fetch_file_cb - : _fetch_asset; + if (!Module.imports!.fetch && typeof ((args).fetch_file_cb) === "function") { + runtimeHelpers.fetch = (args).fetch_file_cb; + } const load_asset = async (asset: AllAssetEntryTypes): Promise => { //TODO we could do module.addRunDependency(asset.name) and delay emscripten run() after all assets are loaded @@ -397,7 +344,7 @@ export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise< console.log(`MONO_WASM: Attempting to fetch '${attemptUrl}' for ${asset.name}`); } try { - const response = await local_fetch(attemptUrl); + const response = await runtimeHelpers.fetch(attemptUrl); if (!response.ok) { error = new Error(`MONO_WASM: Fetch '${attemptUrl}' for ${asset.name} failed ${response.status} ${response.statusText}`); continue;// next source @@ -506,7 +453,7 @@ export async function mono_wasm_load_config(configFilePath: string): Promise Promise; } export const wasm_type_symbol = Symbol.for("wasm type"); @@ -155,29 +156,30 @@ export type CoverageProfilerOptions = { // how we extended emscripten Module export type DotnetModuleMono = EmscriptenModule & DotnetModuleConfig; export type DotnetModuleConfigImports = { - require: (name: string) => any; - fetch: (url: string) => Promise; - fs: { - promises: { - readFile: (path: string) => Promise, - readFileSync: (path: string, options: string | undefined) => string, + require?: (name: string) => any; + fetch?: (url: string) => Promise; + fs?: { + promises?: { + readFile?: (path: string) => Promise, } + readFileSync?: (path: string, options: any | undefined) => string, }; - crypto: { - randomBytes: (size: number) => Buffer + crypto?: { + randomBytes?: (size: number) => Buffer }; - ws: WebSocket & { Server: any }; - path: { - normalize: (path: string) => string, - dirname: (path: string) => string, + ws?: WebSocket & { Server: any }; + path?: { + normalize?: (path: string) => string, + dirname?: (path: string) => string, }; - url: any; + url?: any; } export type DotnetModuleConfig = { disableDotnet6Compatibility?: boolean, config?: MonoConfig | MonoConfigError, configSrc?: string, + scriptDirectory?: string, onConfigLoaded?: () => void; onDotnetReady?: () => void; diff --git a/src/mono/wasm/test-main.js b/src/mono/wasm/test-main.js index f378547b34f0d..abdb61518ba9b 100644 --- a/src/mono/wasm/test-main.js +++ b/src/mono/wasm/test-main.js @@ -214,7 +214,7 @@ const App = { 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); + INTERNAL.mono_wasm_set_main_args(main_assembly_name, app_args); // Automatic signature isn't working correctly const result = await BINDING.call_assembly_entry_point(main_assembly_name, [app_args], "m"); From 4c4c502a14fafed0c8322aea5a08299e0954c9a1 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 26 Nov 2021 01:26:33 +0100 Subject: [PATCH 09/28] move files --- src/mono/wasm/Makefile | 4 +- src/mono/wasm/runtime/.eslintrc.js | 4 +- src/mono/wasm/runtime/CMakeLists.txt | 4 +- .../dotnet.cjs.extpost.js | 0 src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js | 79 +++++++++++++ .../dotnet.cjs.post.js | 0 .../{modularize-cjs => cjs}/dotnet.cjs.pre.js | 0 src/mono/wasm/runtime/es6/dotnet.es6.lib.js | 106 ++++++++++++++++++ .../dotnet.es6.post.js | 0 .../{modularize-es6 => es6}/dotnet.es6.pre.js | 0 src/mono/wasm/runtime/modularize-dotnet.md | 2 +- src/mono/wasm/wasm.proj | 13 ++- 12 files changed, 199 insertions(+), 13 deletions(-) rename src/mono/wasm/runtime/{modularize-cjs => cjs}/dotnet.cjs.extpost.js (100%) create mode 100644 src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js rename src/mono/wasm/runtime/{modularize-cjs => cjs}/dotnet.cjs.post.js (100%) rename src/mono/wasm/runtime/{modularize-cjs => cjs}/dotnet.cjs.pre.js (100%) create mode 100644 src/mono/wasm/runtime/es6/dotnet.es6.lib.js rename src/mono/wasm/runtime/{modularize-es6 => es6}/dotnet.es6.post.js (100%) rename src/mono/wasm/runtime/{modularize-es6 => es6}/dotnet.es6.pre.js (100%) diff --git a/src/mono/wasm/Makefile b/src/mono/wasm/Makefile index 28a6315e1463e..04828bba7240c 100644 --- a/src/mono/wasm/Makefile +++ b/src/mono/wasm/Makefile @@ -93,7 +93,7 @@ $(NATIVE_BIN_DIR)/include/wasm: $(BUILDS_OBJ_DIR): mkdir -p $$@ -$(NATIVE_BIN_DIR)/dotnet.js: runtime/driver.c runtime/pinvoke.c runtime/pinvoke.h runtime/corebindings.c $(NATIVE_BIN_DIR)/src/cjs/runtime.cjs.iffe.js runtime/dotnet.lib.js $(SYSTEM_NATIVE_LIBDIR)/pal_random.lib.js $(MONO_LIBS) $(EMCC_DEFAULT_RSP) | $(NATIVE_BIN_DIR) +$(NATIVE_BIN_DIR)/dotnet.js: runtime/driver.c runtime/pinvoke.c runtime/pinvoke.h runtime/corebindings.c $(NATIVE_BIN_DIR)/src/cjs/runtime.cjs.iffe.js runtime/cjs/dotnet.cjs.lib.js $(SYSTEM_NATIVE_LIBDIR)/pal_random.lib.js $(MONO_LIBS) $(EMCC_DEFAULT_RSP) | $(NATIVE_BIN_DIR) $(DOTNET) build $(CURDIR)/wasm.proj $(_MSBUILD_WASM_BUILD_ARGS) /t:BuildWasmRuntimes $(MSBUILD_ARGS) $(EMCC_DEFAULT_RSP): $(CURDIR)/wasm.proj | $(NATIVE_BIN_DIR)/src Makefile @@ -113,7 +113,7 @@ clean: icu-files: $(wildcard $(ICU_LIBDIR)/*.dat) $(ICU_LIBDIR)/libicuuc.a $(ICU_LIBDIR)/libicui18n.a | $(NATIVE_BIN_DIR) cp $^ $(NATIVE_BIN_DIR) -source-files: runtime/driver.c runtime/pinvoke.c runtime/corebindings.c runtime/dotnet.lib.js $(SYSTEM_NATIVE_LIBDIR)/pal_random.lib.js | $(NATIVE_BIN_DIR)/src +source-files: runtime/driver.c runtime/pinvoke.c runtime/corebindings.c runtime/cjs/dotnet.cjs.lib.js $(SYSTEM_NATIVE_LIBDIR)/pal_random.lib.js | $(NATIVE_BIN_DIR)/src cp $^ $(NATIVE_BIN_DIR)/src header-files: runtime/pinvoke.h | $(NATIVE_BIN_DIR)/include/wasm diff --git a/src/mono/wasm/runtime/.eslintrc.js b/src/mono/wasm/runtime/.eslintrc.js index 8aacf17304191..5acfca7fed012 100644 --- a/src/mono/wasm/runtime/.eslintrc.js +++ b/src/mono/wasm/runtime/.eslintrc.js @@ -19,8 +19,8 @@ module.exports = { "ignorePatterns": [ "node_modules/**/*.*", "bin/**/*.*", - "modularize-cjs/*.js", - "modularize-es6/*.js", + "cjs/*.js", + "es6/*.js", ], "rules": { "@typescript-eslint/no-explicit-any": "off", diff --git a/src/mono/wasm/runtime/CMakeLists.txt b/src/mono/wasm/runtime/CMakeLists.txt index 4deaf16360c6e..9721e39682c9b 100644 --- a/src/mono/wasm/runtime/CMakeLists.txt +++ b/src/mono/wasm/runtime/CMakeLists.txt @@ -24,8 +24,8 @@ target_link_libraries(dotnet ${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/cjs/dotnet.cjs.pre.js;${NATIVE_BIN_DIR}/src/cjs/runtime.cjs.iffe.js;${NATIVE_BIN_DIR}/src/dotnet.lib.js;${NATIVE_BIN_DIR}/src/pal_random.lib.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.post.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.extpost.js;" - LINK_FLAGS "@${NATIVE_BIN_DIR}/src/emcc-default.rsp ${CONFIGURATION_LINK_FLAGS} -DENABLE_NETCORE=1 --extern-pre-js ${NATIVE_BIN_DIR}/src/cjs/runtime.cjs.iffe.js --pre-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.pre.js --js-library ${NATIVE_BIN_DIR}/src/dotnet.lib.js --js-library ${NATIVE_BIN_DIR}/src/pal_random.lib.js --post-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.post.js --extern-post-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.extpost.js " + LINK_DEPENDS "${NATIVE_BIN_DIR}/src/emcc-default.rsp;${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.pre.js;${NATIVE_BIN_DIR}/src/cjs/runtime.cjs.iffe.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.lib.js;${NATIVE_BIN_DIR}/src/pal_random.lib.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.post.js;${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.extpost.js;" + LINK_FLAGS "@${NATIVE_BIN_DIR}/src/emcc-default.rsp ${CONFIGURATION_LINK_FLAGS} -DENABLE_NETCORE=1 --extern-pre-js ${NATIVE_BIN_DIR}/src/cjs/runtime.cjs.iffe.js --pre-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.pre.js --js-library ${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.lib.js --js-library ${NATIVE_BIN_DIR}/src/pal_random.lib.js --post-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.post.js --extern-post-js ${NATIVE_BIN_DIR}/src/cjs/dotnet.cjs.extpost.js " RUNTIME_OUTPUT_DIRECTORY "${NATIVE_BIN_DIR}") if(CMAKE_BUILD_TYPE STREQUAL "Release") diff --git a/src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.extpost.js b/src/mono/wasm/runtime/cjs/dotnet.cjs.extpost.js similarity index 100% rename from src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.extpost.js rename to src/mono/wasm/runtime/cjs/dotnet.cjs.extpost.js diff --git a/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js b/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js new file mode 100644 index 0000000000000..0afe7aa008313 --- /dev/null +++ b/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js @@ -0,0 +1,79 @@ +// 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"; + +const DotnetSupportLib = { + $DOTNET: {}, + // this line will be early early on emscripten runtime creation, passing import and export objects into __dotnet_runtime IFFE + $DOTNET__postset: ` + let __dotnet_replacements = {scriptDirectory, readAsync, fetch: globalThis.fetch}; + let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports( + { isGlobal:ENVIRONMENT_IS_GLOBAL, isNode:ENVIRONMENT_IS_NODE, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, locateFile }, + { mono:MONO, binding:BINDING, internal:INTERNAL, module:Module }, + __dotnet_replacements); + + // here we replace things which are not exposed in another way + __dirname = scriptDirectory = __dotnet_replacements.scriptDirectory; + readAsync = __dotnet_replacements.readAsync; + var fetch = __dotnet_replacements.fetch;`, +}; + +// the methods would be visible to EMCC linker +// --- keep in sync with exports.ts --- +const linked_functions = [ + // mini-wasm.c + "mono_set_timeout", + + // mini-wasm-debugger.c + "mono_wasm_asm_loaded", + "mono_wasm_fire_debugger_agent_message", + "mono_wasm_debugger_log", + "mono_wasm_add_dbg_command_received", + + // mono-threads-wasm.c + "schedule_background_exec", + + // driver.c + "mono_wasm_invoke_js", + "mono_wasm_invoke_js_blazor", + "mono_wasm_trace_logger", + + // corebindings.c + "mono_wasm_invoke_js_with_args", + "mono_wasm_get_object_property", + "mono_wasm_set_object_property", + "mono_wasm_get_by_index", + "mono_wasm_set_by_index", + "mono_wasm_get_global_object", + "mono_wasm_create_cs_owned_object", + "mono_wasm_release_cs_owned_object", + "mono_wasm_typed_array_to_array", + "mono_wasm_typed_array_copy_to", + "mono_wasm_typed_array_from", + "mono_wasm_typed_array_copy_from", + "mono_wasm_add_event_listener", + "mono_wasm_remove_event_listener", + "mono_wasm_cancel_promise", + "mono_wasm_web_socket_open", + "mono_wasm_web_socket_send", + "mono_wasm_web_socket_receive", + "mono_wasm_web_socket_close", + "mono_wasm_web_socket_abort", + "mono_wasm_compile_function", + + // pal_icushim_static.c + "mono_wasm_load_icu_data", + "mono_wasm_get_icudt_name", +]; + +// -- 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.__linker_exports.${linked_function}.apply(__dotnet_runtime, arguments)`; + DotnetSupportLib[linked_function] = new Function(fn_template); +} + +autoAddDeps(DotnetSupportLib, "$DOTNET"); +mergeInto(LibraryManager.library, DotnetSupportLib); diff --git a/src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.post.js b/src/mono/wasm/runtime/cjs/dotnet.cjs.post.js similarity index 100% rename from src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.post.js rename to src/mono/wasm/runtime/cjs/dotnet.cjs.post.js diff --git a/src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.pre.js b/src/mono/wasm/runtime/cjs/dotnet.cjs.pre.js similarity index 100% rename from src/mono/wasm/runtime/modularize-cjs/dotnet.cjs.pre.js rename to src/mono/wasm/runtime/cjs/dotnet.cjs.pre.js diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js new file mode 100644 index 0000000000000..f6ba8e55fdd47 --- /dev/null +++ b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js @@ -0,0 +1,106 @@ +// 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"; + +const DotnetSupportLib = { + $DOTNET: {}, + // this line will be early early on emscripten runtime creation, passing import and export objects into __dotnet_runtime IFFE + $DOTNET__postset: ` + let __dotnet_replacements = {scriptDirectory, readAsync, fetch: globalThis.fetch}; + let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports( + { isGlobal:ENVIRONMENT_IS_GLOBAL, isNode:ENVIRONMENT_IS_NODE, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, locateFile }, + { mono:MONO, binding:BINDING, internal:INTERNAL, module:Module }, + __dotnet_replacements); + + // here we replace things which are not exposed in another way + __dirname = scriptDirectory = __dotnet_replacements.scriptDirectory; + readAsync = __dotnet_replacements.readAsync; + var fetch = __dotnet_replacements.fetch; + + // here we replace things which are broken on NodeJS for ES6 + if (ENVIRONMENT_IS_NODE) { + getBinaryPromise = async () => { + if (!wasmBinary) { + try { + if (typeof fetch === 'function' && !isFileURI(wasmBinaryFile)) { + const response = await fetch(wasmBinaryFile, { credentials: 'same-origin' }); + if (!response['ok']) { + throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; + } + return response['arrayBuffer'](); + } + else if (readAsync) { + return await new Promise(function (resolve, reject) { + readAsync(wasmBinaryFile, function (response) { resolve(new Uint8Array(/** @type{!ArrayBuffer} */(response))) }, reject) + }); + } + + } + catch (err) { + return getBinary(wasmBinaryFile); + } + } + return getBinary(wasmBinaryFile); + } + }`, +}; + +// the methods would be visible to EMCC linker +// --- keep in sync with exports.ts --- +const linked_functions = [ + // mini-wasm.c + "mono_set_timeout", + + // mini-wasm-debugger.c + "mono_wasm_asm_loaded", + "mono_wasm_fire_debugger_agent_message", + "mono_wasm_debugger_log", + "mono_wasm_add_dbg_command_received", + + // mono-threads-wasm.c + "schedule_background_exec", + + // driver.c + "mono_wasm_invoke_js", + "mono_wasm_invoke_js_blazor", + "mono_wasm_trace_logger", + + // corebindings.c + "mono_wasm_invoke_js_with_args", + "mono_wasm_get_object_property", + "mono_wasm_set_object_property", + "mono_wasm_get_by_index", + "mono_wasm_set_by_index", + "mono_wasm_get_global_object", + "mono_wasm_create_cs_owned_object", + "mono_wasm_release_cs_owned_object", + "mono_wasm_typed_array_to_array", + "mono_wasm_typed_array_copy_to", + "mono_wasm_typed_array_from", + "mono_wasm_typed_array_copy_from", + "mono_wasm_add_event_listener", + "mono_wasm_remove_event_listener", + "mono_wasm_cancel_promise", + "mono_wasm_web_socket_open", + "mono_wasm_web_socket_send", + "mono_wasm_web_socket_receive", + "mono_wasm_web_socket_close", + "mono_wasm_web_socket_abort", + "mono_wasm_compile_function", + + // pal_icushim_static.c + "mono_wasm_load_icu_data", + "mono_wasm_get_icudt_name", +]; + +// -- 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.__linker_exports.${linked_function}.apply(__dotnet_runtime, arguments)`; + DotnetSupportLib[linked_function] = new Function(fn_template); +} + +autoAddDeps(DotnetSupportLib, "$DOTNET"); +mergeInto(LibraryManager.library, DotnetSupportLib); diff --git a/src/mono/wasm/runtime/modularize-es6/dotnet.es6.post.js b/src/mono/wasm/runtime/es6/dotnet.es6.post.js similarity index 100% rename from src/mono/wasm/runtime/modularize-es6/dotnet.es6.post.js rename to src/mono/wasm/runtime/es6/dotnet.es6.post.js diff --git a/src/mono/wasm/runtime/modularize-es6/dotnet.es6.pre.js b/src/mono/wasm/runtime/es6/dotnet.es6.pre.js similarity index 100% rename from src/mono/wasm/runtime/modularize-es6/dotnet.es6.pre.js rename to src/mono/wasm/runtime/es6/dotnet.es6.pre.js diff --git a/src/mono/wasm/runtime/modularize-dotnet.md b/src/mono/wasm/runtime/modularize-dotnet.md index ab0d31e4265e9..75d96cfc2a77d 100644 --- a/src/mono/wasm/runtime/modularize-dotnet.md +++ b/src/mono/wasm/runtime/modularize-dotnet.md @@ -19,7 +19,7 @@ In `src\mono\wasm\runtime\CMakeLists.txt` which links only in-tree, we use same - Executed second (2) - Applied only when linking CommonJS - Will try to see if it was executed with `globalThis.Module` and if so, it would use it's instance as `Module`. It would preserve emscriptens `Module.ready` -- Otherwise it would load it would assume it was called via `createDotnetRuntime` export same as described for `modularize-dotnet.prees6.js` below. +- Otherwise it would load it would assume it was called via `createDotnetRuntime` export same as described for `dotnet.es6.pre.js` below. # dotnet.es6.pre.js - Executed second (2) diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index 8b4afed96ef30..ab93616c883bb 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -181,19 +181,20 @@ - - From 3c38597becb7d5cab8b63cfdb8796863a23fb418 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 26 Nov 2021 01:32:29 +0100 Subject: [PATCH 10/28] fix --- src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js | 2 +- src/mono/wasm/runtime/dotnet.lib.js | 104 -------------------- src/mono/wasm/runtime/es6/dotnet.es6.lib.js | 2 +- 3 files changed, 2 insertions(+), 106 deletions(-) delete mode 100644 src/mono/wasm/runtime/dotnet.lib.js diff --git a/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js b/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js index 0afe7aa008313..0a76f5f5ca4ba 100644 --- a/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js +++ b/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js @@ -6,7 +6,7 @@ const DotnetSupportLib = { $DOTNET: {}, - // this line will be early early on emscripten runtime creation, passing import and export objects into __dotnet_runtime IFFE + // this line will be placed early on emscripten runtime creation, passing import and export objects into __dotnet_runtime IFFE $DOTNET__postset: ` let __dotnet_replacements = {scriptDirectory, readAsync, fetch: globalThis.fetch}; let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports( diff --git a/src/mono/wasm/runtime/dotnet.lib.js b/src/mono/wasm/runtime/dotnet.lib.js deleted file mode 100644 index e4d9d4f6815f3..0000000000000 --- a/src/mono/wasm/runtime/dotnet.lib.js +++ /dev/null @@ -1,104 +0,0 @@ -// 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"; - -const DotnetSupportLib = { - $DOTNET: {}, - // this line will be executed early on runtime, passing import and export objects into __dotnet_runtime IFFE - $DOTNET__postset: ` - let __dotnet_replacements = {scriptDirectory, readAsync, fetch: globalThis.fetch}; - let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports( - { isGlobal:ENVIRONMENT_IS_GLOBAL, isNode:ENVIRONMENT_IS_NODE, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, locateFile }, - { mono:MONO, binding:BINDING, internal:INTERNAL, module:Module }, - __dotnet_replacements); - - // here we replace things which are broken on NodeJS for ES6 - if (ENVIRONMENT_IS_NODE) { - __dirname = scriptDirectory = __dotnet_replacements.scriptDirectory; - readAsync = __dotnet_replacements.readAsync; - var fetch = __dotnet_replacements.fetch; - getBinaryPromise = async () => { - if (!wasmBinary) { - try { - if (typeof fetch === 'function' && !isFileURI(wasmBinaryFile)) { - const response = await fetch(wasmBinaryFile, { credentials: 'same-origin' }); - if (!response['ok']) { - throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; - } - return response['arrayBuffer'](); - } - else if (readAsync) { - return await new Promise(function (resolve, reject) { - readAsync(wasmBinaryFile, function (response) { resolve(new Uint8Array(/** @type{!ArrayBuffer} */(response))) }, reject) - }); - } - - } - catch (err) { - return getBinary(wasmBinaryFile); - } - } - return getBinary(wasmBinaryFile); - } - }`, -}; - -// the methods would be visible to EMCC linker -// --- keep in sync with exports.ts --- -const linked_functions = [ - // mini-wasm.c - "mono_set_timeout", - - // mini-wasm-debugger.c - "mono_wasm_asm_loaded", - "mono_wasm_fire_debugger_agent_message", - "mono_wasm_debugger_log", - "mono_wasm_add_dbg_command_received", - - // mono-threads-wasm.c - "schedule_background_exec", - - // driver.c - "mono_wasm_invoke_js", - "mono_wasm_invoke_js_blazor", - "mono_wasm_trace_logger", - - // corebindings.c - "mono_wasm_invoke_js_with_args", - "mono_wasm_get_object_property", - "mono_wasm_set_object_property", - "mono_wasm_get_by_index", - "mono_wasm_set_by_index", - "mono_wasm_get_global_object", - "mono_wasm_create_cs_owned_object", - "mono_wasm_release_cs_owned_object", - "mono_wasm_typed_array_to_array", - "mono_wasm_typed_array_copy_to", - "mono_wasm_typed_array_from", - "mono_wasm_typed_array_copy_from", - "mono_wasm_add_event_listener", - "mono_wasm_remove_event_listener", - "mono_wasm_cancel_promise", - "mono_wasm_web_socket_open", - "mono_wasm_web_socket_send", - "mono_wasm_web_socket_receive", - "mono_wasm_web_socket_close", - "mono_wasm_web_socket_abort", - "mono_wasm_compile_function", - - // pal_icushim_static.c - "mono_wasm_load_icu_data", - "mono_wasm_get_icudt_name", -]; - -// -- 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.__linker_exports.${linked_function}.apply(__dotnet_runtime, arguments)`; - DotnetSupportLib[linked_function] = new Function(fn_template); -} - -autoAddDeps(DotnetSupportLib, "$DOTNET"); -mergeInto(LibraryManager.library, DotnetSupportLib); diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js index f6ba8e55fdd47..341fa01b9078e 100644 --- a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js +++ b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js @@ -6,7 +6,7 @@ const DotnetSupportLib = { $DOTNET: {}, - // this line will be early early on emscripten runtime creation, passing import and export objects into __dotnet_runtime IFFE + // this line will be placed early on emscripten runtime creation, passing import and export objects into __dotnet_runtime IFFE $DOTNET__postset: ` let __dotnet_replacements = {scriptDirectory, readAsync, fetch: globalThis.fetch}; let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports( From da43912900d83e8d6c052f654b22c7adbaea49c2 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 26 Nov 2021 11:14:43 +0100 Subject: [PATCH 11/28] fix build --- .../pkg/sfx/Microsoft.NETCore.App/Directory.Build.props | 9 +++++---- src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs | 2 +- .../wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs | 2 +- src/mono/wasm/runtime/exports.ts | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) 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 fb8396ccf8b5f..f122fd1fcf526 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props @@ -210,6 +210,7 @@ + @@ -218,16 +219,16 @@ - - - + + - + + diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs index b708352ac8657..05d3d6cccbf66 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs @@ -574,7 +574,7 @@ public async Task InvalidArrayId() => await CheckInspectLocalsAtBreakpointSite( // Trying to access object as an array if (!DotnetObjectId.TryParse(c_obj_id, out var id) || id.Scheme != "object") - Assert.True(false, "Unexpected object id format. Maybe this test is out of sync with the object id format in dotnet.lib.js?"); + Assert.True(false, "Unexpected object id format. Maybe this test is out of sync with the object id format in dotnet.cjs.lib.js?"); if (!int.TryParse(id.Value, out var idNum)) Assert.True(false, "Expected a numeric value part of the object id: {c_obj_id}"); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs index 60ede3a0a9423..38745afae6460 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs @@ -808,7 +808,7 @@ internal async Task GetProperties(string id, JToken fn_args = null, bool return null; var locals = frame_props.Value["result"]; - // FIXME: Should be done when generating the list in dotnet.lib.js, but not sure yet + // FIXME: Should be done when generating the list in dotnet.cjs.lib.js, but not sure yet // whether to remove it, and how to do it correctly. if (locals is JArray) { diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index 704753d7a9b55..4528498dd9b20 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -261,7 +261,7 @@ function initializeImportsAndExports( export const __initializeImportsAndExports: any = initializeImportsAndExports; // don't want to export the type // the methods would be visible to EMCC linker -// --- keep in sync with dotnet.lib.js --- +// --- keep in sync with dotnet.cjs.lib.js --- export const __linker_exports: any = { // mini-wasm.c mono_set_timeout, From 42634daa5af7f22816466917f19576afbd8b2e39 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 26 Nov 2021 11:43:35 +0100 Subject: [PATCH 12/28] simplify TS Sample --- .../Wasm.Console.TypeScript.Sample.csproj | 2 ++ src/mono/sample/wasm/console-ts/main.ts | 15 +++++---------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj b/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj index 70838099c9c93..9da43c315c34b 100644 --- a/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj +++ b/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj @@ -9,7 +9,9 @@ true embedded 1 + CompileTypeScript; $(WasmBuildAppDependsOn) diff --git a/src/mono/sample/wasm/console-ts/main.ts b/src/mono/sample/wasm/console-ts/main.ts index 1cb5b800da370..ebada8338f5d8 100644 --- a/src/mono/sample/wasm/console-ts/main.ts +++ b/src/mono/sample/wasm/console-ts/main.ts @@ -2,8 +2,9 @@ import { createRequire } from 'module'; import createDotnetRuntime from 'dotnet' import { dirname } from 'path'; import { fileURLToPath } from 'url'; +import { exit } from 'process'; -const { MONO, BINDING, INTERNAL, Module, RuntimeBuildInfo } = await createDotnetRuntime(() => ({ +const { BINDING } = await createDotnetRuntime(() => ({ imports: { require: createRequire(import.meta.url) }, @@ -16,15 +17,9 @@ const { MONO, BINDING, INTERNAL, Module, RuntimeBuildInfo } = await createDotnet })); try { - - const main_assembly_name = "Wasm.Console.TypeScript.Sample.dll"; - const app_args = process.argv.slice(4); - INTERNAL.mono_wasm_set_main_args(main_assembly_name, app_args); - - // Automatic signature isn't working correctly - const result = await BINDING.call_assembly_entry_point(main_assembly_name, [app_args], "m"); - - console.log("WASM EXIT " + result); + const app_args = process.argv.slice(2); + const result = await BINDING.call_assembly_entry_point("Wasm.Console.TypeScript.Sample.dll", [app_args], "m"); + exit(result) } catch (error) { console.log("WASM ERROR " + error); } From 0678e4888214da8249915b255c3b6f255cb3698d Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 26 Nov 2021 12:55:13 +0100 Subject: [PATCH 13/28] improve exports, reduce console noise, fix build --- .../Wasm.Console.TypeScript.Sample.csproj | 4 +- src/mono/sample/wasm/console-ts/package.json | 4 +- src/mono/wasm/runtime/dist-types/dotnet.d.ts | 80 ++++++++---- .../runtime/dist-types/dotnet.d.ts.sha256 | 2 +- src/mono/wasm/runtime/exports.ts | 119 +++++------------- src/mono/wasm/runtime/icu.ts | 11 +- src/mono/wasm/runtime/imports.ts | 4 +- src/mono/wasm/runtime/startup.ts | 35 +++--- src/mono/wasm/runtime/types.ts | 28 +++-- 9 files changed, 137 insertions(+), 150 deletions(-) diff --git a/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj b/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj index 9da43c315c34b..1aa290ed59bf3 100644 --- a/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj +++ b/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj @@ -4,12 +4,12 @@ bin/main.js true - Debug - true + Release true embedded 1 diff --git a/src/mono/sample/wasm/console-ts/package.json b/src/mono/sample/wasm/console-ts/package.json index fd9d559feec81..67a0427778e2b 100644 --- a/src/mono/sample/wasm/console-ts/package.json +++ b/src/mono/sample/wasm/console-ts/package.json @@ -10,12 +10,12 @@ }, "scripts": { "build": "tsc -p .", - "start": "node bin/Debug/AppBundle/main.js" + "start": "node bin/Release/AppBundle/main.js" }, "author": "Microsoft", "license": "MIT", "dependencies": { - "dotnet": "file://../../../../../artifacts/bin/native/net7.0-Browser-Debug-wasm/" + "dotnet": "file://../../../../../artifacts/bin/native/net7.0-Browser-Release-wasm/" }, "devDependencies": { "@types/node": "16.11.10", diff --git a/src/mono/wasm/runtime/dist-types/dotnet.d.ts b/src/mono/wasm/runtime/dist-types/dotnet.d.ts index cb85aa9fe8430..b97d05b9718cc 100644 --- a/src/mono/wasm/runtime/dist-types/dotnet.d.ts +++ b/src/mono/wasm/runtime/dist-types/dotnet.d.ts @@ -72,8 +72,6 @@ declare class WasmRoot { toString(): string; } -declare function mono_wasm_runtime_ready(): void; - declare const enum ArgsMarshal { Int32 = "i", Int32Enum = "j", @@ -164,6 +162,15 @@ declare type CoverageProfilerOptions = { write_at?: string; send_to?: string; }; +declare type DotnetModuleConfig = { + disableDotnet6Compatibility?: boolean; + config?: MonoConfig | MonoConfigError; + configSrc?: string; + scriptDirectory?: string; + onConfigLoaded?: () => void; + onDotnetReady?: () => void; + imports?: DotnetModuleConfigImports; +}; declare type DotnetModuleConfigImports = { require?: (name: string) => any; fetch?: (url: string) => Promise; @@ -185,15 +192,8 @@ declare type DotnetModuleConfigImports = { }; url?: any; }; -declare type DotnetModuleConfig = { - disableDotnet6Compatibility?: boolean; - config?: MonoConfig | MonoConfigError; - configSrc?: string; - scriptDirectory?: string; - onConfigLoaded?: () => void; - onDotnetReady?: () => void; - imports?: DotnetModuleConfigImports; -}; + +declare function mono_wasm_runtime_ready(): void; declare function mono_wasm_setenv(name: string, value: string): void; declare function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise; @@ -223,13 +223,32 @@ declare function mono_call_assembly_entry_point(assembly: string, args: any[], s declare function mono_wasm_load_bytes_into_heap(bytes: Uint8Array): VoidPtr; -declare const MONO: MONO; -interface MONO { - mono_wasm_runtime_ready: typeof mono_wasm_runtime_ready; +declare type _MemOffset = number | VoidPtr | NativePointer; +declare function setU8(offset: _MemOffset, value: number): void; +declare function setU16(offset: _MemOffset, value: number): void; +declare function setU32(offset: _MemOffset, value: number): void; +declare function setI8(offset: _MemOffset, value: number): void; +declare function setI16(offset: _MemOffset, value: number): void; +declare function setI32(offset: _MemOffset, value: number): void; +declare function setI64(offset: _MemOffset, value: number): void; +declare function setF32(offset: _MemOffset, value: number): void; +declare function setF64(offset: _MemOffset, value: number): void; +declare function getU8(offset: _MemOffset): number; +declare function getU16(offset: _MemOffset): number; +declare function getU32(offset: _MemOffset): number; +declare function getI8(offset: _MemOffset): number; +declare function getI16(offset: _MemOffset): number; +declare function getI32(offset: _MemOffset): number; +declare function getI64(offset: _MemOffset): number; +declare function getF32(offset: _MemOffset): number; +declare function getF64(offset: _MemOffset): number; + +declare const MONO: { mono_wasm_setenv: typeof mono_wasm_setenv; - mono_wasm_load_data_archive: typeof mono_wasm_load_data_archive; mono_wasm_load_bytes_into_heap: typeof mono_wasm_load_bytes_into_heap; mono_wasm_load_icu_data: typeof mono_wasm_load_icu_data; + mono_wasm_runtime_ready: typeof mono_wasm_runtime_ready; + mono_wasm_load_data_archive: typeof mono_wasm_load_data_archive; mono_wasm_load_config: typeof mono_wasm_load_config; mono_load_runtime_and_bcl_args: typeof mono_load_runtime_and_bcl_args; mono_wasm_new_root_buffer: typeof mono_wasm_new_root_buffer; @@ -237,11 +256,28 @@ interface MONO { mono_wasm_release_roots: typeof mono_wasm_release_roots; 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; -} -declare const BINDING: BINDING; -interface BINDING { + loaded_files: never[]; + setI8: typeof setI8; + setI16: typeof setI16; + setI32: typeof setI32; + setI64: typeof setI64; + setU8: typeof setU8; + setU16: typeof setU16; + setU32: typeof setU32; + setF32: typeof setF32; + setF64: typeof setF64; + getI8: typeof getI8; + getI16: typeof getI16; + getI32: typeof getI32; + getI64: typeof getI64; + getU8: typeof getU8; + getU16: typeof getU16; + getU32: typeof getU32; + getF32: typeof getF32; + getF64: typeof getF64; +}; +declare const 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; @@ -252,10 +288,10 @@ 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; -} +}; interface DotnetPublicAPI { - MONO: MONO; - BINDING: BINDING; + MONO: typeof MONO; + BINDING: typeof BINDING; INTERNAL: any; Module: any; RuntimeId: number; diff --git a/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 b/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 index 08361689d1d1f..881f0a5e2af82 100644 --- a/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 +++ b/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 @@ -1 +1 @@ -78af21a88e11709faf2e97c7f4eab76ef277d0262af881eb3001b8d2f385ebdd \ No newline at end of file +106d742df347b40bda6ab3de800fcfa1ebad4f1d93a1c6a78c0bcd627e17a8a2 \ No newline at end of file diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index 4528498dd9b20..e265cf346a9d0 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -5,8 +5,8 @@ import ProductVersion from "consts:productVersion"; import Configuration from "consts:configuration"; import { - mono_wasm_new_root, mono_wasm_new_roots, mono_wasm_release_roots, - mono_wasm_new_root_buffer, mono_wasm_new_root_buffer_from_pointer + mono_wasm_new_root, mono_wasm_release_roots, + mono_wasm_new_root_buffer } from "./roots"; import { mono_wasm_send_dbg_command_with_parms, @@ -26,7 +26,7 @@ import { mono_wasm_add_dbg_command_received, } from "./debug"; import { runtimeHelpers, setImportsAndExports } from "./imports"; -import { DotnetModuleConfigImports, DotnetModuleMono, MonoArray, MonoConfig, MonoConfigError, MonoObject } from "./types"; +import { DotnetModuleConfigImports, DotnetModule } from "./types"; import { mono_load_runtime_and_bcl_args, mono_wasm_load_config, mono_wasm_setenv, mono_wasm_set_runtime_options, @@ -41,8 +41,7 @@ import { mono_wasm_load_icu_data, mono_wasm_get_icudt_name } from "./icu"; import { conv_string, js_string_to_mono_string, mono_intern_string } from "./strings"; import { js_to_mono_obj, js_typed_array_to_array, mono_wasm_typed_array_to_array } from "./js-to-cs"; import { - mono_array_to_js_array, mono_wasm_create_cs_owned_object, unbox_mono_obj, - _unbox_mono_obj_root_with_known_nonprimitive_type + mono_array_to_js_array, mono_wasm_create_cs_owned_object, unbox_mono_obj } from "./cs-to-js"; import { call_static_method, mono_bind_static_method, mono_call_assembly_entry_point, @@ -51,9 +50,7 @@ import { mono_wasm_get_by_index, mono_wasm_get_global_object, mono_wasm_get_object_property, mono_wasm_invoke_js, mono_wasm_invoke_js_blazor, - mono_wasm_invoke_js_with_args, mono_wasm_set_by_index, mono_wasm_set_object_property, - _get_args_root_buffer_for_method_call, _get_buffer_for_method_call, - _handle_exception_for_call, _teardown_after_call + mono_wasm_invoke_js_with_args, mono_wasm_set_by_index, mono_wasm_set_object_property } from "./method-calls"; import { mono_wasm_typed_array_copy_to, mono_wasm_typed_array_from, mono_wasm_typed_array_copy_from, mono_wasm_load_bytes_into_heap } from "./buffers"; import { mono_wasm_cancel_promise } from "./cancelable-promise"; @@ -69,10 +66,9 @@ import { getU8, getU16, getU32, getF32, getF64, } from "./memory"; import { create_weak_ref } from "./weak-ref"; -import { VoidPtr } from "./types/emscripten"; import { fetch_like, readAsync_like } from "./polyfills"; -const MONO: MONO = { +const MONO = { // current "public" MONO API mono_wasm_setenv, mono_wasm_load_bytes_into_heap, @@ -92,12 +88,28 @@ const MONO: MONO = { config: runtimeHelpers.config, loaded_files: [], - // generated bindings closure `library_mono` - mono_wasm_new_root_buffer_from_pointer, - mono_wasm_new_roots, + // memory accessors + setI8, + setI16, + setI32, + setI64, + setU8, + setU16, + setU32, + setF32, + setF64, + getI8, + getI16, + getI32, + getI64, + getU8, + getU16, + getU32, + getF32, + getF64, }; -const BINDING: BINDING = { +const 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, @@ -109,16 +121,6 @@ const BINDING: BINDING = { bind_static_method: mono_bind_static_method, call_assembly_entry_point: mono_call_assembly_entry_point, unbox_mono_obj, - - // generated bindings closure `binding_support` - // todo use the methods directly in the closure, not via BINDING - _get_args_root_buffer_for_method_call, - _get_buffer_for_method_call, - invoke_method: cwraps.mono_wasm_invoke_method, - _handle_exception_for_call, - mono_wasm_try_unbox_primitive_and_get_type: cwraps.mono_wasm_try_unbox_primitive_and_get_type, - _unbox_mono_obj_root_with_known_nonprimitive_type, - _teardown_after_call, }; let exportedAPI: DotnetPublicAPI; @@ -131,12 +133,8 @@ function initializeImportsAndExports( exports: { mono: any, binding: any, internal: any, module: any }, replacements: { scriptDirectory: any, fetch: any, readAsync: any }, ): DotnetPublicAPI { - const module = exports.module as DotnetModuleMono; + const module = exports.module as DotnetModule; const globalThisAny = globalThis as any; - if (module.scriptDirectory) { - replacements.scriptDirectory = module.scriptDirectory; - } - // we want to have same instance of MONO, BINDING and Module in dotnet iffe setImportsAndExports(imports, exports); @@ -194,12 +192,13 @@ function initializeImportsAndExports( if (module.imports.fetch) { runtimeHelpers.fetch = module.imports.fetch; - } else if (globalThisAny.fetch) { - runtimeHelpers.fetch = globalThisAny.fetch; } else { runtimeHelpers.fetch = fetch_like; } + if (module.scriptDirectory) { + replacements.scriptDirectory = module.scriptDirectory; + } replacements.fetch = runtimeHelpers.fetch; replacements.readAsync = readAsync_like; @@ -339,68 +338,14 @@ const INTERNAL: any = { mono_wasm_detach_debugger, mono_wasm_raise_debug_event, mono_wasm_runtime_is_ready: runtimeHelpers.mono_wasm_runtime_is_ready, - - // memory accessors - setI8, - setI16, - setI32, - setI64, - setU8, - setU16, - setU32, - setF32, - setF64, - getI8, - getI16, - getI32, - getI64, - getU8, - getU16, - getU32, - getF32, - getF64, }; -// this represents visibility in the javascript -// like https://github.com/dotnet/aspnetcore/blob/main/src/Components/Web.JS/src/Platform/Mono/MonoTypes.ts -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; - mono_wasm_load_bytes_into_heap: typeof mono_wasm_load_bytes_into_heap; - mono_wasm_load_icu_data: typeof mono_wasm_load_icu_data; - mono_wasm_load_config: typeof mono_wasm_load_config; - mono_load_runtime_and_bcl_args: typeof mono_load_runtime_and_bcl_args; - mono_wasm_new_root_buffer: typeof mono_wasm_new_root_buffer; - mono_wasm_new_root: typeof mono_wasm_new_root; - mono_wasm_release_roots: typeof mono_wasm_release_roots; - - // for Blazor's future! - 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, -} // this represents visibility in the javascript // like https://github.com/dotnet/aspnetcore/blob/main/src/Components/Web.JS/src/Platform/Mono/MonoTypes.ts -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, - js_typed_array_to_array: typeof js_typed_array_to_array, - js_to_mono_obj: typeof js_to_mono_obj, - mono_array_to_js_array: typeof mono_array_to_js_array, - conv_string: typeof conv_string, - 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, + MONO: typeof MONO, + BINDING: typeof BINDING, INTERNAL: any, Module: any, RuntimeId: number, diff --git a/src/mono/wasm/runtime/icu.ts b/src/mono/wasm/runtime/icu.ts index 05ea504cbffde..35f3d9587b213 100644 --- a/src/mono/wasm/runtime/icu.ts +++ b/src/mono/wasm/runtime/icu.ts @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import cwraps from "./cwraps"; +import { MonoInitContext } from "./startup"; import { GlobalizationMode } from "./types"; import { VoidPtr } from "./types/emscripten"; @@ -28,7 +29,7 @@ export function mono_wasm_get_icudt_name(culture: string): string { // @globalization_mode is one of "icu", "invariant", or "auto". // "auto" will use "icu" if any ICU data archives have been loaded, // otherwise "invariant". -export function mono_wasm_globalization_init(globalization_mode: GlobalizationMode): void { +export function mono_wasm_globalization_init(globalization_mode: GlobalizationMode, ctx: MonoInitContext): void { let invariantMode = false; if (globalization_mode === "invariant") @@ -36,9 +37,13 @@ export function mono_wasm_globalization_init(globalization_mode: GlobalizationMo if (!invariantMode) { if (num_icu_assets_loaded_successfully > 0) { - console.debug("MONO_WASM: ICU data archive(s) loaded, disabling invariant mode"); + if (ctx.tracing) { + console.debug("MONO_WASM: ICU data archive(s) loaded, disabling invariant mode"); + } } else if (globalization_mode !== "icu") { - console.debug("MONO_WASM: ICU data archive(s) not loaded, using invariant globalization mode"); + if (ctx.tracing) { + console.debug("MONO_WASM: ICU data archive(s) not loaded, using invariant globalization mode"); + } invariantMode = true; } else { const msg = "invariant globalization mode is inactive and no ICU data archives were loaded"; diff --git a/src/mono/wasm/runtime/imports.ts b/src/mono/wasm/runtime/imports.ts index 3f659d588ea66..7ebe3a5c09bb0 100644 --- a/src/mono/wasm/runtime/imports.ts +++ b/src/mono/wasm/runtime/imports.ts @@ -4,11 +4,11 @@ /* eslint-disable @typescript-eslint/triple-slash-reference */ /// -import { DotnetModuleMono, MonoConfig, RuntimeHelpers } from "./types"; +import { DotnetModule, MonoConfig, RuntimeHelpers } from "./types"; import { EmscriptenModule } from "./types/emscripten"; // these are our public API (except internal) -export let Module: EmscriptenModule & DotnetModuleMono; +export let Module: EmscriptenModule & DotnetModule; export let MONO: any; export let BINDING: any; export let INTERNAL: any; diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index bc56672ddad46..e00ece77d4bf7 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.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 { AllAssetEntryTypes, AssetEntry, CharPtrNull, DotnetModuleMono, GlobalizationMode, MonoConfig, wasm_type_symbol } from "./types"; +import { AllAssetEntryTypes, AssetEntry, CharPtrNull, DotnetModule, GlobalizationMode, MonoConfig, 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"; @@ -22,7 +22,7 @@ export const mono_wasm_runtime_is_initialized = new Promise((resolve, reject) => export async function mono_wasm_pre_init(): Promise { - const moduleExt = Module as DotnetModuleMono; + const moduleExt = Module as DotnetModule; if (moduleExt.configSrc) { try { // sets MONO.config implicitly @@ -159,7 +159,7 @@ function _apply_configuration_from_args(args: MonoConfig) { } function _finalize_startup(args: MonoConfig, ctx: MonoInitContext) { - const moduleExt = Module as DotnetModuleMono; + const moduleExt = Module as DotnetModule; ctx.loaded_files.forEach(value => MONO.loaded_files.push(value.url)); if (ctx.tracing) { @@ -167,24 +167,22 @@ function _finalize_startup(args: MonoConfig, ctx: MonoInitContext) { console.log("MONO_WASM: loaded_files: " + JSON.stringify(ctx.loaded_files)); } - console.debug("MONO_WASM: Initializing mono runtime"); - - mono_wasm_globalization_init(args.globalization_mode!); - - if (ENVIRONMENT_IS_SHELL || ENVIRONMENT_IS_NODE) { - try { - cwraps.mono_wasm_load_runtime("unused", args.debug_level || 0); - } catch (err: any) { - Module.printErr("MONO_WASM: mono_wasm_load_runtime () failed: " + err); - Module.printErr("MONO_WASM: Stacktrace: \n"); - Module.printErr(err.stack); + try { + if (ctx.tracing) { + console.debug("MONO_WASM: Initializing mono runtime"); + } + mono_wasm_globalization_init(args.globalization_mode!, ctx); + cwraps.mono_wasm_load_runtime("unused", args.debug_level || 0); + } catch (err: any) { + Module.printErr("MONO_WASM: mono_wasm_load_runtime () failed: " + err); + Module.printErr("MONO_WASM: Stacktrace: \n"); + Module.printErr(err.stack); - runtime_is_initialized_reject(err); + runtime_is_initialized_reject(err); + if (ENVIRONMENT_IS_SHELL || ENVIRONMENT_IS_NODE) { const wasm_exit = cwraps.mono_wasm_exit; wasm_exit(1); } - } else { - cwraps.mono_wasm_load_runtime("unused", args.debug_level || 0); } bindings_lazy_init(); @@ -309,6 +307,7 @@ export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise< _apply_configuration_from_args(args); + // fetch_file_cb is legacy do we really want to support it ? if (!Module.imports!.fetch && typeof ((args).fetch_file_cb) === "function") { runtimeHelpers.fetch = (args).fetch_file_cb; } @@ -509,7 +508,7 @@ export function mono_wasm_set_main_args(name: string, allRuntimeArguments: strin cwraps.mono_wasm_set_main_args(main_argc, main_argv); } -type MonoInitContext = { +export type MonoInitContext = { tracing: boolean, pending_count: number, loaded_files: { url: string, file: string }[], diff --git a/src/mono/wasm/runtime/types.ts b/src/mono/wasm/runtime/types.ts index fd49bae76c526..3b3306d0e1a54 100644 --- a/src/mono/wasm/runtime/types.ts +++ b/src/mono/wasm/runtime/types.ts @@ -154,7 +154,20 @@ export type CoverageProfilerOptions = { } // how we extended emscripten Module -export type DotnetModuleMono = EmscriptenModule & DotnetModuleConfig; +export type DotnetModule = EmscriptenModule & DotnetModuleConfig; + +export type DotnetModuleConfig = { + disableDotnet6Compatibility?: boolean, + + config?: MonoConfig | MonoConfigError, + configSrc?: string, + scriptDirectory?: string, + onConfigLoaded?: () => void; + onDotnetReady?: () => void; + + imports?: DotnetModuleConfigImports; +} + export type DotnetModuleConfigImports = { require?: (name: string) => any; fetch?: (url: string) => Promise; @@ -173,15 +186,4 @@ export type DotnetModuleConfigImports = { dirname?: (path: string) => string, }; url?: any; -} -export type DotnetModuleConfig = { - disableDotnet6Compatibility?: boolean, - - config?: MonoConfig | MonoConfigError, - configSrc?: string, - scriptDirectory?: string, - onConfigLoaded?: () => void; - onDotnetReady?: () => void; - - imports?: DotnetModuleConfigImports; -} +} \ No newline at end of file From d3b1688ec2a06c8dbeaa58f2d05ed166b636c23b Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 26 Nov 2021 13:46:59 +0100 Subject: [PATCH 14/28] flat sample --- src/mono/sample/wasm/browser-es6/main.js | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/mono/sample/wasm/browser-es6/main.js b/src/mono/sample/wasm/browser-es6/main.js index 53fc1dc572609..1cfe1fb3da6a5 100644 --- a/src/mono/sample/wasm/browser-es6/main.js +++ b/src/mono/sample/wasm/browser-es6/main.js @@ -8,20 +8,14 @@ const { MONO, BINDING, Module, RuntimeBuildInfo } = await createDotnetRuntime((a }, })); -const App = { - init: function () { - const testMeaning = BINDING.bind_static_method("[Wasm.Browser.ES6.Sample] Sample.Test:TestMeaning"); - const ret = testMeaning(); - document.getElementById("out").innerHTML = `${ret} as computed on dotnet ver ${RuntimeBuildInfo.ProductVersion}`; - - console.debug(`ret: ${ret}`); - let exit_code = ret == 42 ? 0 : 1; - wasm_exit(exit_code); - }, -}; - -App.init(); - function wasm_exit(exit_code) { console.log(`WASM EXIT ${exit_code}`); -} \ No newline at end of file +} + +const testMeaning = BINDING.bind_static_method("[Wasm.Browser.ES6.Sample] Sample.Test:TestMeaning"); +const ret = testMeaning(); +document.getElementById("out").innerHTML = `${ret} as computed on dotnet ver ${RuntimeBuildInfo.ProductVersion}`; + +console.debug(`ret: ${ret}`); +let exit_code = ret == 42 ? 0 : 1; +wasm_exit(exit_code); \ No newline at end of file From 50ac5950dd5692e743977b0d5283f2ed2fa8d2a0 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 26 Nov 2021 18:06:23 +0100 Subject: [PATCH 15/28] fix test --- src/tests/FunctionalTests/WebAssembly/Browser/HotReload/main.js | 2 +- .../FunctionalTests/WebAssembly/Browser/RuntimeConfig/main.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/main.js b/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/main.js index 861ddd263cd84..5c56c3d8092f4 100644 --- a/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/main.js +++ b/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/main.js @@ -8,7 +8,7 @@ var Module = { onConfigLoaded: () => { MONO.config.environment_variables["DOTNET_MODIFIABLE_ASSEMBLIES"] = "debug"; }, - onDotNetReady: () => { + onDotnetReady: () => { try { App.init(); } catch (error) { diff --git a/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/main.js b/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/main.js index 88db9c67c1dd9..917fb89ba5e97 100644 --- a/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/main.js +++ b/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/main.js @@ -5,7 +5,7 @@ var Module = { configSrc: "./mono-config.json", - onDotNetReady: () => { + onDotnetReady: () => { try { App.init(); } catch (error) { From ec1c39d75de28790e83a6ca893679eeeb09c97b7 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 30 Nov 2021 14:36:59 +0100 Subject: [PATCH 16/28] try without dealing with eventPipe issue --- src/mono/wasm/build/WasmApp.Native.targets | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets index b02fd347bc868..9fdf3c38aa40c 100644 --- a/src/mono/wasm/build/WasmApp.Native.targets +++ b/src/mono/wasm/build/WasmApp.Native.targets @@ -286,21 +286,7 @@ - - - - - <_MonoRuntimeComponentDontLink Include="libmono-component-diagnostics_tracing-static.a"/> - - - <_MonoRuntimeComponentDontLink Include="libmono-component-hot_reload-static.a"/> - <_MonoRuntimeComponentDontLink Include="libmono-component-debugger-static.a"/> - - - <_MonoRuntimeComponentDontLink Include="libmono-component-hot_reload-stub-static.a"/> - <_MonoRuntimeComponentDontLink Include="libmono-component-debugger-stub-static.a"/> - - + @@ -403,7 +389,7 @@ From 802a459fa72a207360ba4e0052c8783fe96369ae Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 30 Nov 2021 14:38:40 +0100 Subject: [PATCH 17/28] type exports for Blazor --- src/mono/wasm/runtime/dist-types/dotnet.d.ts | 48 +++++++++++++++++-- .../runtime/dist-types/dotnet.d.ts.sha256 | 1 - src/mono/wasm/runtime/export-types.ts | 12 ++++- src/mono/wasm/runtime/exports.ts | 7 ++- src/mono/wasm/runtime/types.ts | 2 +- src/mono/wasm/runtime/types/emscripten.ts | 2 + 6 files changed, 62 insertions(+), 10 deletions(-) delete mode 100644 src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 diff --git a/src/mono/wasm/runtime/dist-types/dotnet.d.ts b/src/mono/wasm/runtime/dist-types/dotnet.d.ts index b97d05b9718cc..45965d2b2ee16 100644 --- a/src/mono/wasm/runtime/dist-types/dotnet.d.ts +++ b/src/mono/wasm/runtime/dist-types/dotnet.d.ts @@ -12,6 +12,44 @@ declare interface NativePointer { declare interface VoidPtr extends NativePointer { __brand: "VoidPtr"; } +declare interface CharPtr extends NativePointer { + __brand: "CharPtr"; +} +declare interface Int32Ptr extends NativePointer { + __brand: "Int32Ptr"; +} +declare interface EmscriptenModule { + HEAP8: Int8Array; + HEAP16: Int16Array; + HEAP32: Int32Array; + HEAPU8: Uint8Array; + HEAPU16: Uint16Array; + HEAPU32: Uint32Array; + HEAPF32: Float32Array; + HEAPF64: Float64Array; + _malloc(size: number): VoidPtr; + _free(ptr: VoidPtr): void; + print(message: string): void; + printErr(message: string): void; + ccall(ident: string, returnType?: string | null, argTypes?: string[], args?: any[], opts?: any): T; + cwrap(ident: string, returnType: string, argTypes?: string[], opts?: any): T; + cwrap(ident: string, ...args: any[]): T; + setValue(ptr: VoidPtr, value: number, type: string, noSafe?: number | boolean): void; + setValue(ptr: Int32Ptr, value: number, type: string, noSafe?: number | boolean): void; + getValue(ptr: number, type: string, noSafe?: number | boolean): number; + UTF8ToString(ptr: CharPtr, maxBytesToRead?: number): string; + UTF8ArrayToString(u8Array: Uint8Array, idx?: number, maxBytesToRead?: number): string; + FS_createPath(parent: string, path: string, canRead?: boolean, canWrite?: boolean): string; + FS_createDataFile(parent: string, name: string, data: TypedArray, canRead: boolean, canWrite: boolean, canOwn?: boolean): string; + removeRunDependency(id: string): void; + addRunDependency(id: string): void; + ready: Promise; + preInit?: (() => Promise)[]; + preRun?: (() => Promise)[]; + postRun?: (() => Promise)[]; + onRuntimeInitialized?: () => void; +} +declare type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array; /** * Allocates a block of memory that can safely contain pointers into the managed heap. @@ -170,7 +208,7 @@ declare type DotnetModuleConfig = { onConfigLoaded?: () => void; onDotnetReady?: () => void; imports?: DotnetModuleConfigImports; -}; +} & EmscriptenModule; declare type DotnetModuleConfigImports = { require?: (name: string) => any; fetch?: (url: string) => Promise; @@ -257,7 +295,7 @@ declare const MONO: { mono_wasm_add_assembly: (name: string, data: VoidPtr, size: number) => number; mono_wasm_load_runtime: (unused: string, debug_level: number) => void; config: MonoConfig | MonoConfigError; - loaded_files: never[]; + loaded_files: string[]; setI8: typeof setI8; setI16: typeof setI16; setI32: typeof setI32; @@ -277,6 +315,7 @@ declare const MONO: { getF32: typeof getF32; getF64: typeof getF64; }; +declare type MONOType = typeof MONO; declare const BINDING: { mono_obj_array_new: (size: number) => MonoArray; mono_obj_array_set: (array: MonoArray, idx: number, obj: MonoObject) => void; @@ -289,11 +328,12 @@ declare const BINDING: { call_assembly_entry_point: typeof mono_call_assembly_entry_point; unbox_mono_obj: typeof unbox_mono_obj; }; +declare type BINDINGType = typeof BINDING; interface DotnetPublicAPI { MONO: typeof MONO; BINDING: typeof BINDING; INTERNAL: any; - Module: any; + Module: EmscriptenModule; RuntimeId: number; RuntimeBuildInfo: { ProductVersion: string; @@ -307,4 +347,4 @@ declare global { } declare const createDotnetRuntime: createDotnetRuntimeType; -export { createDotnetRuntimeType, createDotnetRuntime as default }; +export { BINDINGType, DotnetModuleConfig, DotnetPublicAPI, EmscriptenModule, MONOType, MonoArray, MonoObject, MonoString, VoidPtr, createDotnetRuntimeType, createDotnetRuntime as default }; diff --git a/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 b/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 deleted file mode 100644 index 881f0a5e2af82..0000000000000 --- a/src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 +++ /dev/null @@ -1 +0,0 @@ -106d742df347b40bda6ab3de800fcfa1ebad4f1d93a1c6a78c0bcd627e17a8a2 \ No newline at end of file diff --git a/src/mono/wasm/runtime/export-types.ts b/src/mono/wasm/runtime/export-types.ts index 335beb19ab20a..dfa7a702f554f 100644 --- a/src/mono/wasm/runtime/export-types.ts +++ b/src/mono/wasm/runtime/export-types.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 { DotnetPublicAPI } from "./exports"; -import { DotnetModuleConfig } from "./types"; +import { BINDINGType, DotnetPublicAPI, MONOType } from "./exports"; +import { DotnetModuleConfig, MonoArray, MonoObject, MonoString } from "./types"; +import { EmscriptenModule, VoidPtr } from "./types/emscripten"; // ----------------------------------------------------------- // this files has all public exports from the dotnet.js module @@ -19,3 +20,10 @@ declare const createDotnetRuntime: createDotnetRuntimeType; export default createDotnetRuntime; +export { + VoidPtr, + MonoObject, MonoString, MonoArray, + BINDINGType, MONOType, EmscriptenModule, + DotnetPublicAPI, DotnetModuleConfig, +}; + diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index e265cf346a9d0..185ed916beadd 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -67,6 +67,7 @@ import { } from "./memory"; import { create_weak_ref } from "./weak-ref"; import { fetch_like, readAsync_like } from "./polyfills"; +import { EmscriptenModule } from "./types/emscripten"; const MONO = { // current "public" MONO API @@ -86,7 +87,7 @@ const MONO = { mono_wasm_load_runtime: cwraps.mono_wasm_load_runtime, config: runtimeHelpers.config, - loaded_files: [], + loaded_files: [], // memory accessors setI8, @@ -108,6 +109,7 @@ const MONO = { getF32, getF64, }; +export type MONOType = typeof MONO; const BINDING = { //current "public" BINDING API @@ -122,6 +124,7 @@ const BINDING = { call_assembly_entry_point: mono_call_assembly_entry_point, unbox_mono_obj, }; +export type BINDINGType = typeof BINDING; let exportedAPI: DotnetPublicAPI; @@ -347,7 +350,7 @@ export interface DotnetPublicAPI { MONO: typeof MONO, BINDING: typeof BINDING, INTERNAL: any, - Module: any, + Module: EmscriptenModule, RuntimeId: number, RuntimeBuildInfo: { ProductVersion: string, diff --git a/src/mono/wasm/runtime/types.ts b/src/mono/wasm/runtime/types.ts index 3b3306d0e1a54..4e0ea4e7b3bef 100644 --- a/src/mono/wasm/runtime/types.ts +++ b/src/mono/wasm/runtime/types.ts @@ -166,7 +166,7 @@ export type DotnetModuleConfig = { onDotnetReady?: () => void; imports?: DotnetModuleConfigImports; -} +} & EmscriptenModule export type DotnetModuleConfigImports = { require?: (name: string) => any; diff --git a/src/mono/wasm/runtime/types/emscripten.ts b/src/mono/wasm/runtime/types/emscripten.ts index 534fbf935a7c3..5223bb9e9243e 100644 --- a/src/mono/wasm/runtime/types/emscripten.ts +++ b/src/mono/wasm/runtime/types/emscripten.ts @@ -54,6 +54,8 @@ export declare interface EmscriptenModule { ready: Promise; preInit?: (() => Promise)[]; + preRun?: (() => Promise)[]; + postRun?: (() => Promise)[]; onRuntimeInitialized?: () => void; } From 15b416f06bdf6cd91f8f8d3b0c4de92572ae0ec5 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 30 Nov 2021 14:45:45 +0100 Subject: [PATCH 18/28] keep sha local --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index dbdbce21b052d..a69ea39c17fc5 100644 --- a/.gitignore +++ b/.gitignore @@ -186,6 +186,7 @@ node_modules/ *.metaproj *.metaproj.tmp bin.localpkg/ +src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 # RIA/Silverlight projects Generated_Code/ From 324efda4b9985ea20358324f978aeedfad847dc6 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 30 Nov 2021 20:03:22 +0100 Subject: [PATCH 19/28] types --- src/mono/wasm/runtime/dist-types/dotnet.d.ts | 6 +++--- src/mono/wasm/runtime/export-types.ts | 6 +++--- src/mono/wasm/runtime/package.json | 1 + src/mono/wasm/runtime/types/emscripten.ts | 7 ++++--- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/mono/wasm/runtime/dist-types/dotnet.d.ts b/src/mono/wasm/runtime/dist-types/dotnet.d.ts index 45965d2b2ee16..4cdf6064154f0 100644 --- a/src/mono/wasm/runtime/dist-types/dotnet.d.ts +++ b/src/mono/wasm/runtime/dist-types/dotnet.d.ts @@ -341,10 +341,10 @@ interface DotnetPublicAPI { }; } -declare type createDotnetRuntimeType = (moduleFactory: (api: DotnetPublicAPI) => DotnetModuleConfig) => Promise; +declare function createDotnetRuntime(moduleFactory: (api: DotnetPublicAPI) => DotnetModuleConfig): Promise; +declare type CreateDotnetRuntimeType = typeof createDotnetRuntime; declare global { function getDotnetRuntime(runtimeId: number): DotnetPublicAPI | undefined; } -declare const createDotnetRuntime: createDotnetRuntimeType; -export { BINDINGType, DotnetModuleConfig, DotnetPublicAPI, EmscriptenModule, MONOType, MonoArray, MonoObject, MonoString, VoidPtr, createDotnetRuntimeType, createDotnetRuntime as default }; +export { BINDINGType, CreateDotnetRuntimeType, DotnetModuleConfig, DotnetPublicAPI, EmscriptenModule, MONOType, MonoArray, MonoObject, MonoString, VoidPtr, createDotnetRuntime as default }; diff --git a/src/mono/wasm/runtime/export-types.ts b/src/mono/wasm/runtime/export-types.ts index dfa7a702f554f..77bca1f53b70d 100644 --- a/src/mono/wasm/runtime/export-types.ts +++ b/src/mono/wasm/runtime/export-types.ts @@ -9,14 +9,14 @@ import { EmscriptenModule, VoidPtr } from "./types/emscripten"; // this files has all public exports from the dotnet.js module // ----------------------------------------------------------- -export type createDotnetRuntimeType = (moduleFactory: (api: DotnetPublicAPI) => DotnetModuleConfig) => Promise; +declare function createDotnetRuntime(moduleFactory: (api: DotnetPublicAPI) => DotnetModuleConfig): Promise; +declare type CreateDotnetRuntimeType = typeof createDotnetRuntime; // Here, declare things that go in the global namespace, or augment existing declarations in the global namespace declare global { function getDotnetRuntime(runtimeId: number): DotnetPublicAPI | undefined; } -declare const createDotnetRuntime: createDotnetRuntimeType; export default createDotnetRuntime; @@ -24,6 +24,6 @@ export { VoidPtr, MonoObject, MonoString, MonoArray, BINDINGType, MONOType, EmscriptenModule, - DotnetPublicAPI, DotnetModuleConfig, + DotnetPublicAPI, DotnetModuleConfig, CreateDotnetRuntimeType }; diff --git a/src/mono/wasm/runtime/package.json b/src/mono/wasm/runtime/package.json index c582daf3eae90..fe915ac812cf4 100644 --- a/src/mono/wasm/runtime/package.json +++ b/src/mono/wasm/runtime/package.json @@ -7,6 +7,7 @@ }, "version": "1.0.0", "main": "dotnet.js", + "types": "dotnet.d.ts", "scripts": { "rollup": "rollup -c", "lint": "eslint --no-color --max-warnings=0 ./**/*.ts ./*.js" diff --git a/src/mono/wasm/runtime/types/emscripten.ts b/src/mono/wasm/runtime/types/emscripten.ts index 5223bb9e9243e..2b7b51cf375a5 100644 --- a/src/mono/wasm/runtime/types/emscripten.ts +++ b/src/mono/wasm/runtime/types/emscripten.ts @@ -53,10 +53,11 @@ export declare interface EmscriptenModule { addRunDependency(id: string): void; ready: Promise; - preInit?: (() => Promise)[]; - preRun?: (() => Promise)[]; - postRun?: (() => Promise)[]; + preInit?: (() => void | Promise)[]; + preRun?: (() => void | Promise)[]; + postRun?: (() => void | Promise)[]; onRuntimeInitialized?: () => void; + instantiateWasm: (imports: any, successCallback: Function) => any; } export declare type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array; \ No newline at end of file From 61dc62f16f43b259a0169486472e1ce52f0a7c48 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 1 Dec 2021 05:33:50 +0100 Subject: [PATCH 20/28] move type definitions --- .gitignore | 2 +- src/mono/wasm/runtime/{dist-types => }/dotnet.d.ts | 7 ++++--- src/mono/wasm/runtime/rollup.config.js | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) rename src/mono/wasm/runtime/{dist-types => }/dotnet.d.ts (98%) diff --git a/.gitignore b/.gitignore index a69ea39c17fc5..ff8c457ca1363 100644 --- a/.gitignore +++ b/.gitignore @@ -186,7 +186,7 @@ node_modules/ *.metaproj *.metaproj.tmp bin.localpkg/ -src/mono/wasm/runtime/dist-types/dotnet.d.ts.sha256 +src/mono/wasm/runtime/dotnet.d.ts.sha256 # RIA/Silverlight projects Generated_Code/ diff --git a/src/mono/wasm/runtime/dist-types/dotnet.d.ts b/src/mono/wasm/runtime/dotnet.d.ts similarity index 98% rename from src/mono/wasm/runtime/dist-types/dotnet.d.ts rename to src/mono/wasm/runtime/dotnet.d.ts index 4cdf6064154f0..8b9eaa21bf307 100644 --- a/src/mono/wasm/runtime/dist-types/dotnet.d.ts +++ b/src/mono/wasm/runtime/dotnet.d.ts @@ -44,10 +44,11 @@ declare interface EmscriptenModule { removeRunDependency(id: string): void; addRunDependency(id: string): void; ready: Promise; - preInit?: (() => Promise)[]; - preRun?: (() => Promise)[]; - postRun?: (() => Promise)[]; + preInit?: (() => void | Promise)[]; + preRun?: (() => void | Promise)[]; + postRun?: (() => void | Promise)[]; onRuntimeInitialized?: () => void; + instantiateWasm: (imports: any, successCallback: Function) => any; } declare type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array; diff --git a/src/mono/wasm/runtime/rollup.config.js b/src/mono/wasm/runtime/rollup.config.js index dcdbff8f12bee..b9266366507e9 100644 --- a/src/mono/wasm/runtime/rollup.config.js +++ b/src/mono/wasm/runtime/rollup.config.js @@ -84,7 +84,7 @@ if (isDebug) { // so that we could notice that the API changed and review it typesConfig.output.push({ format: "es", - file: "./dist-types/dotnet.d.ts", + file: "./dotnet.d.ts", banner: banner_generated, plugins: [writeOnChangePlugin()], }); From f3edf8b9b538ac3d071167e4616824315ac53a00 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 1 Dec 2021 05:34:32 +0100 Subject: [PATCH 21/28] remove typescript sample --- src/mono/sample/wasm/console-ts/Program.cs | 15 -------- .../Wasm.Console.TypeScript.Sample.csproj | 36 ------------------- src/mono/sample/wasm/console-ts/main.ts | 25 ------------- .../sample/wasm/console-ts/package-lock.json | 23 ------------ src/mono/sample/wasm/console-ts/package.json | 24 ------------- src/mono/sample/wasm/console-ts/tsconfig.json | 9 ----- 6 files changed, 132 deletions(-) delete mode 100644 src/mono/sample/wasm/console-ts/Program.cs delete mode 100644 src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj delete mode 100644 src/mono/sample/wasm/console-ts/main.ts delete mode 100644 src/mono/sample/wasm/console-ts/package-lock.json delete mode 100644 src/mono/sample/wasm/console-ts/package.json delete mode 100644 src/mono/sample/wasm/console-ts/tsconfig.json diff --git a/src/mono/sample/wasm/console-ts/Program.cs b/src/mono/sample/wasm/console-ts/Program.cs deleted file mode 100644 index 166202aea3b42..0000000000000 --- a/src/mono/sample/wasm/console-ts/Program.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Threading.Tasks; - -public class Test -{ - public static async Task Main(string[] args) - { - await Task.Delay(1); - Console.WriteLine("Hello NodeJS!"); - return args.Length; - } -} diff --git a/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj b/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj deleted file mode 100644 index 1aa290ed59bf3..0000000000000 --- a/src/mono/sample/wasm/console-ts/Wasm.Console.TypeScript.Sample.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - - - bin/main.js - true - Release - true - embedded - 1 - - - CompileTypeScript; - $(WasmBuildAppDependsOn) - - - - - - - - - <_SampleProject>Wasm.Console.TypeScript.Sample.csproj - <_SampleAssembly>Wasm.Console.TypeScript.Sample.dll - - - - - - - - - diff --git a/src/mono/sample/wasm/console-ts/main.ts b/src/mono/sample/wasm/console-ts/main.ts deleted file mode 100644 index ebada8338f5d8..0000000000000 --- a/src/mono/sample/wasm/console-ts/main.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { createRequire } from 'module'; -import createDotnetRuntime from 'dotnet' -import { dirname } from 'path'; -import { fileURLToPath } from 'url'; -import { exit } from 'process'; - -const { BINDING } = await createDotnetRuntime(() => ({ - imports: { - require: createRequire(import.meta.url) - }, - scriptDirectory: dirname(fileURLToPath(import.meta.url)) + '/', - disableDotnet6Compatibility: true, - configSrc: "./mono-config.json", - onAbort: (err: any) => { - console.log("WASM ABORT " + err); - }, -})); - -try { - const app_args = process.argv.slice(2); - const result = await BINDING.call_assembly_entry_point("Wasm.Console.TypeScript.Sample.dll", [app_args], "m"); - exit(result) -} catch (error) { - console.log("WASM ERROR " + error); -} diff --git a/src/mono/sample/wasm/console-ts/package-lock.json b/src/mono/sample/wasm/console-ts/package-lock.json deleted file mode 100644 index da5df8ba099ca..0000000000000 --- a/src/mono/sample/wasm/console-ts/package-lock.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "console-ts", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/node": { - "version": "16.11.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.10.tgz", - "integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==", - "dev": true - }, - "dotnet": { - "version": "file:../../../../../artifacts/bin/native/net7.0-Browser-Debug-wasm" - }, - "typescript": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", - "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", - "dev": true - } - } -} diff --git a/src/mono/sample/wasm/console-ts/package.json b/src/mono/sample/wasm/console-ts/package.json deleted file mode 100644 index 67a0427778e2b..0000000000000 --- a/src/mono/sample/wasm/console-ts/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "console-ts", - "version": "1.0.0", - "description": "TypeScript sample for dotnet in WASM", - "main": "bin/main.js", - "type": "module", - "repository": { - "type": "git", - "url": "git@github.com:dotnet/runtime.git" - }, - "scripts": { - "build": "tsc -p .", - "start": "node bin/Release/AppBundle/main.js" - }, - "author": "Microsoft", - "license": "MIT", - "dependencies": { - "dotnet": "file://../../../../../artifacts/bin/native/net7.0-Browser-Release-wasm/" - }, - "devDependencies": { - "@types/node": "16.11.10", - "typescript": "4.5.2" - } -} diff --git a/src/mono/sample/wasm/console-ts/tsconfig.json b/src/mono/sample/wasm/console-ts/tsconfig.json deleted file mode 100644 index 05a3b61afa31c..0000000000000 --- a/src/mono/sample/wasm/console-ts/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "moduleResolution": "Node", - "target": "ESNext", - "module": "ESNext", - "strict": true, - "outDir": "bin" - } -} \ No newline at end of file From 911bb5b067ffae19e26977d222e35a3a1007fdac Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 1 Dec 2021 07:10:50 +0100 Subject: [PATCH 22/28] Update src/mono/wasm/runtime/modularize-dotnet.md Co-authored-by: Ankit Jain --- src/mono/wasm/runtime/modularize-dotnet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/wasm/runtime/modularize-dotnet.md b/src/mono/wasm/runtime/modularize-dotnet.md index 75d96cfc2a77d..793d94d1fb2bd 100644 --- a/src/mono/wasm/runtime/modularize-dotnet.md +++ b/src/mono/wasm/runtime/modularize-dotnet.md @@ -18,7 +18,7 @@ In `src\mono\wasm\runtime\CMakeLists.txt` which links only in-tree, we use same # dotnet.cjs.pre.js - Executed second (2) - Applied only when linking CommonJS -- Will try to see if it was executed with `globalThis.Module` and if so, it would use it's instance as `Module`. It would preserve emscriptens `Module.ready` +- Will try to see if it was executed with `globalThis.Module` and if so, it would use it's instance as `Module`. It would preserve emscripten's `Module.ready` - Otherwise it would load it would assume it was called via `createDotnetRuntime` export same as described for `dotnet.es6.pre.js` below. # dotnet.es6.pre.js From 072568d08292691c97ceb90570330c4c7c2dcdab Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 1 Dec 2021 07:14:54 +0100 Subject: [PATCH 23/28] Update eng/liveBuilds.targets Co-authored-by: Ankit Jain --- eng/liveBuilds.targets | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets index 82931609803a2..bc2e7e5dff9a0 100644 --- a/eng/liveBuilds.targets +++ b/eng/liveBuilds.targets @@ -191,15 +191,14 @@ NativeSubDirectory="src" IsNative="true" /> + Include="$(LibrariesNativeArtifactsPath)src\cjs\*.js" + NativeSubDirectory="src\cjs" + IsNative="true" /> + Include="$(LibrariesNativeArtifactsPath)src\es6\*.js" + NativeSubDirectory="src\es6" + IsNative="true" /> + Date: Wed, 1 Dec 2021 07:32:05 +0100 Subject: [PATCH 24/28] feedback from @radical --- src/mono/wasm/test-main.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/mono/wasm/test-main.js b/src/mono/wasm/test-main.js index abdb61518ba9b..84b26ec78bac8 100644 --- a/src/mono/wasm/test-main.js +++ b/src/mono/wasm/test-main.js @@ -255,9 +255,6 @@ function set_exit_code(exit_code, reason) { } 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} isXmlDoneCheck=${isXmlDoneCheck} WS.bufferedAmount=${consoleWebSocket.bufferedAmount} ${stack}.`; - if (App.Module) { // Notify the selenium script App.Module.exit_code = exit_code; @@ -269,8 +266,6 @@ function set_exit_code(exit_code, reason) { tests_done_elem.innerHTML = exit_code.toString(); document.body.appendChild(tests_done_elem); - // console.log('WS: ' + messsage); - // originalConsole.log('CDP: ' + messsage); const stop_when_ws_buffer_empty = () => { if (consoleWebSocket.bufferedAmount == 0) { // tell xharness WasmTestMessagesProcessor we are done. From 49fcd8440d6bea619f9ccdee386274a6d3316f37 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 1 Dec 2021 15:56:15 +0100 Subject: [PATCH 25/28] @maraf's feedback --- .../tests/debugger-test/debugger-main.js | 2 +- src/mono/wasm/runtime/dotnet.d.ts | 10 +- src/mono/wasm/runtime/exports.ts | 68 ++++-- src/mono/wasm/runtime/icu.ts | 7 +- src/mono/wasm/runtime/modularize-dotnet.md | 2 +- src/mono/wasm/runtime/startup.ts | 216 +++++++++--------- src/mono/wasm/runtime/types/emscripten.ts | 8 +- 7 files changed, 179 insertions(+), 134 deletions(-) diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-main.js b/src/mono/wasm/debugger/tests/debugger-test/debugger-main.js index c34cdf6bae430..8188bdce68547 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-main.js +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-main.js @@ -17,7 +17,7 @@ var Module = { }; */ }, - onDotNetReady: () => { + onDotnetReady: () => { App.init(); }, }; diff --git a/src/mono/wasm/runtime/dotnet.d.ts b/src/mono/wasm/runtime/dotnet.d.ts index 8b9eaa21bf307..c0627f7a08383 100644 --- a/src/mono/wasm/runtime/dotnet.d.ts +++ b/src/mono/wasm/runtime/dotnet.d.ts @@ -44,10 +44,10 @@ declare interface EmscriptenModule { removeRunDependency(id: string): void; addRunDependency(id: string): void; ready: Promise; - preInit?: (() => void | Promise)[]; - preRun?: (() => void | Promise)[]; - postRun?: (() => void | Promise)[]; - onRuntimeInitialized?: () => void; + preInit?: (() => any)[]; + preRun?: (() => any)[]; + postRun?: (() => any)[]; + onRuntimeInitialized?: () => any; instantiateWasm: (imports: any, successCallback: Function) => any; } declare type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array; @@ -235,7 +235,7 @@ declare type DotnetModuleConfigImports = { declare function mono_wasm_runtime_ready(): void; declare function mono_wasm_setenv(name: string, value: string): void; -declare function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise; +declare function mono_load_runtime_and_bcl_args(config?: MonoConfig | MonoConfigError): Promise; declare function mono_wasm_load_data_archive(data: Uint8Array, prefix: string): boolean; /** * Loads the mono config file (typically called mono-config.json) asynchroniously diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index 185ed916beadd..17f3b66b58b7c 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -33,8 +33,8 @@ import { mono_wasm_load_data_archive, mono_wasm_asm_loaded, mono_wasm_set_main_args, mono_wasm_pre_init, - mono_wasm_on_runtime_initialized, - mono_wasm_runtime_is_initialized + mono_wasm_runtime_is_initialized, + finalize_startup } from "./startup"; import { mono_set_timeout, schedule_background_exec } from "./scheduling"; import { mono_wasm_load_icu_data, mono_wasm_get_icudt_name } from "./icu"; @@ -158,22 +158,23 @@ function initializeImportsAndExports( } }; - 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); + // these could be overriden on DotnetModuleConfig + if (!module.preInit) { + module.preInit = []; + } else if (typeof module.preInit === "function") { + module.preInit = [module.preInit]; } - // this could be overriden on Module - if (!module.onRuntimeInitialized) { - module.onRuntimeInitialized = mono_wasm_on_runtime_initialized; - module.ready = module.ready.then(() => { - return mono_wasm_runtime_is_initialized; - }); + if (!module.preRun) { + module.preRun = []; + } else if (typeof module.preRun === "function") { + module.preRun = [module.preRun]; } + if (!module.postRun) { + module.postRun = []; + } else if (typeof module.postRun === "function") { + module.postRun = [module.postRun]; + } + if (!module.print) { module.print = console.log; } @@ -205,6 +206,7 @@ function initializeImportsAndExports( replacements.fetch = runtimeHelpers.fetch; replacements.readAsync = readAsync_like; + // here we expose objects global namespace for tests and backward compatibility if (imports.isGlobal || !module.disableDotnet6Compatibility) { Object.assign(module, exportedAPI); @@ -216,7 +218,6 @@ function initializeImportsAndExports( return mono_bind_static_method(fqn, signature); }; - // here we expose objects used in tests to global namespace const warnWrap = (name: string, provider: () => any) => { if (typeof globalThisAny[name] !== "undefined") { // it already exists in the global namespace @@ -247,6 +248,39 @@ function initializeImportsAndExports( warnWrap("addRunDependency", () => module.addRunDependency); warnWrap("removeRunDependency", () => module.removeRunDependency); } + + // this is registration of the runtime pre_init, when user set configSrc + if (module.configSrc) { + module.preInit.push(async () => { + module.addRunDependency("mono_wasm_pre_init"); + // execution order == [0] == + await mono_wasm_pre_init(); + module.removeRunDependency("mono_wasm_pre_init"); + }); + } + + // if onRuntimeInitialized is set it's probably Blazor, we let them to do their own init sequence + if (!module.onRuntimeInitialized) { + // this is registration of the runtime initialisation, it's async and uses fetch + module.preRun.push(async () => { + // execution order == [1] == + module.addRunDependency("mono_load_runtime_and_bcl_args"); + await mono_load_runtime_and_bcl_args(); + module.removeRunDependency("mono_load_runtime_and_bcl_args"); + }); + // this is synchronous method, which needs that emscripten is already initialized + // execution order == [2] == + module.onRuntimeInitialized = finalize_startup; + + module.ready = module.ready.then(async () => { + // mono_wasm_runtime_is_initialized is set when finalize_startup is done + await mono_wasm_runtime_is_initialized; + // execution order == [3] == + return exportedAPI; + }); + } + + // this code makes it possible to find dotnet runtime on a page via global namespace, even when there are multiple runtimes at the same time let list: RuntimeList; if (!globalThisAny.getDotnetRuntime) { globalThisAny.getDotnetRuntime = (runtimeId: string) => globalThisAny.getDotnetRuntime.__list.getRuntime(runtimeId); diff --git a/src/mono/wasm/runtime/icu.ts b/src/mono/wasm/runtime/icu.ts index 35f3d9587b213..58ad13628cee9 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 { MonoInitContext } from "./startup"; import { GlobalizationMode } from "./types"; import { VoidPtr } from "./types/emscripten"; @@ -29,7 +28,7 @@ export function mono_wasm_get_icudt_name(culture: string): string { // @globalization_mode is one of "icu", "invariant", or "auto". // "auto" will use "icu" if any ICU data archives have been loaded, // otherwise "invariant". -export function mono_wasm_globalization_init(globalization_mode: GlobalizationMode, ctx: MonoInitContext): void { +export function mono_wasm_globalization_init(globalization_mode: GlobalizationMode, tracing: boolean): void { let invariantMode = false; if (globalization_mode === "invariant") @@ -37,11 +36,11 @@ export function mono_wasm_globalization_init(globalization_mode: GlobalizationMo if (!invariantMode) { if (num_icu_assets_loaded_successfully > 0) { - if (ctx.tracing) { + if (tracing) { console.debug("MONO_WASM: ICU data archive(s) loaded, disabling invariant mode"); } } else if (globalization_mode !== "icu") { - if (ctx.tracing) { + if (tracing) { console.debug("MONO_WASM: ICU data archive(s) not loaded, using invariant globalization mode"); } invariantMode = true; diff --git a/src/mono/wasm/runtime/modularize-dotnet.md b/src/mono/wasm/runtime/modularize-dotnet.md index 793d94d1fb2bd..0ec846fa75926 100644 --- a/src/mono/wasm/runtime/modularize-dotnet.md +++ b/src/mono/wasm/runtime/modularize-dotnet.md @@ -76,7 +76,7 @@ export const { MONO, BINDING } = await createDotnetRuntime(({ MONO, BINDING, Mod // This is called after all assets are loaded , mapping to legacy `config.loaded_cb`. // It happens during emscripten `onRuntimeInitialized` after monoVm init + globalization + assemblies. // This also matches when the top level promise is resolved. - // The original emscripten `Module.ready` promise is replaced this this. + // The original emscripten `Module.ready` promise is replaced with this. // at this point both emscripten and monoVM are fully initialized. Module.FS.chdir(processedArguments.working_dir); diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index e00ece77d4bf7..0104f88e5e251 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.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 { AllAssetEntryTypes, AssetEntry, CharPtrNull, DotnetModule, GlobalizationMode, MonoConfig, wasm_type_symbol } from "./types"; +import { AllAssetEntryTypes, AssetEntry, CharPtrNull, DotnetModule, GlobalizationMode, MonoConfig, MonoConfigError, 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"; @@ -23,36 +23,32 @@ export const mono_wasm_runtime_is_initialized = new Promise((resolve, reject) => export async function mono_wasm_pre_init(): Promise { const moduleExt = Module as DotnetModule; - if (moduleExt.configSrc) { + if (!moduleExt.configSrc) { + return; + } + + 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 { - // sets MONO.config implicitly - await mono_wasm_load_config(moduleExt.configSrc); + moduleExt.onConfigLoaded(); } catch (err: any) { + Module.printErr("MONO_WASM: onConfigLoaded () failed: " + err); + Module.printErr("MONO_WASM: Stacktrace: \n"); + Module.printErr(err.stack); runtime_is_initialized_reject(err); throw err; } - - if (moduleExt.onConfigLoaded) { - try { - moduleExt.onConfigLoaded(); - } - catch (err: any) { - Module.printErr("MONO_WASM: onConfigLoaded () failed: " + err); - Module.printErr("MONO_WASM: Stacktrace: \n"); - Module.printErr(err.stack); - runtime_is_initialized_reject(err); - throw err; - } - } } -} -export async function mono_wasm_on_runtime_initialized(): Promise { - if (!Module.config || Module.config.isError) { - return; - } - await mono_load_runtime_and_bcl_args(Module.config); } // Set environment variable NAME to VALUE @@ -144,87 +140,93 @@ function _handle_fetched_asset(ctx: MonoInitContext, asset: AssetEntry, url: str } } -function _apply_configuration_from_args(args: MonoConfig) { - for (const k in (args.environment_variables || {})) - mono_wasm_setenv(k, args.environment_variables![k]); +function _apply_configuration_from_args(config: MonoConfig) { + for (const k in (config.environment_variables || {})) + mono_wasm_setenv(k, config.environment_variables![k]); - if (args.runtime_options) - mono_wasm_set_runtime_options(args.runtime_options); + if (config.runtime_options) + mono_wasm_set_runtime_options(config.runtime_options); - if (args.aot_profiler_options) - mono_wasm_init_aot_profiler(args.aot_profiler_options); + if (config.aot_profiler_options) + mono_wasm_init_aot_profiler(config.aot_profiler_options); - if (args.coverage_profiler_options) - mono_wasm_init_coverage_profiler(args.coverage_profiler_options); + if (config.coverage_profiler_options) + mono_wasm_init_coverage_profiler(config.coverage_profiler_options); } -function _finalize_startup(args: MonoConfig, ctx: MonoInitContext) { - const moduleExt = Module as DotnetModule; - - ctx.loaded_files.forEach(value => MONO.loaded_files.push(value.url)); - if (ctx.tracing) { - console.log("MONO_WASM: loaded_assets: " + JSON.stringify(ctx.loaded_assets)); - console.log("MONO_WASM: loaded_files: " + JSON.stringify(ctx.loaded_files)); - } - +export function finalize_startup(config?: MonoConfig | MonoConfigError): void { try { - if (ctx.tracing) { - console.debug("MONO_WASM: Initializing mono runtime"); - } - mono_wasm_globalization_init(args.globalization_mode!, ctx); - cwraps.mono_wasm_load_runtime("unused", args.debug_level || 0); - } catch (err: any) { - Module.printErr("MONO_WASM: mono_wasm_load_runtime () failed: " + err); - Module.printErr("MONO_WASM: Stacktrace: \n"); - Module.printErr(err.stack); + if (!config) config = Module.config; - runtime_is_initialized_reject(err); - if (ENVIRONMENT_IS_SHELL || ENVIRONMENT_IS_NODE) { - const wasm_exit = cwraps.mono_wasm_exit; - wasm_exit(1); + if (!config || config.isError) { + return; + } + if (config.diagnostic_tracing) { + console.debug("MONO_WASM: Initializing mono runtime"); } - } - - bindings_lazy_init(); - let tz; - try { - tz = Intl.DateTimeFormat().resolvedOptions().timeZone; - } catch { - //swallow - } - mono_wasm_setenv("TZ", tz || "UTC"); - mono_wasm_runtime_ready(); + const moduleExt = Module as DotnetModule; - //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); + mono_wasm_globalization_init(config.globalization_mode!, config.diagnostic_tracing!); + cwraps.mono_wasm_load_runtime("unused", config.debug_level || 0); + } catch (err: any) { + Module.printErr("MONO_WASM: mono_wasm_load_runtime () failed: " + err); Module.printErr("MONO_WASM: Stacktrace: \n"); Module.printErr(err.stack); + runtime_is_initialized_reject(err); - throw err; + if (ENVIRONMENT_IS_SHELL || ENVIRONMENT_IS_NODE) { + const wasm_exit = cwraps.mono_wasm_exit; + wasm_exit(1); + } } - } - if (moduleExt.onDotnetReady) { + bindings_lazy_init(); + + let tz; try { - moduleExt.onDotnetReady(); + tz = Intl.DateTimeFormat().resolvedOptions().timeZone; + } catch { + //swallow } - catch (err: any) { - Module.printErr("MONO_WASM: onDotnetReady () failed: " + err); - Module.printErr("MONO_WASM: Stacktrace: \n"); - Module.printErr(err.stack); - runtime_is_initialized_reject(err); - throw err; + mono_wasm_setenv("TZ", tz || "UTC"); + mono_wasm_runtime_ready(); + + //legacy config loading + const argsAny: any = config; + 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; + } } - } - runtime_is_initialized_resolve(); + if (moduleExt.onDotnetReady) { + try { + moduleExt.onDotnetReady(); + } + catch (err: any) { + 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(); + } catch (err: any) { + console.error("MONO_WASM: Error in finalize_startup:", err); + runtime_is_initialized_reject(err); + throw err; + } } export function bindings_lazy_init(): void { @@ -290,14 +292,20 @@ export function bindings_lazy_init(): void { } // Initializes the runtime and loads assemblies, debug information, and other files. -export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise { +export async function mono_load_runtime_and_bcl_args(config: MonoConfig | MonoConfigError): Promise { + if (!config || config.isError) { + return; + } + try { - if (args.enable_debugging) - args.debug_level = args.enable_debugging; + if (config.enable_debugging) + config.debug_level = config.enable_debugging; + + config.diagnostic_tracing = config.diagnostic_tracing || false; const ctx: MonoInitContext = { - tracing: args.diagnostic_tracing || false, - pending_count: args.assets.length, + tracing: config.diagnostic_tracing, + pending_count: config.assets.length, loaded_assets: Object.create(null), // dlls and pdbs, used by blazor and the debugger loaded_files: [], @@ -305,17 +313,17 @@ export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise< createDataFile: Module.FS_createDataFile }; - _apply_configuration_from_args(args); + _apply_configuration_from_args(config); // fetch_file_cb is legacy do we really want to support it ? - if (!Module.imports!.fetch && typeof ((args).fetch_file_cb) === "function") { - runtimeHelpers.fetch = (args).fetch_file_cb; + if (!Module.imports!.fetch && typeof ((config).fetch_file_cb) === "function") { + runtimeHelpers.fetch = (config).fetch_file_cb; } - const load_asset = async (asset: AllAssetEntryTypes): Promise => { - //TODO we could do module.addRunDependency(asset.name) and delay emscripten run() after all assets are loaded + const load_asset = async (config: MonoConfig, asset: AllAssetEntryTypes): Promise => { + Module.addRunDependency(asset.name); - const sourcesList = asset.load_remote ? args.remote_sources! : [""]; + const sourcesList = asset.load_remote ? config.remote_sources! : [""]; let error = undefined; for (let sourcePrefix of sourcesList) { // HACK: Special-case because MSBuild doesn't allow "" as an attribute @@ -325,10 +333,10 @@ export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise< let attemptUrl; if (sourcePrefix.trim() === "") { if (asset.behavior === "assembly") - attemptUrl = locateFile(args.assembly_root + "/" + asset.name); + attemptUrl = locateFile(config.assembly_root + "/" + asset.name); else if (asset.behavior === "resource") { const path = asset.culture !== "" ? `${asset.culture}/${asset.name}` : asset.name; - attemptUrl = locateFile(args.assembly_root + "/" + path); + attemptUrl = locateFile(config.assembly_root + "/" + path); } else attemptUrl = asset.name; @@ -360,25 +368,29 @@ export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise< } if (!error) { - //TODO Module.removeRunDependency(configFilePath); break; // this source worked, stop searching } } if (error) { - const isOkToFail = asset.is_optional || (asset.name.match(/\.pdb$/) && args.ignore_pdb_load_errors); + const isOkToFail = asset.is_optional || (asset.name.match(/\.pdb$/) && config.ignore_pdb_load_errors); if (!isOkToFail) throw error; } + Module.removeRunDependency(asset.name); }; const fetch_promises: Promise[] = []; // start fetching all assets in parallel - for (const asset of args.assets) { - fetch_promises.push(load_asset(asset)); + for (const asset of config.assets) { + fetch_promises.push(load_asset(config, asset)); } await Promise.all(fetch_promises); - _finalize_startup(args, ctx); + ctx.loaded_files.forEach(value => MONO.loaded_files.push(value.url)); + if (ctx.tracing) { + console.log("MONO_WASM: loaded_assets: " + JSON.stringify(ctx.loaded_assets)); + console.log("MONO_WASM: loaded_files: " + JSON.stringify(ctx.loaded_files)); + } } catch (err: any) { console.error("MONO_WASM: Error in mono_load_runtime_and_bcl_args:", err); runtime_is_initialized_reject(err); diff --git a/src/mono/wasm/runtime/types/emscripten.ts b/src/mono/wasm/runtime/types/emscripten.ts index 2b7b51cf375a5..88fe9548bced4 100644 --- a/src/mono/wasm/runtime/types/emscripten.ts +++ b/src/mono/wasm/runtime/types/emscripten.ts @@ -53,10 +53,10 @@ export declare interface EmscriptenModule { addRunDependency(id: string): void; ready: Promise; - preInit?: (() => void | Promise)[]; - preRun?: (() => void | Promise)[]; - postRun?: (() => void | Promise)[]; - onRuntimeInitialized?: () => void; + preInit?: (() => any)[]; + preRun?: (() => any)[]; + postRun?: (() => any)[]; + onRuntimeInitialized?: () => any; instantiateWasm: (imports: any, successCallback: Function) => any; } From 00d784d5742cfea2cc1d0e6f5434a177c151e5db Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 1 Dec 2021 16:06:42 +0100 Subject: [PATCH 26/28] tweaks --- src/mono/wasm/runtime/dotnet.d.ts | 2 +- src/mono/wasm/runtime/exports.ts | 4 ++-- src/mono/wasm/runtime/startup.ts | 6 ++---- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/mono/wasm/runtime/dotnet.d.ts b/src/mono/wasm/runtime/dotnet.d.ts index c0627f7a08383..cc4341a54dd3c 100644 --- a/src/mono/wasm/runtime/dotnet.d.ts +++ b/src/mono/wasm/runtime/dotnet.d.ts @@ -235,7 +235,7 @@ declare type DotnetModuleConfigImports = { declare function mono_wasm_runtime_ready(): void; declare function mono_wasm_setenv(name: string, value: string): void; -declare function mono_load_runtime_and_bcl_args(config?: MonoConfig | MonoConfigError): Promise; +declare function mono_load_runtime_and_bcl_args(config: MonoConfig | MonoConfigError | undefined): Promise; declare function mono_wasm_load_data_archive(data: Uint8Array, prefix: string): boolean; /** * Loads the mono config file (typically called mono-config.json) asynchroniously diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index 17f3b66b58b7c..00f9b86568c9d 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -265,12 +265,12 @@ function initializeImportsAndExports( module.preRun.push(async () => { // execution order == [1] == module.addRunDependency("mono_load_runtime_and_bcl_args"); - await mono_load_runtime_and_bcl_args(); + await mono_load_runtime_and_bcl_args(module.config); module.removeRunDependency("mono_load_runtime_and_bcl_args"); }); // this is synchronous method, which needs that emscripten is already initialized // execution order == [2] == - module.onRuntimeInitialized = finalize_startup; + module.onRuntimeInitialized = () => finalize_startup(module.config); module.ready = module.ready.then(async () => { // mono_wasm_runtime_is_initialized is set when finalize_startup is done diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index 0104f88e5e251..3b48330f11712 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -154,10 +154,8 @@ function _apply_configuration_from_args(config: MonoConfig) { mono_wasm_init_coverage_profiler(config.coverage_profiler_options); } -export function finalize_startup(config?: MonoConfig | MonoConfigError): void { +export function finalize_startup(config: MonoConfig | MonoConfigError | undefined): void { try { - if (!config) config = Module.config; - if (!config || config.isError) { return; } @@ -292,7 +290,7 @@ export function bindings_lazy_init(): void { } // Initializes the runtime and loads assemblies, debug information, and other files. -export async function mono_load_runtime_and_bcl_args(config: MonoConfig | MonoConfigError): Promise { +export async function mono_load_runtime_and_bcl_args(config: MonoConfig | MonoConfigError | undefined): Promise { if (!config || config.isError) { return; } From ff39ea511ed328e5cb5b86101748fa261fd7944e Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 1 Dec 2021 17:46:52 +0100 Subject: [PATCH 27/28] fix variables --- src/mono/wasm/runtime/startup.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index 3b48330f11712..2daa91e3d9c67 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -166,6 +166,8 @@ export function finalize_startup(config: MonoConfig | MonoConfigError | undefine const moduleExt = Module as DotnetModule; try { + _apply_configuration_from_args(config); + mono_wasm_globalization_init(config.globalization_mode!, config.diagnostic_tracing!); cwraps.mono_wasm_load_runtime("unused", config.debug_level || 0); } catch (err: any) { @@ -311,8 +313,6 @@ export async function mono_load_runtime_and_bcl_args(config: MonoConfig | MonoCo createDataFile: Module.FS_createDataFile }; - _apply_configuration_from_args(config); - // fetch_file_cb is legacy do we really want to support it ? if (!Module.imports!.fetch && typeof ((config).fetch_file_cb) === "function") { runtimeHelpers.fetch = (config).fetch_file_cb; From 8ddc7102a142d16d1afd8fc28ad34f160394df1b Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 1 Dec 2021 23:05:41 +0100 Subject: [PATCH 28/28] fix exports, fix early malloc --- src/mono/wasm/runtime/exports.ts | 25 ++++++++----------------- src/mono/wasm/runtime/startup.ts | 15 ++++++++++++--- src/mono/wasm/wasm.proj | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index 00f9b86568c9d..f4b44fc9385d8 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -34,7 +34,7 @@ import { mono_wasm_set_main_args, mono_wasm_pre_init, mono_wasm_runtime_is_initialized, - finalize_startup + mono_wasm_on_runtime_initialized } from "./startup"; import { mono_set_timeout, schedule_background_exec } from "./scheduling"; import { mono_wasm_load_icu_data, mono_wasm_get_icudt_name } from "./icu"; @@ -169,11 +169,6 @@ function initializeImportsAndExports( } else if (typeof module.preRun === "function") { module.preRun = [module.preRun]; } - if (!module.postRun) { - module.postRun = []; - } else if (typeof module.postRun === "function") { - module.postRun = [module.postRun]; - } if (!module.print) { module.print = console.log; @@ -261,21 +256,17 @@ function initializeImportsAndExports( // if onRuntimeInitialized is set it's probably Blazor, we let them to do their own init sequence if (!module.onRuntimeInitialized) { - // this is registration of the runtime initialisation, it's async and uses fetch - module.preRun.push(async () => { - // execution order == [1] == - module.addRunDependency("mono_load_runtime_and_bcl_args"); - await mono_load_runtime_and_bcl_args(module.config); - module.removeRunDependency("mono_load_runtime_and_bcl_args"); - }); - // this is synchronous method, which needs that emscripten is already initialized - // execution order == [2] == - module.onRuntimeInitialized = () => finalize_startup(module.config); + // note this would keep running in async-parallel with emscripten's `run()` and `postRun()` + // because it's loading files asynchronously and the emscripten is not awaiting onRuntimeInitialized + // execution order == [1] == + module.onRuntimeInitialized = () => mono_wasm_on_runtime_initialized(); module.ready = module.ready.then(async () => { // mono_wasm_runtime_is_initialized is set when finalize_startup is done await mono_wasm_runtime_is_initialized; - // execution order == [3] == + // TODO we could take over Module.postRun and call it from here if necessary + + // execution order == [2] == return exportedAPI; }); } diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index 2daa91e3d9c67..6ab3aaa943df6 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -51,6 +51,15 @@ export async function mono_wasm_pre_init(): Promise { } +export async function mono_wasm_on_runtime_initialized(): Promise { + if (!Module.config || Module.config.isError) { + return; + } + await mono_load_runtime_and_bcl_args(Module.config); + finalize_startup(Module.config); +} + + // Set environment variable NAME to VALUE // Should be called before mono_load_runtime_and_bcl () in most cases export function mono_wasm_setenv(name: string, value: string): void { @@ -154,7 +163,7 @@ function _apply_configuration_from_args(config: MonoConfig) { mono_wasm_init_coverage_profiler(config.coverage_profiler_options); } -export function finalize_startup(config: MonoConfig | MonoConfigError | undefined): void { +function finalize_startup(config: MonoConfig | MonoConfigError | undefined): void { try { if (!config || config.isError) { return; @@ -319,7 +328,7 @@ export async function mono_load_runtime_and_bcl_args(config: MonoConfig | MonoCo } const load_asset = async (config: MonoConfig, asset: AllAssetEntryTypes): Promise => { - Module.addRunDependency(asset.name); + // TODO Module.addRunDependency(asset.name); const sourcesList = asset.load_remote ? config.remote_sources! : [""]; let error = undefined; @@ -374,7 +383,7 @@ export async function mono_load_runtime_and_bcl_args(config: MonoConfig | MonoCo if (!isOkToFail) throw error; } - Module.removeRunDependency(asset.name); + // TODO Module.removeRunDependency(asset.name); }; const fetch_promises: Promise[] = []; // start fetching all assets in parallel diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index ab93616c883bb..0a8e59dd43936 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -66,7 +66,7 @@ <_EmccCommonFlags Include="-s ALLOW_MEMORY_GROWTH=1" /> <_EmccCommonFlags Include="-s NO_EXIT_RUNTIME=1" /> <_EmccCommonFlags Include="-s FORCE_FILESYSTEM=1" /> - <_EmccCommonFlags Include="-s EXPORTED_RUNTIME_METHODS="['DOTNET','MONO','BINDING','INTERNAL','FS','print','ccall','cwrap','setValue','getValue','UTF8ToString','UTF8ArrayToString','FS_createPath','FS_createDataFile','removeRunDependency','addRunDependency']"" /> + <_EmccCommonFlags Include="-s EXPORTED_RUNTIME_METHODS="['FS','print','ccall','cwrap','setValue','getValue','UTF8ToString','UTF8ArrayToString','FS_createPath','FS_createDataFile','removeRunDependency','addRunDependency']"" /> <_EmccCommonFlags Include="-s EXPORTED_FUNCTIONS="['_free','_malloc']"" /> <_EmccCommonFlags Include="--source-map-base http://example.com" />