Skip to content

Commit 73374e8

Browse files
pavelsavaramaraf
andauthored
[wasm] improve startup (#72275)
- streaming wasm instantiation - more parallel download of DLLs - new hook `downloadResource` and `config.assets[].resolvedUrl ` - improved `locateFile` allows to run dotnet with another working directory - call `init_crypto` in blazor startup sequence Co-authored-by: Marek Fišera <[email protected]>
1 parent 86a7742 commit 73374e8

35 files changed

+1145
-861
lines changed

src/libraries/System.Private.Runtime.InteropServices.JavaScript/tests/timers.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
export function log(message) {
55
// uncomment for debugging
6-
console.log(message);
6+
// console.log(message);
77
}
88

99
export function install() {

src/mono/mono/component/mini-wasm-debugger.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ mono_wasm_send_dbg_command_with_parms (int id, MdbgProtCommandSet command_set, i
375375
gboolean result = FALSE;
376376
MONO_ENTER_GC_UNSAFE;
377377
if (!debugger_enabled) {
378+
PRINT_ERROR_MSG ("DEBUGGING IS NOT ENABLED\n");
378379
mono_wasm_add_dbg_command_received (0, id, 0, 0);
379380
result = TRUE;
380381
goto done;
@@ -401,6 +402,7 @@ mono_wasm_send_dbg_command (int id, MdbgProtCommandSet command_set, int command,
401402
gboolean result = FALSE;
402403
MONO_ENTER_GC_UNSAFE;
403404
if (!debugger_enabled) {
405+
PRINT_ERROR_MSG ("DEBUGGING IS NOT ENABLED\n");
404406
mono_wasm_add_dbg_command_received(0, id, 0, 0);
405407
result = TRUE;
406408
goto done;

src/mono/sample/wasm/Directory.Build.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
<Exec Command="dotnet tool install -g dotnet-serve" IgnoreExitCode="true" />
3939
</Target>
4040
<Target Name="RunSampleWithBrowser" DependsOnTargets="BuildSampleInTree;CheckServe">
41-
<Exec Command="$(_Dotnet) serve -o -d:bin/$(Configuration)/AppBundle -p:8000 --mime .mjs=text/javascript --mime .js=text/javascript --mime .cjs=text/javascript" IgnoreExitCode="true" YieldDuringToolExecution="true" />
41+
<Exec Command="$(_Dotnet) serve -o -d:bin/$(Configuration)/AppBundle -p:8000 --mime .mjs=text/javascript --mime .js=text/javascript --mime .cjs=text/javascript -h Cross-Origin-Opener-Policy:same-origin -h Cross-Origin-Embedder-Policy:require-corp " IgnoreExitCode="true" YieldDuringToolExecution="true" />
4242
</Target>
4343
<Target Name="RunSampleWithBrowserAndSimpleServer" DependsOnTargets="BuildSampleInTree">
4444
<Exec Command="$(_Dotnet) build -c $(Configuration) ..\simple-server\HttpServer.csproj" />

src/mono/sample/wasm/browser/main.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ function sub(a, b) {
2222

2323
try {
2424
const { MONO, RuntimeBuildInfo, IMPORTS } = await createDotnetRuntime(() => {
25-
console.log('user code in createDotnetRuntime');
25+
console.log('user code in createDotnetRuntime callback');
2626
return {
2727
configSrc: "./mono-config.json",
2828
preInit: () => { console.log('user code Module.preInit'); },
@@ -31,7 +31,7 @@ try {
3131
postRun: () => { console.log('user code Module.postRun'); },
3232
}
3333
});
34-
console.log('after createDotnetRuntime');
34+
console.log('user code after createDotnetRuntime()');
3535
IMPORTS.Sample = {
3636
Test: {
3737
add,

src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public async Task CreateJSBreakpoint()
4040
{
4141
// Test that js breakpoints get set correctly
4242
// 13 24
43-
// 13 53
43+
// 14 24
4444
var bp1_res = await SetBreakpoint("/debugger-driver.html", 13, 24);
4545

4646
Assert.EndsWith("debugger-driver.html", bp1_res.Value["breakpointId"].ToString());
@@ -52,23 +52,23 @@ public async Task CreateJSBreakpoint()
5252
Assert.Equal(13, (int)loc["lineNumber"]);
5353
Assert.Equal(24, (int)loc["columnNumber"]);
5454

55-
var bp2_res = await SetBreakpoint("/debugger-driver.html", 13, 53);
55+
var bp2_res = await SetBreakpoint("/debugger-driver.html", 14, 24);
5656

5757
Assert.EndsWith("debugger-driver.html", bp2_res.Value["breakpointId"].ToString());
5858
Assert.Equal(1, bp2_res.Value["locations"]?.Value<JArray>()?.Count);
5959

6060
var loc2 = bp2_res.Value["locations"]?.Value<JArray>()[0];
6161

6262
Assert.NotNull(loc2["scriptId"]);
63-
Assert.Equal(13, (int)loc2["lineNumber"]);
64-
Assert.Equal(53, (int)loc2["columnNumber"]);
63+
Assert.Equal(14, (int)loc2["lineNumber"]);
64+
Assert.Equal(24, (int)loc2["columnNumber"]);
6565
}
6666

6767
[ConditionalFact(nameof(RunningOnChrome))]
6868
public async Task CreateJS0Breakpoint()
6969
{
7070
// 13 24
71-
// 13 53
71+
// 14 24
7272
var bp1_res = await SetBreakpoint("/debugger-driver.html", 13, 0);
7373

7474
Assert.EndsWith("debugger-driver.html", bp1_res.Value["breakpointId"].ToString());
@@ -78,18 +78,18 @@ public async Task CreateJS0Breakpoint()
7878

7979
Assert.NotNull(loc["scriptId"]);
8080
Assert.Equal(13, (int)loc["lineNumber"]);
81-
Assert.Equal(4, (int)loc["columnNumber"]);
81+
Assert.Equal(24, (int)loc["columnNumber"]);
8282

83-
var bp2_res = await SetBreakpoint("/debugger-driver.html", 13, 53);
83+
var bp2_res = await SetBreakpoint("/debugger-driver.html", 14, 0);
8484

8585
Assert.EndsWith("debugger-driver.html", bp2_res.Value["breakpointId"].ToString());
8686
Assert.Equal(1, bp2_res.Value["locations"]?.Value<JArray>()?.Count);
8787

8888
var loc2 = bp2_res.Value["locations"]?.Value<JArray>()[0];
8989

9090
Assert.NotNull(loc2["scriptId"]);
91-
Assert.Equal(13, (int)loc2["lineNumber"]);
92-
Assert.Equal(53, (int)loc2["columnNumber"]);
91+
Assert.Equal(14, (int)loc2["lineNumber"]);
92+
Assert.Equal(24, (int)loc2["columnNumber"]);
9393
}
9494

9595
[ConditionalTheory(nameof(RunningOnChrome))]

src/mono/wasm/debugger/tests/debugger-test/debugger-driver.html

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,30 @@
77
var App = {
88
static_method_table: {},
99
init: function () {
10-
this.int_add = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] Math:IntAdd");
11-
this.use_complex = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] Math:UseComplex");
12-
this.delegates_test = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] Math:DelegatesTest");
13-
this.generic_types_test = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] Math:GenericTypesTest");
14-
this.outer_method = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] Math:OuterMethod");
15-
this.async_method = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] Math/NestedInMath:AsyncTest");
16-
this.method_with_structs = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] DebuggerTests.ValueTypesTest:MethodWithLocalStructs");
17-
this.run_all = getDotnetRuntime(0).INTERNAL.mono_bind_static_method ("[debugger-test] DebuggerTest:run_all");
10+
this.int_add = App.BINDING.bind_static_method("[debugger-test] Math:IntAdd");
11+
this.use_complex = App.BINDING.bind_static_method("[debugger-test] Math:UseComplex");
12+
this.delegates_test = App.BINDING.bind_static_method("[debugger-test] Math:DelegatesTest");
13+
this.generic_types_test = App.BINDING.bind_static_method("[debugger-test] Math:GenericTypesTest");
14+
this.outer_method = App.BINDING.bind_static_method("[debugger-test] Math:OuterMethod");
15+
this.async_method = App.BINDING.bind_static_method("[debugger-test] Math/NestedInMath:AsyncTest");
16+
this.method_with_structs = App.BINDING.bind_static_method("[debugger-test] DebuggerTests.ValueTypesTest:MethodWithLocalStructs");
17+
this.run_all = App.BINDING.bind_static_method("[debugger-test] DebuggerTest:run_all");
1818
this.static_method_table = {};
1919
console.log ("ready");
2020
},
2121
};
2222
function invoke_static_method (method_name, ...args) {
2323
var method = App.static_method_table [method_name];
2424
if (method == undefined)
25-
method = App.static_method_table [method_name] = getDotnetRuntime(0).INTERNAL.mono_bind_static_method (method_name);
25+
method = App.static_method_table[method_name] = App.BINDING.bind_static_method(method_name);
2626

2727
return method (...args);
2828
}
2929

3030
async function invoke_static_method_async (method_name, ...args) {
3131
var method = App.static_method_table [method_name];
3232
if (method == undefined) {
33-
method = App.static_method_table [method_name] = getDotnetRuntime(0).INTERNAL.mono_bind_static_method (method_name);
33+
method = App.static_method_table[method_name] = App.BINDING.bind_static_method(method_name);
3434
}
3535

3636
return await method (...args);

src/mono/wasm/debugger/tests/debugger-test/debugger-main.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,23 @@
66
import createDotnetRuntime from './dotnet.js'
77

88
try {
9-
const { BINDING, INTERNAL } = await createDotnetRuntime(() => ({
9+
const { BINDING } = await createDotnetRuntime(({ INTERNAL }) => ({
1010
configSrc: "./mono-config.json",
1111
onConfigLoaded: (config) => {
1212
config.environment_variables["DOTNET_MODIFIABLE_ASSEMBLIES"] = "debug";
13-
config.diagnostic_tracing = true;
1413
/* For custom logging patch the functions below
14+
config.diagnostic_tracing = true;
1515
config.environment_variables["MONO_LOG_LEVEL"] = "debug";
1616
config.environment_variables["MONO_LOG_MASK"] = "all";
1717
INTERNAL.logging = {
18-
trace: function (domain, log_level, message, isFatal, dataPtr) { },
19-
debugger: function (level, message) { }
18+
trace: (domain, log_level, message, isFatal, dataPtr) => console.log({ domain, log_level, message, isFatal, dataPtr }),
19+
debugger: (level, message) => console.log({ level, message }),
2020
};
2121
*/
2222
},
2323
}));
24-
App.init({ BINDING, INTERNAL })
24+
App.BINDING = BINDING;
25+
App.init()
2526
} catch (err) {
2627
console.log(`WASM ERROR ${err}`);
2728
}

src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<EnableDefaultWasmAssembliesToBundle>false</EnableDefaultWasmAssembliesToBundle>
4343
<WasmAppDir>$(AppDir)</WasmAppDir>
4444
<WasmMainJSPath>debugger-main.js</WasmMainJSPath>
45-
<!-- like is used on blazor -->
45+
<!-- -1 enabled debugging and disables debug logging. -->
4646
<WasmDebugLevel Condition="'$(WasmDebugLevel)'==''">-1</WasmDebugLevel>
4747

4848
<WasmResolveAssembliesBeforeBuild>true</WasmResolveAssembliesBeforeBuild>

src/mono/wasm/runtime/cjs/dotnet.cjs.extpost.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var require = require || undefined;
2+
var __dirname = __dirname || "";
23
// if loaded into global namespace and configured with global Module, we will self start in compatibility mode
34
const __isWorker = typeof globalThis.importScripts === "function";
45
let ENVIRONMENT_IS_GLOBAL = !__isWorker && (typeof globalThis.Module === "object" && globalThis.__dotnet_runtime === __dotnet_runtime);

src/mono/wasm/runtime/cjs/dotnet.cjs.lib.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,30 @@ const isPThread = `false`;
1515
const DotnetSupportLib = {
1616
$DOTNET: {},
1717
// these lines will be placed early on emscripten runtime creation, passing import and export objects into __dotnet_runtime IFFE
18-
// we replace implementation of readAsync and fetch
18+
// we replace implementation of fetch
1919
// replacement of require is there for consistency with ES6 code
2020
$DOTNET__postset: `
2121
let __dotnet_replacement_PThread = ${usePThreads} ? {} : undefined;
2222
if (${usePThreads}) {
2323
__dotnet_replacement_PThread.loadWasmModuleToWorker = PThread.loadWasmModuleToWorker;
2424
__dotnet_replacement_PThread.threadInitTLS = PThread.threadInitTLS;
2525
}
26-
let __dotnet_replacements = {readAsync, fetch: globalThis.fetch, require, updateGlobalBufferAndViews, pthreadReplacements: __dotnet_replacement_PThread};
26+
let __dotnet_replacements = {scriptUrl: undefined, fetch: globalThis.fetch, require, updateGlobalBufferAndViews, pthreadReplacements: __dotnet_replacement_PThread};
27+
if (ENVIRONMENT_IS_NODE) {
28+
__dotnet_replacements.requirePromise = Promise.resolve(require);
29+
}
2730
let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports(
28-
{ 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)},
31+
{ 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)},
2932
{ mono:MONO, binding:BINDING, internal:INTERNAL, module:Module, marshaled_exports: EXPORTS, marshaled_imports: IMPORTS },
3033
__dotnet_replacements);
3134
updateGlobalBufferAndViews = __dotnet_replacements.updateGlobalBufferAndViews;
32-
readAsync = __dotnet_replacements.readAsync;
3335
var fetch = __dotnet_replacements.fetch;
34-
require = __dotnet_replacements.requireOut;
36+
_scriptDir = __dirname = scriptDirectory = __dotnet_replacements.scriptDirectory;
37+
if (ENVIRONMENT_IS_NODE) {
38+
__dotnet_replacements.requirePromise.then(someRequire => {
39+
require = someRequire;
40+
});
41+
}
3542
var noExitRuntime = __dotnet_replacements.noExitRuntime;
3643
if (${usePThreads}) {
3744
PThread.loadWasmModuleToWorker = __dotnet_replacements.pthreadReplacements.loadWasmModuleToWorker;

src/mono/wasm/runtime/cjs/dotnet.cjs.pre.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ if (ENVIRONMENT_IS_GLOBAL) {
55
}
66
globalThis.Module.ready = Module.ready;
77
Module = createDotnetRuntime = globalThis.Module;
8+
if (!createDotnetRuntime.locateFile) createDotnetRuntime.locateFile = createDotnetRuntime.__locateFile = (path) => scriptDirectory + path;
89
}
910
else if (typeof createDotnetRuntime === "object") {
1011
Module = { ready: Module.ready, __undefinedConfig: Object.keys(createDotnetRuntime).length === 1 };
1112
Object.assign(Module, createDotnetRuntime);
1213
createDotnetRuntime = Module;
14+
if (!createDotnetRuntime.locateFile) createDotnetRuntime.locateFile = createDotnetRuntime.__locateFile = (path) => scriptDirectory + path;
1315
}
1416
else if (typeof createDotnetRuntime === "function") {
1517
Module = { ready: Module.ready };
@@ -19,7 +21,8 @@ else if (typeof createDotnetRuntime === "function") {
1921
}
2022
Object.assign(Module, extension);
2123
createDotnetRuntime = Module;
24+
if (!createDotnetRuntime.locateFile) createDotnetRuntime.locateFile = createDotnetRuntime.__locateFile = (path) => scriptDirectory + path;
2225
}
2326
else {
2427
throw new Error("MONO_WASM: Can't locate global Module object or moduleFactory callback of createDotnetRuntime function.")
25-
}
28+
}

src/mono/wasm/runtime/crypto-worker.ts

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export function dotnet_browser_encrypt_decrypt(isEncrypting: boolean, key_buffer
6262
}
6363

6464
if (result.length > output_len) {
65-
console.error(`ENCRYPT DECRYPT: Encrypt/Decrypt length exceeds output length: ${result.length} > ${output_len}`);
65+
console.error(`MONO_WASM_ENCRYPT_DECRYPT: Encrypt/Decrypt length exceeds output length: ${result.length} > ${output_len}`);
6666
return ERR_ARGS;
6767
}
6868

@@ -91,7 +91,7 @@ function _send_simple_msg(msg: any, prefix: string, output_buffer: number, outpu
9191
}
9292

9393
if (result.length > output_len) {
94-
console.error(`${prefix}: Result length exceeds output length: ${result.length} > ${output_len}`);
94+
console.error(`MONO_WASM_ENCRYPT_DECRYPT: ${prefix}: Result length exceeds output length: ${result.length} > ${output_len}`);
9595
return ERR_ARGS;
9696
}
9797

@@ -132,7 +132,7 @@ function _send_msg_worker(msg: any): number | any {
132132
const responseJson = JSON.parse(response);
133133

134134
if (responseJson.error !== undefined) {
135-
console.error(`Worker failed with: ${responseJson.error}`);
135+
console.error(`MONO_WASM_ENCRYPT_DECRYPT: Worker failed with: ${responseJson.error}`);
136136
if (responseJson.error_type == "ArgumentsError")
137137
return ERR_ARGS;
138138
if (responseJson.error_type == "WorkerFailedError")
@@ -144,9 +144,9 @@ function _send_msg_worker(msg: any): number | any {
144144
return responseJson.result;
145145
} catch (err) {
146146
if (err instanceof Error && err.stack !== undefined)
147-
console.error(`${err.stack}`);
147+
console.error(`MONO_WASM_ENCRYPT_DECRYPT: ${err.stack}`);
148148
else
149-
console.error(`_send_msg_worker failed: ${err}`);
149+
console.error(`MONO_WASM_ENCRYPT_DECRYPT: _send_msg_worker failed: ${err}`);
150150
return ERR_OP_FAILED;
151151
}
152152
}
@@ -202,10 +202,9 @@ class LibraryChannel {
202202

203203
public send_msg(msg: string): string {
204204
try {
205-
let state = Atomics.load(this.comm, this.STATE_IDX);
206-
if (state !== this.STATE_IDLE)
207-
console.log(`send_msg, waiting for idle now, ${state}`);
208-
state = this.wait_for_state(pstate => pstate == this.STATE_IDLE, "waiting");
205+
// const state = Atomics.load(this.comm, this.STATE_IDX);
206+
// if (state !== this.STATE_IDLE) console.debug(`MONO_WASM_ENCRYPT_DECRYPT: send_msg, waiting for idle now, ${state}`);
207+
this.wait_for_state(pstate => pstate == this.STATE_IDLE, "waiting");
209208

210209
this.send_request(msg);
211210
return this.read_response();
@@ -214,14 +213,13 @@ class LibraryChannel {
214213
throw err;
215214
}
216215
finally {
217-
const state = Atomics.load(this.comm, this.STATE_IDX);
218-
if (state !== this.STATE_IDLE)
219-
console.log(`state at end of send_msg: ${state}`);
216+
// const state = Atomics.load(this.comm, this.STATE_IDX);
217+
// if (state !== this.STATE_IDLE) console.debug(`MONO_WASM_ENCRYPT_DECRYPT: state at end of send_msg: ${state}`);
220218
}
221219
}
222220

223221
public shutdown(): void {
224-
console.debug("Shutting down crypto");
222+
// console.debug("MONO_WASM_ENCRYPT_DECRYPT: Shutting down crypto");
225223
const state = Atomics.load(this.comm, this.STATE_IDX);
226224
if (state !== this.STATE_IDLE)
227225
throw new Error(`OWNER: Invalid sync communication channel state: ${state}`);
@@ -232,14 +230,15 @@ class LibraryChannel {
232230
Atomics.notify(this.comm, this.STATE_IDX);
233231
}
234232

233+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
235234
private reset(reason: string): void {
236-
console.debug(`reset: ${reason}`);
235+
// console.debug(`MONO_WASM_ENCRYPT_DECRYPT: reset: ${reason}`);
237236
const state = Atomics.load(this.comm, this.STATE_IDX);
238237
if (state === this.STATE_SHUTDOWN)
239238
return;
240239

241240
if (state === this.STATE_RESET || state === this.STATE_IDLE) {
242-
console.debug(`state is already RESET or idle: ${state}`);
241+
// console.debug(`MONO_WASM_ENCRYPT_DECRYPT: state is already RESET or idle: ${state}`);
243242
return;
244243
}
245244

0 commit comments

Comments
 (0)