Skip to content

Commit 3e4e9a5

Browse files
committed
rebase
1 parent d06742c commit 3e4e9a5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+433
-217
lines changed

docs/workflow/debugging/mono/wasm-debugging.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,8 @@ $func166 @ dotnet.wasm:0xba0a
180180
$func2810 @ dotnet.wasm:0xabacf
181181
$func1615 @ dotnet.wasm:0x6f8eb
182182
$func1619 @ dotnet.wasm:0x6ff58
183-
$mono_wasm_invoke_method @ dotnet.wasm:0x96c9
184-
Module._mono_wasm_invoke_method @ dotnet.6.0.1.hopd7ipo8x.js:1
183+
$mono_wasm_invoke_jsexport @ dotnet.wasm:0x96c9
184+
Module.mono_wasm_invoke_jsexport @ dotnet.6.0.1.hopd7ipo8x.js:1
185185
managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_BeginInvokeDotNet @ managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_BeginInvokeDotNet:19
186186
beginInvokeDotNetFromJS @ blazor.webassembly.js:1
187187
b @ blazor.webassembly.js:1
@@ -244,8 +244,8 @@ $mono_jit_runtime_invoke @ dotnet.wasm:0x1dec32
244244
$do_runtime_invoke @ dotnet.wasm:0x95fca
245245
$mono_runtime_try_invoke @ dotnet.wasm:0x966fe
246246
$mono_runtime_invoke @ dotnet.wasm:0x98982
247-
$mono_wasm_invoke_method @ dotnet.wasm:0x227de2
248-
Module._mono_wasm_invoke_method @ dotnet..y6ggkhlo8e.js:9927
247+
$mono_wasm_invoke_jsexport @ dotnet.wasm:0x227de2
248+
Module.mono_wasm_invoke_jsexport @ dotnet..y6ggkhlo8e.js:9927
249249
managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_BeginInvokeDotNet @ managed__Microsoft_AspNetCore_Components_WebAssembly__Microsoft_AspNetCore_Components_WebAssembly_Services_DefaultWebAssemblyJSRuntime_BeginInvokeDotNet:19
250250
beginInvokeDotNetFromJS @ blazor.webassembly.js:1
251251
b @ blazor.webassembly.js:1

src/libraries/Common/src/Interop/Browser/Interop.Runtime.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ internal static unsafe partial class Runtime
4747
public static extern void UninstallWebWorkerInterop();
4848

4949
[MethodImpl(MethodImplOptions.InternalCall)]
50-
public static extern void InvokeJSImportSync(nint data, nint signature);
50+
public static extern void InvokeJSImportSync(nint signature, nint args);
5151
[MethodImpl(MethodImplOptions.InternalCall)]
52-
public static extern void InvokeJSImportSyncSend(nint targetNativeTID, nint data, nint signature);
52+
public static extern void InvokeJSImportSyncSend(nint targetNativeTID, nint signature, nint args);
5353
[MethodImpl(MethodImplOptions.InternalCall)]
54-
public static extern void InvokeJSImportAsyncPost(nint targetNativeTID, nint data, nint signature);
54+
public static extern void InvokeJSImportAsyncPost(nint targetNativeTID, nint signature, nint args);
5555
[MethodImpl(MethodImplOptions.InternalCall)]
5656
public static extern void CancelPromise(nint taskHolderGCHandle);
5757
[MethodImpl(MethodImplOptions.InternalCall)]
@@ -60,7 +60,7 @@ internal static unsafe partial class Runtime
6060
[MethodImpl(MethodImplOptions.InternalCall)]
6161
public static extern unsafe void BindJSImport(void* signature, out int is_exception, out object result);
6262
[MethodImpl(MethodImplOptions.InternalCall)]
63-
public static extern void InvokeJSImport(int importHandle, nint data);
63+
public static extern void InvokeJSImportST(int importHandle, nint args);
6464
[MethodImpl(MethodImplOptions.InternalCall)]
6565
public static extern void CancelPromise(nint gcHandle);
6666
#endif

src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSGeneratorFactory.cs

+6
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ ResolvedGenerator fail(string failReason)
4242
return ResolvedGenerator.NotSupported(new(info, context));
4343

4444
// void
45+
case { TypeInfo: JSSimpleTypeInfo(KnownManagedType.Void), JSType: JSTypeFlags.OneWay }:
46+
return ResolvedGenerator.Resolved(new VoidGenerator(MarshalerType.OneWay));
4547
case { TypeInfo: JSSimpleTypeInfo(KnownManagedType.Void), JSType: JSTypeFlags.Discard }:
4648
case { TypeInfo: JSSimpleTypeInfo(KnownManagedType.Void), JSType: JSTypeFlags.Void }:
4749
case { TypeInfo: JSSimpleTypeInfo(KnownManagedType.Void), JSType: JSTypeFlags.None }:
@@ -52,6 +54,10 @@ ResolvedGenerator fail(string failReason)
5254
case { JSType: JSTypeFlags.Discard }:
5355
return fail(SR.DiscardOnlyVoid);
5456

57+
// oneway no void
58+
case { JSType: JSTypeFlags.OneWay }:
59+
return fail(SR.OneWayOnlyVoid);
60+
5561
// primitive
5662
case { TypeInfo: JSSimpleTypeInfo simple }:
5763
return Create(info, isToJs, simple.KnownType, Array.Empty<KnownManagedType>(), jsMarshalingInfo.JSType, Array.Empty<JSTypeFlags>(), fail);

src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSTypeFlags.cs

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ internal enum JSTypeFlags : int
2222
MemoryView = 0x800,
2323
Any = 0x1000,
2424
Discard = 0x2000,
25+
OneWay = 0x4000,
2526
Missing = 0x4000_0000,
2627
}
2728
}

src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Resources/Strings.resx

+3
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@
184184
<data name="DiscardOnlyVoid" xml:space="preserve">
185185
<value>'JSType.Discard' could be only used with void return argument.</value>
186186
</data>
187+
<data name="OneWayOnlyVoid" xml:space="preserve">
188+
<value>'JSType.OneWay' could be only used with void returning method.</value>
189+
</data>
187190
<data name="FuncArgumentNotSupported" xml:space="preserve">
188191
<value>Type {0} is not supported as argument of marshaled function.</value>
189192
<comment>{0} is a type of the argument</comment>

src/libraries/System.Runtime.InteropServices.JavaScript/src/CompatibilitySuppressions.xml

+12
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,16 @@
1212
<Left>ref/net9.0/System.Runtime.InteropServices.JavaScript.dll</Left>
1313
<Right>runtimes/browser/lib/net9.0/System.Runtime.InteropServices.JavaScript.dll</Right>
1414
</Suppression>
15+
<Suppression>
16+
<DiagnosticId>CP0001</DiagnosticId>
17+
<Target>T:System.Runtime.InteropServices.JavaScript.JSType.OneWay</Target>
18+
<Left>ref/net9.0/System.Runtime.InteropServices.JavaScript.dll</Left>
19+
<Right>runtimes/browser/lib/net9.0/System.Runtime.InteropServices.JavaScript.dll</Right>
20+
</Suppression>
21+
<Suppression>
22+
<DiagnosticId>CP0002</DiagnosticId>
23+
<Target>M:System.Runtime.InteropServices.JavaScript.JSMarshalerType.get_OneWay</Target>
24+
<Left>ref/net9.0/System.Runtime.InteropServices.JavaScript.dll</Left>
25+
<Right>runtimes/browser/lib/net9.0/System.Runtime.InteropServices.JavaScript.dll</Right>
26+
</Suppression>
1527
</Suppressions>

src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Collections.Generic;
5+
using System.Diagnostics;
46
using System.Diagnostics.CodeAnalysis;
57
using System.Reflection;
68
using System.Runtime.CompilerServices;
@@ -28,6 +30,7 @@ public static void CallEntrypoint(JSMarshalerArgument* arguments_buffer)
2830
#if FEATURE_WASM_MANAGED_THREADS
2931
// when we arrive here, we are on the thread which owns the proxies
3032
arg_exc.AssertCurrentThreadContext();
33+
Debug.Assert(arg_result.slot.Type == MarshalerType.TaskPreCreated);
3134
#endif
3235

3336
arg_1.ToManaged(out IntPtr assemblyNamePtr);
@@ -47,6 +50,7 @@ public static void CallEntrypoint(JSMarshalerArgument* arguments_buffer)
4750
}
4851
}
4952

53+
// the marshaled signature is: void LoadLazyAssembly(byte[] dll, byte[] pdb)
5054
public static void LoadLazyAssembly(JSMarshalerArgument* arguments_buffer)
5155
{
5256
ref JSMarshalerArgument arg_exc = ref arguments_buffer[0];
@@ -70,6 +74,7 @@ public static void LoadLazyAssembly(JSMarshalerArgument* arguments_buffer)
7074
}
7175
}
7276

77+
// the marshaled signature is: void LoadSatelliteAssembly(byte[] dll)
7378
public static void LoadSatelliteAssembly(JSMarshalerArgument* arguments_buffer)
7479
{
7580
ref JSMarshalerArgument arg_exc = ref arguments_buffer[0];
@@ -91,10 +96,8 @@ public static void LoadSatelliteAssembly(JSMarshalerArgument* arguments_buffer)
9196
}
9297
}
9398

94-
// The JS layer invokes this method when the JS wrapper for a JS owned object
95-
// has been collected by the JS garbage collector
96-
// the marshaled signature is:
97-
// void ReleaseJSOwnedObjectByGCHandle(GCHandle gcHandle)
99+
// The JS layer invokes this method when the JS wrapper for a JS owned object has been collected by the JS garbage collector
100+
// the marshaled signature is: void ReleaseJSOwnedObjectByGCHandle(GCHandle gcHandle)
98101
public static void ReleaseJSOwnedObjectByGCHandle(JSMarshalerArgument* arguments_buffer)
99102
{
100103
ref JSMarshalerArgument arg_exc = ref arguments_buffer[0]; // initialized by caller in alloc_stack_frame()

src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptImports.Generated.cs

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ internal static unsafe partial class JavaScriptImports
5757

5858
#if DEBUG
5959
[JSImport("globalThis.console.log")]
60+
[return: JSMarshalAs<JSType.OneWay>]
6061
public static partial void Log([JSMarshalAs<JSType.String>] string message);
6162
#endif
6263
}

src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSFunctionBinding.cs

+21-12
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ internal JSFunctionBinding() { }
3030
internal static volatile uint nextImportHandle = 1;
3131
internal int ImportHandle;
3232
internal bool IsAsync;
33+
internal bool IsOneWay;
3334
#if DEBUG
3435
internal string? FunctionName;
3536
#endif
@@ -285,6 +286,11 @@ internal static unsafe void InvokeJSImportImpl(JSFunctionBinding signature, Span
285286
arguments[1].slot.GCHandle = holder.GCHandle;
286287
}
287288

289+
if (signature.IsOneWay)
290+
{
291+
arguments[1].slot.Type = MarshalerType.OneWay;
292+
}
293+
288294
#if FEATURE_WASM_MANAGED_THREADS
289295
// if we are on correct thread already or this is synchronous call, just call it
290296
if (targetContext.IsCurrentThread())
@@ -299,15 +305,15 @@ internal static unsafe void InvokeJSImportImpl(JSFunctionBinding signature, Span
299305
#endif
300306

301307
}
302-
else if (!signature.IsAsync)
308+
else if (signature.IsAsync || signature.IsOneWay)
303309
{
304-
//sync
305-
DispatchJSImportSyncSend(signature, targetContext, arguments);
310+
//async
311+
DispatchJSImportAsyncPost(signature, targetContext, arguments);
306312
}
307313
else
308314
{
309-
//async
310-
DispatchJSImportAsyncPost(signature, targetContext, arguments);
315+
//sync
316+
DispatchJSImportSyncSend(signature, targetContext, arguments);
311317
}
312318
#else
313319
InvokeJSImportCurrent(signature, arguments);
@@ -332,9 +338,9 @@ internal static unsafe void InvokeJSImportCurrent(JSFunctionBinding signature, S
332338
fixed (JSMarshalerArgument* args = arguments)
333339
{
334340
#if FEATURE_WASM_MANAGED_THREADS
335-
Interop.Runtime.InvokeJSImportSync((nint)args, (nint)signature.Header);
341+
Interop.Runtime.InvokeJSImportSync((nint)signature.Header, (nint)args);
336342
#else
337-
Interop.Runtime.InvokeJSImport(signature.ImportHandle, (nint)args);
343+
Interop.Runtime.InvokeJSImportST(signature.ImportHandle, (nint)args);
338344
#endif
339345
}
340346

@@ -361,7 +367,7 @@ internal static unsafe void DispatchJSImportSyncSend(JSFunctionBinding signature
361367
// we also don't throw PNSE here, because we know that the target has JS interop installed and that it could not block
362368
// so it could take some time, while target is CPU busy, but not forever
363369
// see also https://github.com/dotnet/runtime/issues/76958#issuecomment-1921418290
364-
Interop.Runtime.InvokeJSImportSyncSend(targetContext.JSNativeTID, args, sig);
370+
Interop.Runtime.InvokeJSImportSyncSend(targetContext.JSNativeTID, sig, args);
365371

366372
ref JSMarshalerArgument exceptionArg = ref arguments[0];
367373
if (exceptionArg.slot.Type != MarshalerType.None)
@@ -375,7 +381,10 @@ internal static unsafe void DispatchJSImportSyncSend(JSFunctionBinding signature
375381
#endif
376382
internal static unsafe void DispatchJSImportAsyncPost(JSFunctionBinding signature, JSProxyContext targetContext, Span<JSMarshalerArgument> arguments)
377383
{
378-
// this copy is freed in mono_wasm_invoke_import_async
384+
// meaning JS side needs to dispose it
385+
ref JSMarshalerArgument exc = ref arguments[0];
386+
exc.slot.ReceiverShouldFree = true;
387+
379388
var bytes = sizeof(JSMarshalerArgument) * arguments.Length;
380389
void* cpy = (void*)Marshal.AllocHGlobal(bytes);
381390
void* src = Unsafe.AsPointer(ref arguments[0]);
@@ -385,7 +394,7 @@ internal static unsafe void DispatchJSImportAsyncPost(JSFunctionBinding signatur
385394
// we already know that we are not on the right thread
386395
// this will return quickly after sending the message
387396
// async
388-
Interop.Runtime.InvokeJSImportAsyncPost(targetContext.JSNativeTID, (nint)cpy, sig);
397+
Interop.Runtime.InvokeJSImportAsyncPost(targetContext.JSNativeTID, sig, (nint)cpy);
389398

390399
}
391400

@@ -431,8 +440,8 @@ internal static unsafe void ResolveOrRejectPromise(JSProxyContext targetContext,
431440
else
432441
{
433442
// meaning JS side needs to dispose it
434-
ref JSMarshalerArgument res = ref arguments[1];
435-
res.slot.BooleanValue = true;
443+
ref JSMarshalerArgument exc = ref arguments[0];
444+
exc.slot.ReceiverShouldFree = true;
436445

437446
// this copy is freed in mono_wasm_resolve_or_reject_promise
438447
var bytes = sizeof(JSMarshalerArgument) * arguments.Length;

src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs

+1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ public static unsafe JSFunctionBinding GetMethodSignature(ReadOnlySpan<JSMarshal
153153
var type = signature.Sigs[i] = types[i + 1]._signatureType;
154154
}
155155
signature.IsAsync = types[0]._signatureType.Type == MarshalerType.Task;
156+
signature.IsOneWay = types[0]._signatureType.Type == MarshalerType.OneWay;
156157

157158
signature.Header[0].ImportHandle = signature.ImportHandle;
158159
signature.Header[0].FunctionNameLength = functionNameBytes;

src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSMarshalerArgument.cs

+3
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ internal struct JSMarshalerArgumentImpl
6060

6161
[FieldOffset(16)]
6262
internal IntPtr ContextHandle;
63+
64+
[FieldOffset(20)]
65+
internal bool ReceiverShouldFree;
6366
}
6467

6568
/// <summary>

src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSMarshalerType.cs

+9
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ private JSMarshalerType(JSFunctionBinding.JSBindingType signatureType)
4444
Type = MarshalerType.Discard
4545
});
4646

47+
/// <summary>
48+
/// Dispatches the call asynchronously and doesn't wait for result.
49+
/// </summary>
50+
/// <returns>The marshaler metadata.</returns>
51+
public static JSMarshalerType OneWay { get; } = new JSMarshalerType(new JSFunctionBinding.JSBindingType
52+
{
53+
Type = MarshalerType.OneWay
54+
});
55+
4756
/// <summary>
4857
/// Marshal as JavaScript <see href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean">Boolean</see> type.
4958
/// </summary>

src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSProxyContext.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ private JSProxyContext()
3636
#else
3737
public nint ContextHandle;
3838
public nint JSNativeTID; // target thread where JavaScript is running
39-
public int ManagedTID;
39+
public nint NativeTID; // current pthread id
40+
public int ManagedTID; // current managed thread id
4041
public bool IsMainThread;
4142
public JSSynchronizationContext SynchronizationContext;
4243

@@ -58,7 +59,7 @@ public static IntPtr GetNativeThreadId()
5859
public JSProxyContext(bool isMainThread, JSSynchronizationContext synchronizationContext)
5960
{
6061
SynchronizationContext = synchronizationContext;
61-
JSNativeTID = GetNativeThreadId();
62+
NativeTID = JSNativeTID = GetNativeThreadId();
6263
ManagedTID = Environment.CurrentManagedThreadId;
6364
IsMainThread = isMainThread;
6465
ContextHandle = (nint)GCHandle.Alloc(this, GCHandleType.Normal);

src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSSynchronizationContext.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ private unsafe void ScheduleJSPump()
179179
{
180180
// While we COULD pump here, we don't want to. We want the pump to happen on the next event loop turn.
181181
// Otherwise we could get a chain where a pump generates a new work item and that makes us pump again, forever.
182-
TargetThreadScheduleBackgroundJob(ProxyContext.JSNativeTID, (delegate* unmanaged[Cdecl]<void>)&BackgroundJobHandler);
182+
TargetThreadScheduleBackgroundJob(ProxyContext.NativeTID, (delegate* unmanaged[Cdecl]<void>)&BackgroundJobHandler);
183183
}
184184

185185
public override void Post(SendOrPostCallback d, object? state)

src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSType.cs

+9
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ public sealed class Discard : JSType
2828
internal Discard() { }
2929
}
3030

31+
/// <summary>
32+
/// Could return immediately without waiting for the execution to finish, when dispatching the call to another thread.
33+
/// Suppresses marshaling of the JavaScript function's return value.
34+
/// </summary>
35+
public sealed class OneWay : JSType
36+
{
37+
internal OneWay() { }
38+
}
39+
3140
/// <summary>
3241
/// Marshal as JavaScript <see href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean">Boolean</see> type.
3342
/// </summary>

src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/MarshalerType.cs

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ internal enum MarshalerType : byte
3434
Span,
3535
Action,
3636
Function,
37+
OneWay,
3738

3839
#if !JSIMPORTGENERATOR
3940
// only on runtime

src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSExportTest.cs

+11
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ await JsExportTestAsync(value,
2424
"boolean");
2525
}
2626

27+
[Theory]
28+
[MemberData(nameof(MarshalInt32Cases))]
29+
public async Task JsExportInt32OneWay(int value)
30+
{
31+
JavaScriptTestHelper.optimizedReached=0;
32+
33+
JavaScriptTestHelper.invoke1O(value);
34+
await Task.Yield();
35+
Assert.Equal(value, JavaScriptTestHelper.optimizedReached);
36+
}
37+
2738
private async Task JsExportTestAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] T>(T value
2839
, Func<T, string, Task<T>> invoke, string echoName, string jsType, string? jsClass = null)
2940
{

src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs

+9
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,15 @@ public void JsImportInt16(short value)
527527
#endregion Int16
528528

529529
#region Int32
530+
[Theory]
531+
[MemberData(nameof(MarshalInt32Cases))]
532+
public async Task JsImportInt32OneWay(int value)
533+
{
534+
JavaScriptTestHelper.store1OneWay_Int32(value);
535+
await Task.Yield();
536+
Assert.Equal(value, JavaScriptTestHelper.retrieve1_Int32());
537+
}
538+
530539
[Theory]
531540
[MemberData(nameof(MarshalInt32Cases))]
532541
public void JsImportInt32(int value)

0 commit comments

Comments
 (0)