Skip to content

Commit 25c2073

Browse files
authored
[wasm] Decrease the startup ceremony (#62587)
* new API MONO.mono_run_main_and_exit and MONO.mono_run_main * default onAbort * console-v8-cjs sample * reduced setup ceremony
1 parent 7b2925b commit 25c2073

File tree

12 files changed

+128
-24
lines changed

12 files changed

+128
-24
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Threading.Tasks;
6+
7+
public class Test
8+
{
9+
public static async Task<int> Main(string[] args)
10+
{
11+
await Task.Delay(1);
12+
Console.WriteLine("Hello World!");
13+
for (int i = 0; i < args.Length; i++) {
14+
Console.WriteLine($"args[{i}] = {args[i]}");
15+
}
16+
return args.Length;
17+
}
18+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<WasmCopyAppZipToHelixTestDir Condition="'$(ArchiveTests)' == 'true'">true</WasmCopyAppZipToHelixTestDir>
4+
<WasmMainJSPath>main.js</WasmMainJSPath>
5+
<WasmGenerateRunV8Script>true</WasmGenerateRunV8Script>
6+
<WasmEnableES6>false</WasmEnableES6>
7+
</PropertyGroup>
8+
9+
<PropertyGroup>
10+
<_SampleProject>Wasm.Console.V8.CJS.Sample.csproj</_SampleProject>
11+
<_SampleAssembly>Wasm.Console.V8.CJS.Sample.dll</_SampleAssembly>
12+
</PropertyGroup>
13+
14+
<Target Name="RunSample" DependsOnTargets="RunSampleWithV8" />
15+
</Project>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
load("./dotnet.js")
2+
3+
const dllName = "Wasm.Console.V8.CJS.Sample.dll";
4+
const app_args = Array.from(arguments);
5+
6+
async function main() {
7+
const { MONO } = await createDotnetRuntime();
8+
await MONO.mono_run_main_and_exit(dllName, app_args);
9+
}
10+
11+
main();

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ if (ENVIRONMENT_IS_GLOBAL) {
66
globalThis.Module.ready = Module.ready;
77
Module = createDotnetRuntime = globalThis.Module;
88
}
9+
else if (typeof createDotnetRuntime === "object") {
10+
Module = { ready: Module.ready, __undefinedConfig: Object.keys(createDotnetRuntime).length === 1 };
11+
Object.assign(Module, createDotnetRuntime);
12+
createDotnetRuntime = Module;
13+
}
914
else if (typeof createDotnetRuntime === "function") {
10-
ENVIRONMENT_IS_GLOBAL = false;
1115
Module = { ready: Module.ready };
1216
const extension = createDotnetRuntime({ MONO, BINDING, INTERNAL, Module })
1317
if (extension.ready) {

src/mono/wasm/runtime/dotnet.d.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ declare interface EmscriptenModule {
4747
preInit?: (() => any)[];
4848
preRun?: (() => any)[];
4949
postRun?: (() => any)[];
50+
onAbort?: {
51+
(error: any): void;
52+
};
5053
onRuntimeInitialized?: () => any;
5154
instantiateWasm: (imports: any, successCallback: Function) => any;
5255
}
@@ -258,7 +261,7 @@ declare function unbox_mono_obj(mono_obj: MonoObject): any;
258261
declare function mono_array_to_js_array(mono_array: MonoArray): any[] | null;
259262

260263
declare function mono_bind_static_method(fqn: string, signature?: ArgsMarshalString): Function;
261-
declare function mono_call_assembly_entry_point(assembly: string, args: any[], signature: ArgsMarshalString): any;
264+
declare function mono_call_assembly_entry_point(assembly: string, args?: any[], signature?: ArgsMarshalString): number;
262265

263266
declare function mono_wasm_load_bytes_into_heap(bytes: Uint8Array): VoidPtr;
264267

@@ -282,6 +285,9 @@ declare function getI64(offset: _MemOffset): number;
282285
declare function getF32(offset: _MemOffset): number;
283286
declare function getF64(offset: _MemOffset): number;
284287

288+
declare function mono_run_main_and_exit(main_assembly_name: string, args: string[]): Promise<void>;
289+
declare function mono_run_main(main_assembly_name: string, args: string[]): Promise<number>;
290+
285291
declare const MONO: {
286292
mono_wasm_setenv: typeof mono_wasm_setenv;
287293
mono_wasm_load_bytes_into_heap: typeof mono_wasm_load_bytes_into_heap;
@@ -293,6 +299,8 @@ declare const MONO: {
293299
mono_wasm_new_root_buffer: typeof mono_wasm_new_root_buffer;
294300
mono_wasm_new_root: typeof mono_wasm_new_root;
295301
mono_wasm_release_roots: typeof mono_wasm_release_roots;
302+
mono_run_main: typeof mono_run_main;
303+
mono_run_main_and_exit: typeof mono_run_main_and_exit;
296304
mono_wasm_add_assembly: (name: string, data: VoidPtr, size: number) => number;
297305
mono_wasm_load_runtime: (unused: string, debug_level: number) => void;
298306
config: MonoConfig | MonoConfigError;
@@ -342,7 +350,7 @@ interface DotnetPublicAPI {
342350
};
343351
}
344352

345-
declare function createDotnetRuntime(moduleFactory: (api: DotnetPublicAPI) => DotnetModuleConfig): Promise<DotnetPublicAPI>;
353+
declare function createDotnetRuntime(moduleFactory: DotnetModuleConfig | ((api: DotnetPublicAPI) => DotnetModuleConfig)): Promise<DotnetPublicAPI>;
346354
declare type CreateDotnetRuntimeType = typeof createDotnetRuntime;
347355
declare global {
348356
function getDotnetRuntime(runtimeId: number): DotnetPublicAPI | undefined;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ if (typeof createDotnetRuntime === "function") {
99
Object.assign(Module, extension);
1010
createDotnetRuntime = Module;
1111
}
12+
else if (typeof createDotnetRuntime === "object") {
13+
Module = { ready: Module.ready, __undefinedConfig: Object.keys(createDotnetRuntime).length === 1 };
14+
Object.assign(Module, createDotnetRuntime);
15+
createDotnetRuntime = Module;
16+
}
1217
else {
1318
throw new Error("MONO_WASM: Can't use moduleFactory callback of createDotnetRuntime function.")
1419
}

src/mono/wasm/runtime/export-types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { EmscriptenModule, VoidPtr } from "./types/emscripten";
99
// this files has all public exports from the dotnet.js module
1010
// -----------------------------------------------------------
1111

12-
declare function createDotnetRuntime(moduleFactory: (api: DotnetPublicAPI) => DotnetModuleConfig): Promise<DotnetPublicAPI>;
12+
declare function createDotnetRuntime(moduleFactory: DotnetModuleConfig | ((api: DotnetPublicAPI) => DotnetModuleConfig)): Promise<DotnetPublicAPI>;
1313
declare type CreateDotnetRuntimeType = typeof createDotnetRuntime;
1414

1515
// Here, declare things that go in the global namespace, or augment existing declarations in the global namespace

src/mono/wasm/runtime/exports.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import {
3131
mono_load_runtime_and_bcl_args, mono_wasm_load_config,
3232
mono_wasm_setenv, mono_wasm_set_runtime_options,
3333
mono_wasm_load_data_archive, mono_wasm_asm_loaded,
34-
mono_wasm_set_main_args,
3534
mono_wasm_pre_init,
3635
mono_wasm_runtime_is_initialized,
3736
mono_wasm_on_runtime_initialized
@@ -68,6 +67,7 @@ import {
6867
import { create_weak_ref } from "./weak-ref";
6968
import { fetch_like, readAsync_like } from "./polyfills";
7069
import { EmscriptenModule } from "./types/emscripten";
70+
import { mono_on_abort, mono_run_main, mono_run_main_and_exit } from "./run";
7171

7272
const MONO = {
7373
// current "public" MONO API
@@ -81,6 +81,8 @@ const MONO = {
8181
mono_wasm_new_root_buffer,
8282
mono_wasm_new_root,
8383
mono_wasm_release_roots,
84+
mono_run_main,
85+
mono_run_main_and_exit,
8486

8587
// for Blazor's future!
8688
mono_wasm_add_assembly: cwraps.mono_wasm_add_assembly,
@@ -157,6 +159,10 @@ function initializeImportsAndExports(
157159
Configuration
158160
}
159161
};
162+
if (exports.module.__undefinedConfig) {
163+
module.disableDotnet6Compatibility = true;
164+
module.configSrc = "./mono-config.json";
165+
}
160166

161167
// these could be overriden on DotnetModuleConfig
162168
if (!module.preInit) {
@@ -271,6 +277,10 @@ function initializeImportsAndExports(
271277
});
272278
}
273279

280+
if (!module.onAbort) {
281+
module.onAbort = () => mono_on_abort;
282+
}
283+
274284
// this code makes it possible to find dotnet runtime on a page via global namespace, even when there are multiple runtimes at the same time
275285
let list: RuntimeList;
276286
if (!globalThisAny.getDotnetRuntime) {
@@ -345,7 +355,6 @@ const INTERNAL: any = {
345355
mono_wasm_enable_on_demand_gc: cwraps.mono_wasm_enable_on_demand_gc,
346356
mono_profiler_init_aot: cwraps.mono_profiler_init_aot,
347357
mono_wasm_set_runtime_options,
348-
mono_wasm_set_main_args: mono_wasm_set_main_args,
349358
mono_wasm_exec_regression: cwraps.mono_wasm_exec_regression,
350359
mono_method_resolve,//MarshalTests.cs
351360
mono_bind_static_method,// MarshalTests.cs

src/mono/wasm/runtime/method-calls.ts

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ export function mono_bind_static_method(fqn: string, signature?: ArgsMarshalStri
261261
return mono_bind_method(method, null, signature, fqn);
262262
}
263263

264-
export function mono_bind_assembly_entry_point(assembly: string, signature: ArgsMarshalString): Function {
264+
export function mono_bind_assembly_entry_point(assembly: string, signature?: ArgsMarshalString): Function {
265265
bindings_lazy_init();// TODO remove this once Blazor does better startup
266266

267267
const asm = cwraps.mono_wasm_assembly_load(assembly);
@@ -272,23 +272,20 @@ export function mono_bind_assembly_entry_point(assembly: string, signature: Args
272272
if (!method)
273273
throw new Error("Could not find entry point for assembly: " + assembly);
274274

275-
if (typeof signature === "undefined")
275+
if (!signature)
276276
signature = mono_method_get_call_signature(method);
277277

278-
return function (...args: any[]) {
279-
try {
280-
if (args.length > 0 && Array.isArray(args[0]))
281-
args[0] = js_array_to_mono_array(args[0], true, false);
282-
283-
const result = call_method(method, undefined, signature, args);
284-
return Promise.resolve(result);
285-
} catch (error) {
286-
return Promise.reject(error);
287-
}
278+
return async function (...args: any[]) {
279+
if (args.length > 0 && Array.isArray(args[0]))
280+
args[0] = js_array_to_mono_array(args[0], true, false);
281+
return call_method(method, undefined, signature!, args);
288282
};
289283
}
290284

291-
export function mono_call_assembly_entry_point(assembly: string, args: any[], signature: ArgsMarshalString): any {
285+
export function mono_call_assembly_entry_point(assembly: string, args?: any[], signature?: ArgsMarshalString): number {
286+
if (!args) {
287+
args = [[]];
288+
}
292289
return mono_bind_assembly_entry_point(assembly, signature)(...args);
293290
}
294291

src/mono/wasm/runtime/run.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Module } from "./imports";
2+
import { mono_call_assembly_entry_point } from "./method-calls";
3+
import { mono_wasm_set_main_args, runtime_is_initialized_reject } from "./startup";
4+
5+
6+
export async function mono_run_main_and_exit(main_assembly_name: string, args: string[]): Promise<void> {
7+
try {
8+
const result = await mono_run_main(main_assembly_name, args);
9+
set_exit_code(result);
10+
} catch (error) {
11+
set_exit_code(1, error);
12+
}
13+
}
14+
15+
export async function mono_run_main(main_assembly_name: string, args: string[]): Promise<number> {
16+
mono_wasm_set_main_args(main_assembly_name, args);
17+
return mono_call_assembly_entry_point(main_assembly_name, [args], "m");
18+
}
19+
20+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
21+
export function mono_on_abort(error: any): void {
22+
runtime_is_initialized_reject(error);
23+
set_exit_code(1, error);
24+
}
25+
26+
function set_exit_code(exit_code: number, reason?: any) {
27+
if (reason) {
28+
Module.printErr(reason.toString());
29+
if (reason.stack) {
30+
Module.printErr(reason.stack);
31+
}
32+
}
33+
const globalThisAny: any = globalThis;
34+
if (typeof globalThisAny.exit === "function") {
35+
globalThisAny.exit(exit_code);
36+
}
37+
else if (typeof globalThisAny.quit === "function") {
38+
globalThisAny.quit(exit_code);
39+
}
40+
}

0 commit comments

Comments
 (0)