Skip to content

Commit

Permalink
[wasm] Decrease the startup ceremony (#62587)
Browse files Browse the repository at this point in the history
* new API MONO.mono_run_main_and_exit and MONO.mono_run_main
* default onAbort
* console-v8-cjs sample
* reduced setup ceremony
  • Loading branch information
pavelsavara authored Dec 10, 2021
1 parent 7b2925b commit 25c2073
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 24 deletions.
18 changes: 18 additions & 0 deletions src/mono/sample/wasm/console-v8-cjs/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Threading.Tasks;

public class Test
{
public static async Task<int> Main(string[] args)
{
await Task.Delay(1);
Console.WriteLine("Hello World!");
for (int i = 0; i < args.Length; i++) {
Console.WriteLine($"args[{i}] = {args[i]}");
}
return args.Length;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<WasmCopyAppZipToHelixTestDir Condition="'$(ArchiveTests)' == 'true'">true</WasmCopyAppZipToHelixTestDir>
<WasmMainJSPath>main.js</WasmMainJSPath>
<WasmGenerateRunV8Script>true</WasmGenerateRunV8Script>
<WasmEnableES6>false</WasmEnableES6>
</PropertyGroup>

<PropertyGroup>
<_SampleProject>Wasm.Console.V8.CJS.Sample.csproj</_SampleProject>
<_SampleAssembly>Wasm.Console.V8.CJS.Sample.dll</_SampleAssembly>
</PropertyGroup>

<Target Name="RunSample" DependsOnTargets="RunSampleWithV8" />
</Project>
11 changes: 11 additions & 0 deletions src/mono/sample/wasm/console-v8-cjs/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
load("./dotnet.js")

const dllName = "Wasm.Console.V8.CJS.Sample.dll";
const app_args = Array.from(arguments);

async function main() {
const { MONO } = await createDotnetRuntime();
await MONO.mono_run_main_and_exit(dllName, app_args);
}

main();
6 changes: 5 additions & 1 deletion src/mono/wasm/runtime/cjs/dotnet.cjs.pre.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ if (ENVIRONMENT_IS_GLOBAL) {
globalThis.Module.ready = Module.ready;
Module = createDotnetRuntime = globalThis.Module;
}
else if (typeof createDotnetRuntime === "object") {
Module = { ready: Module.ready, __undefinedConfig: Object.keys(createDotnetRuntime).length === 1 };
Object.assign(Module, createDotnetRuntime);
createDotnetRuntime = Module;
}
else if (typeof createDotnetRuntime === "function") {
ENVIRONMENT_IS_GLOBAL = false;
Module = { ready: Module.ready };
const extension = createDotnetRuntime({ MONO, BINDING, INTERNAL, Module })
if (extension.ready) {
Expand Down
12 changes: 10 additions & 2 deletions src/mono/wasm/runtime/dotnet.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ declare interface EmscriptenModule {
preInit?: (() => any)[];
preRun?: (() => any)[];
postRun?: (() => any)[];
onAbort?: {
(error: any): void;
};
onRuntimeInitialized?: () => any;
instantiateWasm: (imports: any, successCallback: Function) => any;
}
Expand Down Expand Up @@ -258,7 +261,7 @@ declare function unbox_mono_obj(mono_obj: MonoObject): any;
declare function mono_array_to_js_array(mono_array: MonoArray): any[] | null;

declare function mono_bind_static_method(fqn: string, signature?: ArgsMarshalString): Function;
declare function mono_call_assembly_entry_point(assembly: string, args: any[], signature: ArgsMarshalString): any;
declare function mono_call_assembly_entry_point(assembly: string, args?: any[], signature?: ArgsMarshalString): number;

declare function mono_wasm_load_bytes_into_heap(bytes: Uint8Array): VoidPtr;

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

declare function mono_run_main_and_exit(main_assembly_name: string, args: string[]): Promise<void>;
declare function mono_run_main(main_assembly_name: string, args: string[]): Promise<number>;

declare const MONO: {
mono_wasm_setenv: typeof mono_wasm_setenv;
mono_wasm_load_bytes_into_heap: typeof mono_wasm_load_bytes_into_heap;
Expand All @@ -293,6 +299,8 @@ declare const MONO: {
mono_wasm_new_root_buffer: typeof mono_wasm_new_root_buffer;
mono_wasm_new_root: typeof mono_wasm_new_root;
mono_wasm_release_roots: typeof mono_wasm_release_roots;
mono_run_main: typeof mono_run_main;
mono_run_main_and_exit: typeof mono_run_main_and_exit;
mono_wasm_add_assembly: (name: string, data: VoidPtr, size: number) => number;
mono_wasm_load_runtime: (unused: string, debug_level: number) => void;
config: MonoConfig | MonoConfigError;
Expand Down Expand Up @@ -342,7 +350,7 @@ interface DotnetPublicAPI {
};
}

declare function createDotnetRuntime(moduleFactory: (api: DotnetPublicAPI) => DotnetModuleConfig): Promise<DotnetPublicAPI>;
declare function createDotnetRuntime(moduleFactory: DotnetModuleConfig | ((api: DotnetPublicAPI) => DotnetModuleConfig)): Promise<DotnetPublicAPI>;
declare type CreateDotnetRuntimeType = typeof createDotnetRuntime;
declare global {
function getDotnetRuntime(runtimeId: number): DotnetPublicAPI | undefined;
Expand Down
5 changes: 5 additions & 0 deletions src/mono/wasm/runtime/es6/dotnet.es6.pre.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ if (typeof createDotnetRuntime === "function") {
Object.assign(Module, extension);
createDotnetRuntime = Module;
}
else if (typeof createDotnetRuntime === "object") {
Module = { ready: Module.ready, __undefinedConfig: Object.keys(createDotnetRuntime).length === 1 };
Object.assign(Module, createDotnetRuntime);
createDotnetRuntime = Module;
}
else {
throw new Error("MONO_WASM: Can't use moduleFactory callback of createDotnetRuntime function.")
}
Expand Down
2 changes: 1 addition & 1 deletion src/mono/wasm/runtime/export-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { EmscriptenModule, VoidPtr } from "./types/emscripten";
// this files has all public exports from the dotnet.js module
// -----------------------------------------------------------

declare function createDotnetRuntime(moduleFactory: (api: DotnetPublicAPI) => DotnetModuleConfig): Promise<DotnetPublicAPI>;
declare function createDotnetRuntime(moduleFactory: DotnetModuleConfig | ((api: DotnetPublicAPI) => DotnetModuleConfig)): Promise<DotnetPublicAPI>;
declare type CreateDotnetRuntimeType = typeof createDotnetRuntime;

// Here, declare things that go in the global namespace, or augment existing declarations in the global namespace
Expand Down
13 changes: 11 additions & 2 deletions src/mono/wasm/runtime/exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ 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,
mono_wasm_set_main_args,
mono_wasm_pre_init,
mono_wasm_runtime_is_initialized,
mono_wasm_on_runtime_initialized
Expand Down Expand Up @@ -68,6 +67,7 @@ import {
import { create_weak_ref } from "./weak-ref";
import { fetch_like, readAsync_like } from "./polyfills";
import { EmscriptenModule } from "./types/emscripten";
import { mono_on_abort, mono_run_main, mono_run_main_and_exit } from "./run";

const MONO = {
// current "public" MONO API
Expand All @@ -81,6 +81,8 @@ const MONO = {
mono_wasm_new_root_buffer,
mono_wasm_new_root,
mono_wasm_release_roots,
mono_run_main,
mono_run_main_and_exit,

// for Blazor's future!
mono_wasm_add_assembly: cwraps.mono_wasm_add_assembly,
Expand Down Expand Up @@ -157,6 +159,10 @@ function initializeImportsAndExports(
Configuration
}
};
if (exports.module.__undefinedConfig) {
module.disableDotnet6Compatibility = true;
module.configSrc = "./mono-config.json";
}

// these could be overriden on DotnetModuleConfig
if (!module.preInit) {
Expand Down Expand Up @@ -271,6 +277,10 @@ function initializeImportsAndExports(
});
}

if (!module.onAbort) {
module.onAbort = () => mono_on_abort;
}

// this code makes it possible to find dotnet runtime on a page via global namespace, even when there are multiple runtimes at the same time
let list: RuntimeList;
if (!globalThisAny.getDotnetRuntime) {
Expand Down Expand Up @@ -345,7 +355,6 @@ const INTERNAL: any = {
mono_wasm_enable_on_demand_gc: cwraps.mono_wasm_enable_on_demand_gc,
mono_profiler_init_aot: cwraps.mono_profiler_init_aot,
mono_wasm_set_runtime_options,
mono_wasm_set_main_args: mono_wasm_set_main_args,
mono_wasm_exec_regression: cwraps.mono_wasm_exec_regression,
mono_method_resolve,//MarshalTests.cs
mono_bind_static_method,// MarshalTests.cs
Expand Down
23 changes: 10 additions & 13 deletions src/mono/wasm/runtime/method-calls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ export function mono_bind_static_method(fqn: string, signature?: ArgsMarshalStri
return mono_bind_method(method, null, signature, fqn);
}

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

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

if (typeof signature === "undefined")
if (!signature)
signature = mono_method_get_call_signature(method);

return function (...args: any[]) {
try {
if (args.length > 0 && Array.isArray(args[0]))
args[0] = js_array_to_mono_array(args[0], true, false);

const result = call_method(method, undefined, signature, args);
return Promise.resolve(result);
} catch (error) {
return Promise.reject(error);
}
return async function (...args: any[]) {
if (args.length > 0 && Array.isArray(args[0]))
args[0] = js_array_to_mono_array(args[0], true, false);
return call_method(method, undefined, signature!, args);
};
}

export function mono_call_assembly_entry_point(assembly: string, args: any[], signature: ArgsMarshalString): any {
export function mono_call_assembly_entry_point(assembly: string, args?: any[], signature?: ArgsMarshalString): number {
if (!args) {
args = [[]];
}
return mono_bind_assembly_entry_point(assembly, signature)(...args);
}

Expand Down
40 changes: 40 additions & 0 deletions src/mono/wasm/runtime/run.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Module } from "./imports";
import { mono_call_assembly_entry_point } from "./method-calls";
import { mono_wasm_set_main_args, runtime_is_initialized_reject } from "./startup";


export async function mono_run_main_and_exit(main_assembly_name: string, args: string[]): Promise<void> {
try {
const result = await mono_run_main(main_assembly_name, args);
set_exit_code(result);
} catch (error) {
set_exit_code(1, error);
}
}

export async function mono_run_main(main_assembly_name: string, args: string[]): Promise<number> {
mono_wasm_set_main_args(main_assembly_name, args);
return mono_call_assembly_entry_point(main_assembly_name, [args], "m");
}

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function mono_on_abort(error: any): void {
runtime_is_initialized_reject(error);
set_exit_code(1, error);
}

function set_exit_code(exit_code: number, reason?: any) {
if (reason) {
Module.printErr(reason.toString());
if (reason.stack) {
Module.printErr(reason.stack);
}
}
const globalThisAny: any = globalThis;
if (typeof globalThisAny.exit === "function") {
globalThisAny.exit(exit_code);
}
else if (typeof globalThisAny.quit === "function") {
globalThisAny.quit(exit_code);
}
}
1 change: 1 addition & 0 deletions src/mono/wasm/runtime/types/emscripten.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export declare interface EmscriptenModule {
preInit?: (() => any)[];
preRun?: (() => any)[];
postRun?: (() => any)[];
onAbort?: { (error: any): void };
onRuntimeInitialized?: () => any;
instantiateWasm: (imports: any, successCallback: Function) => any;
}
Expand Down
6 changes: 1 addition & 5 deletions src/mono/wasm/test-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,9 @@ const App = {
return;
}
try {

const main_assembly_name = processedArguments.applicationArgs[1];
const app_args = processedArguments.applicationArgs.slice(2);
INTERNAL.mono_wasm_set_main_args(main_assembly_name, app_args);

// Automatic signature isn't working correctly
const result = await BINDING.call_assembly_entry_point(main_assembly_name, [app_args], "m");
const result = await MONO.mono_run_main(main_assembly_name, app_args);
set_exit_code(result);
} catch (error) {
set_exit_code(1, error);
Expand Down

0 comments on commit 25c2073

Please sign in to comment.