Skip to content

Commit

Permalink
[browser] make cwraps more conditional (#87274)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelsavara authored Jun 19, 2023
1 parent 9e93f42 commit 3386b86
Show file tree
Hide file tree
Showing 17 changed files with 146 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

<ItemGroup>
<WasmExtraFilesToDeploy Include="index.html" />
<WasmExtraFilesToDeploy Include="main.js" />
<WasmExtraFilesToDeploy Include="mock.js" Condition="'$(MonoDiagnosticsMock)' == 'true'"/>
<!-- this option requires running dotnet-dsrouter and a real dotnet-trace client -->
<WasmExtraConfig Condition="'$(MonoDiagnosticsMock)' != 'true'" Include="environmentVariables" Value='
Expand Down
2 changes: 2 additions & 0 deletions src/mono/wasm/build/WasmApp.Native.targets
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@
<EmscriptenEnvVars Include="EM_FROZEN_CACHE=True" />
<EmscriptenEnvVars Include="DISABLE_LEGACY_JS_INTEROP=1" Condition="'$(WasmEnableLegacyJsInterop)' == 'false'" />
<EmscriptenEnvVars Include="DISABLE_LEGACY_JS_INTEROP=0" Condition="'$(WasmEnableLegacyJsInterop)' != 'false'" />
<EmscriptenEnvVars Include="ENABLE_AOT_PROFILER=$([System.Convert]::ToInt32($(WasmProfilers.Contains('aot'))))" />
<EmscriptenEnvVars Include="ENABLE_BROWSER_PROFILER=$([System.Convert]::ToInt32($(WasmProfilers.Contains('browser'))))" />
</ItemGroup>

<ItemGroup Condition="'$(WasmAllowUndefinedSymbols)' == 'true'">
Expand Down
82 changes: 47 additions & 35 deletions src/mono/wasm/runtime/cwraps.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

import MonoWasmThreads from "consts:monoWasmThreads";
import WasmEnableLegacyJsInterop from "consts:wasmEnableLegacyJsInterop";

import type {
MonoArray, MonoAssembly, MonoClass,
MonoMethod, MonoObject,
MonoType, MonoObjectRef, MonoStringRef, JSMarshalerArguments
} from "./types/internal";
import type { VoidPtr, CharPtrPtr, Int32Ptr, CharPtr, ManagedPointer } from "./types/emscripten";
import WasmEnableLegacyJsInterop from "consts:WasmEnableLegacyJsInterop";
import { disableLegacyJsInterop, Module } from "./globals";
import { linkerDisableLegacyJsInterop, linkerEnableAotProfiler, linkerEnableBrowserProfiler, Module } from "./globals";
import { mono_log_error } from "./logging";

type SigLine = [lazy: boolean, name: string, returnType: string | null, argTypes?: string[], opts?: any];
type SigLine = [lazyOrSkip: boolean | (() => boolean), name: string, returnType: string | null, argTypes?: string[], opts?: any];

const legacy_interop_cwraps: SigLine[] = WasmEnableLegacyJsInterop ? [
[true, "mono_wasm_array_get_ref", "void", ["number", "number", "number"]],
Expand All @@ -29,6 +31,17 @@ const legacy_interop_cwraps: SigLine[] = WasmEnableLegacyJsInterop ? [
[true, "mono_wasm_array_length_ref", "number", ["number"]],
] : [];

const diagnostics_cwraps: SigLine[] = MonoWasmThreads ? [
// MONO.diagnostics
[true, "mono_wasm_event_pipe_enable", "bool", ["string", "number", "number", "string", "bool", "number"]],
[true, "mono_wasm_event_pipe_session_start_streaming", "bool", ["number"]],
[true, "mono_wasm_event_pipe_session_disable", "bool", ["number"]],
[true, "mono_wasm_diagnostic_server_create_thread", "bool", ["string", "number"]],
[true, "mono_wasm_diagnostic_server_thread_attach_to_runtime", "void", []],
[true, "mono_wasm_diagnostic_server_post_resume_runtime", "void", []],
[true, "mono_wasm_diagnostic_server_create_stream", "number", []],
] : [];

// when the method is assigned/cached at usage, instead of being invoked directly from cwraps, it can't be marked lazy, because it would be re-bound on each call
const fn_signatures: SigLine[] = [
// MONO
Expand Down Expand Up @@ -61,22 +74,14 @@ const fn_signatures: SigLine[] = [
[true, "mono_wasm_assembly_get_entry_point", "number", ["number", "number"]],
[true, "mono_wasm_class_get_type", "number", ["number"]],

// MONO.diagnostics
[true, "mono_wasm_event_pipe_enable", "bool", ["string", "number", "number", "string", "bool", "number"]],
[true, "mono_wasm_event_pipe_session_start_streaming", "bool", ["number"]],
[true, "mono_wasm_event_pipe_session_disable", "bool", ["number"]],
[true, "mono_wasm_diagnostic_server_create_thread", "bool", ["string", "number"]],
[true, "mono_wasm_diagnostic_server_thread_attach_to_runtime", "void", []],
[true, "mono_wasm_diagnostic_server_post_resume_runtime", "void", []],
[true, "mono_wasm_diagnostic_server_create_stream", "number", []],

//INTERNAL
[false, "mono_wasm_exit", "void", ["number"]],
[true, "mono_wasm_getenv", "number", ["string"]],
[true, "mono_wasm_set_main_args", "void", ["number", "number"]],
[false, "mono_wasm_enable_on_demand_gc", "void", ["number"]],
// These two need to be lazy because they may be missing
[true, "mono_wasm_profiler_init_aot", "void", ["string"]],
[() => !linkerEnableAotProfiler, "mono_wasm_profiler_init_aot", "void", ["string"]],
[() => !linkerEnableBrowserProfiler, "mono_wasm_profiler_init_aot", "void", ["string"]],
[true, "mono_wasm_profiler_init_browser", "void", ["number"]],
[false, "mono_wasm_exec_regression", "number", ["number", "string"]],
[false, "mono_wasm_invoke_method_bound", "number", ["number", "number", "number"]],
Expand Down Expand Up @@ -132,6 +137,7 @@ const fn_signatures: SigLine[] = [
[true, "mono_jiterp_get_opcode_info", "number", ["number", "number"]],
[true, "mono_wasm_is_zero_page_reserved", "number", []],
[true, "mono_jiterp_is_special_interface", "number", ["number"]],
...diagnostics_cwraps,
...legacy_interop_cwraps
];

Expand All @@ -152,6 +158,22 @@ export interface t_LegacyCwraps {
mono_wasm_array_length_ref(array: MonoObjectRef): number;
}

export interface t_DiagnosticsCwraps {
// MONO.diagnostics
mono_wasm_event_pipe_enable(outputPath: string | null, stream: VoidPtr, bufferSizeInMB: number, providers: string, rundownRequested: boolean, outSessionId: VoidPtr): boolean;
mono_wasm_event_pipe_session_start_streaming(sessionId: number): boolean;
mono_wasm_event_pipe_session_disable(sessionId: number): boolean;
mono_wasm_diagnostic_server_create_thread(websocketURL: string, threadIdOutPtr: VoidPtr): boolean;
mono_wasm_diagnostic_server_thread_attach_to_runtime(): void;
mono_wasm_diagnostic_server_post_resume_runtime(): void;
mono_wasm_diagnostic_server_create_stream(): VoidPtr;
}

export interface t_ProfilerCwraps {
mono_wasm_profiler_init_aot(desc: string): void;
mono_wasm_profiler_init_browser(desc: string): void;
}

export interface t_Cwraps {
// MONO
mono_wasm_register_root(start: VoidPtr, size: number, name: string): number;
Expand Down Expand Up @@ -182,23 +204,11 @@ export interface t_Cwraps {
mono_wasm_assembly_get_entry_point(assembly: MonoAssembly, idx: number): MonoMethod;
mono_wasm_intern_string_ref(strRef: MonoStringRef): void;


// MONO.diagnostics
mono_wasm_event_pipe_enable(outputPath: string | null, stream: VoidPtr, bufferSizeInMB: number, providers: string, rundownRequested: boolean, outSessionId: VoidPtr): boolean;
mono_wasm_event_pipe_session_start_streaming(sessionId: number): boolean;
mono_wasm_event_pipe_session_disable(sessionId: number): boolean;
mono_wasm_diagnostic_server_create_thread(websocketURL: string, threadIdOutPtr: VoidPtr): boolean;
mono_wasm_diagnostic_server_thread_attach_to_runtime(): void;
mono_wasm_diagnostic_server_post_resume_runtime(): void;
mono_wasm_diagnostic_server_create_stream(): VoidPtr;

//INTERNAL
mono_wasm_exit(exit_code: number): number;
mono_wasm_getenv(name: string): CharPtr;
mono_wasm_enable_on_demand_gc(enable: number): void;
mono_wasm_set_main_args(argc: number, argv: VoidPtr): void;
mono_wasm_profiler_init_aot(desc: string): void;
mono_wasm_profiler_init_browser(desc: string): void;
mono_wasm_exec_regression(verbose_level: number, image: string): number;
mono_wasm_invoke_method_bound(method: MonoMethod, args: JSMarshalerArguments, fail: MonoStringRef): number;
mono_wasm_write_managed_pointer_unsafe(destination: VoidPtr | MonoObjectRef, pointer: ManagedPointer): void;
Expand Down Expand Up @@ -265,6 +275,8 @@ const wrapped_c_functions: t_Cwraps = <any>{};

export default wrapped_c_functions;
export const legacy_c_functions: t_LegacyCwraps & t_Cwraps = wrapped_c_functions as any;
export const diagnostics_c_functions: t_DiagnosticsCwraps & t_Cwraps = wrapped_c_functions as any;
export const profiler_c_functions: t_ProfilerCwraps & t_Cwraps = wrapped_c_functions as any;

// see src/mono/wasm/driver.c I52_ERROR_xxx
export const enum I52Error {
Expand All @@ -275,7 +287,7 @@ export const enum I52Error {

const fastCwrapTypes = ["void", "number", null];

function cwrap(name: string, returnType: string | null, argTypes: string[] | undefined, opts: any, throwOnError: boolean): Function {
function cwrap(name: string, returnType: string | null, argTypes: string[] | undefined, opts: any): Function {
// Attempt to bypass emscripten's generated wrapper if it is safe to do so
let fce =
// Special cwrap options disable the fast path
Expand All @@ -301,29 +313,29 @@ function cwrap(name: string, returnType: string | null, argTypes: string[] | und

if (typeof (fce) !== "function") {
const msg = `cwrap ${name} not found or not a function`;
if (throwOnError)
throw new Error(msg);
else
mono_log_error("" + msg);
throw new Error(msg);
}
return fce;
}

export function init_c_exports(): void {
const lfns = WasmEnableLegacyJsInterop && !disableLegacyJsInterop ? legacy_interop_cwraps : [];
const lfns = WasmEnableLegacyJsInterop && !linkerDisableLegacyJsInterop ? legacy_interop_cwraps : [];
const fns = [...fn_signatures, ...lfns];
for (const sig of fns) {
const wf: any = wrapped_c_functions;
const [lazy, name, returnType, argTypes, opts] = sig;
if (lazy) {
const [lazyOrSkip, name, returnType, argTypes, opts] = sig;
const maybeSkip = typeof lazyOrSkip === "function";
if (lazyOrSkip === true || maybeSkip) {
// lazy init on first run
wf[name] = function (...args: any[]) {
const fce = cwrap(name, returnType, argTypes, opts, true);
const isNotSkipped = !maybeSkip || !lazyOrSkip();
mono_assert(isNotSkipped, () => `cwrap ${name} should not be called when binding was skipped`);
const fce = cwrap(name, returnType, argTypes, opts);
wf[name] = fce;
return fce(...args);
};
} else {
const fce = cwrap(name, returnType, argTypes, opts, false);
const fce = cwrap(name, returnType, argTypes, opts);
wf[name] = fce;
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/mono/wasm/runtime/diagnostics/browser/controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

import cwraps from "../../cwraps";
import MonoWasmThreads from "consts:monoWasmThreads";

import { diagnostics_c_functions as cwraps } from "../../cwraps";
import { INTERNAL } from "../../globals";
import { mono_log_info, mono_log_debug, mono_log_warn } from "../../logging";
import { withStackAlloc, getI32 } from "../../memory";
Expand Down Expand Up @@ -52,6 +54,7 @@ export function getController(): ServerController {
}

export async function startDiagnosticServer(websocket_url: string): Promise<ServerController | null> {
mono_assert(MonoWasmThreads, "The diagnostic server requires threads to be enabled during build time.");
const sizeOfPthreadT = 4;
mono_log_info(`starting the diagnostic server url: ${websocket_url}`);
const result: number | undefined = withStackAlloc(sizeOfPthreadT, (pthreadIdPtr) => {
Expand Down
34 changes: 17 additions & 17 deletions src/mono/wasm/runtime/diagnostics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,22 @@ export async function mono_wasm_init_diagnostics(): Promise<void> {
if (!MonoWasmThreads) {
mono_log_warn("ignoring diagnostics options because this runtime does not support diagnostics");
return;
} else {
const options = diagnostic_options_from_environment();
if (!options)
return;
diagnosticsInitialized = true;
if (!is_nullish(options?.server)) {
if (options.server.connectUrl === undefined || typeof (options.server.connectUrl) !== "string") {
throw new Error("server.connectUrl must be a string");
}
const url = options.server.connectUrl;
const suspend = boolsyOption(options.server.suspend);
const controller = await startDiagnosticServer(url);
if (controller) {
diagnosticsServerEnabled = true;
if (suspend) {
suspendOnStartup = true;
}
}
const options = diagnostic_options_from_environment();
if (!options)
return;
diagnosticsInitialized = true;
if (!is_nullish(options?.server)) {
if (options.server.connectUrl === undefined || typeof (options.server.connectUrl) !== "string") {
throw new Error("server.connectUrl must be a string");
}
const url = options.server.connectUrl;
const suspend = boolsyOption(options.server.suspend);
const controller = await startDiagnosticServer(url);
if (controller) {
diagnosticsServerEnabled = true;
if (suspend) {
suspendOnStartup = true;
}
}
}
Expand Down Expand Up @@ -144,6 +143,7 @@ function diagnostic_options_from_ports_spec(val: string): DiagnosticOptions | nu
}

export function mono_wasm_diagnostic_server_on_runtime_server_init(out_options: VoidPtr): void {
mono_assert(MonoWasmThreads, "The diagnostic server requires threads to be enabled during build time.");
if (diagnosticsServerEnabled) {
/* called on the main thread when the runtime is sufficiently initialized */
const controller = getController();
Expand Down
6 changes: 4 additions & 2 deletions src/mono/wasm/runtime/diagnostics/server_pthread/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
// The .NET Foundation licenses this file to you under the MIT license.

/// <reference lib="webworker" />

import MonoWasmThreads from "consts:monoWasmThreads";
import monoDiagnosticsMock from "consts:monoDiagnosticsMock";

import { PromiseAndController, assertNever } from "../../types/internal";
import { pthread_self } from "../../pthreads/worker";
import { createPromiseController } from "../../globals";
import cwraps from "../../cwraps";
import { diagnostics_c_functions as cwraps } from "../../cwraps";
import { EventPipeSessionIDImpl } from "../shared/types";
import { CharPtr } from "../../types/emscripten";
import {
Expand Down Expand Up @@ -284,6 +285,7 @@ function parseProtocolCommand(data: ArrayBuffer | BinaryProtocolCommand): ParseC

/// Called by the runtime to initialize the diagnostic server workers
export function mono_wasm_diagnostic_server_on_server_thread_created(websocketUrlPtr: CharPtr): void {
mono_assert(MonoWasmThreads, "The diagnostic server requires threads to be enabled during build time.");
const websocketUrl = utf8ToString(websocketUrlPtr);
mono_log_debug(`mono_wasm_diagnostic_server_on_server_thread_created, url ${websocketUrl}`);
let mock: PromiseAndController<Mock> | undefined = undefined;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
import {
EventPipeSessionIDImpl
} from "../shared/types";
import MonoWasmThreads from "consts:monoWasmThreads";

import { EventPipeSessionIDImpl } from "../shared/types";
import { EventPipeSocketConnection, takeOverSocket } from "./socket-connection";
import { StreamQueue, allocateQueue } from "./stream-queue";
import type { MockRemoteSocket } from "../mock";
import type { VoidPtr } from "../../types/emscripten";
import cwraps from "../../cwraps";
import { diagnostics_c_functions as cwraps } from "../../cwraps";
import {
EventPipeCommandCollectTracing2,
EventPipeCollectTracingCommandProvider,
Expand All @@ -24,6 +24,7 @@ export class EventPipeStreamingSession {
}

export async function makeEventPipeStreamingSession(ws: WebSocket | MockRemoteSocket, cmd: EventPipeCommandCollectTracing2): Promise<EventPipeStreamingSession> {
mono_assert(MonoWasmThreads, "The diagnostic server requires threads to be enabled during build time.");
// First, create the native IPC stream and get its queue.
const ipcStreamAddr = cwraps.mono_wasm_diagnostic_server_create_stream(); // FIXME: this should be a wrapped in a JS object so we can free it when we're done.
const queueAddr = getQueueAddrFromStreamAddr(ipcStreamAddr);
Expand Down
2 changes: 1 addition & 1 deletion src/mono/wasm/runtime/diagnostics/shared/create-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import * as memory from "../../memory";
import { VoidPtr } from "../../types/emscripten";
import cwraps from "../../cwraps";
import { diagnostics_c_functions as cwraps } from "../../cwraps";
import type { EventPipeSessionIDImpl } from "./types";

const sizeOfInt32 = 4;
Expand Down
30 changes: 26 additions & 4 deletions src/mono/wasm/runtime/es6/dotnet.es6.lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@

// because we can't pass custom define symbols to acorn optimizer, we use environment variables to pass other build options
const DISABLE_LEGACY_JS_INTEROP = process.env.DISABLE_LEGACY_JS_INTEROP === "1";
const ENABLE_BROWSER_PROFILER = process.env.ENABLE_BROWSER_PROFILER === "1";
const ENABLE_AOT_PROFILER = process.env.ENABLE_AOT_PROFILER === "1";

function setup(disableLegacyJsInterop) {
function setup(linkerSetup) {
const pthreadReplacements = {};
const dotnet_replacements = {
fetch: globalThis.fetch,
Expand All @@ -29,8 +31,8 @@ function setup(disableLegacyJsInterop) {

Module.__dotnet_runtime.passEmscriptenInternals({
isPThread: ENVIRONMENT_IS_PTHREAD,
disableLegacyJsInterop,
quit_, ExitStatus
quit_, ExitStatus,
...linkerSetup
});
Module.__dotnet_runtime.initializeReplacements(dotnet_replacements);

Expand Down Expand Up @@ -58,7 +60,11 @@ function setup(disableLegacyJsInterop) {
}

const postset = `
DOTNET.setup(${DISABLE_LEGACY_JS_INTEROP ? "true" : "false"});
DOTNET.setup({ `+
`linkerDisableLegacyJsInterop: ${DISABLE_LEGACY_JS_INTEROP ? "true" : "false"},` +
`linkerEnableAotProfiler: ${ENABLE_AOT_PROFILER ? "true" : "false"}, ` +
`linkerEnableBrowserProfiler: ${ENABLE_BROWSER_PROFILER ? "true" : "false"}` +
`});
`;

const DotnetSupportLib = {
Expand Down Expand Up @@ -131,6 +137,22 @@ linked_functions = [...linked_functions,
"mono_wasm_install_js_worker_interop",
"mono_wasm_uninstall_js_worker_interop",
]

if (ENABLE_AOT_PROFILER) {
linked_functions = [...linked_functions,
"mono_wasm_invoke_js_with_args_ref",
"mono_wasm_get_object_property_ref",
"mono_wasm_set_object_property_ref",
"mono_wasm_get_by_index_ref",
"mono_wasm_set_by_index_ref",
"mono_wasm_get_global_object_ref",
"mono_wasm_create_cs_owned_object_ref",
"mono_wasm_typed_array_to_array_ref",
"mono_wasm_typed_array_from_ref",
"mono_wasm_invoke_js_blazor",
]
}

#endif
if (!DISABLE_LEGACY_JS_INTEROP) {
linked_functions = [...linked_functions,
Expand Down
Loading

0 comments on commit 3386b86

Please sign in to comment.