diff --git a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/timers.mjs b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/timers.mjs
index 4e471c397c2085..eceb916ef01e83 100644
--- a/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/timers.mjs
+++ b/src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/timers.mjs
@@ -3,7 +3,7 @@
export function log(message) {
// uncomment for debugging
- console.log(message);
+ // console.log(message);
}
export function install() {
diff --git a/src/mono/mono/component/mini-wasm-debugger.c b/src/mono/mono/component/mini-wasm-debugger.c
index a13e273ebb9eba..5de1f3422090ca 100644
--- a/src/mono/mono/component/mini-wasm-debugger.c
+++ b/src/mono/mono/component/mini-wasm-debugger.c
@@ -375,6 +375,7 @@ mono_wasm_send_dbg_command_with_parms (int id, MdbgProtCommandSet command_set, i
gboolean result = FALSE;
MONO_ENTER_GC_UNSAFE;
if (!debugger_enabled) {
+ PRINT_ERROR_MSG ("DEBUGGING IS NOT ENABLED\n");
mono_wasm_add_dbg_command_received (0, id, 0, 0);
result = TRUE;
goto done;
@@ -401,6 +402,7 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command,
gboolean result = FALSE;
MONO_ENTER_GC_UNSAFE;
if (!debugger_enabled) {
+ PRINT_ERROR_MSG ("DEBUGGING IS NOT ENABLED\n");
mono_wasm_add_dbg_command_received(0, id, 0, 0);
result = TRUE;
goto done;
diff --git a/src/mono/sample/wasm/Directory.Build.targets b/src/mono/sample/wasm/Directory.Build.targets
index aae2441538ae93..6979b8536abaa5 100644
--- a/src/mono/sample/wasm/Directory.Build.targets
+++ b/src/mono/sample/wasm/Directory.Build.targets
@@ -38,7 +38,7 @@
-
+
diff --git a/src/mono/sample/wasm/browser/main.js b/src/mono/sample/wasm/browser/main.js
index 06f216259f5cba..5198baccca6e99 100644
--- a/src/mono/sample/wasm/browser/main.js
+++ b/src/mono/sample/wasm/browser/main.js
@@ -22,7 +22,7 @@ function sub(a, b) {
try {
const { MONO, RuntimeBuildInfo, IMPORTS } = await createDotnetRuntime(() => {
- console.log('user code in createDotnetRuntime');
+ console.log('user code in createDotnetRuntime callback');
return {
configSrc: "./mono-config.json",
preInit: () => { console.log('user code Module.preInit'); },
@@ -31,7 +31,7 @@ try {
postRun: () => { console.log('user code Module.postRun'); },
}
});
- console.log('after createDotnetRuntime');
+ console.log('user code after createDotnetRuntime()');
IMPORTS.Sample = {
Test: {
add,
diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs
index 86542396ea1575..c714647be9df9c 100644
--- a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs
+++ b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs
@@ -40,7 +40,7 @@ public async Task CreateJSBreakpoint()
{
// Test that js breakpoints get set correctly
// 13 24
- // 13 53
+ // 14 24
var bp1_res = await SetBreakpoint("/debugger-driver.html", 13, 24);
Assert.EndsWith("debugger-driver.html", bp1_res.Value["breakpointId"].ToString());
@@ -52,7 +52,7 @@ public async Task CreateJSBreakpoint()
Assert.Equal(13, (int)loc["lineNumber"]);
Assert.Equal(24, (int)loc["columnNumber"]);
- var bp2_res = await SetBreakpoint("/debugger-driver.html", 13, 53);
+ var bp2_res = await SetBreakpoint("/debugger-driver.html", 14, 24);
Assert.EndsWith("debugger-driver.html", bp2_res.Value["breakpointId"].ToString());
Assert.Equal(1, bp2_res.Value["locations"]?.Value()?.Count);
@@ -60,15 +60,15 @@ public async Task CreateJSBreakpoint()
var loc2 = bp2_res.Value["locations"]?.Value()[0];
Assert.NotNull(loc2["scriptId"]);
- Assert.Equal(13, (int)loc2["lineNumber"]);
- Assert.Equal(53, (int)loc2["columnNumber"]);
+ Assert.Equal(14, (int)loc2["lineNumber"]);
+ Assert.Equal(24, (int)loc2["columnNumber"]);
}
[ConditionalFact(nameof(RunningOnChrome))]
public async Task CreateJS0Breakpoint()
{
// 13 24
- // 13 53
+ // 14 24
var bp1_res = await SetBreakpoint("/debugger-driver.html", 13, 0);
Assert.EndsWith("debugger-driver.html", bp1_res.Value["breakpointId"].ToString());
@@ -78,9 +78,9 @@ public async Task CreateJS0Breakpoint()
Assert.NotNull(loc["scriptId"]);
Assert.Equal(13, (int)loc["lineNumber"]);
- Assert.Equal(4, (int)loc["columnNumber"]);
+ Assert.Equal(24, (int)loc["columnNumber"]);
- var bp2_res = await SetBreakpoint("/debugger-driver.html", 13, 53);
+ var bp2_res = await SetBreakpoint("/debugger-driver.html", 14, 0);
Assert.EndsWith("debugger-driver.html", bp2_res.Value["breakpointId"].ToString());
Assert.Equal(1, bp2_res.Value["locations"]?.Value()?.Count);
@@ -88,8 +88,8 @@ public async Task CreateJS0Breakpoint()
var loc2 = bp2_res.Value["locations"]?.Value()[0];
Assert.NotNull(loc2["scriptId"]);
- Assert.Equal(13, (int)loc2["lineNumber"]);
- Assert.Equal(53, (int)loc2["columnNumber"]);
+ Assert.Equal(14, (int)loc2["lineNumber"]);
+ Assert.Equal(24, (int)loc2["columnNumber"]);
}
[ConditionalTheory(nameof(RunningOnChrome))]
diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-driver.html b/src/mono/wasm/debugger/tests/debugger-test/debugger-driver.html
index 239039451ccdd7..5c6917121db2ac 100644
--- a/src/mono/wasm/debugger/tests/debugger-test/debugger-driver.html
+++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-driver.html
@@ -7,14 +7,14 @@
var App = {
static_method_table: {},
init: function () {
- this.int_add = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] Math:IntAdd");
- this.use_complex = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] Math:UseComplex");
- this.delegates_test = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] Math:DelegatesTest");
- this.generic_types_test = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] Math:GenericTypesTest");
- this.outer_method = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] Math:OuterMethod");
- this.async_method = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] Math/NestedInMath:AsyncTest");
- this.method_with_structs = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] DebuggerTests.ValueTypesTest:MethodWithLocalStructs");
- this.run_all = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] DebuggerTest:run_all");
+ this.int_add = App.BINDING.bind_static_method("[debugger-test] Math:IntAdd");
+ this.use_complex = App.BINDING.bind_static_method("[debugger-test] Math:UseComplex");
+ this.delegates_test = App.BINDING.bind_static_method("[debugger-test] Math:DelegatesTest");
+ this.generic_types_test = App.BINDING.bind_static_method("[debugger-test] Math:GenericTypesTest");
+ this.outer_method = App.BINDING.bind_static_method("[debugger-test] Math:OuterMethod");
+ this.async_method = App.BINDING.bind_static_method("[debugger-test] Math/NestedInMath:AsyncTest");
+ this.method_with_structs = App.BINDING.bind_static_method("[debugger-test] DebuggerTests.ValueTypesTest:MethodWithLocalStructs");
+ this.run_all = App.BINDING.bind_static_method("[debugger-test] DebuggerTest:run_all");
this.static_method_table = {};
console.log ("ready");
},
@@ -22,7 +22,7 @@
function invoke_static_method (method_name, ...args) {
var method = App.static_method_table [method_name];
if (method == undefined)
- method = App.static_method_table [method_name] = getDotnetRuntime(0).INTERNAL.mono_bind_static_method (method_name);
+ method = App.static_method_table[method_name] = App.BINDING.bind_static_method(method_name);
return method (...args);
}
@@ -30,7 +30,7 @@
async function invoke_static_method_async (method_name, ...args) {
var method = App.static_method_table [method_name];
if (method == undefined) {
- method = App.static_method_table [method_name] = getDotnetRuntime(0).INTERNAL.mono_bind_static_method (method_name);
+ method = App.static_method_table[method_name] = App.BINDING.bind_static_method(method_name);
}
return await method (...args);
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 fd1735ed069493..19dc0175e269b5 100644
--- a/src/mono/wasm/debugger/tests/debugger-test/debugger-main.js
+++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-main.js
@@ -6,22 +6,23 @@
import createDotnetRuntime from './dotnet.js'
try {
- const { BINDING, INTERNAL } = await createDotnetRuntime(() => ({
+ const { BINDING } = await createDotnetRuntime(({ INTERNAL }) => ({
configSrc: "./mono-config.json",
onConfigLoaded: (config) => {
config.environment_variables["DOTNET_MODIFIABLE_ASSEMBLIES"] = "debug";
- config.diagnostic_tracing = true;
/* For custom logging patch the functions below
+ config.diagnostic_tracing = true;
config.environment_variables["MONO_LOG_LEVEL"] = "debug";
config.environment_variables["MONO_LOG_MASK"] = "all";
INTERNAL.logging = {
- trace: function (domain, log_level, message, isFatal, dataPtr) { },
- debugger: function (level, message) { }
+ trace: (domain, log_level, message, isFatal, dataPtr) => console.log({ domain, log_level, message, isFatal, dataPtr }),
+ debugger: (level, message) => console.log({ level, message }),
};
*/
},
}));
- App.init({ BINDING, INTERNAL })
+ App.BINDING = BINDING;
+ App.init()
} catch (err) {
console.log(`WASM ERROR ${err}`);
}
diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj
index 71b405b41ef585..affb28a8212df4 100644
--- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj
+++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj
@@ -42,7 +42,7 @@
false
$(AppDir)
debugger-main.js
-
+
-1
true
diff --git a/src/mono/wasm/runtime/cjs/dotnet.cjs.extpost.js b/src/mono/wasm/runtime/cjs/dotnet.cjs.extpost.js
index daa0782d477ad0..703855c301d975 100644
--- a/src/mono/wasm/runtime/cjs/dotnet.cjs.extpost.js
+++ b/src/mono/wasm/runtime/cjs/dotnet.cjs.extpost.js
@@ -1,4 +1,5 @@
var require = require || undefined;
+var __dirname = __dirname || "";
// if loaded into global namespace and configured with global Module, we will self start in compatibility mode
const __isWorker = typeof globalThis.importScripts === "function";
let ENVIRONMENT_IS_GLOBAL = !__isWorker && (typeof globalThis.Module === "object" && globalThis.__dotnet_runtime === __dotnet_runtime);
diff --git a/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js b/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js
index 803054f4973d86..da7bb6ff5fdf59 100644
--- a/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js
+++ b/src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js
@@ -15,7 +15,7 @@ const isPThread = `false`;
const DotnetSupportLib = {
$DOTNET: {},
// these lines will be placed early on emscripten runtime creation, passing import and export objects into __dotnet_runtime IFFE
- // we replace implementation of readAsync and fetch
+ // we replace implementation of fetch
// replacement of require is there for consistency with ES6 code
$DOTNET__postset: `
let __dotnet_replacement_PThread = ${usePThreads} ? {} : undefined;
@@ -23,15 +23,22 @@ if (${usePThreads}) {
__dotnet_replacement_PThread.loadWasmModuleToWorker = PThread.loadWasmModuleToWorker;
__dotnet_replacement_PThread.threadInitTLS = PThread.threadInitTLS;
}
-let __dotnet_replacements = {readAsync, fetch: globalThis.fetch, require, updateGlobalBufferAndViews, pthreadReplacements: __dotnet_replacement_PThread};
+let __dotnet_replacements = {scriptUrl: undefined, fetch: globalThis.fetch, require, updateGlobalBufferAndViews, pthreadReplacements: __dotnet_replacement_PThread};
+if (ENVIRONMENT_IS_NODE) {
+ __dotnet_replacements.requirePromise = Promise.resolve(require);
+}
let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports(
- { isESM:false, isGlobal:ENVIRONMENT_IS_GLOBAL, isNode:ENVIRONMENT_IS_NODE, isWorker:ENVIRONMENT_IS_WORKER, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, isPThread:${isPThread}, locateFile, quit_, ExitStatus, requirePromise:Promise.resolve(require)},
+ { isESM:false, isGlobal:ENVIRONMENT_IS_GLOBAL, isNode:ENVIRONMENT_IS_NODE, isWorker:ENVIRONMENT_IS_WORKER, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, isPThread:${isPThread}, quit_, ExitStatus, requirePromise:Promise.resolve(require)},
{ mono:MONO, binding:BINDING, internal:INTERNAL, module:Module, marshaled_exports: EXPORTS, marshaled_imports: IMPORTS },
__dotnet_replacements);
updateGlobalBufferAndViews = __dotnet_replacements.updateGlobalBufferAndViews;
-readAsync = __dotnet_replacements.readAsync;
var fetch = __dotnet_replacements.fetch;
-require = __dotnet_replacements.requireOut;
+_scriptDir = __dirname = scriptDirectory = __dotnet_replacements.scriptDirectory;
+if (ENVIRONMENT_IS_NODE) {
+ __dotnet_replacements.requirePromise.then(someRequire => {
+ require = someRequire;
+ });
+}
var noExitRuntime = __dotnet_replacements.noExitRuntime;
if (${usePThreads}) {
PThread.loadWasmModuleToWorker = __dotnet_replacements.pthreadReplacements.loadWasmModuleToWorker;
diff --git a/src/mono/wasm/runtime/cjs/dotnet.cjs.pre.js b/src/mono/wasm/runtime/cjs/dotnet.cjs.pre.js
index 71eba317ad02a2..19253e1ef595cc 100644
--- a/src/mono/wasm/runtime/cjs/dotnet.cjs.pre.js
+++ b/src/mono/wasm/runtime/cjs/dotnet.cjs.pre.js
@@ -5,11 +5,13 @@ if (ENVIRONMENT_IS_GLOBAL) {
}
globalThis.Module.ready = Module.ready;
Module = createDotnetRuntime = globalThis.Module;
+ if (!createDotnetRuntime.locateFile) createDotnetRuntime.locateFile = createDotnetRuntime.__locateFile = (path) => scriptDirectory + path;
}
else if (typeof createDotnetRuntime === "object") {
Module = { ready: Module.ready, __undefinedConfig: Object.keys(createDotnetRuntime).length === 1 };
Object.assign(Module, createDotnetRuntime);
createDotnetRuntime = Module;
+ if (!createDotnetRuntime.locateFile) createDotnetRuntime.locateFile = createDotnetRuntime.__locateFile = (path) => scriptDirectory + path;
}
else if (typeof createDotnetRuntime === "function") {
Module = { ready: Module.ready };
@@ -19,7 +21,8 @@ else if (typeof createDotnetRuntime === "function") {
}
Object.assign(Module, extension);
createDotnetRuntime = Module;
+ if (!createDotnetRuntime.locateFile) createDotnetRuntime.locateFile = createDotnetRuntime.__locateFile = (path) => scriptDirectory + path;
}
else {
throw new Error("MONO_WASM: Can't locate global Module object or moduleFactory callback of createDotnetRuntime function.")
-}
+}
\ No newline at end of file
diff --git a/src/mono/wasm/runtime/crypto-worker.ts b/src/mono/wasm/runtime/crypto-worker.ts
index c270bc924b1d29..d43ccdc93b0a6e 100644
--- a/src/mono/wasm/runtime/crypto-worker.ts
+++ b/src/mono/wasm/runtime/crypto-worker.ts
@@ -62,7 +62,7 @@ export function dotnet_browser_encrypt_decrypt(isEncrypting: boolean, key_buffer
}
if (result.length > output_len) {
- console.error(`ENCRYPT DECRYPT: Encrypt/Decrypt length exceeds output length: ${result.length} > ${output_len}`);
+ console.error(`MONO_WASM_ENCRYPT_DECRYPT: Encrypt/Decrypt length exceeds output length: ${result.length} > ${output_len}`);
return ERR_ARGS;
}
@@ -91,7 +91,7 @@ function _send_simple_msg(msg: any, prefix: string, output_buffer: number, outpu
}
if (result.length > output_len) {
- console.error(`${prefix}: Result length exceeds output length: ${result.length} > ${output_len}`);
+ console.error(`MONO_WASM_ENCRYPT_DECRYPT: ${prefix}: Result length exceeds output length: ${result.length} > ${output_len}`);
return ERR_ARGS;
}
@@ -132,7 +132,7 @@ function _send_msg_worker(msg: any): number | any {
const responseJson = JSON.parse(response);
if (responseJson.error !== undefined) {
- console.error(`Worker failed with: ${responseJson.error}`);
+ console.error(`MONO_WASM_ENCRYPT_DECRYPT: Worker failed with: ${responseJson.error}`);
if (responseJson.error_type == "ArgumentsError")
return ERR_ARGS;
if (responseJson.error_type == "WorkerFailedError")
@@ -144,9 +144,9 @@ function _send_msg_worker(msg: any): number | any {
return responseJson.result;
} catch (err) {
if (err instanceof Error && err.stack !== undefined)
- console.error(`${err.stack}`);
+ console.error(`MONO_WASM_ENCRYPT_DECRYPT: ${err.stack}`);
else
- console.error(`_send_msg_worker failed: ${err}`);
+ console.error(`MONO_WASM_ENCRYPT_DECRYPT: _send_msg_worker failed: ${err}`);
return ERR_OP_FAILED;
}
}
@@ -202,10 +202,9 @@ class LibraryChannel {
public send_msg(msg: string): string {
try {
- let state = Atomics.load(this.comm, this.STATE_IDX);
- if (state !== this.STATE_IDLE)
- console.log(`send_msg, waiting for idle now, ${state}`);
- state = this.wait_for_state(pstate => pstate == this.STATE_IDLE, "waiting");
+ // const state = Atomics.load(this.comm, this.STATE_IDX);
+ // if (state !== this.STATE_IDLE) console.debug(`MONO_WASM_ENCRYPT_DECRYPT: send_msg, waiting for idle now, ${state}`);
+ this.wait_for_state(pstate => pstate == this.STATE_IDLE, "waiting");
this.send_request(msg);
return this.read_response();
@@ -214,14 +213,13 @@ class LibraryChannel {
throw err;
}
finally {
- const state = Atomics.load(this.comm, this.STATE_IDX);
- if (state !== this.STATE_IDLE)
- console.log(`state at end of send_msg: ${state}`);
+ // const state = Atomics.load(this.comm, this.STATE_IDX);
+ // if (state !== this.STATE_IDLE) console.debug(`MONO_WASM_ENCRYPT_DECRYPT: state at end of send_msg: ${state}`);
}
}
public shutdown(): void {
- console.debug("Shutting down crypto");
+ // console.debug("MONO_WASM_ENCRYPT_DECRYPT: Shutting down crypto");
const state = Atomics.load(this.comm, this.STATE_IDX);
if (state !== this.STATE_IDLE)
throw new Error(`OWNER: Invalid sync communication channel state: ${state}`);
@@ -232,14 +230,15 @@ class LibraryChannel {
Atomics.notify(this.comm, this.STATE_IDX);
}
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
private reset(reason: string): void {
- console.debug(`reset: ${reason}`);
+ // console.debug(`MONO_WASM_ENCRYPT_DECRYPT: reset: ${reason}`);
const state = Atomics.load(this.comm, this.STATE_IDX);
if (state === this.STATE_SHUTDOWN)
return;
if (state === this.STATE_RESET || state === this.STATE_IDLE) {
- console.debug(`state is already RESET or idle: ${state}`);
+ // console.debug(`MONO_WASM_ENCRYPT_DECRYPT: state is already RESET or idle: ${state}`);
return;
}
diff --git a/src/mono/wasm/runtime/debug.ts b/src/mono/wasm/runtime/debug.ts
index d27cd44e87ba9a..40ab3a4201743b 100644
--- a/src/mono/wasm/runtime/debug.ts
+++ b/src/mono/wasm/runtime/debug.ts
@@ -1,13 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+import Configuration from "consts:configuration";
import { INTERNAL, Module, MONO, runtimeHelpers } from "./imports";
import { toBase64StringImpl } from "./base64";
import cwraps from "./cwraps";
import { VoidPtr, CharPtr } from "./types/emscripten";
-const commands_received : any = new Map();
+const commands_received: any = new Map();
const wasm_func_map = new Map();
-commands_received.remove = function (key: number) : CommandResponse { const value = this.get(key); this.delete(key); return value;};
+commands_received.remove = function (key: number): CommandResponse { const value = this.get(key); this.delete(key); return value; };
let _call_function_res_cache: any = {};
let _next_call_function_res_id = 0;
let _debugger_buffer_len = -1;
@@ -15,7 +16,7 @@ let _debugger_buffer: VoidPtr;
let _assembly_name_str: string; //keep this variable, it's used by BrowserDebugProxy
let _entrypoint_method_token: number; //keep this variable, it's used by BrowserDebugProxy
-const regexes:any[] = [];
+const regexes: any[] = [];
// V8
// at :wasm-function[1900]:0x83f63
@@ -66,7 +67,7 @@ export function mono_wasm_add_dbg_command_received(res_ok: boolean, id: number,
}
};
if (commands_received.has(id))
- console.warn("Addind an id that already exists in commands_received");
+ console.warn(`MONO_WASM: Adding an id (${id}) that already exists in commands_received`);
commands_received.set(id, buffer_obj);
}
@@ -178,7 +179,7 @@ function _create_proxy_from_object_id(objectId: string, details: any) {
if (objectId.startsWith("dotnet:array:")) {
let ret: Array;
if (details.items === undefined) {
- ret = details.map ((p: any) => p.value);
+ ret = details.map((p: any) => p.value);
return ret;
}
if (details.dimensionsDetails === undefined || details.dimensionsDetails.length === 1) {
@@ -363,27 +364,34 @@ export function mono_wasm_debugger_log(level: number, message_ptr: CharPtr): voi
return;
}
- console.debug(`Debugger.Debug: ${message}`);
+ if (Configuration === "Debug") {
+ console.debug(`MONO_WASM: Debugger.Debug: ${message}`);
+ }
}
function _readSymbolMapFile(filename: string): void {
try {
- const res = Module.FS_readFile(filename, {flags: "r", encoding: "utf8"});
+ const res = Module.FS_readFile(filename, { flags: "r", encoding: "utf8" });
res.split(/[\r\n]/).forEach((line: string) => {
- const parts:string[] = line.split(/:/);
+ const parts: string[] = line.split(/:/);
if (parts.length < 2)
return;
parts[1] = parts.splice(1).join(":");
wasm_func_map.set(Number(parts[0]), parts[1]);
});
-
- console.debug(`Loaded ${wasm_func_map.size} symbols`);
- } catch (error:any) {
- if (error.errno == 44) // NOENT
- console.debug(`Could not find symbols file ${filename}. Ignoring.`);
- else
- console.log(`Error loading symbol file ${filename}: ${JSON.stringify(error)}`);
+ if (Configuration === "Debug") {
+ console.debug(`MONO_WASM: Loaded ${wasm_func_map.size} symbols`);
+ }
+ } catch (error: any) {
+ if (error.errno == 44) {// NOENT
+ if (Configuration === "Debug") {
+ console.debug(`MONO_WASM: Could not find symbols file ${filename}. Ignoring.`);
+ }
+ }
+ else {
+ console.log(`MONO_WASM: Error loading symbol file ${filename}: ${JSON.stringify(error)}`);
+ }
return;
}
}
@@ -395,11 +403,10 @@ export function mono_wasm_symbolicate_string(message: string): string {
const origMessage = message;
- for (let i = 0; i < regexes.length; i ++)
- {
+ for (let i = 0; i < regexes.length; i++) {
const newRaw = message.replace(new RegExp(regexes[i], "g"), (substring, ...args) => {
const groups = args.find(arg => {
- return typeof(arg) == "object" && arg.replaceSection !== undefined;
+ return typeof (arg) == "object" && arg.replaceSection !== undefined;
});
if (groups === undefined)
@@ -421,7 +428,7 @@ export function mono_wasm_symbolicate_string(message: string): string {
return origMessage;
} catch (error) {
- console.debug(`failed to symbolicate: ${error}`);
+ console.debug(`MONO_WASM: failed to symbolicate: ${error}`);
return message;
}
}
@@ -506,7 +513,7 @@ export function setup_proxy_console(id: string, originalConsole: Console, origin
};
}
- const originalConsoleObj : any = originalConsole;
+ const originalConsoleObj: any = originalConsole;
const methods = ["debug", "trace", "warn", "info", "error"];
for (const m of methods) {
if (typeof (originalConsoleObj[m]) !== "function") {
diff --git a/src/mono/wasm/runtime/dotnet.d.ts b/src/mono/wasm/runtime/dotnet.d.ts
index 80ef5ec1d7999a..5e5c5a5db50947 100644
--- a/src/mono/wasm/runtime/dotnet.d.ts
+++ b/src/mono/wasm/runtime/dotnet.d.ts
@@ -50,14 +50,14 @@ declare interface EmscriptenModule {
stackRestore(stack: VoidPtr): void;
stackAlloc(size: number): VoidPtr;
ready: Promise;
+ instantiateWasm?: (imports: WebAssembly.Imports, successCallback: (instance: WebAssembly.Instance, module: WebAssembly.Module) => void) => any;
preInit?: (() => any)[];
preRun?: (() => any)[];
+ onRuntimeInitialized?: () => any;
postRun?: (() => any)[];
onAbort?: {
(error: any): void;
};
- onRuntimeInitialized?: () => any;
- instantiateWasm: (imports: any, successCallback: Function) => any;
}
declare type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array;
@@ -141,12 +141,18 @@ interface MonoObjectRef extends ManagedPointer {
__brandMonoObjectRef: "MonoObjectRef";
}
declare type MonoConfig = {
- isError: false;
- assembly_root: string;
- assets: AllAssetEntryTypes[];
+ isError?: false;
+ assembly_root?: string;
+ assets?: AssetEntry[];
+ /**
+ * Either this or enable_debugging needs to be set
+ * debug_level > 0 enables debugging and sets the debug log level to debug_level
+ * debug_level == 0 disables debugging and enables interpreter optimizations
+ * debug_level < 0 enabled debugging and disables debug logging.
+ */
debug_level?: number;
enable_debugging?: number;
- globalization_mode: GlobalizationMode;
+ globalization_mode?: GlobalizationMode;
diagnostic_tracing?: boolean;
remote_sources?: string[];
environment_variables?: {
@@ -164,43 +170,24 @@ declare type MonoConfigError = {
message: string;
error: any;
};
-declare type AllAssetEntryTypes = AssetEntry | AssemblyEntry | SatelliteAssemblyEntry | VfsEntry | IcuData;
-declare type AssetEntry = {
+interface ResourceRequest {
name: string;
behavior: AssetBehaviours;
+ resolvedUrl?: string;
+ hash?: string;
+}
+interface AssetEntry extends ResourceRequest {
virtual_path?: string;
culture?: string;
load_remote?: boolean;
is_optional?: boolean;
buffer?: ArrayBuffer;
-};
-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"
+ pending?: LoadingResource;
}
+declare type AssetBehaviours = "resource" | "assembly" | "pdb" | "heap" | "icu" | "vfs" | "dotnetwasm";
+declare type GlobalizationMode = "icu" | // load ICU globalization data from any runtime assets with behavior "icu".
+"invariant" | // operate in invariant globalization mode.
+"auto";
declare type AOTProfilerOptions = {
write_at?: string;
send_to?: string;
@@ -223,12 +210,13 @@ declare type DiagnosticServerOptions = {
};
declare type DotnetModuleConfig = {
disableDotnet6Compatibility?: boolean;
- config?: MonoConfig | MonoConfigError;
+ config?: MonoConfig;
configSrc?: string;
- onConfigLoaded?: (config: MonoConfig) => Promise;
- onDotnetReady?: () => void;
+ onConfigLoaded?: (config: MonoConfig) => void | Promise;
+ onDotnetReady?: () => void | Promise;
imports?: DotnetModuleConfigImports;
exports?: string[];
+ downloadResource?: (request: ResourceRequest) => LoadingResource;
} & Partial;
declare type DotnetModuleConfigImports = {
require?: (name: string) => any;
@@ -251,6 +239,11 @@ declare type DotnetModuleConfigImports = {
};
url?: any;
};
+interface LoadingResource {
+ name: string;
+ url: string;
+ response: Promise;
+}
declare type EventPipeSessionID = bigint;
declare const eventLevel: {
@@ -301,7 +294,7 @@ interface Diagnostics {
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 | undefined): Promise;
+declare function mono_wasm_load_runtime(unused?: string, debug_level?: number): void;
declare function mono_wasm_load_data_archive(data: Uint8Array, prefix: string): boolean;
/**
* Loads the mono config file (typically called mono-config.json) asynchroniously
@@ -311,6 +304,10 @@ declare function mono_wasm_load_data_archive(data: Uint8Array, prefix: string):
* @throws Will throw an error if the config file loading fails
*/
declare function mono_wasm_load_config(configFilePath: string): Promise;
+/**
+* @deprecated
+*/
+declare function mono_load_runtime_and_bcl_args(cfg?: MonoConfig | MonoConfigError | undefined): Promise;
declare function mono_wasm_load_icu_data(offset: VoidPtr): boolean;
@@ -447,7 +444,7 @@ declare const MONO: {
mono_run_main_and_exit: typeof mono_run_main_and_exit;
mono_wasm_get_assembly_exports: typeof mono_wasm_get_assembly_exports;
mono_wasm_add_assembly: (name: string, data: VoidPtr, size: number) => number;
- mono_wasm_load_runtime: (unused: string, debug_level: number) => void;
+ mono_wasm_load_runtime: typeof mono_wasm_load_runtime;
config: MonoConfig | MonoConfigError;
loaded_files: string[];
setB32: typeof setB32;
@@ -575,4 +572,4 @@ declare class ArraySegment implements IMemoryView, IDisposable {
get byteLength(): number;
}
-export { ArraySegment, BINDINGType, CreateDotnetRuntimeType, DotnetModuleConfig, DotnetPublicAPI, EmscriptenModule, IMemoryView, MONOType, ManagedError, ManagedObject, MemoryViewType, MonoArray, MonoObject, MonoString, Span, VoidPtr, createDotnetRuntime as default };
+export { ArraySegment, AssetBehaviours, AssetEntry, BINDINGType, CreateDotnetRuntimeType, DotnetModuleConfig, DotnetPublicAPI, EmscriptenModule, IMemoryView, LoadingResource, MONOType, ManagedError, ManagedObject, MemoryViewType, MonoArray, MonoConfig, MonoObject, MonoString, ResourceRequest, Span, VoidPtr, createDotnetRuntime as default };
diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js
index a3b2850c25af1b..d0499e9ff08b75 100644
--- a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js
+++ b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js
@@ -20,55 +20,29 @@ const DotnetSupportLib = {
// This is async init of it, note it would become available only after first tick.
// Also fix of scriptDirectory would be delayed
// Emscripten's getBinaryPromise is not async for NodeJs, but we would like to have it async, so we replace it.
- // We also replace implementation of readAsync and fetch
+ // We also replace implementation of fetch
$DOTNET__postset: `
let __dotnet_replacement_PThread = ${usePThreads} ? {} : undefined;
if (${usePThreads}) {
__dotnet_replacement_PThread.loadWasmModuleToWorker = PThread.loadWasmModuleToWorker;
__dotnet_replacement_PThread.threadInitTLS = PThread.threadInitTLS;
}
-let __dotnet_replacements = {readAsync, fetch: globalThis.fetch, require, updateGlobalBufferAndViews, pthreadReplacements: __dotnet_replacement_PThread};
+let __dotnet_replacements = {scriptUrl: import.meta.url, fetch: globalThis.fetch, require, updateGlobalBufferAndViews, pthreadReplacements: __dotnet_replacement_PThread};
if (ENVIRONMENT_IS_NODE) {
- __dotnet_replacements.requirePromise = import(/* webpackIgnore: true */'module').then(mod => {
- const require = mod.createRequire(import.meta.url);
- const path = require('path');
- const url = require('url');
- __dotnet_replacements.require = require;
- __dirname = scriptDirectory = path.dirname(url.fileURLToPath(import.meta.url)) + '/';
- return require;
- });
- 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);
- }
+ __dotnet_replacements.requirePromise = import(/* webpackIgnore: true */'module').then(mod => mod.createRequire(import.meta.url));
}
let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports(
- { isESM:true, isGlobal:false, isNode:ENVIRONMENT_IS_NODE, isWorker:ENVIRONMENT_IS_WORKER, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, isPThread:${isPThread}, locateFile, quit_, ExitStatus, requirePromise:__dotnet_replacements.requirePromise },
+ { isESM:true, isGlobal:false, isNode:ENVIRONMENT_IS_NODE, isWorker:ENVIRONMENT_IS_WORKER, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, isPThread:${isPThread}, quit_, ExitStatus, requirePromise:__dotnet_replacements.requirePromise },
{ mono:MONO, binding:BINDING, internal:INTERNAL, module:Module, marshaled_exports: EXPORTS, marshaled_imports: IMPORTS },
__dotnet_replacements);
updateGlobalBufferAndViews = __dotnet_replacements.updateGlobalBufferAndViews;
-readAsync = __dotnet_replacements.readAsync;
var fetch = __dotnet_replacements.fetch;
-require = __dotnet_replacements.requireOut;
+_scriptDir = __dirname = scriptDirectory = __dotnet_replacements.scriptDirectory;
+if (ENVIRONMENT_IS_NODE) {
+ __dotnet_replacements.requirePromise.then(someRequire => {
+ require = someRequire;
+ });
+}
var noExitRuntime = __dotnet_replacements.noExitRuntime;
if (${usePThreads}) {
PThread.loadWasmModuleToWorker = __dotnet_replacements.pthreadReplacements.loadWasmModuleToWorker;
diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.pre.js b/src/mono/wasm/runtime/es6/dotnet.es6.pre.js
index 1da0e8e712726c..51648406a6554c 100644
--- a/src/mono/wasm/runtime/es6/dotnet.es6.pre.js
+++ b/src/mono/wasm/runtime/es6/dotnet.es6.pre.js
@@ -1,5 +1,7 @@
const MONO = {}, BINDING = {}, INTERNAL = {}, IMPORTS = {}, EXPORTS = {};
let ENVIRONMENT_IS_GLOBAL = false;
+var require = require || undefined;
+var __dirname = __dirname || '';
if (typeof createDotnetRuntime === "function") {
Module = { ready: Module.ready };
const extension = createDotnetRuntime({ MONO, BINDING, INTERNAL, IMPORTS, EXPORTS, Module })
@@ -8,14 +10,14 @@ if (typeof createDotnetRuntime === "function") {
}
Object.assign(Module, extension);
createDotnetRuntime = Module;
+ if (!createDotnetRuntime.locateFile) createDotnetRuntime.locateFile = createDotnetRuntime.__locateFile = (path) => scriptDirectory + path;
}
else if (typeof createDotnetRuntime === "object") {
Module = { ready: Module.ready, __undefinedConfig: Object.keys(createDotnetRuntime).length === 1 };
Object.assign(Module, createDotnetRuntime);
createDotnetRuntime = Module;
+ if (!createDotnetRuntime.locateFile) createDotnetRuntime.locateFile = createDotnetRuntime.__locateFile = (path) => scriptDirectory + path;
}
else {
throw new Error("MONO_WASM: Can't use moduleFactory callback of createDotnetRuntime function.")
-}
-var require = require || undefined;
-var __dirname = __dirname || '';
\ No newline at end of file
+}
\ 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 057ed83770920e..9f70faf8e32355 100644
--- a/src/mono/wasm/runtime/export-types.ts
+++ b/src/mono/wasm/runtime/export-types.ts
@@ -3,7 +3,7 @@
import { BINDINGType, DotnetPublicAPI, MONOType } from "./exports";
import { IDisposable, IMemoryView, ManagedError, ManagedObject, MemoryViewType } from "./marshal";
-import { DotnetModuleConfig, MonoArray, MonoObject, MonoString } from "./types";
+import { AssetBehaviours, AssetEntry, DotnetModuleConfig, LoadingResource, MonoArray, MonoConfig, MonoObject, MonoString, ResourceRequest } from "./types";
import { EmscriptenModule, TypedArray, VoidPtr } from "./types/emscripten";
// -----------------------------------------------------------
@@ -55,7 +55,8 @@ export {
VoidPtr,
MonoObject, MonoString, MonoArray,
BINDINGType, MONOType, EmscriptenModule,
- DotnetPublicAPI, DotnetModuleConfig, CreateDotnetRuntimeType,
+ DotnetPublicAPI, DotnetModuleConfig, CreateDotnetRuntimeType, MonoConfig,
+ AssetEntry, ResourceRequest, LoadingResource, AssetBehaviours,
IMemoryView, MemoryViewType, ManagedObject, ManagedError, Span, ArraySegment
};
diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts
index 134724eff538ac..b97e106cfc186d 100644
--- a/src/mono/wasm/runtime/exports.ts
+++ b/src/mono/wasm/runtime/exports.ts
@@ -31,13 +31,14 @@ import {
mono_wasm_debugger_attached,
mono_wasm_set_entrypoint_breakpoint,
} from "./debug";
-import { ENVIRONMENT_IS_WEB, ENVIRONMENT_IS_WORKER, ExitStatusError, runtimeHelpers, setImportsAndExports } from "./imports";
-import { DotnetModuleConfigImports, DotnetModule, is_nullish, MonoConfig, MonoConfigError } from "./types";
+import { ENVIRONMENT_IS_WORKER, runtimeHelpers, set_imports_exports } from "./imports";
+import { DotnetModule, is_nullish, MonoConfig, MonoConfigError, EarlyImports, EarlyExports, EarlyReplacements } from "./types";
import {
mono_load_runtime_and_bcl_args, mono_wasm_load_config,
mono_wasm_setenv, mono_wasm_set_runtime_options,
mono_wasm_load_data_archive, mono_wasm_asm_loaded,
- configure_emscripten_startup
+ configure_emscripten_startup,
+ mono_wasm_load_runtime,
} from "./startup";
import { mono_set_timeout, schedule_background_exec } from "./scheduling";
import { mono_wasm_load_icu_data, mono_wasm_get_icudt_name } from "./icu";
@@ -70,10 +71,9 @@ import {
setI8, setI16, setI32, setI52,
setU8, setU16, setU32, setF32, setF64,
getI8, getI16, getI32, getI52,
- getU8, getU16, getU32, getF32, getF64, afterUpdateGlobalBufferAndViews, getI64Big, setI64Big, getU52, setU52, setB32, getB32,
+ getU8, getU16, getU32, getF32, getF64, getI64Big, setI64Big, getU52, setU52, setB32, getB32,
} from "./memory";
import { create_weak_ref } from "./weak-ref";
-import { fetch_like, readAsync_like } from "./polyfills";
import { EmscriptenModule } from "./types/emscripten";
import { mono_run_main, mono_run_main_and_exit } from "./run";
import { dynamic_import, get_global_this, get_property, get_typeof_property, has_property, mono_wasm_bind_js_function, mono_wasm_invoke_bound_function, set_property } from "./invoke-js";
@@ -90,8 +90,8 @@ import {
dotnet_browser_encrypt_decrypt,
dotnet_browser_derive_bits,
} from "./crypto-worker";
-import { mono_wasm_pthread_on_pthread_attached, afterThreadInitTLS } from "./pthreads/worker";
-import { afterLoadWasmModuleToWorker } from "./pthreads/browser";
+import { mono_wasm_pthread_on_pthread_attached } from "./pthreads/worker";
+import { init_polyfills } from "./polyfills";
const MONO = {
// current "public" MONO API
@@ -110,9 +110,8 @@ const MONO = {
mono_run_main_and_exit,
mono_wasm_get_assembly_exports,
- // for Blazor's future!
mono_wasm_add_assembly: cwraps.mono_wasm_add_assembly,
- mono_wasm_load_runtime: cwraps.mono_wasm_load_runtime,
+ mono_wasm_load_runtime,
config: runtimeHelpers.config,
loaded_files: [],
@@ -203,26 +202,21 @@ export type BINDINGType = typeof BINDING;
let exportedAPI: DotnetPublicAPI;
-// We need to replace some of the methods in the Emscripten PThreads support with our own
-type PThreadReplacements = {
- loadWasmModuleToWorker: Function,
- threadInitTLS: Function
-}
-
// this is executed early during load of emscripten runtime
// it exports methods to global objects MONO, BINDING and Module in backward compatible way
// At runtime this will be referred to as 'createDotnetRuntime'
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
function initializeImportsAndExports(
- imports: { isESM: boolean, isGlobal: boolean, isNode: boolean, isWorker: boolean, isShell: boolean, isWeb: boolean, isPThread: boolean, locateFile: Function, quit_: Function, ExitStatus: ExitStatusError, requirePromise: Promise },
- exports: { mono: any, binding: any, internal: any, module: any, marshaled_exports: any, marshaled_imports: any },
- replacements: { fetch: any, readAsync: any, require: any, requireOut: any, noExitRuntime: boolean, updateGlobalBufferAndViews: Function, pthreadReplacements: PThreadReplacements | undefined | null },
+ imports: EarlyImports,
+ exports: EarlyExports,
+ replacements: EarlyReplacements,
): DotnetPublicAPI {
const module = exports.module as DotnetModule;
const globalThisAny = globalThis as any;
// we want to have same instance of MONO, BINDING and Module in dotnet iffe
- setImportsAndExports(imports, exports);
+ set_imports_exports(imports, exports);
+ init_polyfills(replacements);
// here we merge methods from the local objects into exported objects
Object.assign(exports.mono, MONO);
@@ -252,49 +246,6 @@ function initializeImportsAndExports(
if (!module.printErr) {
module.printErr = console.error.bind(console);
}
- module.imports = module.imports || {};
- if (!module.imports.require) {
- module.imports.require = (name) => {
- const resolved = (module.imports)[name];
- if (resolved) {
- return resolved;
- }
- if (replacements.require) {
- return replacements.require(name);
- }
- throw new Error(`Please provide Module.imports.${name} or Module.imports.require`);
- };
- }
-
- if (module.imports.fetch) {
- runtimeHelpers.fetch = module.imports.fetch;
- }
- else {
- runtimeHelpers.fetch = fetch_like;
- }
- replacements.fetch = runtimeHelpers.fetch;
- replacements.readAsync = readAsync_like;
- replacements.requireOut = module.imports.require;
- const originalUpdateGlobalBufferAndViews = replacements.updateGlobalBufferAndViews;
- replacements.updateGlobalBufferAndViews = (buffer: ArrayBufferLike) => {
- originalUpdateGlobalBufferAndViews(buffer);
- afterUpdateGlobalBufferAndViews(buffer);
- };
-
- replacements.noExitRuntime = ENVIRONMENT_IS_WEB;
-
- if (replacements.pthreadReplacements) {
- const originalLoadWasmModuleToWorker = replacements.pthreadReplacements.loadWasmModuleToWorker;
- replacements.pthreadReplacements.loadWasmModuleToWorker = (worker: Worker, onFinishedLoading: Function): void => {
- originalLoadWasmModuleToWorker(worker, onFinishedLoading);
- afterLoadWasmModuleToWorker(worker);
- };
- const originalThreadInitTLS = replacements.pthreadReplacements.threadInitTLS;
- replacements.pthreadReplacements.threadInitTLS = (): void => {
- originalThreadInitTLS();
- afterThreadInitTLS();
- };
- }
if (typeof module.disableDotnet6Compatibility === "undefined") {
module.disableDotnet6Compatibility = imports.isESM;
@@ -307,7 +258,7 @@ function initializeImportsAndExports(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
module.mono_bind_static_method = (fqn: string, signature: string/*ArgsMarshalString*/): Function => {
- console.warn("Module.mono_bind_static_method is obsolete, please use BINDING.bind_static_method instead");
+ console.warn("MONO_WASM: Module.mono_bind_static_method is obsolete, please use BINDING.bind_static_method instead");
return mono_bind_static_method(fqn, signature);
};
@@ -322,7 +273,7 @@ function initializeImportsAndExports(
if (is_nullish(value)) {
const stack = (new Error()).stack;
const nextLine = stack ? stack.substr(stack.indexOf("\n", 8) + 1) : "";
- console.warn(`global ${name} is obsolete, please use Module.${name} instead ${nextLine}`);
+ console.warn(`MONO_WASM: global ${name} is obsolete, please use Module.${name} instead ${nextLine}`);
value = provider();
}
return value;
@@ -353,14 +304,16 @@ function initializeImportsAndExports(
}
list.registerRuntime(exportedAPI);
- configure_emscripten_startup(module, exportedAPI);
-
if (ENVIRONMENT_IS_WORKER) {
// HACK: Emscripten's dotnet.worker.js expects the exports of dotnet.js module to be Module object
// until we have our own fix for dotnet.worker.js file
+ // we also skip all emscripten startup event and configuration of worker's JS state
+ // note that emscripten events are not firing either
return exportedAPI.Module;
}
+ configure_emscripten_startup(module, exportedAPI);
+
return exportedAPI;
}
diff --git a/src/mono/wasm/runtime/icu.ts b/src/mono/wasm/runtime/icu.ts
index da5d03bd8cb8a4..551d0d92d70a6b 100644
--- a/src/mono/wasm/runtime/icu.ts
+++ b/src/mono/wasm/runtime/icu.ts
@@ -2,8 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
import cwraps from "./cwraps";
-import { Module } from "./imports";
-import { GlobalizationMode } from "./types";
+import { Module, runtimeHelpers } from "./imports";
+import { MonoConfig } from "./types";
import { VoidPtr } from "./types/emscripten";
let num_icu_assets_loaded_successfully = 0;
@@ -29,19 +29,21 @@ 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, tracing: boolean): void {
+export function mono_wasm_globalization_init(): void {
+ const config = Module.config as MonoConfig;
let invariantMode = false;
-
- if (globalization_mode === "invariant")
+ if (!config.globalization_mode)
+ config.globalization_mode = "auto";
+ if (config.globalization_mode === "invariant")
invariantMode = true;
if (!invariantMode) {
if (num_icu_assets_loaded_successfully > 0) {
- if (tracing) {
+ if (runtimeHelpers.diagnostic_tracing) {
console.debug("MONO_WASM: ICU data archive(s) loaded, disabling invariant mode");
}
- } else if (globalization_mode !== "icu") {
- if (tracing) {
+ } else if (config.globalization_mode !== "icu") {
+ if (runtimeHelpers.diagnostic_tracing) {
console.debug("MONO_WASM: ICU data archive(s) not loaded, using invariant globalization mode");
}
invariantMode = true;
diff --git a/src/mono/wasm/runtime/imports.ts b/src/mono/wasm/runtime/imports.ts
index 37daf4d7de39eb..3a7e97fbbd5d25 100644
--- a/src/mono/wasm/runtime/imports.ts
+++ b/src/mono/wasm/runtime/imports.ts
@@ -4,7 +4,7 @@
/* eslint-disable @typescript-eslint/triple-slash-reference */
///
-import { DotnetModule, MonoConfig, RuntimeHelpers } from "./types";
+import { DotnetModule, EarlyExports, EarlyImports, MonoConfig, RuntimeHelpers } from "./types";
import { EmscriptenModule } from "./types/emscripten";
// these are our public API (except internal)
@@ -22,20 +22,11 @@ export let ENVIRONMENT_IS_SHELL: boolean;
export let ENVIRONMENT_IS_WEB: boolean;
export let ENVIRONMENT_IS_WORKER: boolean;
export let ENVIRONMENT_IS_PTHREAD: boolean;
-export let locateFile: Function;
-export let quit: Function;
-export let ExitStatus: ExitStatusError;
-export let requirePromise: Promise;
-export let readFile: Function;
-
-export interface ExitStatusError {
- new(status: number): any;
-}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
-export function setImportsAndExports(
- imports: { isESM: boolean, isNode: boolean, isShell: boolean, isWeb: boolean, isWorker: boolean, isPThread: boolean, locateFile: Function, ExitStatus: ExitStatusError, quit_: Function, requirePromise: Promise },
- exports: { mono: any, binding: any, internal: any, module: any, marshaled_exports: any, marshaled_imports: any },
+export function set_imports_exports(
+ imports: EarlyImports,
+ exports: EarlyExports,
): void {
MONO = exports.mono;
BINDING = exports.binding;
@@ -51,10 +42,9 @@ export function setImportsAndExports(
ENVIRONMENT_IS_WEB = imports.isWeb;
ENVIRONMENT_IS_WORKER = imports.isWorker;
ENVIRONMENT_IS_PTHREAD = imports.isPThread;
- locateFile = imports.locateFile;
- quit = imports.quit_;
- ExitStatus = imports.ExitStatus;
- requirePromise = imports.requirePromise;
+ runtimeHelpers.quit = imports.quit_;
+ runtimeHelpers.ExitStatus = imports.ExitStatus;
+ runtimeHelpers.requirePromise = imports.requirePromise;
}
let monoConfig: MonoConfig = {} as any;
@@ -63,6 +53,8 @@ let runtime_is_ready = false;
export const runtimeHelpers: RuntimeHelpers = {
namespace: "System.Runtime.InteropServices.JavaScript",
classname: "Runtime",
+ mono_wasm_load_runtime_done: false,
+ mono_wasm_bindings_is_ready: false,
get mono_wasm_runtime_is_ready() {
return runtime_is_ready;
},
@@ -78,5 +70,7 @@ export const runtimeHelpers: RuntimeHelpers = {
MONO.config = value;
Module.config = value;
},
+ diagnostic_tracing: false,
+ enable_debugging: false,
fetch: null
};
diff --git a/src/mono/wasm/runtime/invoke-cs.ts b/src/mono/wasm/runtime/invoke-cs.ts
index 7443716303deae..9075100f805cff 100644
--- a/src/mono/wasm/runtime/invoke-cs.ts
+++ b/src/mono/wasm/runtime/invoke-cs.ts
@@ -33,8 +33,8 @@ export function mono_wasm_bind_cs_function(fully_qualified_name: MonoStringRef,
const js_fqn = conv_string_root(fqn_root)!;
mono_assert(js_fqn, "fully_qualified_name must be string");
- if (runtimeHelpers.config.diagnostic_tracing) {
- console.trace(`MONO_WASM: Binding [JSExport] ${js_fqn}`);
+ if (runtimeHelpers.diagnostic_tracing) {
+ console.debug(`MONO_WASM: Binding [JSExport] ${js_fqn}`);
}
const { assembly, namespace, classname, methodname } = parseFQN(js_fqn);
@@ -201,6 +201,7 @@ function _walk_exports_to_set_function(assembly: string, namespace: string, clas
}
export async function mono_wasm_get_assembly_exports(assembly: string): Promise {
+ mono_assert(runtimeHelpers.mono_wasm_bindings_is_ready, "Expected binding to be initialized later during startup sequence.");
const asm = assembly_load(assembly);
if (!asm)
throw new Error("Could not find assembly: " + assembly);
diff --git a/src/mono/wasm/runtime/invoke-js.ts b/src/mono/wasm/runtime/invoke-js.ts
index 814e0ae784fdf1..1eae1e83902c55 100644
--- a/src/mono/wasm/runtime/invoke-js.ts
+++ b/src/mono/wasm/runtime/invoke-js.ts
@@ -23,8 +23,8 @@ export function mono_wasm_bind_js_function(function_name: MonoStringRef, module_
const js_function_name = conv_string_root(function_name_root)!;
const js_module_name = conv_string_root(module_name_root)!;
- if (runtimeHelpers.config.diagnostic_tracing) {
- console.trace(`MONO_WASM: Binding [JSImport] ${js_function_name} from ${js_module_name}`);
+ if (runtimeHelpers.diagnostic_tracing) {
+ console.debug(`MONO_WASM: Binding [JSImport] ${js_function_name} from ${js_module_name}`);
}
const fn = mono_wasm_lookup_function(js_function_name, js_module_name);
const args_count = get_signature_argument_count(signature);
@@ -174,16 +174,16 @@ export async function dynamic_import(module_name: string, module_url: string): P
let promise = importedModulesPromises.get(module_name);
const newPromise = !promise;
if (newPromise) {
- if (runtimeHelpers.config.diagnostic_tracing)
- console.trace(`MONO_WASM: importing ES6 module '${module_name}' from '${module_url}'`);
- promise = import(module_url);
+ if (runtimeHelpers.diagnostic_tracing)
+ console.debug(`MONO_WASM: importing ES6 module '${module_name}' from '${module_url}'`);
+ promise = import(/* webpackIgnore: true */module_url);
importedModulesPromises.set(module_name, promise);
}
const module = await promise;
if (newPromise) {
importedModules.set(module_name, module);
- if (runtimeHelpers.config.diagnostic_tracing)
- console.trace(`MONO_WASM: imported ES6 module '${module_name}' from '${module_url}'`);
+ if (runtimeHelpers.diagnostic_tracing)
+ console.debug(`MONO_WASM: imported ES6 module '${module_name}' from '${module_url}'`);
}
return module;
}
diff --git a/src/mono/wasm/runtime/method-binding.ts b/src/mono/wasm/runtime/method-binding.ts
index 581f3ae5c74b43..350530fc11900a 100644
--- a/src/mono/wasm/runtime/method-binding.ts
+++ b/src/mono/wasm/runtime/method-binding.ts
@@ -327,7 +327,7 @@ export function _compile_converter_for_marshal_string(args_marshal: string/*Args
converter.compiled_function = compiledFunction;
} catch (exc) {
converter.compiled_function = null;
- console.warn("compiling converter failed for", bodyJs, "with error", exc);
+ console.warn("MONO_WASM: compiling converter failed for", bodyJs, "with error", exc);
throw exc;
}
@@ -360,7 +360,7 @@ export function _compile_converter_for_marshal_string(args_marshal: string/*Args
converter.compiled_variadic_function = compiledVariadicFunction;
} catch (exc) {
converter.compiled_variadic_function = null;
- console.warn("compiling converter failed for", bodyJs, "with error", exc);
+ console.warn("MONO_WASM: compiling converter failed for", bodyJs, "with error", exc);
throw exc;
}
diff --git a/src/mono/wasm/runtime/method-calls.ts b/src/mono/wasm/runtime/method-calls.ts
index 2b33a3477bb98b..3f0301f64b8e2c 100644
--- a/src/mono/wasm/runtime/method-calls.ts
+++ b/src/mono/wasm/runtime/method-calls.ts
@@ -6,7 +6,7 @@ import {
JSHandle, MonoArray, MonoMethod, MonoObject,
MonoObjectNull, MonoString, coerceNull as coerceNull,
VoidPtrNull, MonoObjectRef,
- MonoStringRef, is_nullish
+ MonoStringRef, is_nullish, mono_assert
} from "./types";
import { INTERNAL, Module, runtimeHelpers } from "./imports";
import { mono_array_root_to_js_array, unbox_mono_obj_root } from "./cs-to-js";
@@ -22,7 +22,6 @@ import {
} from "./method-binding";
import { conv_string_root, js_string_to_mono_string, js_string_to_mono_string_root } from "./strings";
import cwraps from "./cwraps";
-import { bindings_lazy_init } from "./startup";
import { _create_temp_frame, _release_temp_frame } from "./memory";
import { VoidPtr, Int32Ptr } from "./types/emscripten";
import { assembly_load } from "./class-loader";
@@ -174,8 +173,7 @@ function _call_method_with_converted_args(
}
export function call_static_method(fqn: string, args: any[], signature: string/*ArgsMarshalString*/): any {
- bindings_lazy_init();// TODO remove this once Blazor does better startup
-
+ mono_assert(runtimeHelpers.mono_wasm_bindings_is_ready, "Expected binding to be initialized later during startup sequence.");
const method = mono_method_resolve(fqn);
if (typeof signature === "undefined")
@@ -185,8 +183,7 @@ export function call_static_method(fqn: string, args: any[], signature: string/*
}
export function mono_bind_static_method(fqn: string, signature?: string/*ArgsMarshalString*/): Function {
- bindings_lazy_init();// TODO remove this once Blazor does better startup
-
+ mono_assert(runtimeHelpers.mono_wasm_bindings_is_ready, "Expected binding to be initialized later during startup sequence.");
const method = mono_method_resolve(fqn);
if (typeof signature === "undefined")
@@ -196,8 +193,7 @@ export function mono_bind_static_method(fqn: string, signature?: string/*ArgsMar
}
export function mono_bind_assembly_entry_point(assembly: string, signature?: string/*ArgsMarshalString*/): Function {
- bindings_lazy_init();// TODO remove this once Blazor does better startup
-
+ mono_assert(runtimeHelpers.mono_wasm_bindings_is_ready, "Expected binding to be initialized later during startup sequence.");
const asm = assembly_load(assembly);
if (!asm)
throw new Error("Could not find assembly: " + assembly);
@@ -221,6 +217,7 @@ export function mono_bind_assembly_entry_point(assembly: string, signature?: str
}
export function mono_call_assembly_entry_point(assembly: string, args?: any[], signature?: string/*ArgsMarshalString*/): number {
+ mono_assert(runtimeHelpers.mono_wasm_bindings_is_ready, "Expected binding to be initialized later during startup sequence.");
if (!args) {
args = [[]];
}
diff --git a/src/mono/wasm/runtime/modularize-dotnet.md b/src/mono/wasm/runtime/modularize-dotnet.md
index edb83dfb3f0472..8267620ca60b96 100644
--- a/src/mono/wasm/runtime/modularize-dotnet.md
+++ b/src/mono/wasm/runtime/modularize-dotnet.md
@@ -73,7 +73,7 @@ export const { MONO, BINDING } = await createDotnetRuntime(({ MONO, BINDING, Mod
}
onDotnetReady: () => {
// Only when there is no `onRuntimeInitialized` override.
- // This is called after all assets are loaded , mapping to legacy `config.loaded_cb`.
+ // This is called after all assets are loaded.
// 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 with this.
diff --git a/src/mono/wasm/runtime/polyfills.ts b/src/mono/wasm/runtime/polyfills.ts
index 6bd29aa4c117df..abb90829d7cb44 100644
--- a/src/mono/wasm/runtime/polyfills.ts
+++ b/src/mono/wasm/runtime/polyfills.ts
@@ -1,23 +1,20 @@
+import Configuration from "consts:configuration";
import MonoWasmThreads from "consts:monoWasmThreads";
-import { ENVIRONMENT_IS_ESM, ENVIRONMENT_IS_NODE, Module, requirePromise } from "./imports";
+import { ENVIRONMENT_IS_ESM, ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, ENVIRONMENT_IS_WEB, ENVIRONMENT_IS_WORKER, INTERNAL, Module, runtimeHelpers } from "./imports";
+import { afterUpdateGlobalBufferAndViews } from "./memory";
+import { afterLoadWasmModuleToWorker } from "./pthreads/browser";
+import { afterThreadInitTLS } from "./pthreads/worker";
+import { DotnetModuleConfigImports, EarlyReplacements } from "./types";
let node_fs: any | undefined = undefined;
let node_url: any | undefined = undefined;
-export async function init_polyfills(): Promise {
+export function init_polyfills(replacements: EarlyReplacements): void {
+ const anyModule = Module as any;
+
// performance.now() is used by emscripten and doesn't work in JSC
if (typeof globalThis.performance === "undefined") {
- if (ENVIRONMENT_IS_NODE && ENVIRONMENT_IS_ESM) {
- const node_require = await requirePromise;
- const { performance } = node_require("perf_hooks");
- globalThis.performance = performance;
- } else {
- globalThis.performance = {
- now: function () {
- return Date.now();
- }
- } as any;
- }
+ globalThis.performance = dummyPerformance as any;
}
if (typeof globalThis.URL === "undefined") {
globalThis.URL = class URL {
@@ -121,13 +118,104 @@ export async function init_polyfills(): Promise {
}
};
}
+
+ // require replacement
+ const imports = anyModule.imports = Module.imports || {};
+ const requireWrapper = (wrappedRequire: Function) => (name: string) => {
+ const resolved = (Module.imports)[name];
+ if (resolved) {
+ return resolved;
+ }
+ return wrappedRequire(name);
+ };
+ if (imports.require) {
+ runtimeHelpers.requirePromise = replacements.requirePromise = Promise.resolve(requireWrapper(imports.require));
+ }
+ else if (replacements.require) {
+ runtimeHelpers.requirePromise = replacements.requirePromise = Promise.resolve(requireWrapper(replacements.require));
+ } else if (replacements.requirePromise) {
+ runtimeHelpers.requirePromise = replacements.requirePromise.then(require => requireWrapper(require));
+ } else {
+ runtimeHelpers.requirePromise = replacements.requirePromise = Promise.resolve(requireWrapper((name: string) => {
+ throw new Error(`Please provide Module.imports.${name} or Module.imports.require`);
+ }));
+ }
+
+ // script location
+ runtimeHelpers.scriptDirectory = replacements.scriptDirectory = detectScriptDirectory(replacements);
+ anyModule.mainScriptUrlOrBlob = replacements.scriptUrl;// this is needed by worker threads
+ if (Configuration === "Debug") {
+ console.debug(`MONO_WASM: starting script ${replacements.scriptUrl}`);
+ console.debug(`MONO_WASM: starting in ${runtimeHelpers.scriptDirectory}`);
+ }
+ if (anyModule.__locateFile === anyModule.locateFile) {
+ // above it's our early version from dotnet.es6.pre.js, we could replace it with better
+ anyModule.locateFile = runtimeHelpers.locateFile = (path) => {
+ if (isPathAbsolute(path)) return path;
+ return runtimeHelpers.scriptDirectory + path;
+ };
+ } else {
+ // we use what was given to us
+ runtimeHelpers.locateFile = anyModule.locateFile;
+ }
+
+ // fetch poly
+ if (imports.fetch) {
+ replacements.fetch = runtimeHelpers.fetch_like = imports.fetch;
+ }
+ else {
+ replacements.fetch = runtimeHelpers.fetch_like = fetch_like;
+ }
+
+ // misc
+ replacements.noExitRuntime = ENVIRONMENT_IS_WEB;
+
+ // threads
+ if (MonoWasmThreads) {
+ if (replacements.pthreadReplacements) {
+ const originalLoadWasmModuleToWorker = replacements.pthreadReplacements.loadWasmModuleToWorker;
+ replacements.pthreadReplacements.loadWasmModuleToWorker = (worker: Worker, onFinishedLoading: Function): void => {
+ originalLoadWasmModuleToWorker(worker, onFinishedLoading);
+ afterLoadWasmModuleToWorker(worker);
+ };
+ const originalThreadInitTLS = replacements.pthreadReplacements.threadInitTLS;
+ replacements.pthreadReplacements.threadInitTLS = (): void => {
+ originalThreadInitTLS();
+ afterThreadInitTLS();
+ };
+ }
+ }
+
+ // memory
+ const originalUpdateGlobalBufferAndViews = replacements.updateGlobalBufferAndViews;
+ replacements.updateGlobalBufferAndViews = (buffer: ArrayBufferLike) => {
+ originalUpdateGlobalBufferAndViews(buffer);
+ afterUpdateGlobalBufferAndViews(buffer);
+ };
}
-export async function fetch_like(url: string): Promise {
+export async function init_polyfills_async(): Promise {
+ if (ENVIRONMENT_IS_NODE && ENVIRONMENT_IS_ESM) {
+ // wait for locateFile setup on NodeJs
+ INTERNAL.require = await runtimeHelpers.requirePromise;
+ if (globalThis.performance === dummyPerformance) {
+ const { performance } = INTERNAL.require("perf_hooks");
+ globalThis.performance = performance;
+ }
+ }
+}
+
+const dummyPerformance = {
+ now: function () {
+ return Date.now();
+ }
+};
+
+export async function fetch_like(url: string, init?: RequestInit): Promise {
try {
if (ENVIRONMENT_IS_NODE) {
if (!node_fs) {
- const node_require = await requirePromise;
+ const node_require = await runtimeHelpers.requirePromise;
node_url = node_require("url");
node_fs = node_require("fs");
}
@@ -144,7 +232,7 @@ export async function fetch_like(url: string): Promise {
};
}
else if (typeof (globalThis.fetch) === "function") {
- return globalThis.fetch(url, { credentials: "same-origin" });
+ return globalThis.fetch(url, init || { credentials: "same-origin" });
}
else if (typeof (read) === "function") {
// note that it can't open files with unicode names, like Strae.xml
@@ -169,10 +257,67 @@ export async function fetch_like(url: string): Promise {
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);
- });
+function normalizeFileUrl(filename: string) {
+ // unix vs windows
+ // remove query string
+ return filename.replace(/\\/g, "/").replace(/[?#].*/, "");
+}
+
+function normalizeDirectoryUrl(dir: string) {
+ return dir.slice(0, dir.lastIndexOf("/")) + "/";
+}
+
+export function detectScriptDirectory(replacements: EarlyReplacements): string {
+ if (ENVIRONMENT_IS_WORKER) {
+ // Check worker, not web, since window could be polyfilled
+ replacements.scriptUrl = self.location.href;
+ }
+ // when ENVIRONMENT_IS_ESM we have scriptUrl from import.meta.url from dotnet.es6.lib.js
+ if (!ENVIRONMENT_IS_ESM) {
+ if (ENVIRONMENT_IS_WEB) {
+ if (
+ (typeof (globalThis.document) === "object") &&
+ (typeof (globalThis.document.createElement) === "function")
+ ) {
+ // blazor injects a module preload link element for dotnet.[version].[sha].js
+ const blazorDotNetJS = Array.from(document.head.getElementsByTagName("link")).filter(elt => elt.rel !== undefined && elt.rel == "modulepreload" && elt.href !== undefined && elt.href.indexOf("dotnet") != -1 && elt.href.indexOf(".js") != -1);
+ if (blazorDotNetJS.length == 1) {
+ replacements.scriptUrl = blazorDotNetJS[0].href;
+ } else {
+ const temp = globalThis.document.createElement("a");
+ temp.href = "dotnet.js";
+ replacements.scriptUrl = temp.href;
+ }
+ }
+ }
+ if (ENVIRONMENT_IS_NODE) {
+ if (typeof __filename !== "undefined") {
+ // unix vs windows
+ replacements.scriptUrl = __filename;
+ }
+ }
+ }
+ if (!replacements.scriptUrl) {
+ // probably V8 shell in non ES6
+ replacements.scriptUrl = "./dotnet.js";
+ }
+ replacements.scriptUrl = normalizeFileUrl(replacements.scriptUrl);
+ return normalizeDirectoryUrl(replacements.scriptUrl);
}
+
+const protocolRx = /^[a-zA-Z][a-zA-Z\d+\-.]*?:\/\//;
+const windowsAbsoluteRx = /[a-zA-Z]:[\\/]/;
+function isPathAbsolute(path: string): boolean {
+ if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {
+ // unix /x.json
+ // windows \x.json
+ // windows C:\x.json
+ // windows C:/x.json
+ return path.startsWith("/") || path.startsWith("\\") || path.indexOf("///") !== -1 || windowsAbsoluteRx.test(path);
+ }
+
+ // anything with protocol is always absolute
+ // windows file:///C:/x.json
+ // windows http://C:/x.json
+ return protocolRx.test(path);
+}
\ No newline at end of file
diff --git a/src/mono/wasm/runtime/run.ts b/src/mono/wasm/runtime/run.ts
index ae7174c3f639d2..c7a2f020373c6f 100644
--- a/src/mono/wasm/runtime/run.ts
+++ b/src/mono/wasm/runtime/run.ts
@@ -1,14 +1,14 @@
-import { ExitStatus, INTERNAL, Module, quit, runtimeHelpers } from "./imports";
+import { INTERNAL, Module, runtimeHelpers } from "./imports";
import { mono_call_assembly_entry_point } from "./method-calls";
import { mono_wasm_wait_for_debugger } from "./debug";
-import { mono_wasm_set_main_args, runtime_is_initialized_reject } from "./startup";
+import { abort_startup, mono_wasm_set_main_args } from "./startup";
export async function mono_run_main_and_exit(main_assembly_name: string, args: string[]): Promise {
try {
const result = await mono_run_main(main_assembly_name, args);
set_exit_code(result);
} catch (error) {
- if (error instanceof ExitStatus) {
+ if (error instanceof runtimeHelpers.ExitStatus) {
return;
}
set_exit_code(1, error);
@@ -18,7 +18,7 @@ export async function mono_run_main_and_exit(main_assembly_name: string, args: s
export async function mono_run_main(main_assembly_name: string, args: string[]): Promise {
mono_wasm_set_main_args(main_assembly_name, args);
if (runtimeHelpers.wait_for_debugger == -1) {
- console.log("waiting for debugger...");
+ console.log("MONO_WASM: waiting for debugger...");
return await mono_wasm_wait_for_debugger().then(() => mono_call_assembly_entry_point(main_assembly_name, [args], "m"));
}
return mono_call_assembly_entry_point(main_assembly_name, [args], "m");
@@ -26,12 +26,13 @@ export async function mono_run_main(main_assembly_name: string, args: string[]):
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function mono_on_abort(error: any): void {
- runtime_is_initialized_reject(error);
+ abort_startup(error, false);
set_exit_code(1, error);
}
-function set_exit_code(exit_code: number, reason?: any) {
- if (reason && !(reason instanceof ExitStatus)) {
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+export function set_exit_code(exit_code: number, reason?: any): void {
+ if (reason && !(reason instanceof runtimeHelpers.ExitStatus)) {
if (reason instanceof Error)
Module.printErr(INTERNAL.mono_wasm_stringify_as_error_with_stack(reason));
else if (typeof reason == "string")
@@ -40,7 +41,7 @@ function set_exit_code(exit_code: number, reason?: any) {
Module.printErr(JSON.stringify(reason));
}
else {
- reason = new ExitStatus(exit_code);
+ reason = new runtimeHelpers.ExitStatus(exit_code);
}
- quit(exit_code, reason);
+ runtimeHelpers.quit(exit_code, reason);
}
diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts
index 6ff13c33114ae0..137c12a87947aa 100644
--- a/src/mono/wasm/runtime/startup.ts
+++ b/src/mono/wasm/runtime/startup.ts
@@ -2,189 +2,351 @@
// The .NET Foundation licenses this file to you under the MIT license.
import MonoWasmThreads from "consts:monoWasmThreads";
-import { AllAssetEntryTypes, mono_assert, AssetEntry, CharPtrNull, DotnetModule, GlobalizationMode, MonoConfig, MonoConfigError, wasm_type_symbol, MonoObject } from "./types";
-import { ENVIRONMENT_IS_ESM, ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_PTHREAD, ENVIRONMENT_IS_SHELL, INTERNAL, locateFile, Module, MONO, requirePromise, runtimeHelpers } from "./imports";
+import { mono_assert, CharPtrNull, DotnetModule, MonoConfig, wasm_type_symbol, MonoObject, MonoConfigError, LoadingResource, AssetEntry, ResourceRequest } from "./types";
+import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_PTHREAD, ENVIRONMENT_IS_SHELL, INTERNAL, Module, MONO, runtimeHelpers } from "./imports";
import cwraps from "./cwraps";
import { mono_wasm_raise_debug_event, mono_wasm_runtime_ready } from "./debug";
-import GuardedPromise from "./guarded-promise";
import { mono_wasm_globalization_init, mono_wasm_load_icu_data } from "./icu";
import { toBase64StringImpl } from "./base64";
import { mono_wasm_init_aot_profiler, mono_wasm_init_coverage_profiler } from "./profiler";
-import { mono_wasm_init_diagnostics, } from "./diagnostics";
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";
import { DotnetPublicAPI } from "./exports";
-import { mono_on_abort } from "./run";
+import { mono_on_abort, set_exit_code } from "./run";
import { initialize_marshalers_to_cs } from "./marshal-to-cs";
import { initialize_marshalers_to_js } from "./marshal-to-js";
import { mono_wasm_new_root } from "./roots";
import { init_crypto } from "./crypto-worker";
-import { init_polyfills } from "./polyfills";
+import { init_polyfills_async } from "./polyfills";
import * as pthreads_worker from "./pthreads/worker";
-
-export let runtime_is_initialized_resolve: () => void;
-export let runtime_is_initialized_reject: (reason?: any) => void;
-export const mono_wasm_runtime_is_initialized = new GuardedPromise((resolve, reject) => {
- runtime_is_initialized_resolve = resolve;
- runtime_is_initialized_reject = reject;
-});
-
-let ctx: DownloadAssetsContext | null = null;
-
+import { createPromiseController } from "./promise-controller";
+import { string_decoder } from "./strings";
+import { mono_wasm_init_diagnostics } from "./diagnostics/index";
+
+let all_assets_loaded_in_memory: Promise | null = null;
+const loaded_files: { url?: string, file: string }[] = [];
+const loaded_assets: { [id: string]: [VoidPtr, number] } = Object.create(null);
+let instantiated_assets_count = 0;
+let downloded_assets_count = 0;
+const max_parallel_downloads = 100;
+// in order to prevent net::ERR_INSUFFICIENT_RESOURCES if we start downloading too many files at same time
+let parallel_count = 0;
+let throttling_promise: Promise | undefined = undefined;
+let throttling_promise_resolve: Function | undefined = undefined;
+let config: MonoConfig = undefined as any;
+
+const afterInstantiateWasm = createPromiseController();
+const beforePreInit = createPromiseController();
+const afterPreInit = createPromiseController();
+const afterPreRun = createPromiseController();
+const beforeOnRuntimeInitialized = createPromiseController();
+const afterOnRuntimeInitialized = createPromiseController();
+const afterPostRun = createPromiseController();
+
+// we are making emscripten startup async friendly
+// emscripten is executing the events without awaiting it and so we need to block progress via PromiseControllers above
export function configure_emscripten_startup(module: DotnetModule, exportedAPI: DotnetPublicAPI): void {
- // HACK: Emscripten expects us to provide it a fully qualified path where it can find
- // our main script so that it can be loaded from inside of workers, because workers
- // have their paths relative to the root instead of relative to our location
- // In the browser we can create a hyperlink and set its href to a relative URL,
- // and the browser will convert it into an absolute one for us
- if (
- (typeof (globalThis.document) === "object") &&
- (typeof (globalThis.document.createElement) === "function")
- ) {
- // blazor injects a module preload link element for dotnet.[version].[sha].js
- const blazorDotNetJS = Array.from(document.head.getElementsByTagName("link")).filter(elt => elt.rel !== undefined && elt.rel == "modulepreload" && elt.href !== undefined && elt.href.indexOf("dotnet") != -1 && elt.href.indexOf(".js") != -1);
- if (blazorDotNetJS.length == 1) {
- const hr = blazorDotNetJS[0].href;
- console.log("determined url of main script to be " + hr);
- (module)["mainScriptUrlOrBlob"] = hr;
- } else {
- const temp = globalThis.document.createElement("a");
- temp.href = "dotnet.js";
- console.log("determined url of main script to be " + temp.href);
- (module)["mainScriptUrlOrBlob"] = temp.href;
- }
+ // these all could be overridden on DotnetModuleConfig, we are chaing them to async below, as opposed to emscripten
+ // when user set configSrc or config, we are running our default startup sequence.
+ const userInstantiateWasm: undefined | ((imports: WebAssembly.Imports, successCallback: (instance: WebAssembly.Instance, module: WebAssembly.Module) => void) => any) = module.instantiateWasm;
+ const userPreInit: (() => void)[] = !module.preInit ? [] : typeof module.preInit === "function" ? [module.preInit] : module.preInit;
+ const userPreRun: (() => void)[] = !module.preRun ? [] : typeof module.preRun === "function" ? [module.preRun] : module.preRun as any;
+ const userpostRun: (() => void)[] = !module.postRun ? [] : typeof module.postRun === "function" ? [module.postRun] : module.postRun as any;
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
+ const userOnRuntimeInitialized: () => void = module.onRuntimeInitialized ? module.onRuntimeInitialized : () => { };
+ const isCustomStartup = !module.configSrc && !module.config; // like blazor
+
+ // execution order == [0] ==
+ // - default or user Module.instantiateWasm (will start downloading dotnet.wasm)
+ module.instantiateWasm = (imports, callback) => instantiateWasm(imports, callback, userInstantiateWasm);
+ // execution order == [1] ==
+ module.preInit = [() => preInit(isCustomStartup, userPreInit)];
+ // execution order == [2] ==
+ module.preRun = [() => preRunAsync(userPreRun)];
+ // execution order == [4] ==
+ module.onRuntimeInitialized = () => onRuntimeInitializedAsync(isCustomStartup, userOnRuntimeInitialized);
+ // execution order == [5] ==
+ module.postRun = [() => postRunAsync(userpostRun)];
+ // execution order == [6] ==
+ module.ready = module.ready.then(async () => {
+ // wait for previous stage
+ await afterPostRun.promise;
+ // - here we resolve the promise returned by createDotnetRuntime export
+ return exportedAPI;
+ // - any code after createDotnetRuntime is executed now
+ });
+ // execution order == [*] ==
+ if (!module.onAbort) {
+ module.onAbort = () => mono_on_abort;
}
+}
+
+let wasm_module_imports: WebAssembly.Imports | null = null;
+let wasm_success_callback: null | ((instance: WebAssembly.Instance, module: WebAssembly.Module) => void) = null;
+
+function instantiateWasm(
+ imports: WebAssembly.Imports,
+ successCallback: (instance: WebAssembly.Instance, module: WebAssembly.Module) => void,
+ userInstantiateWasm?: (imports: WebAssembly.Imports, successCallback: (instance: WebAssembly.Instance, module: WebAssembly.Module) => void) => any): any[] {
+ // this is called so early that even Module exports like addRunDependency don't exist yet
- // these could be overridden on DotnetModuleConfig
- if (!module.preInit) {
- module.preInit = [];
- } else if (typeof module.preInit === "function") {
- module.preInit = [module.preInit];
+ if (!Module.configSrc && !Module.config && !userInstantiateWasm) {
+ Module.print("MONO_WASM: configSrc nor config was specified");
}
- if (!module.preRun) {
- module.preRun = [];
- } else if (typeof module.preRun === "function") {
- module.preRun = [module.preRun];
+ if (Module.config) {
+ config = runtimeHelpers.config = Module.config as MonoConfig;
+ } else {
+ config = runtimeHelpers.config = Module.config = {} as any;
}
- if (!module.postRun) {
- module.postRun = [];
- } else if (typeof module.postRun === "function") {
- module.postRun = [module.postRun];
+ runtimeHelpers.diagnostic_tracing = !!config.diagnostic_tracing;
+ runtimeHelpers.enable_debugging = config.enable_debugging ? config.enable_debugging : 0;
+ if (!config.assets) {
+ config.assets = [];
}
- // when user set configSrc or config, we are running our default startup sequence.
- if (module.configSrc || module.config) {
- // execution order == [0] ==
- // - default or user Module.instantiateWasm (will start downloading dotnet.wasm)
- // - all user Module.preInit
-
- // execution order == [1] ==
- module.preInit.push(mono_wasm_pre_init);
- // - download Module.config from configSrc
- // - download assets like DLLs
-
- // execution order == [2] ==
- // - all user Module.preRun callbacks
-
- // execution order == [3] ==
- // - user Module.onRuntimeInitialized callback
-
- // execution order == [4] ==
- module.postRun.unshift(mono_wasm_after_runtime_initialized);
- // - load DLLs into WASM memory
- // - apply globalization and other env variables
- // - call mono_wasm_load_runtime
-
- // execution order == [5] ==
- // - all user Module.postRun callbacks
-
- // execution order == [6] ==
- module.ready = module.ready.then(async () => {
- // mono_wasm_runtime_is_initialized promise is resolved when finalize_startup is done
- await mono_wasm_runtime_is_initialized;
- // - here we resolve the promise returned by createDotnetRuntime export
- return exportedAPI;
- // - any code after createDotnetRuntime is executed now
+ if (userInstantiateWasm) {
+ const exports = userInstantiateWasm(imports, (instance: WebAssembly.Instance, module: WebAssembly.Module) => {
+ afterInstantiateWasm.promise_control.resolve(null);
+ successCallback(instance, module);
});
-
- }
- // Otherwise startup sequence is up to user code, like Blazor
-
- if (MonoWasmThreads && ENVIRONMENT_IS_PTHREAD) {
- mono_wasm_pthread_worker_init();
+ return exports;
}
- if (!module.onAbort) {
- module.onAbort = () => mono_on_abort;
- }
+ wasm_module_imports = imports;
+ wasm_success_callback = successCallback;
+ _instantiate_wasm_module();
+ return []; // No exports
}
-async function mono_wasm_pre_init(): Promise {
- const moduleExt = Module as DotnetModule;
-
- Module.addRunDependency("mono_wasm_pre_init");
-
- // wait for locateFile setup on NodeJs
- if (ENVIRONMENT_IS_NODE && ENVIRONMENT_IS_ESM) {
- INTERNAL.require = await requirePromise;
+function preInit(isCustomStartup: boolean, userPreInit: (() => void)[]) {
+ Module.addRunDependency("mono_pre_init");
+ try {
+ mono_wasm_pre_init_essential();
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: preInit");
+ beforePreInit.promise_control.resolve(null);
+ // all user Module.preInit callbacks
+ userPreInit.forEach(fn => fn());
+ } catch (err) {
+ _print_error("MONO_WASM: user preInint() failed", err);
+ abort_startup(err, true);
+ throw err;
}
-
- init_polyfills();
- init_crypto();
-
- if (moduleExt.configSrc) {
+ // this will start immediately but return on first await.
+ // It will block our `preRun` by afterPreInit promise
+ // It will block emscripten `userOnRuntimeInitialized` by pending addRunDependency("mono_pre_init")
+ (async () => {
try {
- // sets MONO.config implicitly
- await mono_wasm_load_config(moduleExt.configSrc);
- }
- catch (err: any) {
- runtime_is_initialized_reject(err);
+ await mono_wasm_pre_init_essential_async();
+ if (!isCustomStartup) {
+ // - download Module.config from configSrc
+ // - start download assets like DLLs
+ await mono_wasm_pre_init_full();
+ }
+ } catch (err) {
+ abort_startup(err, true);
throw err;
}
+ // signal next stage
+ afterPreInit.promise_control.resolve(null);
+ Module.removeRunDependency("mono_pre_init");
+ })();
+}
- if (moduleExt.onConfigLoaded) {
- try {
- await moduleExt.onConfigLoaded(runtimeHelpers.config);
- }
- catch (err: any) {
- _print_error("MONO_WASM: onConfigLoaded () failed", err);
- runtime_is_initialized_reject(err);
- throw err;
- }
- }
+async function preRunAsync(userPreRun: (() => void)[]) {
+ Module.addRunDependency("mono_pre_run_async");
+ // wait for previous stages
+ await afterInstantiateWasm.promise;
+ await afterPreInit.promise;
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: preRunAsync");
+ try {
+ // all user Module.preRun callbacks
+ userPreRun.map(fn => fn());
+ } catch (err) {
+ _print_error("MONO_WASM: user callback preRun() failed", err);
+ abort_startup(err, true);
+ throw err;
}
+ // signal next stage
+ afterPreRun.promise_control.resolve(null);
+ Module.removeRunDependency("mono_pre_run_async");
+}
- if (moduleExt.config) {
+async function onRuntimeInitializedAsync(isCustomStartup: boolean, userOnRuntimeInitialized: () => void) {
+ // wait for previous stage
+ await afterPreRun.promise;
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: onRuntimeInitialized");
+ // signal this stage, this will allow pending assets to allocate memory
+ beforeOnRuntimeInitialized.promise_control.resolve(null);
+ try {
+ if (!isCustomStartup) {
+ // wait for all assets in memory
+ await all_assets_loaded_in_memory;
+ const expected_asset_count = config.assets ? config.assets.length : 0;
+ mono_assert(downloded_assets_count == expected_asset_count, "Expected assets to be downloaded");
+ mono_assert(instantiated_assets_count == expected_asset_count, "Expected assets to be in memory");
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: all assets are loaded in wasm memory");
+
+ // load runtime
+ await mono_wasm_before_user_runtime_initialized();
+ }
+ // call user code
try {
- // start downloading assets asynchronously
- // next event of emscripten would bre triggered by last `removeRunDependency`
- await mono_download_assets(Module.config);
+ userOnRuntimeInitialized();
}
catch (err: any) {
- runtime_is_initialized_reject(err);
+ _print_error("MONO_WASM: user callback onRuntimeInitialized() failed", err);
throw err;
}
+ // finish
+ await mono_wasm_after_user_runtime_initialized();
+ } catch (err) {
+ _print_error("MONO_WASM: onRuntimeInitializedAsync() failed", err);
+ abort_startup(err, true);
+ throw err;
}
- if (!moduleExt.configSrc && !moduleExt.config) {
- Module.print("MONO_WASM: configSrc nor config was specified");
+ // signal next stage
+ afterOnRuntimeInitialized.promise_control.resolve(null);
+}
+
+async function postRunAsync(userpostRun: (() => void)[]) {
+ // wait for previous stage
+ await afterOnRuntimeInitialized.promise;
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: postRunAsync");
+ try {
+ // all user Module.postRun callbacks
+ userpostRun.map(fn => fn());
+ } catch (err) {
+ _print_error("MONO_WASM: user callback posRun() failed", err);
+ abort_startup(err, true);
+ throw err;
+ }
+ // signal next stage
+ afterPostRun.promise_control.resolve(null);
+}
+
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+export function abort_startup(reason: any, should_exit: boolean): void {
+ if (runtimeHelpers.diagnostic_tracing) console.trace("MONO_WASM: abort_startup");
+ afterInstantiateWasm.promise_control.reject(reason);
+ beforePreInit.promise_control.reject(reason);
+ afterPreInit.promise_control.reject(reason);
+ afterPreRun.promise_control.reject(reason);
+ beforeOnRuntimeInitialized.promise_control.reject(reason);
+ afterOnRuntimeInitialized.promise_control.reject(reason);
+ afterPostRun.promise_control.reject(reason);
+ if (should_exit) {
+ set_exit_code(1, reason);
}
+}
+
+// runs in both blazor and non-blazor
+function mono_wasm_pre_init_essential(): void {
+ Module.addRunDependency("mono_wasm_pre_init_essential");
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: mono_wasm_pre_init_essential");
+
+ // init_polyfills() is already called from export.ts
+ init_crypto();
- Module.removeRunDependency("mono_wasm_pre_init");
+ Module.removeRunDependency("mono_wasm_pre_init_essential");
}
-async function mono_wasm_after_runtime_initialized(): Promise {
+// runs in both blazor and non-blazor
+async function mono_wasm_pre_init_essential_async(): Promise {
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: mono_wasm_pre_init_essential_async");
+ Module.addRunDependency("mono_wasm_pre_init_essential_async");
+
+ await init_polyfills_async();
+ if (MonoWasmThreads && ENVIRONMENT_IS_PTHREAD) {
+ await mono_wasm_pthread_worker_init();
+ }
+
+ Module.removeRunDependency("mono_wasm_pre_init_essential_async");
+}
+
+// runs just in non-blazor
+async function mono_wasm_pre_init_full(): Promise {
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: mono_wasm_pre_init_full");
+ Module.addRunDependency("mono_wasm_pre_init_full");
+
+ if (Module.configSrc) {
+ await mono_wasm_load_config(Module.configSrc);
+ }
+ await mono_download_assets();
+
+ Module.removeRunDependency("mono_wasm_pre_init_full");
+}
+
+// runs just in non-blazor
+async function mono_wasm_before_user_runtime_initialized(): Promise {
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: mono_wasm_before_user_runtime_initialized");
+
if (!Module.config || Module.config.isError) {
return;
}
- finalize_assets(Module.config);
- await finalize_startup(Module.config);
- if (!ctx || !ctx.loaded_files || ctx.loaded_files.length == 0) {
- Module.print("MONO_WASM: no files were loaded into runtime");
+
+ try {
+ loaded_files.forEach(value => MONO.loaded_files.push(value.url));
+ if (!loaded_files || loaded_files.length == 0) {
+ Module.print("MONO_WASM: no files were loaded into runtime");
+ }
+
+ await _apply_configuration_from_args();
+ mono_wasm_globalization_init();
+
+ if (!runtimeHelpers.mono_wasm_load_runtime_done) mono_wasm_load_runtime("unused", config.debug_level || 0);
+ if (!runtimeHelpers.mono_wasm_runtime_is_ready) mono_wasm_runtime_ready();
+ setTimeout(() => {
+ // when there are free CPU cycles
+ string_decoder.init_fields();
+ });
+ } catch (err: any) {
+ _print_error("MONO_WASM: Error in mono_wasm_before_user_runtime_initialized", err);
+ throw err;
}
}
+// runs in both blazor and non-blazor
+async function mono_wasm_after_user_runtime_initialized(): Promise {
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: mono_wasm_after_user_runtime_initialized");
+ try {
+ if (!Module.disableDotnet6Compatibility && Module.exports) {
+ // Export emscripten defined in module through EXPORTED_RUNTIME_METHODS
+ // Useful to export IDBFS or other similar types generally exposed as
+ // global types when emscripten is not modularized.
+ const globalThisAny = globalThis as any;
+ for (let i = 0; i < Module.exports.length; ++i) {
+ const exportName = Module.exports[i];
+ const exportValue = (Module)[exportName];
+
+ if (exportValue != undefined) {
+ globalThisAny[exportName] = exportValue;
+ }
+ else {
+ console.warn(`MONO_WASM: The exported symbol ${exportName} could not be found in the emscripten module`);
+ }
+ }
+ }
+
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: Initializing mono runtime");
+
+ if (Module.onDotnetReady) {
+ try {
+ await Module.onDotnetReady();
+ }
+ catch (err: any) {
+ _print_error("MONO_WASM: onDotnetReady () failed", err);
+ throw err;
+ }
+ }
+ } catch (err: any) {
+ _print_error("MONO_WASM: Error in mono_wasm_after_user_runtime_initialized", err);
+ throw err;
+ }
+}
+
+
function _print_error(message: string, err: any): void {
Module.printErr(`${message}: ${JSON.stringify(err)}`);
if (err.stack) {
@@ -215,14 +377,65 @@ export function mono_wasm_set_runtime_options(options: string[]): void {
cwraps.mono_wasm_parse_runtime_options(options.length, argv);
}
-// this need to be run only after onRuntimeInitialized event, when the memory is ready
-function _handle_fetched_asset(asset: AssetEntry, url?: string) {
- mono_assert(ctx, "Context is expected");
- mono_assert(asset.buffer, "asset.buffer is expected");
- const bytes = new Uint8Array(asset.buffer);
- if (ctx.tracing)
- console.trace(`MONO_WASM: Loaded:${asset.name} as ${asset.behavior} size ${bytes.length} from ${url}`);
+async function _instantiate_wasm_module(): Promise {
+ // this is called so early that even Module exports like addRunDependency don't exist yet
+ try {
+ if (!config.assets && Module.configSrc) {
+ // when we are starting with mono-config,json, it could have dotnet.wasm location in it, we have to wait for it
+ await mono_wasm_load_config(Module.configSrc);
+ }
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: instantiateWasm");
+ let assetToLoad: AssetEntry = {
+ name: "dotnet.wasm",
+ behavior: "dotnetwasm"
+ };
+ const assetfromConfig = config.assets!.find(a => a.behavior === "dotnetwasm");
+ if (assetfromConfig) {
+ assetToLoad = assetfromConfig;
+ } else {
+ config.assets!.push(assetToLoad);
+ }
+
+ const pendingAsset = await start_asset_download(assetToLoad);
+ await beforePreInit.promise;
+ Module.addRunDependency("_instantiate_wasm_module");
+ mono_assert(pendingAsset && pendingAsset.pending, () => `Can't load ${assetToLoad.name}`);
+
+ const response = await pendingAsset.pending.response;
+ const contentType = response.headers ? response.headers.get("Content-Type") : undefined;
+ let compiledInstance: WebAssembly.Instance;
+ let compiledModule: WebAssembly.Module;
+ if (typeof WebAssembly.instantiateStreaming === "function" && contentType === "application/wasm") {
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: mono_wasm_after_user_runtime_initialized streaming");
+ const streamingResult = await WebAssembly.instantiateStreaming(response, wasm_module_imports!);
+ compiledInstance = streamingResult.instance;
+ compiledModule = streamingResult.module;
+ } else {
+ const arrayBuffer = await response.arrayBuffer();
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: mono_wasm_after_user_runtime_initialized streaming");
+ const arrayBufferResult = await WebAssembly.instantiate(arrayBuffer, wasm_module_imports!);
+ compiledInstance = arrayBufferResult.instance;
+ compiledModule = arrayBufferResult.module;
+ }
+ ++instantiated_assets_count;
+ wasm_success_callback!(compiledInstance, compiledModule);
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: instantiateWasm done");
+ afterInstantiateWasm.promise_control.resolve(null);
+ wasm_success_callback = null;
+ wasm_module_imports = null;
+ } catch (err) {
+ _print_error("MONO_WASM: _instantiate_wasm_module() failed", err);
+ abort_startup(err, true);
+ throw err;
+ }
+ Module.removeRunDependency("_instantiate_wasm_module");
+}
+
+// this need to be run only after onRuntimeInitialized event, when the memory is ready
+function _instantiate_asset(asset: AssetEntry, url: string, bytes: Uint8Array) {
+ if (runtimeHelpers.diagnostic_tracing)
+ console.debug(`MONO_WASM: Loaded:${asset.name} as ${asset.behavior} size ${bytes.length} from ${url}`);
const virtualName: string = typeof (asset.virtual_path) === "string"
? asset.virtual_path
@@ -232,12 +445,13 @@ function _handle_fetched_asset(asset: AssetEntry, url?: string) {
switch (asset.behavior) {
case "resource":
case "assembly":
- ctx.loaded_files.push({ url: url, file: virtualName });
+ case "pdb":
+ loaded_files.push({ url: url, file: virtualName });
// falls through
case "heap":
case "icu":
offset = mono_wasm_load_bytes_into_heap(bytes);
- ctx.loaded_assets[virtualName] = [offset, bytes.length];
+ loaded_assets[virtualName] = [offset, bytes.length];
break;
case "vfs": {
@@ -252,8 +466,8 @@ function _handle_fetched_asset(asset: AssetEntry, url?: string) {
if (fileName.startsWith("/"))
fileName = fileName.substr(1);
if (parentDirectory) {
- if (ctx.tracing)
- console.trace(`MONO_WASM: Creating directory '${parentDirectory}'`);
+ if (runtimeHelpers.diagnostic_tracing)
+ console.debug(`MONO_WASM: Creating directory '${parentDirectory}'`);
Module.FS_createPath(
"/", parentDirectory, true, true // fixme: should canWrite be false?
@@ -262,8 +476,8 @@ function _handle_fetched_asset(asset: AssetEntry, url?: string) {
parentDirectory = "/";
}
- if (ctx.tracing)
- console.trace(`MONO_WASM: Creating file '${fileName}' in directory '${parentDirectory}'`);
+ if (runtimeHelpers.diagnostic_tracing)
+ console.debug(`MONO_WASM: Creating file '${fileName}' in directory '${parentDirectory}'`);
if (!mono_wasm_load_data_archive(bytes, parentDirectory)) {
Module.FS_createDataFile(
@@ -281,8 +495,8 @@ function _handle_fetched_asset(asset: AssetEntry, url?: string) {
const hasPpdb = cwraps.mono_wasm_add_assembly(virtualName, offset!, bytes.length);
if (!hasPpdb) {
- const index = ctx.loaded_files.findIndex(element => element.file == virtualName);
- ctx.loaded_files.splice(index, 1);
+ const index = loaded_files.findIndex(element => element.file == virtualName);
+ loaded_files.splice(index, 1);
}
}
else if (asset.behavior === "icu") {
@@ -292,15 +506,20 @@ function _handle_fetched_asset(asset: AssetEntry, url?: string) {
else if (asset.behavior === "resource") {
cwraps.mono_wasm_add_satellite_assembly(virtualName, asset.culture!, offset!, bytes.length);
}
+ ++instantiated_assets_count;
}
-async function _apply_configuration_from_args(config: MonoConfig): Promise {
- const envars = (config.environment_variables || {});
- if (typeof (envars) !== "object")
- throw new Error("Expected config.environment_variables to be unset or a dictionary-style object");
+// runs just in non-blazor
+async function _apply_configuration_from_args() {
+ try {
+ const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
+ mono_wasm_setenv("TZ", tz || "UTC");
+ } catch {
+ mono_wasm_setenv("TZ", "UTC");
+ }
- for (const k in envars) {
- const v = envars![k];
+ for (const k in config.environment_variables) {
+ const v = config.environment_variables![k];
if (typeof (v) === "string")
mono_wasm_setenv(k, v);
else
@@ -321,330 +540,274 @@ async function _apply_configuration_from_args(config: MonoConfig): Promise
}
}
-async function finalize_startup(config: MonoConfig | MonoConfigError | undefined): Promise {
- const globalThisAny = globalThis as any;
-
+export function mono_wasm_load_runtime(unused?: string, debug_level?: number): void {
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: mono_wasm_load_runtime");
+ if (runtimeHelpers.mono_wasm_load_runtime_done) {
+ return;
+ }
+ runtimeHelpers.mono_wasm_load_runtime_done = true;
try {
- if (!config || config.isError) {
- return;
- }
- if (config.diagnostic_tracing) {
- console.debug("MONO_WASM: Initializing mono runtime");
- }
-
- const moduleExt = Module as DotnetModule;
-
- if (!Module.disableDotnet6Compatibility && Module.exports) {
- // Export emscripten defined in module through EXPORTED_RUNTIME_METHODS
- // Useful to export IDBFS or other similar types generally exposed as
- // global types when emscripten is not modularized.
- for (let i = 0; i < Module.exports.length; ++i) {
- const exportName = Module.exports[i];
- const exportValue = (Module)[exportName];
-
- if (exportValue) {
- globalThisAny[exportName] = exportValue;
- }
- else {
- console.warn(`MONO_WASM: The exported symbol ${exportName} could not be found in the emscripten module`);
- }
- }
- }
-
- try {
- await _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);
- runtimeHelpers.wait_for_debugger = config.wait_for_debugger;
- } catch (err: any) {
- _print_error("MONO_WASM: mono_wasm_load_runtime () failed", err);
-
- runtime_is_initialized_reject(err);
- if (ENVIRONMENT_IS_SHELL || ENVIRONMENT_IS_NODE) {
- const wasm_exit = cwraps.mono_wasm_exit;
- wasm_exit(1);
+ if (debug_level == undefined) {
+ debug_level = 0;
+ if (config && config.debug_level) {
+ debug_level = 0 + debug_level;
}
- return;
- }
-
- bindings_lazy_init();
-
- let tz;
- try {
- tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
- } catch {
- //swallow
}
- mono_wasm_setenv("TZ", tz || "UTC");
- mono_wasm_runtime_ready();
+ cwraps.mono_wasm_load_runtime(unused || "unused", debug_level);
+ runtimeHelpers.wait_for_debugger = config.wait_for_debugger;
- //legacy config loading
- const argsAny: any = config;
- if (argsAny.loaded_cb) {
- try {
- argsAny.loaded_cb();
- }
- catch (err: any) {
- _print_error("MONO_WASM: loaded_cb () failed", err);
- runtime_is_initialized_reject(err);
- throw err;
- }
- }
+ if (!runtimeHelpers.mono_wasm_bindings_is_ready) bindings_init();
+ } catch (err: any) {
+ _print_error("MONO_WASM: mono_wasm_load_runtime () failed", err);
- if (moduleExt.onDotnetReady) {
- try {
- moduleExt.onDotnetReady();
- }
- catch (err: any) {
- _print_error("MONO_WASM: onDotnetReady () failed", err);
- runtime_is_initialized_reject(err);
- throw err;
- }
+ abort_startup(err, false);
+ if (ENVIRONMENT_IS_SHELL || ENVIRONMENT_IS_NODE) {
+ const wasm_exit = cwraps.mono_wasm_exit;
+ wasm_exit(1);
}
-
- runtime_is_initialized_resolve();
- } catch (err: any) {
- _print_error("MONO_WASM: Error in finalize_startup", err);
- runtime_is_initialized_reject(err);
throw err;
}
}
-export function bindings_lazy_init(): void {
- if (runtimeHelpers.mono_wasm_bindings_is_ready)
+export function bindings_init(): void {
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: bindings_init");
+ if (runtimeHelpers.mono_wasm_bindings_is_ready) {
return;
+ }
runtimeHelpers.mono_wasm_bindings_is_ready = true;
+ try {
- // please keep System.Runtime.InteropServices.JavaScript.JSHostImplementation.MappedType in sync
- (Object.prototype)[wasm_type_symbol] = 0;
- (Array.prototype)[wasm_type_symbol] = 1;
- (ArrayBuffer.prototype)[wasm_type_symbol] = 2;
- (DataView.prototype)[wasm_type_symbol] = 3;
- (Function.prototype)[wasm_type_symbol] = 4;
- (Uint8Array.prototype)[wasm_type_symbol] = 11;
-
- runtimeHelpers._box_buffer_size = 65536;
- runtimeHelpers._unbox_buffer_size = 65536;
- runtimeHelpers._box_buffer = Module._malloc(runtimeHelpers._box_buffer_size);
- runtimeHelpers._unbox_buffer = Module._malloc(runtimeHelpers._unbox_buffer_size);
- runtimeHelpers._i52_error_scratch_buffer = Module._malloc(4);
- runtimeHelpers._class_int32 = find_corlib_class("System", "Int32");
- runtimeHelpers._class_uint32 = find_corlib_class("System", "UInt32");
- runtimeHelpers._class_double = find_corlib_class("System", "Double");
- runtimeHelpers._class_boolean = find_corlib_class("System", "Boolean");
- runtimeHelpers.bind_runtime_method = bind_runtime_method;
-
- const bindingAssembly = INTERNAL.BINDING_ASM;
- const binding_fqn_asm = bindingAssembly.substring(bindingAssembly.indexOf("[") + 1, bindingAssembly.indexOf("]")).trim();
- const binding_fqn_class = bindingAssembly.substring(bindingAssembly.indexOf("]") + 1).trim();
-
- const binding_module = cwraps.mono_wasm_assembly_load(binding_fqn_asm);
- if (!binding_module)
- throw "Can't find bindings module assembly: " + binding_fqn_asm;
-
- if (binding_fqn_class && binding_fqn_class.length) {
- runtimeHelpers.runtime_interop_exports_classname = binding_fqn_class;
- if (binding_fqn_class.indexOf(".") != -1) {
- const idx = binding_fqn_class.lastIndexOf(".");
- runtimeHelpers.runtime_interop_namespace = binding_fqn_class.substring(0, idx);
- runtimeHelpers.runtime_interop_exports_classname = binding_fqn_class.substring(idx + 1);
+ // please keep System.Runtime.InteropServices.JavaScript.JSHostImplementation.MappedType in sync
+ (Object.prototype)[wasm_type_symbol] = 0;
+ (Array.prototype)[wasm_type_symbol] = 1;
+ (ArrayBuffer.prototype)[wasm_type_symbol] = 2;
+ (DataView.prototype)[wasm_type_symbol] = 3;
+ (Function.prototype)[wasm_type_symbol] = 4;
+ (Uint8Array.prototype)[wasm_type_symbol] = 11;
+
+ runtimeHelpers._box_buffer_size = 65536;
+ runtimeHelpers._unbox_buffer_size = 65536;
+ runtimeHelpers._box_buffer = Module._malloc(runtimeHelpers._box_buffer_size);
+ runtimeHelpers._unbox_buffer = Module._malloc(runtimeHelpers._unbox_buffer_size);
+ runtimeHelpers._i52_error_scratch_buffer = Module._malloc(4);
+ runtimeHelpers._class_int32 = find_corlib_class("System", "Int32");
+ runtimeHelpers._class_uint32 = find_corlib_class("System", "UInt32");
+ runtimeHelpers._class_double = find_corlib_class("System", "Double");
+ runtimeHelpers._class_boolean = find_corlib_class("System", "Boolean");
+ runtimeHelpers.bind_runtime_method = bind_runtime_method;
+
+ const bindingAssembly = INTERNAL.BINDING_ASM;
+ const binding_fqn_asm = bindingAssembly.substring(bindingAssembly.indexOf("[") + 1, bindingAssembly.indexOf("]")).trim();
+ const binding_fqn_class = bindingAssembly.substring(bindingAssembly.indexOf("]") + 1).trim();
+
+ const binding_module = cwraps.mono_wasm_assembly_load(binding_fqn_asm);
+ if (!binding_module)
+ throw "Can't find bindings module assembly: " + binding_fqn_asm;
+
+ if (binding_fqn_class && binding_fqn_class.length) {
+ runtimeHelpers.runtime_interop_exports_classname = binding_fqn_class;
+ if (binding_fqn_class.indexOf(".") != -1) {
+ const idx = binding_fqn_class.lastIndexOf(".");
+ runtimeHelpers.runtime_interop_namespace = binding_fqn_class.substring(0, idx);
+ runtimeHelpers.runtime_interop_exports_classname = binding_fqn_class.substring(idx + 1);
+ }
}
- }
- runtimeHelpers.runtime_interop_exports_class = cwraps.mono_wasm_assembly_find_class(binding_module, runtimeHelpers.runtime_interop_namespace, runtimeHelpers.runtime_interop_exports_classname);
- if (!runtimeHelpers.runtime_interop_exports_class)
- throw "Can't find " + binding_fqn_class + " class";
+ runtimeHelpers.runtime_interop_exports_class = cwraps.mono_wasm_assembly_find_class(binding_module, runtimeHelpers.runtime_interop_namespace, runtimeHelpers.runtime_interop_exports_classname);
+ if (!runtimeHelpers.runtime_interop_exports_class)
+ throw "Can't find " + binding_fqn_class + " class";
- runtimeHelpers.get_call_sig_ref = get_method("GetCallSignatureRef");
- if (!runtimeHelpers.get_call_sig_ref)
- throw "Can't find GetCallSignatureRef method";
+ runtimeHelpers.get_call_sig_ref = get_method("GetCallSignatureRef");
+ if (!runtimeHelpers.get_call_sig_ref)
+ throw "Can't find GetCallSignatureRef method";
- runtimeHelpers.complete_task_method = get_method("CompleteTask");
- if (!runtimeHelpers.complete_task_method)
- throw "Can't find CompleteTask method";
+ runtimeHelpers.complete_task_method = get_method("CompleteTask");
+ if (!runtimeHelpers.complete_task_method)
+ throw "Can't find CompleteTask method";
- runtimeHelpers.create_task_method = get_method("CreateTaskCallback");
- if (!runtimeHelpers.create_task_method)
- throw "Can't find CreateTaskCallback method";
+ runtimeHelpers.create_task_method = get_method("CreateTaskCallback");
+ if (!runtimeHelpers.create_task_method)
+ throw "Can't find CreateTaskCallback method";
- runtimeHelpers.call_delegate = get_method("CallDelegate");
- if (!runtimeHelpers.call_delegate)
- throw "Can't find CallDelegate method";
+ runtimeHelpers.call_delegate = get_method("CallDelegate");
+ if (!runtimeHelpers.call_delegate)
+ throw "Can't find CallDelegate method";
- initialize_marshalers_to_js();
- initialize_marshalers_to_cs();
+ initialize_marshalers_to_js();
+ initialize_marshalers_to_cs();
- _create_primitive_converters();
-
- runtimeHelpers._box_root = mono_wasm_new_root();
- runtimeHelpers._null_root = mono_wasm_new_root();
-}
+ _create_primitive_converters();
-// Initializes the runtime and loads assemblies, debug information, and other files.
-export async function mono_load_runtime_and_bcl_args(config: MonoConfig | MonoConfigError | undefined): Promise {
- await mono_download_assets(config);
- finalize_assets(config);
+ runtimeHelpers._box_root = mono_wasm_new_root();
+ runtimeHelpers._null_root = mono_wasm_new_root();
+ } catch (err) {
+ _print_error("MONO_WASM: Error in bindings_init", err);
+ throw err;
+ }
}
-async function mono_download_assets(config: MonoConfig | MonoConfigError | undefined): Promise {
- if (!config || config.isError) {
- return;
+function downloadResource(request: ResourceRequest): LoadingResource {
+ if (typeof Module.downloadResource === "function") {
+ return Module.downloadResource(request);
}
+ const options: any = {};
+ if (request.hash) {
+ options.integrity = request.hash;
+ }
+ const response = runtimeHelpers.fetch_like(request.resolvedUrl!, options);
+ return {
+ name: request.name, url: request.resolvedUrl!, response
+ };
+}
- try {
- if (config.enable_debugging)
- config.debug_level = config.enable_debugging;
-
-
- config.diagnostic_tracing = config.diagnostic_tracing || false;
- ctx = {
- tracing: config.diagnostic_tracing,
- pending_count: config.assets.length,
- downloading_count: config.assets.length,
- fetch_all_promises: null,
- resolved_promises: [],
- loaded_assets: Object.create(null),
- // dlls and pdbs, used by blazor and the debugger
- loaded_files: [],
+async function start_asset_download(asset: AssetEntry): Promise {
+ // we don't addRunDependency to allow download in parallel with onRuntimeInitialized event!
+ if (asset.buffer) {
+ ++downloded_assets_count;
+ const buffer = asset.buffer;
+ asset.buffer = undefined;//GC later
+ asset.pending = {
+ url: "undefined://" + asset.name,
+ name: asset.name,
+ response: Promise.resolve({
+ arrayBuffer: () => buffer,
+ headers: {
+ get: () => undefined,
+ }
+ }) as any
};
+ return Promise.resolve(asset);
+ }
+ if (asset.pending) {
+ ++downloded_assets_count;
+ return asset;
+ }
- // 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;
- }
-
- const max_parallel_downloads = 100;
- // in order to prevent net::ERR_INSUFFICIENT_RESOURCES if we start downloading too many files at same time
- let parallel_count = 0;
- let throttling_promise: Promise | undefined = undefined;
- let throttling_promise_resolve: Function | undefined = undefined;
-
- const load_asset = async (config: MonoConfig, asset: AllAssetEntryTypes): Promise => {
- while (throttling_promise) {
- await throttling_promise;
- }
- ++parallel_count;
- if (parallel_count == max_parallel_downloads) {
- if (ctx!.tracing)
- console.trace("MONO_WASM: Throttling further parallel downloads");
-
- throttling_promise = new Promise((resolve) => {
- throttling_promise_resolve = resolve;
- });
- }
-
- const moduleDependencyId = asset.name + (asset.culture || "");
- Module.addRunDependency(moduleDependencyId);
-
- const sourcesList = asset.load_remote ? config.remote_sources! : [""];
- let error = undefined;
- let result: MonoInitFetchResult | undefined = undefined;
-
- if (asset.buffer) {
- --ctx!.downloading_count;
- return { asset, attemptUrl: undefined };
- }
+ while (throttling_promise) {
+ await throttling_promise;
+ }
+ ++parallel_count;
+ if (parallel_count == max_parallel_downloads) {
+ if (runtimeHelpers.diagnostic_tracing)
+ console.debug("MONO_WASM: Throttling further parallel downloads");
- for (let sourcePrefix of sourcesList) {
- // HACK: Special-case because MSBuild doesn't allow "" as an attribute
- if (sourcePrefix === "./")
- sourcePrefix = "";
-
- let attemptUrl;
- if (sourcePrefix.trim() === "") {
- if (asset.behavior === "assembly")
- attemptUrl = locateFile(config.assembly_root + "/" + asset.name);
- else if (asset.behavior === "resource") {
- const path = asset.culture !== "" ? `${asset.culture}/${asset.name}` : asset.name;
- attemptUrl = locateFile(config.assembly_root + "/" + path);
- }
- else
- attemptUrl = asset.name;
- } else {
- attemptUrl = sourcePrefix + asset.name;
- }
- if (asset.name === attemptUrl) {
- if (ctx!.tracing)
- console.trace(`MONO_WASM: Attempting to fetch '${attemptUrl}'`);
- } else {
- if (ctx!.tracing)
- console.trace(`MONO_WASM: Attempting to fetch '${attemptUrl}' for ${asset.name}`);
- }
- try {
- 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
- }
-
- asset.buffer = await response.arrayBuffer();
- result = { asset, attemptUrl };
- --ctx!.downloading_count;
- error = undefined;
- }
- catch (err) {
- error = new Error(`MONO_WASM: Fetch '${attemptUrl}' for ${asset.name} failed ${err}`);
- continue; //next source
- }
+ throttling_promise = new Promise((resolve) => {
+ throttling_promise_resolve = resolve;
+ });
+ }
- if (!error) {
- break; // this source worked, stop searching
+ const sourcesList = asset.load_remote && config.remote_sources ? config.remote_sources : [""];
+
+ let error = undefined;
+ let result: AssetEntry | undefined = undefined;
+ for (let sourcePrefix of sourcesList) {
+ sourcePrefix = sourcePrefix.trim();
+ // HACK: Special-case because MSBuild doesn't allow "" as an attribute
+ if (sourcePrefix === "./")
+ sourcePrefix = "";
+
+ let attemptUrl;
+ if (!asset.resolvedUrl) {
+ if (sourcePrefix === "") {
+ if (asset.behavior === "assembly" || asset.behavior === "pdb")
+ attemptUrl = config.assembly_root + "/" + asset.name;
+ else if (asset.behavior === "resource") {
+ const path = asset.culture !== "" ? `${asset.culture}/${asset.name}` : asset.name;
+ attemptUrl = config.assembly_root + "/" + path;
}
+ else
+ attemptUrl = asset.name;
+ } else {
+ attemptUrl = sourcePrefix + asset.name;
}
-
- --parallel_count;
- if (throttling_promise && parallel_count == ((max_parallel_downloads / 2) | 0)) {
- if (ctx!.tracing)
- console.trace("MONO_WASM: Resuming more parallel downloads");
- throttling_promise_resolve!();
- throttling_promise = undefined;
- }
-
- if (error) {
- const isOkToFail = asset.is_optional || (asset.name.match(/\.pdb$/) && config.ignore_pdb_load_errors);
- if (!isOkToFail)
- throw error;
+ attemptUrl = runtimeHelpers.locateFile(attemptUrl);
+ }
+ else {
+ attemptUrl = asset.resolvedUrl;
+ }
+ if (asset.name === attemptUrl) {
+ if (runtimeHelpers.diagnostic_tracing)
+ console.debug(`MONO_WASM: Attempting to download '${attemptUrl}'`);
+ } else {
+ if (runtimeHelpers.diagnostic_tracing)
+ console.debug(`MONO_WASM: Attempting to download '${attemptUrl}' for ${asset.name}`);
+ }
+ try {
+ const loadingResource = downloadResource({
+ name: asset.name,
+ resolvedUrl: attemptUrl,
+ hash: asset.hash,
+ behavior: asset.behavior
+ });
+ const response = await loadingResource.response;
+ if (!response.ok) {
+ error = new Error(`MONO_WASM: download '${attemptUrl}' for ${asset.name} failed ${response.status} ${response.statusText}`);
+ continue;// next source
}
- Module.removeRunDependency(moduleDependencyId);
-
- return result;
- };
- const fetch_promises: Promise<(MonoInitFetchResult | undefined)>[] = [];
+ asset.pending = loadingResource;
+ result = asset;
+ ++downloded_assets_count;
+ error = undefined;
+ }
+ catch (err) {
+ error = new Error(`MONO_WASM: download '${attemptUrl}' for ${asset.name} failed ${err}`);
+ continue; //next source
+ }
- // start fetching all assets in parallel
- for (const asset of config.assets) {
- fetch_promises.push(load_asset(config, asset));
+ if (!error) {
+ break; // this source worked, stop searching
}
+ }
- ctx.fetch_all_promises = Promise.all(fetch_promises);
- ctx.resolved_promises = await ctx.fetch_all_promises;
- } catch (err: any) {
- Module.printErr("MONO_WASM: Error in mono_download_assets: " + err);
- runtime_is_initialized_reject(err);
- throw err;
+ --parallel_count;
+ if (throttling_promise && parallel_count == ((max_parallel_downloads / 2) | 0)) {
+ if (runtimeHelpers.diagnostic_tracing)
+ console.debug("MONO_WASM: Resuming more parallel downloads");
+ throttling_promise_resolve!();
+ throttling_promise = undefined;
+ }
+
+ if (error) {
+ const isOkToFail = asset.is_optional || (asset.name.match(/\.pdb$/) && config.ignore_pdb_load_errors);
+ if (!isOkToFail)
+ throw error;
}
-}
-function finalize_assets(config: MonoConfig | MonoConfigError | undefined): void {
- mono_assert(config && !config.isError, "Expected config");
- mono_assert(ctx && ctx.downloading_count == 0, "Expected assets to be downloaded");
+ return result;
+}
+async function mono_download_assets(): Promise {
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: mono_download_assets");
try {
- for (const fetch_result of ctx.resolved_promises!) {
- if (fetch_result) {
- _handle_fetched_asset(fetch_result.asset, fetch_result.attemptUrl);
- --ctx.pending_count;
+ const asset_promises: Promise[] = [];
+
+ // start fetching and instantiating all assets in parallel
+ for (const asset of config.assets || []) {
+ if (asset.behavior != "dotnetwasm") {
+ const downloadedAsset = await start_asset_download(asset);
+ if (downloadedAsset) {
+ asset_promises.push((async () => {
+ const url = downloadedAsset.pending!.url;
+ const response = await downloadedAsset.pending!.response;
+ downloadedAsset.pending = undefined; //GC
+ const buffer = await response.arrayBuffer();
+ await beforeOnRuntimeInitialized.promise;
+ // this is after onRuntimeInitialized
+ _instantiate_asset(downloadedAsset, url, new Uint8Array(buffer));
+ })());
+ }
}
}
- ctx.loaded_files.forEach(value => MONO.loaded_files.push(value.url));
- if (ctx.tracing) {
- console.trace("MONO_WASM: loaded_assets: " + JSON.stringify(ctx.loaded_assets));
- console.trace("MONO_WASM: loaded_files: " + JSON.stringify(ctx.loaded_files));
- }
+ // this await will get past the onRuntimeInitialized because we are not blocking via addRunDependency
+ // and we are not awating it here
+ all_assets_loaded_in_memory = Promise.all(asset_promises) as any;
+ // OPTIMIZATION explained:
+ // we do it this way so that we could allocate memory immediately after asset is downloaded (and after onRuntimeInitialized which happened already)
+ // spreading in time
+ // rather than to block all downloads after onRuntimeInitialized or block onRuntimeInitialized after all downloads are done. That would create allocation burst.
} catch (err: any) {
- Module.printErr("MONO_WASM: Error in finalize_assets: " + err);
- runtime_is_initialized_reject(err);
+ Module.printErr("MONO_WASM: Error in mono_download_assets: " + err);
throw err;
}
}
@@ -703,6 +866,7 @@ export function mono_wasm_load_data_archive(data: Uint8Array, prefix: string): b
return true;
}
+let configLoaded = false;
/**
* Loads the mono config file (typically called mono-config.json) asynchroniously
* Note: the run dependencies are so emsdk actually awaits it in order.
@@ -711,25 +875,45 @@ export function mono_wasm_load_data_archive(data: Uint8Array, prefix: string): b
* @throws Will throw an error if the config file loading fails
*/
export async function mono_wasm_load_config(configFilePath: string): Promise {
- const module = Module;
+ if (configLoaded) {
+ return;
+ }
+ if (runtimeHelpers.diagnostic_tracing) console.debug("MONO_WASM: mono_wasm_load_config");
try {
- module.addRunDependency(configFilePath);
-
- const configResponse = await runtimeHelpers.fetch(configFilePath);
- const config = (await configResponse.json()) || {};
-
+ const resolveSrc = runtimeHelpers.locateFile(configFilePath);
+ const configResponse = await runtimeHelpers.fetch_like(resolveSrc);
+ const configData: MonoConfig = (await configResponse.json()) || {};
+ // merge
+ configData.assets = [...(config.assets || []), ...(configData.assets || [])];
+ config = runtimeHelpers.config = Module.config = Object.assign(Module.config as any, configData);
+
+ // normalize
config.environment_variables = config.environment_variables || {};
config.assets = config.assets || [];
config.runtime_options = config.runtime_options || [];
- config.globalization_mode = config.globalization_mode || GlobalizationMode.AUTO;
+ config.globalization_mode = config.globalization_mode || "auto";
+ if (config.enable_debugging)
+ config.debug_level = config.enable_debugging;
+
+ if (typeof (config.environment_variables) !== "object")
+ throw new Error("Expected config.environment_variables to be unset or a dictionary-style object");
- runtimeHelpers.config = config;
- Module.removeRunDependency(configFilePath);
+ if (Module.onConfigLoaded) {
+ try {
+ await Module.onConfigLoaded(runtimeHelpers.config);
+ }
+ catch (err: any) {
+ _print_error("MONO_WASM: onConfigLoaded() failed", err);
+ throw err;
+ }
+ }
+ runtimeHelpers.diagnostic_tracing = !!runtimeHelpers.config.diagnostic_tracing;
+ runtimeHelpers.enable_debugging = runtimeHelpers.config.enable_debugging ? runtimeHelpers.config.enable_debugging : 0;
+ configLoaded = true;
} catch (err) {
const errMessage = `Failed to load config file ${configFilePath} ${err}`;
- Module.printErr(errMessage);
- runtimeHelpers.config = { message: errMessage, error: err, isError: true };
- runtime_is_initialized_reject(err);
+ abort_startup(errMessage, true);
+ config = runtimeHelpers.config = Module.config = { message: errMessage, error: err, isError: true };
throw err;
}
}
@@ -770,21 +954,6 @@ export function mono_wasm_set_main_args(name: string, allRuntimeArguments: strin
cwraps.mono_wasm_set_main_args(main_argc, main_argv);
}
-type MonoInitFetchResult = {
- asset: AllAssetEntryTypes,
- attemptUrl?: string,
-}
-
-export type DownloadAssetsContext = {
- tracing: boolean,
- downloading_count: number,
- pending_count: number,
- fetch_all_promises: Promise<(MonoInitFetchResult | undefined)[]> | null;
- resolved_promises: (MonoInitFetchResult | undefined)[] | null;
- loaded_files: { url?: string, file: string }[],
- loaded_assets: { [id: string]: [VoidPtr, number] },
-}
-
/// Called when dotnet.worker.js receives an emscripten "load" event from the main thread.
///
/// Notes:
@@ -797,3 +966,12 @@ async function mono_wasm_pthread_worker_init(): Promise {
console.debug("MONO_WASM: pthread created", ev.pthread_self.pthread_id);
});
}
+
+/**
+* @deprecated
+*/
+export async function mono_load_runtime_and_bcl_args(cfg?: MonoConfig | MonoConfigError | undefined): Promise {
+ config = Module.config = runtimeHelpers.config = Object.assign(runtimeHelpers.config || {}, cfg || {}) as any;
+ await mono_download_assets();
+ await all_assets_loaded_in_memory;
+}
diff --git a/src/mono/wasm/runtime/types.ts b/src/mono/wasm/runtime/types.ts
index ac1dee3e8dca7e..9abff18eb75a20 100644
--- a/src/mono/wasm/runtime/types.ts
+++ b/src/mono/wasm/runtime/types.ts
@@ -65,12 +65,19 @@ export function coerceNull(ptr: T | nu
}
export type MonoConfig = {
- isError: false,
- assembly_root: string, // the subfolder containing managed assemblies and pdbs
- 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
- globalization_mode: GlobalizationMode, // configures the runtime's globalization mode
+ isError?: false,
+ assembly_root?: string, // the subfolder containing managed assemblies and pdbs. This is relative to dotnet.js script.
+ assets?: AssetEntry[], // a list of assets to load along with the runtime. each asset is a dictionary-style Object with the following properties:
+
+ /**
+ * Either this or enable_debugging needs to be set
+ * debug_level > 0 enables debugging and sets the debug log level to debug_level
+ * debug_level == 0 disables debugging and enables interpreter optimizations
+ * debug_level < 0 enabled debugging and disables debug logging.
+ */
+ debug_level?: number,
+ enable_debugging?: number, // Either this or debug_level needs to be set
+ 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 "/".
environment_variables?: {
@@ -90,46 +97,31 @@ export type MonoConfigError = {
error: any
}
-export type AllAssetEntryTypes = AssetEntry | AssemblyEntry | SatelliteAssemblyEntry | VfsEntry | IcuData;
-
-// Types of assets that can be in the mono-config.js/mono-config.json file (taken from /src/tasks/WasmAppBuilder/WasmAppBuilder.cs)
-export type AssetEntry = {
+export interface ResourceRequest {
name: string, // the name of the asset, including extension.
behavior: AssetBehaviours, // determines how the asset will be handled once loaded
+ resolvedUrl?: string;
+ hash?: string;
+}
+
+// Types of assets that can be in the mono-config.js/mono-config.json file (taken from /src/tasks/WasmAppBuilder/WasmAppBuilder.cs)
+export interface AssetEntry extends ResourceRequest {
virtual_path?: string, // if specified, overrides the path of the asset in the virtual filesystem and similar data structures once loaded.
culture?: string,
load_remote?: boolean, // if true, an attempt will be made to load the asset from each location in @args.remote_sources.
is_optional?: boolean // if true, any failure to load this asset will be ignored.
buffer?: ArrayBuffer // if provided, we don't have to fetch it
+ pending?: LoadingResource // if provided, we don't have to start fetching it
}
-export interface AssemblyEntry extends AssetEntry {
- name: "assembly"
-}
-
-export interface SatelliteAssemblyEntry extends AssetEntry {
- name: "resource",
- culture: string
-}
-
-export interface VfsEntry extends AssetEntry {
- name: "vfs",
- virtual_path: string
-}
-
-export interface IcuData extends AssetEntry {
- name: "icu",
- load_remote: boolean
-}
-
-// Note that since these are annoated as `declare const enum` they are replaces by tsc with their raw value during compilation
-export const enum AssetBehaviours {
- Resource = "resource", // load asset as a managed resource assembly
- Assembly = "assembly", // load asset as a managed assembly (or debugging information)
- Heap = "heap", // store asset into the native heap
- ICU = "icu", // load asset as an ICU data archive
- VFS = "vfs", // load asset into the virtual filesystem (for fopen, File.Open, etc)
-}
+export type AssetBehaviours =
+ "resource" // load asset as a managed resource assembly
+ | "assembly" // load asset as a managed assembly
+ | "pdb" // load asset as a managed debugging information
+ | "heap" // store asset into the native heap
+ | "icu" // load asset as an ICU data archive
+ | "vfs" // load asset into the virtual filesystem (for fopen, File.Open, etc)
+ | "dotnetwasm"; // the binary of the dotnet runtime
export type RuntimeHelpers = {
get_call_sig_ref: MonoMethod;
@@ -154,22 +146,30 @@ export type RuntimeHelpers = {
_class_uint32: MonoClass;
_class_double: MonoClass;
_class_boolean: MonoClass;
+ mono_wasm_load_runtime_done: boolean;
mono_wasm_runtime_is_ready: boolean;
mono_wasm_bindings_is_ready: boolean;
loaded_files: string[];
config: MonoConfig;
+ diagnostic_tracing: boolean;
+ enable_debugging: number;
wait_for_debugger?: number;
- fetch: (url: string) => Promise;
+ fetch_like: (url: string, init?: RequestInit) => Promise;
+ scriptDirectory?: string
+ requirePromise: Promise
+ ExitStatus: ExitStatusError;
+ quit: Function,
+ locateFile: (path: string, prefix?: string) => string,
}
export const wasm_type_symbol = Symbol.for("wasm type");
-export const enum GlobalizationMode {
- ICU = "icu", // load ICU globalization data from any runtime assets with behavior "icu".
- INVARIANT = "invariant", // operate in invariant globalization mode.
- AUTO = "auto" // (default): if "icu" behavior assets are present, use ICU, otherwise invariant.
-}
+export type GlobalizationMode =
+ "icu" | // load ICU globalization data from any runtime assets with behavior "icu".
+ "invariant" | // operate in invariant globalization mode.
+ "auto" // (default): if "icu" behavior assets are present, use ICU, otherwise invariant.
+
export type AOTProfilerOptions = {
write_at?: string, // should be in the format ::, default: 'WebAssembly.Runtime::StopProfile'
@@ -211,13 +211,14 @@ export type DotnetModule = EmscriptenModule & DotnetModuleConfig;
export type DotnetModuleConfig = {
disableDotnet6Compatibility?: boolean,
- config?: MonoConfig | MonoConfigError,
+ config?: MonoConfig,
configSrc?: string,
- onConfigLoaded?: (config: MonoConfig) => Promise;
- onDotnetReady?: () => void;
+ onConfigLoaded?: (config: MonoConfig) => void | Promise;
+ onDotnetReady?: () => void | Promise;
imports?: DotnetModuleConfigImports;
exports?: string[];
+ downloadResource?: (request: ResourceRequest) => LoadingResource
} & Partial
export type DotnetModuleConfigImports = {
@@ -240,6 +241,13 @@ export type DotnetModuleConfigImports = {
url?: any;
}
+export interface LoadingResource {
+ name: string;
+ url: string;
+ response: Promise;
+}
+
+
// see src\mono\wasm\runtime\rollup.config.js
// inline this, because the lambda could allocate closure on hot path otherwise
export function mono_assert(condition: unknown, messageFactory: string | (() => string)): asserts condition {
@@ -301,6 +309,44 @@ export function is_nullish(value: T | null | undefined): value is null | unde
return (value === undefined) || (value === null);
}
+export type EarlyImports = {
+ isESM: boolean,
+ isGlobal: boolean,
+ isNode: boolean,
+ isWorker: boolean,
+ isShell: boolean,
+ isWeb: boolean,
+ isPThread: boolean,
+ quit_: Function,
+ ExitStatus: ExitStatusError,
+ requirePromise: Promise
+};
+export type EarlyExports = {
+ mono: any,
+ binding: any,
+ internal: any,
+ module: any,
+ marshaled_exports: any,
+ marshaled_imports: any
+};
+export type EarlyReplacements = {
+ fetch: any,
+ require: any,
+ requirePromise: Promise,
+ noExitRuntime: boolean,
+ updateGlobalBufferAndViews: Function,
+ pthreadReplacements: PThreadReplacements | undefined | null
+ scriptDirectory: string;
+ scriptUrl: string
+}
+export interface ExitStatusError {
+ new(status: number): any;
+}
+export type PThreadReplacements = {
+ loadWasmModuleToWorker: Function,
+ threadInitTLS: Function
+}
+
/// Always throws. Used to handle unreachable switch branches when TypeScript refines the type of a variable
/// to 'never' after you handle all the cases it knows about.
export function assertNever(x: never): never {
@@ -317,4 +363,3 @@ export function notThenable(x: T | PromiseLike): x is T {
/// An identifier for an EventPipe session. The id is unique during the lifetime of the runtime.
/// Primarily intended for debugging purposes.
export type EventPipeSessionID = bigint;
-
diff --git a/src/mono/wasm/runtime/types/emscripten.ts b/src/mono/wasm/runtime/types/emscripten.ts
index 6a9ea3605c21e8..1b503808774ea6 100644
--- a/src/mono/wasm/runtime/types/emscripten.ts
+++ b/src/mono/wasm/runtime/types/emscripten.ts
@@ -58,12 +58,12 @@ export declare interface EmscriptenModule {
ready: Promise;
+ instantiateWasm?: (imports: WebAssembly.Imports, successCallback: (instance: WebAssembly.Instance, module: WebAssembly.Module) => void) => any;
preInit?: (() => any)[];
preRun?: (() => any)[];
+ onRuntimeInitialized?: () => any;
postRun?: (() => any)[];
onAbort?: { (error: any): void };
- onRuntimeInitialized?: () => any;
- instantiateWasm: (imports: any, successCallback: Function) => any;
}
export declare type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array;
diff --git a/src/mono/wasm/runtime/types/node.d.ts b/src/mono/wasm/runtime/types/node.d.ts
new file mode 100644
index 00000000000000..1c3f1daa20579a
--- /dev/null
+++ b/src/mono/wasm/runtime/types/node.d.ts
@@ -0,0 +1,3 @@
+// only when script loaded as CJS
+declare const __filename: string;
+declare const __dirname: string;
\ No newline at end of file
diff --git a/src/mono/wasm/runtime/workers/dotnet-crypto-worker.js b/src/mono/wasm/runtime/workers/dotnet-crypto-worker.js
index e831deec516f9b..7e000aa5649ea6 100644
--- a/src/mono/wasm/runtime/workers/dotnet-crypto-worker.js
+++ b/src/mono/wasm/runtime/workers/dotnet-crypto-worker.js
@@ -7,9 +7,9 @@
import { setup_proxy_console } from "../debug";
-class FailedOrStoppedLoopError extends Error {}
-class ArgumentsError extends Error {}
-class WorkerFailedError extends Error {}
+class FailedOrStoppedLoopError extends Error { }
+class ArgumentsError extends Error { }
+class WorkerFailedError extends Error { }
var ChannelWorker = {
_impl: class {
@@ -41,7 +41,7 @@ var ChannelWorker = {
}
async run_message_loop(async_op) {
- for (;;) {
+ for (; ;) {
try {
// Wait for signal to perform operation
let state;
@@ -62,7 +62,7 @@ var ChannelWorker = {
catch (err) {
resp.error_type = typeof err;
resp.error = _stringify_err(err);
- console.error(`Request error: ${resp.error}. req was: ${req}`);
+ console.error(`MONO_WASM: Request error: ${resp.error}. req was: ${req}`);
}
// Send response
@@ -73,13 +73,13 @@ var ChannelWorker = {
if (state === this.STATE_SHUTDOWN)
break;
if (state === this.STATE_RESET)
- console.debug(`caller failed, resetting worker`);
+ console.debug("MONO_WASM: caller failed, resetting worker");
} else {
- console.error(`Worker failed to handle the request: ${_stringify_err(err)}`);
+ console.error(`MONO_WASM: Worker failed to handle the request: ${_stringify_err(err)}`);
this._change_state_locked(this.STATE_REQ_FAILED);
Atomics.store(this.comm, this.LOCK_IDX, this.LOCK_UNLOCKED);
- console.debug(`set state to failed, now waiting to get RESET`);
+ console.debug("MONO_WASM: set state to failed, now waiting to get RESET");
Atomics.wait(this.comm, this.STATE_IDX, this.STATE_REQ_FAILED);
const state = Atomics.load(this.comm, this.STATE_IDX);
if (state !== this.STATE_RESET) {
@@ -96,19 +96,19 @@ var ChannelWorker = {
const lock_state = Atomics.load(this.comm, this.LOCK_IDX);
if (state !== this.STATE_IDLE && state !== this.STATE_REQ && state !== this.STATE_REQ_P)
- console.error(`-- state is not idle at the top of the loop: ${state}, and lock_state: ${lock_state}`);
+ console.error(`MONO_WASM: -- state is not idle at the top of the loop: ${state}, and lock_state: ${lock_state}`);
if (lock_state !== this.LOCK_UNLOCKED && state !== this.STATE_REQ && state !== this.STATE_REQ_P && state !== this.STATE_IDLE)
- console.error(`-- lock is not unlocked at the top of the loop: ${lock_state}, and state: ${state}`);
+ console.error(`MONO_WASM: -- lock is not unlocked at the top of the loop: ${lock_state}, and state: ${state}`);
}
Atomics.store(this.comm, this.MSG_SIZE_IDX, 0);
this._change_state_locked(this.STATE_SHUTDOWN);
- console.debug("******* run_message_loop ending");
+ console.debug("MONO_WASM: ******* run_message_loop ending");
}
_read_request() {
var request = "";
- for (;;) {
+ for (; ;) {
this._acquire_lock();
try {
this._throw_if_reset_or_shutdown();
@@ -147,13 +147,13 @@ var ChannelWorker = {
_send_response(msg) {
if (Atomics.load(this.comm, this.STATE_IDX) !== this.STATE_REQ)
- throw new WorkerFailedError(`WORKER: Invalid sync communication channel state.`);
+ throw new WorkerFailedError("WORKER: Invalid sync communication channel state.");
var state; // State machine variable
const msg_len = msg.length;
var msg_written = 0;
- for (;;) {
+ for (; ;) {
this._acquire_lock();
try {
@@ -199,7 +199,7 @@ var ChannelWorker = {
}
_acquire_lock() {
- for (;;) {
+ for (; ;) {
const lockState = Atomics.compareExchange(this.comm, this.LOCK_IDX, this.LOCK_UNLOCKED, this.LOCK_OWNED);
this._throw_if_reset_or_shutdown();
@@ -251,7 +251,7 @@ async function sign(type, key, data) {
key = new Uint8Array([0]);
}
- const cryptoKey = await crypto.subtle.importKey("raw", key, {name: "HMAC", hash: hash_name}, false /* extractable */, ["sign"]);
+ const cryptoKey = await crypto.subtle.importKey("raw", key, { name: "HMAC", hash: hash_name }, false /* extractable */, ["sign"]);
const signResult = await crypto.subtle.sign("HMAC", cryptoKey, data);
return Array.from(new Uint8Array(signResult));
}
diff --git a/src/mono/wasm/templates/templates/browser/app-support.js b/src/mono/wasm/templates/templates/browser/app-support.js
index cb9d6241be37a4..0588becc7fb9ba 100644
--- a/src/mono/wasm/templates/templates/browser/app-support.js
+++ b/src/mono/wasm/templates/templates/browser/app-support.js
@@ -142,12 +142,6 @@ function applyArguments() {
}
}
-const anchorTagForAbsoluteUrlConversions = document.createElement('a');
-const toAbsoluteUrl = function toAbsoluteUrl(path, prefix) {
- anchorTagForAbsoluteUrlConversions.href = prefix + path;
- return anchorTagForAbsoluteUrlConversions.href;
-}
-
try {
const argsResponse = await fetch('./runArgs.json')
if (!argsResponse.ok) {
@@ -163,7 +157,6 @@ try {
disableDotnet6Compatibility: true,
config: null,
configSrc: "./mono-config.json",
- locateFile: toAbsoluteUrl,
onConfigLoaded: (config) => {
if (!Module.config) {
const err = new Error("Could not find ./mono-config.json. Cancelling run");
diff --git a/src/mono/wasm/templates/templates/console/app-support.mjs b/src/mono/wasm/templates/templates/console/app-support.mjs
index 0645f743a54ed8..573a2fc14f312f 100644
--- a/src/mono/wasm/templates/templates/console/app-support.mjs
+++ b/src/mono/wasm/templates/templates/console/app-support.mjs
@@ -47,22 +47,22 @@ function set_exit_code(exit_code, reason) {
}
if (App && App.INTERNAL) {
- let _flush = function(_stream) {
- return new Promise((resolve, reject) => {
- _stream.on('error', (error) => reject(error));
- _stream.write('', function() { resolve () });
- });
+ let _flush = function (_stream) {
+ return new Promise((resolve, reject) => {
+ _stream.on('error', (error) => reject(error));
+ _stream.write('', function () { resolve() });
+ });
};
let stderrFlushed = _flush(process.stderr);
let stdoutFlushed = _flush(process.stdout);
- Promise.all([ stdoutFlushed, stderrFlushed ])
- .then(
- () => App.INTERNAL.mono_wasm_exit(exit_code),
- reason => {
- console.error(`flushing std* streams failed: ${reason}`);
- App.INTERNAL.mono_wasm_exit(123456);
- });
+ Promise.all([stdoutFlushed, stderrFlushed])
+ .then(
+ () => App.INTERNAL.mono_wasm_exit(exit_code),
+ reason => {
+ console.error(`flushing std* streams failed: ${reason}`);
+ App.INTERNAL.mono_wasm_exit(123456);
+ });
}
}
@@ -111,12 +111,6 @@ function mergeArguments() {
is_debugging = runArgs.debugging === true;
}
-let toAbsoluteUrl = function (path, prefix) {
- if (prefix.startsWith("/")) {
- return path;
- }
- return prefix + path;
-}
try {
try {
@@ -135,7 +129,6 @@ try {
disableDotnet6Compatibility: true,
config: null,
configSrc: "./mono-config.json",
- locateFile: toAbsoluteUrl,
onConfigLoaded: (config) => {
if (!Module.config) {
const err = new Error("Could not find ./mono-config.json. Cancelling run");
diff --git a/src/mono/wasm/test-main.js b/src/mono/wasm/test-main.js
index a39f3e5ae5dcad..f781652f5062b5 100644
--- a/src/mono/wasm/test-main.js
+++ b/src/mono/wasm/test-main.js
@@ -349,20 +349,6 @@ if (typeof globalThis.crypto === 'undefined') {
}
}
-let toAbsoluteUrl = function (path, prefix) {
- if (prefix.startsWith("/")) {
- return path;
- }
- return prefix + path;
-}
-if (is_browser) {
- const anchorTagForAbsoluteUrlConversions = document.createElement('a');
- toAbsoluteUrl = function toAbsoluteUrl(path, prefix) {
- anchorTagForAbsoluteUrlConversions.href = prefix + path;
- return anchorTagForAbsoluteUrlConversions.href;
- }
-}
-
Promise.all([argsPromise, loadDotnetPromise]).then(async ([_, createDotnetRuntime]) => {
applyArguments();
@@ -370,7 +356,6 @@ Promise.all([argsPromise, loadDotnetPromise]).then(async ([_, createDotnetRuntim
disableDotnet6Compatibility: true,
config: null,
configSrc: "./mono-config.json",
- locateFile: toAbsoluteUrl,
onConfigLoaded: (config) => {
if (!Module.config) {
const err = new Error("Could not find ./mono-config.json. Cancelling run");