diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSGeneratorFactory.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSGeneratorFactory.cs index 9d0577cb7d541..16f2dda426a1c 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSGeneratorFactory.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSGeneratorFactory.cs @@ -42,8 +42,8 @@ ResolvedGenerator fail(string failReason) return ResolvedGenerator.NotSupported(new(info, context)); // void - case { TypeInfo: JSSimpleTypeInfo(KnownManagedType.Void), JSType: JSTypeFlags.OneWay }: - return ResolvedGenerator.Resolved(new VoidGenerator(MarshalerType.OneWay)); + case { TypeInfo: JSSimpleTypeInfo(KnownManagedType.Void), JSType: JSTypeFlags.DiscardNoWait }: + return ResolvedGenerator.Resolved(new VoidGenerator(MarshalerType.DiscardNoWait)); case { TypeInfo: JSSimpleTypeInfo(KnownManagedType.Void), JSType: JSTypeFlags.Discard }: case { TypeInfo: JSSimpleTypeInfo(KnownManagedType.Void), JSType: JSTypeFlags.Void }: case { TypeInfo: JSSimpleTypeInfo(KnownManagedType.Void), JSType: JSTypeFlags.None }: @@ -55,8 +55,8 @@ ResolvedGenerator fail(string failReason) return fail(SR.DiscardOnlyVoid); // oneway no void - case { JSType: JSTypeFlags.OneWay }: - return fail(SR.OneWayOnlyVoid); + case { JSType: JSTypeFlags.DiscardNoWait }: + return fail(SR.DiscardNoWaitOnlyVoid); // primitive case { TypeInfo: JSSimpleTypeInfo simple }: diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSTypeFlags.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSTypeFlags.cs index e39fbe19425ba..5b34284f2225b 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSTypeFlags.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSTypeFlags.cs @@ -22,7 +22,7 @@ internal enum JSTypeFlags : int MemoryView = 0x800, Any = 0x1000, Discard = 0x2000, - OneWay = 0x4000, + DiscardNoWait = 0x4000, Missing = 0x4000_0000, } } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Resources/Strings.resx b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Resources/Strings.resx index 1e27fdcd8bb96..6aa6b8b9bb337 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Resources/Strings.resx +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Resources/Strings.resx @@ -184,8 +184,8 @@ 'JSType.Discard' could be only used with void return argument. - - 'JSType.OneWay' could be only used with void returning method. + + 'JSType.DiscardNoWait' could be only used with void returning method. Type {0} is not supported as argument of marshaled function. diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/CompatibilitySuppressions.xml b/src/libraries/System.Runtime.InteropServices.JavaScript/src/CompatibilitySuppressions.xml index b5cc7926a5169..07a5ec1d2531e 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/CompatibilitySuppressions.xml +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/CompatibilitySuppressions.xml @@ -14,13 +14,13 @@ CP0001 - T:System.Runtime.InteropServices.JavaScript.JSType.OneWay + T:System.Runtime.InteropServices.JavaScript.JSType.DiscardNoWait ref/net9.0/System.Runtime.InteropServices.JavaScript.dll runtimes/browser/lib/net9.0/System.Runtime.InteropServices.JavaScript.dll CP0002 - M:System.Runtime.InteropServices.JavaScript.JSMarshalerType.get_OneWay + M:System.Runtime.InteropServices.JavaScript.JSMarshalerType.get_DiscardNoWait ref/net9.0/System.Runtime.InteropServices.JavaScript.dll runtimes/browser/lib/net9.0/System.Runtime.InteropServices.JavaScript.dll diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptImports.Generated.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptImports.Generated.cs index db356f8afe4c2..7d734d8babe78 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptImports.Generated.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptImports.Generated.cs @@ -57,7 +57,7 @@ internal static unsafe partial class JavaScriptImports #if DEBUG [JSImport("globalThis.console.log")] - [return: JSMarshalAs] + [return: JSMarshalAs] // this means that the message will arrive out of order, especially across threads. public static partial void Log([JSMarshalAs] string message); #endif } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSFunctionBinding.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSFunctionBinding.cs index 43afa95f76b1d..666f2caeb5a4a 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSFunctionBinding.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSFunctionBinding.cs @@ -30,54 +30,51 @@ internal JSFunctionBinding() { } internal static volatile uint nextImportHandle = 1; internal int ImportHandle; internal bool IsAsync; - internal bool IsOneWay; + internal bool IsDiscardNoWait; #if DEBUG internal string? FunctionName; #endif - [StructLayout(LayoutKind.Sequential, Pack = 4)] + // keep in sync with JSBindingHeaderOffsets in marshal.ts + [StructLayout(LayoutKind.Explicit, Pack = 4)] internal struct JSBindingHeader { internal const int JSMarshalerSignatureHeaderSize = 4 * 8; // without Exception and Result + [FieldOffset(0)] public int Version; + [FieldOffset(4)] public int ArgumentCount; + [FieldOffset(8)] public int ImportHandle; - public int _Reserved; + [FieldOffset(16)] public int FunctionNameOffset; + [FieldOffset(20)] public int FunctionNameLength; + [FieldOffset(24)] public int ModuleNameOffset; + [FieldOffset(28)] public int ModuleNameLength; + [FieldOffset(32)] public JSBindingType Exception; + [FieldOffset(64)] public JSBindingType Result; } - [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 32)] + // keep in sync with JSBindingTypeOffsets in marshal.ts + [StructLayout(LayoutKind.Explicit, Pack = 4, Size = 32)] internal struct JSBindingType { + [FieldOffset(0)] internal MarshalerType Type; - internal MarshalerType __ReservedB1; - internal MarshalerType __ReservedB2; - internal MarshalerType __ReservedB3; - internal IntPtr __Reserved; - internal IntPtr JSCustomMarshallerCode; - internal int JSCustomMarshallerCodeLength; + [FieldOffset(16)] internal MarshalerType ResultMarshalerType; - internal MarshalerType __ReservedB4; - internal MarshalerType __ReservedB5; - internal MarshalerType __ReservedB6; + [FieldOffset(20)] internal MarshalerType Arg1MarshalerType; - internal MarshalerType __ReservedB7; - internal MarshalerType __ReservedB8; - internal MarshalerType __ReservedB9; + [FieldOffset(24)] internal MarshalerType Arg2MarshalerType; - internal MarshalerType __ReservedB10; - internal MarshalerType __ReservedB11; - internal MarshalerType __ReservedB12; + [FieldOffset(28)] internal MarshalerType Arg3MarshalerType; - internal MarshalerType __ReservedB13; - internal MarshalerType __ReservedB14; - internal MarshalerType __ReservedB15; } internal unsafe int ArgumentCount @@ -286,9 +283,9 @@ internal static unsafe void InvokeJSImportImpl(JSFunctionBinding signature, Span arguments[1].slot.GCHandle = holder.GCHandle; } - if (signature.IsOneWay) + if (signature.IsDiscardNoWait) { - arguments[1].slot.Type = MarshalerType.OneWay; + arguments[1].slot.Type = MarshalerType.DiscardNoWait; } #if FEATURE_WASM_MANAGED_THREADS @@ -305,7 +302,7 @@ internal static unsafe void InvokeJSImportImpl(JSFunctionBinding signature, Span #endif } - else if (signature.IsAsync || signature.IsOneWay) + else if (signature.IsAsync || signature.IsDiscardNoWait) { //async DispatchJSImportAsyncPost(signature, targetContext, arguments); diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs index 335aa72371eee..736f2de5a134d 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs @@ -153,7 +153,7 @@ public static unsafe JSFunctionBinding GetMethodSignature(ReadOnlySpan /// The marshaler metadata. - public static JSMarshalerType OneWay { get; } = new JSMarshalerType(new JSFunctionBinding.JSBindingType + public static JSMarshalerType DiscardNoWait { get; } = new JSMarshalerType(new JSFunctionBinding.JSBindingType { - Type = MarshalerType.OneWay + Type = MarshalerType.DiscardNoWait }); /// diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSType.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSType.cs index 8f9a5ef68f156..7d86122eae7f5 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSType.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSType.cs @@ -32,9 +32,9 @@ internal Discard() { } /// Could return immediately without waiting for the execution to finish, when dispatching the call to another thread. /// Suppresses marshaling of the JavaScript function's return value. /// - public sealed class OneWay : JSType + public sealed class DiscardNoWait : JSType { - internal OneWay() { } + internal DiscardNoWait() { } } /// diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/MarshalerType.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/MarshalerType.cs index d9f11387dedaa..ee9e4e247b25e 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/MarshalerType.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/MarshalerType.cs @@ -34,7 +34,7 @@ internal enum MarshalerType : byte Span, Action, Function, - OneWay, + DiscardNoWait, #if !JSIMPORTGENERATOR // only on runtime diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Func.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Func.cs index 271acab66bae0..d53c92400755c 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Func.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Marshaling/JSMarshalerArgument.Func.cs @@ -20,7 +20,7 @@ public void InvokeJS() // and would also allow the JS function to be collected - Span arguments = stackalloc JSMarshalerArgument[4]; + Span arguments = stackalloc JSMarshalerArgument[2]; ref JSMarshalerArgument args_exception = ref arguments[0]; ref JSMarshalerArgument args_return = ref arguments[1]; #if FEATURE_WASM_MANAGED_THREADS @@ -51,7 +51,7 @@ public ActionJS(JSObject holder, ArgumentToJSCallback arg1Marshaler) public void InvokeJS(T arg1) { - Span arguments = stackalloc JSMarshalerArgument[4]; + Span arguments = stackalloc JSMarshalerArgument[3]; ref JSMarshalerArgument args_exception = ref arguments[0]; ref JSMarshalerArgument args_return = ref arguments[1]; ref JSMarshalerArgument args_arg1 = ref arguments[2]; @@ -258,7 +258,7 @@ public TResult InvokeJS() // JSObject (held by this lambda) would be collected by GC after the lambda is collected // and would also allow the JS function to be collected - Span arguments = stackalloc JSMarshalerArgument[4]; + Span arguments = stackalloc JSMarshalerArgument[2]; ref JSMarshalerArgument args_exception = ref arguments[0]; ref JSMarshalerArgument args_return = ref arguments[1]; #if FEATURE_WASM_MANAGED_THREADS @@ -295,7 +295,7 @@ public FuncJS(JSObject holder, ArgumentToJSCallback arg1Marshaler, ArgumentTo public TResult InvokeJS(T arg1) { - Span arguments = stackalloc JSMarshalerArgument[4]; + Span arguments = stackalloc JSMarshalerArgument[3]; ref JSMarshalerArgument args_exception = ref arguments[0]; ref JSMarshalerArgument args_return = ref arguments[1]; ref JSMarshalerArgument args_arg1 = ref arguments[2]; diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs index 30eadd7a7f2c7..bcc2c85e9e785 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs @@ -26,12 +26,11 @@ await JsExportTestAsync(value, [Theory] [MemberData(nameof(MarshalInt32Cases))] - public async Task JsExportInt32OneWay(int value) + public async Task JsExportInt32DiscardNoWait(int value) { JavaScriptTestHelper.optimizedReached=0; - JavaScriptTestHelper.invoke1O(value); - await Task.Yield(); + await JavaScriptTestHelper.Delay(0); Assert.Equal(value, JavaScriptTestHelper.optimizedReached); } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs index 68598527681bd..96b89ffa9e4f4 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs @@ -529,10 +529,10 @@ public void JsImportInt16(short value) #region Int32 [Theory] [MemberData(nameof(MarshalInt32Cases))] - public async Task JsImportInt32OneWay(int value) + public async Task JsImportInt32DiscardNoWait(int value) { - JavaScriptTestHelper.store1OneWay_Int32(value); - await Task.Yield(); + JavaScriptTestHelper.store1DiscardNoWait_Int32(value); + await JavaScriptTestHelper.Delay(0); Assert.Equal(value, JavaScriptTestHelper.retrieve1_Int32()); } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index 6d6a484890782..e5ea3a887e24b 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -15,7 +15,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests public partial class JavaScriptTestHelper { [JSImport("globalThis.console.log")] - [return: JSMarshalAs] + [return: JSMarshalAs] public static partial void Log([JSMarshalAs] string message); [JSImport("globalThis.window.location.toString")] @@ -28,12 +28,15 @@ public partial class JavaScriptTestHelper public static partial string ReboundMemberEcho(string message); [JSExport] - [return: JSMarshalAs] + [return: JSMarshalAs] // this means that the message will arrive out of order, especially across threads. public static void ConsoleWriteLine([JSMarshalAs] string message) { Console.WriteLine(message); } + [JSImport("delay", "JavaScriptTestHelper")] + public static partial Task Delay(int ms); + [JSImport("catch1toString", "JavaScriptTestHelper")] public static partial string catch1toString(string message, string functionName); @@ -76,7 +79,7 @@ public static void Optimized1V(int a1) public static partial void invoke1V(int a1); [JSExport] - [return: JSMarshalAs] + [return: JSMarshalAs] // this means that the message will arrive out of order, especially across threads. public static void Optimized1O(int a1) { optimizedReached += a1; @@ -274,8 +277,8 @@ internal static partial void Relaxed(string a1, Exception ex, internal static partial void store1_Int32([JSMarshalAs] int value); [JSImport("store1", "JavaScriptTestHelper")] - [return: JSMarshalAs] - internal static partial void store1OneWay_Int32([JSMarshalAs] int value); + [return: JSMarshalAs] // this means that the message will arrive out of order, especially across threads. + internal static partial void store1DiscardNoWait_Int32([JSMarshalAs] int value); [JSImport("retrieve1", "JavaScriptTestHelper")] [return: JSMarshalAs] diff --git a/src/mono/browser/runtime/driver.c b/src/mono/browser/runtime/driver.c index 1d0133a57e6e8..d76a8bacd9282 100644 --- a/src/mono/browser/runtime/driver.c +++ b/src/mono/browser/runtime/driver.c @@ -263,7 +263,8 @@ mono_wasm_invoke_jsexport_async_post_cb (MonoMethod *method, void* args) { mono_wasm_invoke_jsexport (method, args); // TODO assert receiver_should_free ? - free (args); + if (args) + free (args); } // async diff --git a/src/mono/browser/runtime/invoke-cs.ts b/src/mono/browser/runtime/invoke-cs.ts index 2978e7ea8afce..287ee5ca6f681 100644 --- a/src/mono/browser/runtime/invoke-cs.ts +++ b/src/mono/browser/runtime/invoke-cs.ts @@ -39,15 +39,15 @@ export function mono_wasm_bind_cs_function(method: MonoMethod, assemblyName: str const res_sig = get_sig(signature, 1); let res_marshaler_type = get_signature_type(res_sig); - // hack until we have public API for JSType.OneWay + // hack until we have public API for JSType.DiscardNoWait if (WasmEnableThreads && shortClassName === "DefaultWebAssemblyJSRuntime" && namespaceName === "Microsoft.AspNetCore.Components.WebAssembly.Services" && (methodName === "BeginInvokeDotNet" || methodName === "EndInvokeJS")) { - res_marshaler_type = MarshalerType.OneWay; + res_marshaler_type = MarshalerType.DiscardNoWait; } const is_async = res_marshaler_type == MarshalerType.Task; - const is_oneway = res_marshaler_type == MarshalerType.OneWay; + const is_discard_no_wait = res_marshaler_type == MarshalerType.DiscardNoWait; if (is_async) { res_marshaler_type = MarshalerType.TaskPreCreated; } @@ -60,7 +60,7 @@ export function mono_wasm_bind_cs_function(method: MonoMethod, assemblyName: str arg_marshalers, res_converter, is_async, - is_oneway, + is_discard_no_wait, isDisposed: false, }; let bound_fn: Function; @@ -75,7 +75,7 @@ export function mono_wasm_bind_cs_function(method: MonoMethod, assemblyName: str else { bound_fn = bind_fn(closure); } - } else if (is_oneway) { + } else if (is_discard_no_wait) { bound_fn = bind_fn(closure); } else { if (args_count == 0 && !res_converter) { @@ -285,7 +285,7 @@ function bind_fn(closure: BindingClosure) { const method = closure.method; const fqn = closure.fullyQualifiedName; const is_async = closure.is_async; - const is_oneway = closure.is_oneway; + const is_discard_no_wait = closure.is_discard_no_wait; if (!WasmEnableThreads) (closure) = null; return function bound_fn(...js_args: any[]) { const mark = startMeasure(); @@ -313,7 +313,7 @@ function bind_fn(closure: BindingClosure) { // in case the C# side returned synchronously js_result = end_marshal_task_to_js(args, undefined, js_result); } - else if (is_oneway) { + else if (is_discard_no_wait) { // call C# side, fire and forget invoke_async_jsexport(method, args, 2 + args_count); } @@ -338,7 +338,7 @@ type BindingClosure = { arg_marshalers: (BoundMarshalerToCs)[], res_converter: BoundMarshalerToJs | undefined, is_async: boolean, - is_oneway: boolean, + is_discard_no_wait: boolean, isDisposed: boolean, } diff --git a/src/mono/browser/runtime/invoke-js.ts b/src/mono/browser/runtime/invoke-js.ts index f429bf3e98b9f..75d7c96b9c737 100644 --- a/src/mono/browser/runtime/invoke-js.ts +++ b/src/mono/browser/runtime/invoke-js.ts @@ -96,7 +96,7 @@ function bind_js_import(signature: JSFunctionSignature): Function { const res_marshaler_type = get_signature_type(res_sig); const res_converter = bind_arg_marshal_to_cs(res_sig, res_marshaler_type, 1); - const is_oneway = res_marshaler_type == MarshalerType.OneWay; + const is_discard_no_wait = res_marshaler_type == MarshalerType.DiscardNoWait; const is_async = res_marshaler_type == MarshalerType.Task || res_marshaler_type == MarshalerType.TaskPreCreated; const closure: BindingClosure = { @@ -107,12 +107,12 @@ function bind_js_import(signature: JSFunctionSignature): Function { res_converter, has_cleanup, arg_cleanup, - is_oneway, + is_discard_no_wait, is_async, isDisposed: false, }; let bound_fn: WrappedJSFunction; - if (is_async || is_oneway || has_cleanup) { + if (is_async || is_discard_no_wait || has_cleanup) { bound_fn = bind_fn(closure); } else { @@ -165,7 +165,7 @@ function bind_js_import(signature: JSFunctionSignature): Function { } let wrapped_fn: WrappedJSFunction; - if (is_async || is_oneway) { + if (is_async || is_discard_no_wait) { wrapped_fn = async_bound_fn; } else { @@ -279,7 +279,7 @@ function bind_fn(closure: BindingClosure) { const fqn = closure.fqn; if (!WasmEnableThreads) (closure) = null; return function bound_fn(args: JSMarshalerArguments) { - const is_async = WasmEnableThreads && is_receiver_should_free(args); + const receiver_should_free = WasmEnableThreads && is_receiver_should_free(args); const mark = startMeasure(); try { mono_assert(!WasmEnableThreads || !closure.isDisposed, "The function was already disposed"); @@ -309,7 +309,7 @@ function bind_fn(closure: BindingClosure) { marshal_exception_to_cs(args, ex); } finally { - if (is_async) { + if (receiver_should_free) { Module._free(args as any); } endMeasure(mark, MeasuredBlock.callCsFunction, fqn); @@ -327,7 +327,7 @@ type BindingClosure = { arg_marshalers: (BoundMarshalerToJs)[], res_converter: BoundMarshalerToCs | undefined, has_cleanup: boolean, - is_oneway: boolean, + is_discard_no_wait: boolean, is_async: boolean, arg_cleanup: (Function | undefined)[] } diff --git a/src/mono/browser/runtime/marshal-to-cs.ts b/src/mono/browser/runtime/marshal-to-cs.ts index 132de0f75dcd4..fa0f299a5f2b8 100644 --- a/src/mono/browser/runtime/marshal-to-cs.ts +++ b/src/mono/browser/runtime/marshal-to-cs.ts @@ -59,12 +59,12 @@ export function initialize_marshalers_to_cs(): void { js_to_cs_marshalers.set(MarshalerType.None, _marshal_null_to_cs);// also void js_to_cs_marshalers.set(MarshalerType.Discard, _marshal_null_to_cs);// also void js_to_cs_marshalers.set(MarshalerType.Void, _marshal_null_to_cs);// also void - js_to_cs_marshalers.set(MarshalerType.OneWay, _marshal_null_to_cs);// also void + js_to_cs_marshalers.set(MarshalerType.DiscardNoWait, _marshal_null_to_cs);// also void } } export function bind_arg_marshal_to_cs(sig: JSMarshalerType, marshaler_type: MarshalerType, index: number): BoundMarshalerToCs | undefined { - if (marshaler_type === MarshalerType.None || marshaler_type === MarshalerType.Void || marshaler_type === MarshalerType.Discard || marshaler_type === MarshalerType.OneWay) { + if (marshaler_type === MarshalerType.None || marshaler_type === MarshalerType.Void || marshaler_type === MarshalerType.Discard || marshaler_type === MarshalerType.DiscardNoWait) { return undefined; } let res_marshaler: MarshalerToCs | undefined = undefined; diff --git a/src/mono/browser/runtime/marshal-to-js.ts b/src/mono/browser/runtime/marshal-to-js.ts index 29f6bcdb54c45..f02c81765e6a4 100644 --- a/src/mono/browser/runtime/marshal-to-js.ts +++ b/src/mono/browser/runtime/marshal-to-js.ts @@ -55,12 +55,12 @@ export function initialize_marshalers_to_js(): void { cs_to_js_marshalers.set(MarshalerType.None, _marshal_null_to_js); cs_to_js_marshalers.set(MarshalerType.Void, _marshal_null_to_js); cs_to_js_marshalers.set(MarshalerType.Discard, _marshal_null_to_js); - cs_to_js_marshalers.set(MarshalerType.OneWay, _marshal_null_to_js); + cs_to_js_marshalers.set(MarshalerType.DiscardNoWait, _marshal_null_to_js); } } export function bind_arg_marshal_to_js(sig: JSMarshalerType, marshaler_type: MarshalerType, index: number): BoundMarshalerToJs | undefined { - if (marshaler_type === MarshalerType.None || marshaler_type === MarshalerType.Void || marshaler_type === MarshalerType.Discard || marshaler_type === MarshalerType.OneWay) { + if (marshaler_type === MarshalerType.None || marshaler_type === MarshalerType.Void || marshaler_type === MarshalerType.Discard || marshaler_type === MarshalerType.DiscardNoWait) { return undefined; } @@ -338,7 +338,7 @@ function create_task_holder(res_converter?: MarshalerToJs) { export function mono_wasm_resolve_or_reject_promise(args: JSMarshalerArguments): void { const exc = get_arg(args, 0); - const is_async = WasmEnableThreads && is_receiver_should_free(args); + const receiver_should_free = WasmEnableThreads && is_receiver_should_free(args); try { loaderHelpers.assert_runtime_running(); @@ -353,7 +353,7 @@ export function mono_wasm_resolve_or_reject_promise(args: JSMarshalerArguments): mono_assert(holder, () => `Cannot find Promise for JSHandle ${js_handle}`); holder.resolve_or_reject(type, js_handle, arg_value); - if (is_async) { + if (receiver_should_free) { // this works together with AllocHGlobal in JSFunctionBinding.ResolveOrRejectPromise Module._free(args as any); } @@ -363,7 +363,7 @@ export function mono_wasm_resolve_or_reject_promise(args: JSMarshalerArguments): } } catch (ex: any) { - if (is_async) { + if (receiver_should_free) { mono_assert(false, () => `Failed to resolve or reject promise ${ex}`); } marshal_exception_to_cs(exc, ex); diff --git a/src/mono/browser/runtime/marshal.ts b/src/mono/browser/runtime/marshal.ts index 6d0f6ec0308fa..c3c07d1c18895 100644 --- a/src/mono/browser/runtime/marshal.ts +++ b/src/mono/browser/runtime/marshal.ts @@ -20,8 +20,47 @@ export const imported_js_function_symbol = Symbol.for("wasm imported_js_function export const proxy_debug_symbol = Symbol.for("wasm proxy_debug"); export const JavaScriptMarshalerArgSize = 32; +// keep in sync with JSMarshalerArgumentImpl offsets +const enum JSMarshalerArgumentOffsets { + BooleanValue = 0, + ByteValue = 0, + CharValue = 0, + Int16Value = 0, + Int32Value = 0, + Int64Value = 0, + SingleValue = 0, + DoubleValue = 0, + IntPtrValue = 0, + JSHandle = 4, + GCHandle = 4, + Length = 8, + Type = 12, + ElementType = 13, + ContextHandle = 16, + ReceiverShouldFree = 20, +} export const JSMarshalerTypeSize = 32; +// keep in sync with JSFunctionBinding.JSBindingType +const enum JSBindingTypeOffsets { + Type = 0, + ResultMarshalerType = 16, + Arg1MarshalerType = 20, + Arg2MarshalerType = 24, + Arg3MarshalerType = 28, +} export const JSMarshalerSignatureHeaderSize = 4 * 8; // without Exception and Result +// keep in sync with JSFunctionBinding.JSBindingHeader +const enum JSBindingHeaderOffsets { + Version = 0, + ArgumentCount = 4, + ImportHandle = 8, + FunctionNameOffset = 16, + FunctionNameLength = 20, + ModuleNameOffset = 24, + ModuleNameLength = 28, + Exception = 32, + Result = 64, +} export function alloc_stack_frame(size: number): JSMarshalerArguments { if (WasmEnableThreads) { @@ -48,12 +87,12 @@ export function is_args_exception(args: JSMarshalerArguments): boolean { export function is_receiver_should_free(args: JSMarshalerArguments): boolean { if (WasmEnableThreads) return false; mono_assert(args, "Null args"); - return getB32(args + 20); + return getB32(args + JSMarshalerArgumentOffsets.ReceiverShouldFree); } export function set_receiver_should_free(args: JSMarshalerArguments): void { mono_assert(args, "Null args"); - setB32(args + 20, true); + setB32(args + JSMarshalerArgumentOffsets.ReceiverShouldFree, true); } export function set_args_context(args: JSMarshalerArguments): void { @@ -72,58 +111,58 @@ export function get_sig(signature: JSFunctionSignature, index: number): JSMarsha export function get_signature_type(sig: JSMarshalerType): MarshalerType { mono_assert(sig, "Null sig"); - return getU8(sig); + return getU8(sig + JSBindingTypeOffsets.Type); } export function get_signature_res_type(sig: JSMarshalerType): MarshalerType { mono_assert(sig, "Null sig"); - return getU8(sig + 16); + return getU8(sig + JSBindingTypeOffsets.ResultMarshalerType); } export function get_signature_arg1_type(sig: JSMarshalerType): MarshalerType { mono_assert(sig, "Null sig"); - return getU8(sig + 20); + return getU8(sig + JSBindingTypeOffsets.Arg1MarshalerType); } export function get_signature_arg2_type(sig: JSMarshalerType): MarshalerType { mono_assert(sig, "Null sig"); - return getU8(sig + 24); + return getU8(sig + JSBindingTypeOffsets.Arg2MarshalerType); } export function get_signature_arg3_type(sig: JSMarshalerType): MarshalerType { mono_assert(sig, "Null sig"); - return getU8(sig + 28); + return getU8(sig + JSBindingTypeOffsets.Arg2MarshalerType); } export function get_signature_argument_count(signature: JSFunctionSignature): number { mono_assert(signature, "Null signatures"); - return getI32(signature + 4); + return getI32(signature + JSBindingHeaderOffsets.ArgumentCount); } export function get_signature_version(signature: JSFunctionSignature): number { mono_assert(signature, "Null signatures"); - return getI32(signature); + return getI32(signature + JSBindingHeaderOffsets.Version); } export function get_signature_handle(signature: JSFunctionSignature): number { mono_assert(signature, "Null signatures"); - return getI32(signature + 8); + return getI32(signature + JSBindingHeaderOffsets.ImportHandle); } export function get_signature_function_name(signature: JSFunctionSignature): string | null { mono_assert(signature, "Null signatures"); - const functionNameOffset = getI32(signature + 16); + const functionNameOffset = getI32(signature + JSBindingHeaderOffsets.FunctionNameOffset); if (functionNameOffset === 0) return null; - const functionNameLength = getI32(signature + 20); + const functionNameLength = getI32(signature + JSBindingHeaderOffsets.FunctionNameLength); mono_assert(functionNameOffset, "Null name"); return utf16ToString(signature + functionNameOffset, signature + functionNameOffset + functionNameLength); } export function get_signature_module_name(signature: JSFunctionSignature): string | null { mono_assert(signature, "Null signatures"); - const moduleNameOffset = getI32(signature + 24); + const moduleNameOffset = getI32(signature + JSBindingHeaderOffsets.ModuleNameOffset); if (moduleNameOffset === 0) return null; - const moduleNameLength = getI32(signature + 28); + const moduleNameLength = getI32(signature + JSBindingHeaderOffsets.ModuleNameLength); return utf16ToString(signature + moduleNameOffset, signature + moduleNameOffset + moduleNameLength); } @@ -134,24 +173,24 @@ export function get_sig_type(sig: JSMarshalerType): MarshalerType { export function get_arg_type(arg: JSMarshalerArgument): MarshalerType { mono_assert(arg, "Null arg"); - const type = getU8(arg + 12); + const type = getU8(arg + JSMarshalerArgumentOffsets.Type); return type; } export function get_arg_element_type(arg: JSMarshalerArgument): MarshalerType { mono_assert(arg, "Null arg"); - const type = getU8(arg + 13); + const type = getU8(arg + JSMarshalerArgumentOffsets.ElementType); return type; } export function set_arg_type(arg: JSMarshalerArgument, type: MarshalerType): void { mono_assert(arg, "Null arg"); - setU8(arg + 12, type); + setU8(arg + JSMarshalerArgumentOffsets.Type, type); } export function set_arg_element_type(arg: JSMarshalerArgument, type: MarshalerType): void { mono_assert(arg, "Null arg"); - setU8(arg + 13, type); + setU8(arg + JSMarshalerArgumentOffsets.ElementType, type); } export function get_arg_b8(arg: JSMarshalerArgument): boolean { @@ -274,29 +313,29 @@ export function set_arg_f32(arg: JSMarshalerArgument, value: number): void { export function get_arg_js_handle(arg: JSMarshalerArgument): JSHandle { mono_assert(arg, "Null arg"); - return getI32(arg + 4); + return getI32(arg + JSMarshalerArgumentOffsets.JSHandle); } export function set_arg_proxy_context(arg: JSMarshalerArgument): void { if (!WasmEnableThreads) return; mono_assert(arg, "Null arg"); - setI32(arg + 16, runtimeHelpers.proxyGCHandle); + setI32(arg + JSMarshalerArgumentOffsets.ContextHandle, runtimeHelpers.proxyGCHandle); } export function set_js_handle(arg: JSMarshalerArgument, jsHandle: JSHandle): void { mono_assert(arg, "Null arg"); - setI32(arg + 4, jsHandle); + setI32(arg + JSMarshalerArgumentOffsets.JSHandle, jsHandle); set_arg_proxy_context(arg); } export function get_arg_gc_handle(arg: JSMarshalerArgument): GCHandle { mono_assert(arg, "Null arg"); - return getI32(arg + 4); + return getI32(arg + JSMarshalerArgumentOffsets.GCHandle); } export function set_gc_handle(arg: JSMarshalerArgument, gcHandle: GCHandle): void { mono_assert(arg, "Null arg"); - setI32(arg + 4, gcHandle); + setI32(arg + JSMarshalerArgumentOffsets.GCHandle, gcHandle); set_arg_proxy_context(arg); } @@ -307,12 +346,12 @@ export function get_string_root(arg: JSMarshalerArgument): WasmRoot export function get_arg_length(arg: JSMarshalerArgument): number { mono_assert(arg, "Null arg"); - return getI32(arg + 8); + return getI32(arg + JSMarshalerArgumentOffsets.Length); } export function set_arg_length(arg: JSMarshalerArgument, size: number): void { mono_assert(arg, "Null arg"); - setI32(arg + 8, size); + setI32(arg + JSMarshalerArgumentOffsets.Length, size); } export function set_root(arg: JSMarshalerArgument, root: WasmRoot): void { @@ -393,7 +432,7 @@ export class ManagedError extends Error implements IDisposable { export function get_signature_marshaler(signature: JSFunctionSignature, index: number): JSHandle { mono_assert(signature, "Null signatures"); const sig = get_sig(signature, index); - return getU32(sig + 8); + return getU32(sig + JSBindingHeaderOffsets.ImportHandle); } diff --git a/src/mono/browser/runtime/memory.ts b/src/mono/browser/runtime/memory.ts index cef0f641e50bf..ab4beebf1285a 100644 --- a/src/mono/browser/runtime/memory.ts +++ b/src/mono/browser/runtime/memory.ts @@ -392,9 +392,7 @@ export function localHeapViewF64(): Float64Array { export function copyBytes(srcPtr: VoidPtr, dstPtr: VoidPtr, bytes: number): void { const heap = localHeapViewU8(); - const src = heap.subarray(srcPtr as any, srcPtr as any + bytes); - const dst = heap.subarray(dstPtr as any, dstPtr as any + bytes); - dst.set(src); + heap.copyWithin(dstPtr as any, srcPtr as any, srcPtr as any + bytes); } // when we run with multithreading enabled, we need to make sure that the memory views are updated on each worker diff --git a/src/mono/browser/runtime/strings.ts b/src/mono/browser/runtime/strings.ts index aae59c50b69a9..d0d798c161b28 100644 --- a/src/mono/browser/runtime/strings.ts +++ b/src/mono/browser/runtime/strings.ts @@ -244,7 +244,9 @@ function storeStringInInternTable(string: string, root: WasmRoot, in function stringToMonoStringNewRoot(string: string, result: WasmRoot): void { const bufferLen = (string.length + 1) * 2; - // TODO this could be stack allocated + // TODO this could be stack allocated for small strings + // or temp_malloc/alloca for large strings + // or skip the scratch buffer entirely, and make a new MonoString of size string.length, pin it, and then call stringToUTF16 to write directly into the MonoString's chars const buffer = Module._malloc(bufferLen); stringToUTF16(buffer as any, buffer as any + bufferLen, string); cwraps.mono_wasm_string_from_utf16_ref(buffer, string.length, result.address); diff --git a/src/mono/browser/runtime/types/internal.ts b/src/mono/browser/runtime/types/internal.ts index a2eb9b623f90c..3f021a50a01ce 100644 --- a/src/mono/browser/runtime/types/internal.ts +++ b/src/mono/browser/runtime/types/internal.ts @@ -337,7 +337,7 @@ export enum MarshalerType { Span, Action, Function, - OneWay, + DiscardNoWait, // only on runtime JSException,