Skip to content

Commit

Permalink
[browser][MT] fix nested synchronous JS interop call detection (#99296)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelsavara committed Mar 6, 2024
1 parent 7183d70 commit 2e1bde2
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public static int SlowRuntimeTimeoutModifier
public static bool IsWasmThreadingSupported => IsBrowser && IsEnvironmentVariableTrue("IsBrowserThreadingSupported");
public static bool IsNotWasmThreadingSupported => !IsWasmThreadingSupported;
public static bool IsWasmBackgroundExec => IsBrowser && IsEnvironmentVariableTrue("IsWasmBackgroundExec");
public static bool IsThreadingSupportedNotBrowserBackgroundExec => IsWasmThreadingSupported && !IsWasmBackgroundExec;
public static bool IsWasmBackgroundExecOrSingleThread => IsWasmBackgroundExec || IsNotWasmThreadingSupported;
public static bool IsThreadingSupportedOrBrowserBackgroundExec => IsWasmBackgroundExec || !IsBrowser;
public static bool IsBinaryFormatterSupported => IsNotMobile && !IsNativeAot;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ internal static unsafe void InvokeJSFunction(JSObject jsFunction, Span<JSMarshal

#if FEATURE_WASM_MANAGED_THREADS
ref JSMarshalerArgument exc = ref arguments[0];
exc.slot.CallerNativeTID = jsFunction.ProxyContext.NativeTID;
exc.slot.CallerNativeTID = JSProxyContext.GetNativeThreadId();

// if we are on correct thread already, just call it
if (jsFunction.ProxyContext.IsCurrentThread())
Expand Down Expand Up @@ -297,7 +297,7 @@ internal static unsafe void InvokeJSImportImpl(JSFunctionBinding signature, Span
ref JSMarshalerArgument res = ref arguments[1];
#if FEATURE_WASM_MANAGED_THREADS
var targetContext = JSProxyContext.SealJSImportCapturing();
exc.slot.CallerNativeTID = targetContext.NativeTID;
exc.slot.CallerNativeTID = JSProxyContext.GetNativeThreadId();
exc.slot.ContextHandle = targetContext.ContextHandle;
res.slot.ContextHandle = targetContext.ContextHandle;
#else
Expand Down Expand Up @@ -467,7 +467,7 @@ internal static unsafe void ResolveOrRejectPromise(JSProxyContext targetContext,
{
ref JSMarshalerArgument exc = ref arguments[0];
#if FEATURE_WASM_MANAGED_THREADS
exc.slot.CallerNativeTID = targetContext.NativeTID;
exc.slot.CallerNativeTID = JSProxyContext.GetNativeThreadId();

if (targetContext.IsCurrentThread())
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ namespace System.Runtime.InteropServices.JavaScript.Tests
{
public class JSExportAsyncTest : JSInteropTestBase, IAsyncLifetime
{
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupportedNotBrowserBackgroundExec))]
public void SyncJsImportJsExportThrows()
{
var ex = Assert.Throws<JSException>(()=>JavaScriptTestHelper.invoke1_Boolean(true, nameof(JavaScriptTestHelper.EchoBoolean)));
Assert.Contains("Cannot call synchronous C# method", ex.Message);
}

[Theory]
[MemberData(nameof(MarshalBooleanCases))]
public async Task JsExportBooleanAsync(bool value)
Expand Down Expand Up @@ -150,6 +157,7 @@ public void JsExportIntPtr(IntPtr value)
[MemberData(nameof(MarshalIntPtrCases))]
public unsafe void JsExportVoidPtr(IntPtr xvalue)
{
JavaScriptTestHelper.AssertWasmBackgroundExec();
void* value = (void*)xvalue;
void* res = JavaScriptTestHelper.invoke1_VoidPtr(value, nameof(JavaScriptTestHelper.EchoVoidPtr));
Assert.True(value == res);
Expand Down Expand Up @@ -180,6 +188,7 @@ public void JsExportDateTimeOffset(DateTimeOffset value)
[MemberData(nameof(MarshalNullableBooleanCases))]
public void JsExportNullableBoolean(bool? value)
{
JavaScriptTestHelper.AssertWasmBackgroundExec();
JsExportTest(value,
JavaScriptTestHelper.invoke1_NullableBoolean,
nameof(JavaScriptTestHelper.EchoNullableBoolean),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ public unsafe void OutOfRange()
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWasmBackgroundExecOrSingleThread))]
public unsafe void OptimizedPaths()
{
JavaScriptTestHelper.AssertWasmBackgroundExec();
JavaScriptTestHelper.optimizedReached = 0;
JavaScriptTestHelper.invoke0V();
Assert.Equal(1, JavaScriptTestHelper.optimizedReached);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1020,14 +1020,24 @@ public static JSObject EchoIJSObject([JSMarshalAs<JSType.Object>] JSObject arg1)
[JSImport("INTERNAL.forceDisposeProxies")]
internal static partial void ForceDisposeProxies(bool disposeMethods, bool verbose);

public static void AssertWasmBackgroundExec()
{
if (PlatformDetection.IsWasmBackgroundExec && Environment.CurrentManagedThreadId == 1)
{
throw new Exception("With WasmBackgroundExec we are expecting to run tests on the thread pool");
}
}

static JSObject _module;
public static async Task InitializeAsync()
{
AssertWasmBackgroundExec();
if (_module == null)
{
_module = await JSHost.ImportAsync("JavaScriptTestHelper", "../JavaScriptTestHelper.mjs"); ;
await Setup();
}
AssertWasmBackgroundExec();

#if FEATURE_WASM_MANAGED_THREADS
// are we in the UI thread ?
Expand All @@ -1037,6 +1047,7 @@ public static async Task InitializeAsync()
// this gives browser chance to serve UI thread event loop before every test
await Task.Yield();
}
AssertWasmBackgroundExec();
}

public static Task DisposeAsync()
Expand Down
2 changes: 1 addition & 1 deletion src/mono/browser/runtime/invoke-js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ function bind_js_import(signature: JSFunctionSignature): Function {
try {
forceThreadMemoryViewRefresh();
const caller_tid = get_caller_native_tid(args);
runtimeHelpers.isPendingSynchronousCall = runtimeHelpers.currentThreadTID === caller_tid;
runtimeHelpers.isPendingSynchronousCall = runtimeHelpers.managedThreadTID === caller_tid;
bound_fn(args);
}
finally {
Expand Down

0 comments on commit 2e1bde2

Please sign in to comment.