From 357bc117044a7e47a68ef8a9fa0de525cd464636 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 28 Mar 2024 17:09:55 +0100 Subject: [PATCH 1/5] disableManagedTransition on UI thread --- src/mono/browser/runtime/marshal-to-cs.ts | 6 +++--- src/mono/browser/runtime/marshal-to-js.ts | 6 +++--- src/mono/browser/runtime/roots.ts | 5 ++++- src/mono/browser/runtime/startup.ts | 2 ++ src/mono/browser/runtime/strings.ts | 4 ++++ src/mono/browser/runtime/types/internal.ts | 1 + 6 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/mono/browser/runtime/marshal-to-cs.ts b/src/mono/browser/runtime/marshal-to-cs.ts index 6e954ae983df39..800f5a370e1812 100644 --- a/src/mono/browser/runtime/marshal-to-cs.ts +++ b/src/mono/browser/runtime/marshal-to-cs.ts @@ -22,7 +22,6 @@ import { _zero_region, localHeapViewF64, localHeapViewI32, localHeapViewU8 } fro import { stringToMonoStringRoot, stringToUTF16 } from "./strings"; import { JSMarshalerArgument, JSMarshalerArguments, JSMarshalerType, MarshalerToCs, MarshalerToJs, BoundMarshalerToCs, MarshalerType } from "./types/internal"; import { TypedArray } from "./types/emscripten"; -import { gc_locked } from "./gc-lock"; export const jsinteropDoc = "For more information see https://aka.ms/dotnet-wasm-jsinterop"; @@ -224,6 +223,7 @@ function _marshal_string_to_cs_impl (arg: JSMarshalerArgument, value: string) { set_arg_intptr(arg, buffer); set_arg_length(arg, value.length); } else { + mono_assert(!WasmEnableThreads, "Marshaling strings by reference is not supported in multithreaded mode"); const root = get_string_root(arg); try { stringToMonoStringRoot(value, root); @@ -463,7 +463,7 @@ export function marshal_array_to_cs_impl (arg: JSMarshalerArgument, value: Array mono_check(Array.isArray(value), "Value is not an Array"); _zero_region(buffer_ptr, buffer_length); if (!WasmEnableJsInteropByValue) { - mono_assert(!WasmEnableThreads || !gc_locked, "GC must not be locked when creating a GC root"); + mono_assert(!WasmEnableThreads, "Marshaling strings by reference is not supported in multithreaded mode"); cwraps.mono_wasm_register_root(buffer_ptr, buffer_length, "marshal_array_to_cs"); } for (let index = 0; index < length; index++) { @@ -474,7 +474,7 @@ export function marshal_array_to_cs_impl (arg: JSMarshalerArgument, value: Array mono_check(Array.isArray(value), "Value is not an Array"); _zero_region(buffer_ptr, buffer_length); if (!WasmEnableJsInteropByValue) { - mono_assert(!WasmEnableThreads || !gc_locked, "GC must not be locked when creating a GC root"); + mono_assert(!WasmEnableThreads, "Marshaling objects by reference is not supported in multithreaded mode"); cwraps.mono_wasm_register_root(buffer_ptr, buffer_length, "marshal_array_to_cs"); } for (let index = 0; index < length; index++) { diff --git a/src/mono/browser/runtime/marshal-to-js.ts b/src/mono/browser/runtime/marshal-to-js.ts index 1cc4575bf55b87..e636aa5f52974b 100644 --- a/src/mono/browser/runtime/marshal-to-js.ts +++ b/src/mono/browser/runtime/marshal-to-js.ts @@ -22,7 +22,6 @@ import { TypedArray } from "./types/emscripten"; import { get_marshaler_to_cs_by_type, jsinteropDoc, marshal_exception_to_cs } from "./marshal-to-cs"; import { localHeapViewF64, localHeapViewI32, localHeapViewU8 } from "./memory"; import { call_delegate } from "./managed-exports"; -import { gc_locked } from "./gc-lock"; import { mono_log_debug } from "./logging"; import { invoke_later_when_on_ui_thread_async } from "./invoke-js"; @@ -390,6 +389,7 @@ export function marshal_string_to_js (arg: JSMarshalerArgument): string | null { Module._free(buffer as any); return value; } else { + mono_assert(!WasmEnableThreads, "Marshaling strings by reference is not supported in multithreaded mode"); const root = get_string_root(arg); try { const value = monoStringToString(root); @@ -504,7 +504,7 @@ function _marshal_array_to_js_impl (arg: JSMarshalerArgument, element_type: Mars result[index] = marshal_string_to_js(element_arg); } if (!WasmEnableJsInteropByValue) { - mono_assert(!WasmEnableThreads || !gc_locked, "GC must not be locked when disposing a GC root"); + mono_assert(!WasmEnableThreads, "Marshaling string by reference is not supported in multithreaded mode"); cwraps.mono_wasm_deregister_root(buffer_ptr); } } else if (element_type == MarshalerType.Object) { @@ -514,7 +514,7 @@ function _marshal_array_to_js_impl (arg: JSMarshalerArgument, element_type: Mars result[index] = _marshal_cs_object_to_js(element_arg); } if (!WasmEnableJsInteropByValue) { - mono_assert(!WasmEnableThreads || !gc_locked, "GC must not be locked when disposing a GC root"); + mono_assert(!WasmEnableThreads, "Marshaling objects by reference is not supported in multithreaded mode"); cwraps.mono_wasm_deregister_root(buffer_ptr); } } else if (element_type == MarshalerType.JSObject) { diff --git a/src/mono/browser/runtime/roots.ts b/src/mono/browser/runtime/roots.ts index cef2a17f0decbe..6068439c4652a3 100644 --- a/src/mono/browser/runtime/roots.ts +++ b/src/mono/browser/runtime/roots.ts @@ -4,7 +4,7 @@ import WasmEnableThreads from "consts:wasmEnableThreads"; import cwraps from "./cwraps"; -import { Module, mono_assert } from "./globals"; +import { Module, mono_assert, runtimeHelpers } from "./globals"; import { VoidPtr, ManagedPointer, NativePointer } from "./types/emscripten"; import { MonoObjectRef, MonoObjectRefNull, MonoObject, is_nullish, WasmRoot, WasmRootBuffer } from "./types/internal"; import { _zero_region, localHeapViewU32 } from "./memory"; @@ -24,6 +24,7 @@ const _external_root_free_instances: WasmExternalRoot[] = []; * For small numbers of roots, it is preferable to use the mono_wasm_new_root and mono_wasm_new_roots APIs instead. */ export function mono_wasm_new_root_buffer (capacity: number, name?: string): WasmRootBuffer { + if (WasmEnableThreads && runtimeHelpers.disableManagedTransition) throw new Error("External roots are not supported when threads are enabled"); if (capacity <= 0) throw new Error("capacity >= 1"); @@ -44,6 +45,7 @@ export function mono_wasm_new_root_buffer (capacity: number, name?: string): Was * Releasing this root will not de-allocate the root space. You still need to call .release(). */ export function mono_wasm_new_external_root (address: VoidPtr | MonoObjectRef): WasmRoot { + if (WasmEnableThreads && runtimeHelpers.disableManagedTransition) throw new Error("External roots are not supported when threads are enabled"); let result: WasmExternalRoot; if (!address) @@ -67,6 +69,7 @@ export function mono_wasm_new_external_root (address: Void * When you are done using the root you must call its .release() method. */ export function mono_wasm_new_root (value: T | undefined = undefined): WasmRoot { + if (WasmEnableThreads && runtimeHelpers.disableManagedTransition) throw new Error("External roots are not supported when threads are enabled"); let result: WasmRoot; if (_scratch_root_free_instances.length > 0) { diff --git a/src/mono/browser/runtime/startup.ts b/src/mono/browser/runtime/startup.ts index 2ab5110ec46875..273c0baf808d96 100644 --- a/src/mono/browser/runtime/startup.ts +++ b/src/mono/browser/runtime/startup.ts @@ -296,6 +296,8 @@ async function onRuntimeInitializedAsync (userOnRuntimeInitialized: () => void) runtimeHelpers.runtimeReady = true; update_thread_info(); bindings_init(); + + runtimeHelpers.disableManagedTransition = true; } else { // load mono runtime and apply environment settings (if necessary) await start_runtime(); diff --git a/src/mono/browser/runtime/strings.ts b/src/mono/browser/runtime/strings.ts index c5cb3e7b321797..89a843b7c1ff03 100644 --- a/src/mono/browser/runtime/strings.ts +++ b/src/mono/browser/runtime/strings.ts @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +import WasmEnableThreads from "consts:wasmEnableThreads"; + import { mono_wasm_new_root, mono_wasm_new_root_buffer } from "./roots"; import { MonoString, MonoStringNull, WasmRoot, WasmRootBuffer } from "./types/internal"; import { Module } from "./globals"; @@ -118,6 +120,7 @@ export function stringToUTF16Ptr (str: string): VoidPtr { } export function monoStringToString (root: WasmRoot): string | null { + if (WasmEnableThreads) return null as any; if (root.value === MonoStringNull) return null; @@ -152,6 +155,7 @@ export function monoStringToString (root: WasmRoot): string | null { } export function stringToMonoStringRoot (string: string, result: WasmRoot): void { + if (WasmEnableThreads) return; result.clear(); if (string === null) diff --git a/src/mono/browser/runtime/types/internal.ts b/src/mono/browser/runtime/types/internal.ts index b333e254703b02..2017a86922423e 100644 --- a/src/mono/browser/runtime/types/internal.ts +++ b/src/mono/browser/runtime/types/internal.ts @@ -206,6 +206,7 @@ export type RuntimeHelpers = { getMemory(): WebAssembly.Memory, getWasmIndirectFunctionTable(): WebAssembly.Table, runtimeReady: boolean, + disableManagedTransition: boolean, monoThreadInfo: PThreadInfo, proxyGCHandle: GCHandle | undefined, managedThreadTID: PThreadPtr, From 46c289ea1fe871bfc246ba9b3d81fa3d74a9bbcb Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 28 Mar 2024 17:34:52 +0100 Subject: [PATCH 2/5] link --- src/mono/browser/runtime/startup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/browser/runtime/startup.ts b/src/mono/browser/runtime/startup.ts index 273c0baf808d96..24fbb1d16a04f2 100644 --- a/src/mono/browser/runtime/startup.ts +++ b/src/mono/browser/runtime/startup.ts @@ -288,7 +288,7 @@ async function onRuntimeInitializedAsync (userOnRuntimeInitialized: () => void) runtimeHelpers.ioThreadTID = tcwraps.mono_wasm_create_io_thread(); } - // TODO make UI thread not managed + // TODO make UI thread not managed/attached https://github.com/dotnet/runtime/issues/100411 tcwraps.mono_wasm_register_ui_thread(); monoThreadInfo.isAttached = true; monoThreadInfo.isRegistered = true; From 48b1799446fe38f114acb78144a8b7653de1c419 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 2 Apr 2024 20:42:53 +0200 Subject: [PATCH 3/5] fix --- src/mono/browser/runtime/exports-internal.ts | 3 +++ src/mono/browser/runtime/gc-lock.ts | 3 +++ src/mono/browser/runtime/strings.ts | 5 ++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/mono/browser/runtime/exports-internal.ts b/src/mono/browser/runtime/exports-internal.ts index 074b54a18fcc7e..803ed692744fa0 100644 --- a/src/mono/browser/runtime/exports-internal.ts +++ b/src/mono/browser/runtime/exports-internal.ts @@ -128,6 +128,9 @@ export function cwraps_internal (internal: any): void { /* @deprecated not GC safe, legacy support for Blazor */ export function monoObjectAsBoolOrNullUnsafe (obj: MonoObject): boolean | null { + // TODO https://github.com/dotnet/runtime/issues/100411 + // after Blazor stops using monoObjectAsBoolOrNullUnsafe + if (obj === MonoObjectNull) { return null; } diff --git a/src/mono/browser/runtime/gc-lock.ts b/src/mono/browser/runtime/gc-lock.ts index 7a85513fd5ebde..f787c4710bab11 100644 --- a/src/mono/browser/runtime/gc-lock.ts +++ b/src/mono/browser/runtime/gc-lock.ts @@ -7,6 +7,9 @@ import cwraps from "./cwraps"; export let gc_locked = false; +// TODO https://github.com/dotnet/runtime/issues/100411 +// after Blazor stops using mono_wasm_gc_lock, mono_wasm_gc_unlock + export function mono_wasm_gc_lock (): void { if (gc_locked) { throw new Error("GC is already locked"); diff --git a/src/mono/browser/runtime/strings.ts b/src/mono/browser/runtime/strings.ts index 89a843b7c1ff03..a596b4e35ef5a2 100644 --- a/src/mono/browser/runtime/strings.ts +++ b/src/mono/browser/runtime/strings.ts @@ -120,7 +120,10 @@ export function stringToUTF16Ptr (str: string): VoidPtr { } export function monoStringToString (root: WasmRoot): string | null { - if (WasmEnableThreads) return null as any; + // TODO https://github.com/dotnet/runtime/issues/100411 + // after Blazor stops using monoStringToStringUnsafe + // mono_assert(!WasmEnableThreads, "Marshaling strings by reference is not supported in multithreaded mode"); + if (root.value === MonoStringNull) return null; From 0f8cbaa8e0208e39c57e1c9bf8330e41f4a9fdd3 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 3 Apr 2024 10:20:09 +0200 Subject: [PATCH 4/5] Update src/mono/browser/runtime/roots.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marek Fišera --- src/mono/browser/runtime/roots.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/browser/runtime/roots.ts b/src/mono/browser/runtime/roots.ts index 6068439c4652a3..f4cb6c14ed15dd 100644 --- a/src/mono/browser/runtime/roots.ts +++ b/src/mono/browser/runtime/roots.ts @@ -45,7 +45,7 @@ export function mono_wasm_new_root_buffer (capacity: number, name?: string): Was * Releasing this root will not de-allocate the root space. You still need to call .release(). */ export function mono_wasm_new_external_root (address: VoidPtr | MonoObjectRef): WasmRoot { - if (WasmEnableThreads && runtimeHelpers.disableManagedTransition) throw new Error("External roots are not supported when threads are enabled"); + if (WasmEnableThreads && runtimeHelpers.disableManagedTransition) throw new Error("External roots are not supported in multithreaded mode"); let result: WasmExternalRoot; if (!address) From 02d3500ba5e0832ae0720ddf0d4ac9e8debc4e37 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 3 Apr 2024 10:20:16 +0200 Subject: [PATCH 5/5] Update src/mono/browser/runtime/roots.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marek Fišera --- src/mono/browser/runtime/roots.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/browser/runtime/roots.ts b/src/mono/browser/runtime/roots.ts index f4cb6c14ed15dd..fdd4b2a5302f2a 100644 --- a/src/mono/browser/runtime/roots.ts +++ b/src/mono/browser/runtime/roots.ts @@ -69,7 +69,7 @@ export function mono_wasm_new_external_root (address: Void * When you are done using the root you must call its .release() method. */ export function mono_wasm_new_root (value: T | undefined = undefined): WasmRoot { - if (WasmEnableThreads && runtimeHelpers.disableManagedTransition) throw new Error("External roots are not supported when threads are enabled"); + if (WasmEnableThreads && runtimeHelpers.disableManagedTransition) throw new Error("External roots are not supported in multithreaded mode"); let result: WasmRoot; if (_scratch_root_free_instances.length > 0) {