Skip to content

Commit

Permalink
[browser][MT] JSType.OneWay -> JSType.DiscardNoWait (dotnet#98647)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelsavara authored Feb 19, 2024
1 parent 03c9d36 commit 2df0ad1
Show file tree
Hide file tree
Showing 24 changed files with 150 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 }:
Expand All @@ -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 }:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal enum JSTypeFlags : int
MemoryView = 0x800,
Any = 0x1000,
Discard = 0x2000,
OneWay = 0x4000,
DiscardNoWait = 0x4000,
Missing = 0x4000_0000,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@
<data name="DiscardOnlyVoid" xml:space="preserve">
<value>'JSType.Discard' could be only used with void return argument.</value>
</data>
<data name="OneWayOnlyVoid" xml:space="preserve">
<value>'JSType.OneWay' could be only used with void returning method.</value>
<data name="DiscardNoWaitOnlyVoid" xml:space="preserve">
<value>'JSType.DiscardNoWait' could be only used with void returning method.</value>
</data>
<data name="FuncArgumentNotSupported" xml:space="preserve">
<value>Type {0} is not supported as argument of marshaled function.</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:System.Runtime.InteropServices.JavaScript.JSType.OneWay</Target>
<Target>T:System.Runtime.InteropServices.JavaScript.JSType.DiscardNoWait</Target>
<Left>ref/net9.0/System.Runtime.InteropServices.JavaScript.dll</Left>
<Right>runtimes/browser/lib/net9.0/System.Runtime.InteropServices.JavaScript.dll</Right>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:System.Runtime.InteropServices.JavaScript.JSMarshalerType.get_OneWay</Target>
<Target>M:System.Runtime.InteropServices.JavaScript.JSMarshalerType.get_DiscardNoWait</Target>
<Left>ref/net9.0/System.Runtime.InteropServices.JavaScript.dll</Left>
<Right>runtimes/browser/lib/net9.0/System.Runtime.InteropServices.JavaScript.dll</Right>
</Suppression>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ internal static unsafe partial class JavaScriptImports

#if DEBUG
[JSImport("globalThis.console.log")]
[return: JSMarshalAs<JSType.OneWay>]
[return: JSMarshalAs<JSType.DiscardNoWait>] // this means that the message will arrive out of order, especially across threads.
public static partial void Log([JSMarshalAs<JSType.String>] string message);
#endif
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public static unsafe JSFunctionBinding GetMethodSignature(ReadOnlySpan<JSMarshal
var type = signature.Sigs[i] = types[i + 1]._signatureType;
}
signature.IsAsync = types[0]._signatureType.Type == MarshalerType.Task;
signature.IsOneWay = types[0]._signatureType.Type == MarshalerType.OneWay;
signature.IsDiscardNoWait = types[0]._signatureType.Type == MarshalerType.DiscardNoWait;

signature.Header[0].ImportHandle = signature.ImportHandle;
signature.Header[0].FunctionNameLength = functionNameBytes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public partial struct JSMarshalerArgument
{
internal JSMarshalerArgumentImpl slot;

// keep in sync with JSMarshalerArgumentOffsets in marshal.ts
[StructLayout(LayoutKind.Explicit, Pack = 32, Size = 32)]
internal struct JSMarshalerArgumentImpl
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ private JSMarshalerType(JSFunctionBinding.JSBindingType signatureType)
/// Dispatches the call asynchronously and doesn't wait for result.
/// </summary>
/// <returns>The marshaler metadata.</returns>
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
});

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
/// </summary>
public sealed class OneWay : JSType
public sealed class DiscardNoWait : JSType
{
internal OneWay() { }
internal DiscardNoWait() { }
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ internal enum MarshalerType : byte
Span,
Action,
Function,
OneWay,
DiscardNoWait,

#if !JSIMPORTGENERATOR
// only on runtime
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public void InvokeJS()
// and would also allow the JS function to be collected


Span<JSMarshalerArgument> arguments = stackalloc JSMarshalerArgument[4];
Span<JSMarshalerArgument> arguments = stackalloc JSMarshalerArgument[2];
ref JSMarshalerArgument args_exception = ref arguments[0];
ref JSMarshalerArgument args_return = ref arguments[1];
#if FEATURE_WASM_MANAGED_THREADS
Expand Down Expand Up @@ -51,7 +51,7 @@ public ActionJS(JSObject holder, ArgumentToJSCallback<T> arg1Marshaler)
public void InvokeJS(T arg1)
{

Span<JSMarshalerArgument> arguments = stackalloc JSMarshalerArgument[4];
Span<JSMarshalerArgument> 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];
Expand Down Expand Up @@ -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<JSMarshalerArgument> arguments = stackalloc JSMarshalerArgument[4];
Span<JSMarshalerArgument> arguments = stackalloc JSMarshalerArgument[2];
ref JSMarshalerArgument args_exception = ref arguments[0];
ref JSMarshalerArgument args_return = ref arguments[1];
#if FEATURE_WASM_MANAGED_THREADS
Expand Down Expand Up @@ -295,7 +295,7 @@ public FuncJS(JSObject holder, ArgumentToJSCallback<T> arg1Marshaler, ArgumentTo
public TResult InvokeJS(T arg1)
{

Span<JSMarshalerArgument> arguments = stackalloc JSMarshalerArgument[4];
Span<JSMarshalerArgument> 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];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
public partial class JavaScriptTestHelper
{
[JSImport("globalThis.console.log")]
[return: JSMarshalAs<JSType.OneWay>]
[return: JSMarshalAs<JSType.DiscardNoWait>]
public static partial void Log([JSMarshalAs<JSType.String>] string message);

[JSImport("globalThis.window.location.toString")]
Expand All @@ -28,12 +28,15 @@ public partial class JavaScriptTestHelper
public static partial string ReboundMemberEcho(string message);

[JSExport]
[return: JSMarshalAs<JSType.OneWay>]
[return: JSMarshalAs<JSType.DiscardNoWait>] // this means that the message will arrive out of order, especially across threads.
public static void ConsoleWriteLine([JSMarshalAs<JSType.String>] 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);

Expand Down Expand Up @@ -76,7 +79,7 @@ public static void Optimized1V(int a1)
public static partial void invoke1V(int a1);

[JSExport]
[return: JSMarshalAs<JSType.OneWay>]
[return: JSMarshalAs<JSType.DiscardNoWait>] // this means that the message will arrive out of order, especially across threads.
public static void Optimized1O(int a1)
{
optimizedReached += a1;
Expand Down Expand Up @@ -274,8 +277,8 @@ internal static partial void Relaxed(string a1, Exception ex,
internal static partial void store1_Int32([JSMarshalAs<JSType.Number>] int value);

[JSImport("store1", "JavaScriptTestHelper")]
[return: JSMarshalAs<JSType.OneWay>]
internal static partial void store1OneWay_Int32([JSMarshalAs<JSType.Number>] int value);
[return: JSMarshalAs<JSType.DiscardNoWait>] // this means that the message will arrive out of order, especially across threads.
internal static partial void store1DiscardNoWait_Int32([JSMarshalAs<JSType.Number>] int value);

[JSImport("retrieve1", "JavaScriptTestHelper")]
[return: JSMarshalAs<JSType.Number>]
Expand Down
3 changes: 2 additions & 1 deletion src/mono/browser/runtime/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 8 additions & 8 deletions src/mono/browser/runtime/invoke-cs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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) (<any>closure) = null;
return function bound_fn(...js_args: any[]) {
const mark = startMeasure();
Expand Down Expand Up @@ -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);
}
Expand All @@ -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,
}

Expand Down
Loading

0 comments on commit 2df0ad1

Please sign in to comment.