Skip to content

Commit 93483ba

Browse files
authored
[browser][MT] fix error propagation when calling JSImport of missing JS function (#100408)
1 parent f37a5c1 commit 93483ba

File tree

4 files changed

+36
-11
lines changed

4 files changed

+36
-11
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ public void MissingImport()
4343
Assert.Contains("intentionallyMissingImport must be a Function but was undefined", ex.Message);
4444
}
4545

46+
[Fact]
47+
public async Task MissingImportAsync()
48+
{
49+
var ex = await Assert.ThrowsAsync<JSException>(() => JavaScriptTestHelper.IntentionallyMissingImportAsync());
50+
Assert.Contains("intentionallyMissingImportAsync must be a Function but was undefined", ex.Message);
51+
}
52+
4653
#if !FEATURE_WASM_MANAGED_THREADS // because in MT JSHost.ImportAsync is really async, it will finish before the caller could cancel it
4754
[Fact]
4855
public async Task CancelableImportAsync()

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ public static void ConsoleWriteLine([JSMarshalAs<JSType.String>] string message)
4040
[JSImport("intentionallyMissingImport", "JavaScriptTestHelper")]
4141
public static partial void IntentionallyMissingImport();
4242

43+
[JSImport("intentionallyMissingImportAsync", "JavaScriptTestHelper")]
44+
public static partial Task IntentionallyMissingImportAsync();
45+
4346
[JSImport("catch1toString", "JavaScriptTestHelper")]
4447
public static partial string catch1toString(string message, string functionName);
4548

src/mono/browser/runtime/invoke-js.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import WasmEnableThreads from "consts:wasmEnableThreads";
55
import BuildConfiguration from "consts:configuration";
66

7-
import { marshal_exception_to_cs, bind_arg_marshal_to_cs } from "./marshal-to-cs";
8-
import { get_signature_argument_count, bound_js_function_symbol, get_sig, get_signature_version, get_signature_type, imported_js_function_symbol, get_signature_handle, get_signature_function_name, get_signature_module_name, is_receiver_should_free, get_caller_native_tid, get_sync_done_semaphore_ptr } from "./marshal";
7+
import { marshal_exception_to_cs, bind_arg_marshal_to_cs, marshal_task_to_cs } from "./marshal-to-cs";
8+
import { get_signature_argument_count, bound_js_function_symbol, get_sig, get_signature_version, get_signature_type, imported_js_function_symbol, get_signature_handle, get_signature_function_name, get_signature_module_name, is_receiver_should_free, get_caller_native_tid, get_sync_done_semaphore_ptr, get_arg } from "./marshal";
99
import { forceThreadMemoryViewRefresh } from "./memory";
1010
import { JSFunctionSignature, JSMarshalerArguments, BoundMarshalerToJs, JSFnHandle, BoundMarshalerToCs, JSHandle, MarshalerType, VoidPtrNull } from "./types/internal";
1111
import { VoidPtr } from "./types/emscripten";
@@ -28,7 +28,6 @@ export function mono_wasm_bind_js_import_ST (signature: JSFunctionSignature): Vo
2828
bind_js_import(signature);
2929
return VoidPtrNull;
3030
} catch (ex: any) {
31-
Module.err(ex.toString());
3231
return stringToUTF16Ptr(normalize_exception(ex));
3332
}
3433
}
@@ -45,9 +44,25 @@ export function mono_wasm_invoke_jsimport_MT (signature: JSFunctionSignature, ar
4544
try {
4645
bound_fn = bind_js_import(signature);
4746
} catch (ex: any) {
48-
Module.err(ex.toString());
49-
marshal_exception_to_cs(<any>args, ex);
50-
return;
47+
// propagate the exception back to caller, which could be on different thread. Handle both sync and async signatures.
48+
try {
49+
const res_sig = get_sig(signature, 1);
50+
const res_type = get_signature_type(res_sig);
51+
if (res_type === MarshalerType.Task) {
52+
const res = get_arg(args, 1);
53+
marshal_task_to_cs(res, Promise.reject(ex));
54+
} else {
55+
marshal_exception_to_cs(<any>args, ex);
56+
if (monoThreadInfo.isUI) {
57+
const done_semaphore = get_sync_done_semaphore_ptr(args);
58+
tcwraps.mono_threads_wasm_sync_run_in_target_thread_done(done_semaphore);
59+
}
60+
}
61+
return;
62+
} catch (ex2: any) {
63+
runtimeHelpers.nativeExit(ex2);
64+
return;
65+
}
5166
}
5267
}
5368
mono_assert(bound_fn, () => `Imported function handle expected ${function_handle}`);

src/mono/browser/runtime/marshal-to-cs.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ export function initialize_marshalers_to_cs (): void {
4848
js_to_cs_marshalers.set(MarshalerType.JSException, marshal_exception_to_cs);
4949
js_to_cs_marshalers.set(MarshalerType.JSObject, marshal_js_object_to_cs);
5050
js_to_cs_marshalers.set(MarshalerType.Object, marshal_cs_object_to_cs);
51-
js_to_cs_marshalers.set(MarshalerType.Task, _marshal_task_to_cs);
52-
js_to_cs_marshalers.set(MarshalerType.TaskResolved, _marshal_task_to_cs);
53-
js_to_cs_marshalers.set(MarshalerType.TaskRejected, _marshal_task_to_cs);
51+
js_to_cs_marshalers.set(MarshalerType.Task, marshal_task_to_cs);
52+
js_to_cs_marshalers.set(MarshalerType.TaskResolved, marshal_task_to_cs);
53+
js_to_cs_marshalers.set(MarshalerType.TaskRejected, marshal_task_to_cs);
5454
js_to_cs_marshalers.set(MarshalerType.Action, _marshal_function_to_cs);
5555
js_to_cs_marshalers.set(MarshalerType.Function, _marshal_function_to_cs);
5656
js_to_cs_marshalers.set(MarshalerType.None, _marshal_null_to_cs);// also void
@@ -295,7 +295,7 @@ function _marshal_function_to_cs (arg: JSMarshalerArgument, value: Function, _?:
295295
}
296296

297297

298-
function _marshal_task_to_cs (arg: JSMarshalerArgument, value: Promise<any>, _?: MarshalerType, res_converter?: MarshalerToCs) {
298+
export function marshal_task_to_cs (arg: JSMarshalerArgument, value: Promise<any>, _?: MarshalerType, res_converter?: MarshalerToCs) {
299299
const handleIsPreallocated = get_arg_type(arg) == MarshalerType.TaskPreCreated;
300300
if (value === null || value === undefined) {
301301
if (WasmEnableThreads && handleIsPreallocated) {
@@ -415,7 +415,7 @@ export function marshal_cs_object_to_cs (arg: JSMarshalerArgument, value: any):
415415
) {
416416
throw new Error("NotImplementedException: TypedArray");
417417
} else if (isThenable(value)) {
418-
_marshal_task_to_cs(arg, value);
418+
marshal_task_to_cs(arg, value);
419419
} else if (value instanceof Span) {
420420
throw new Error("NotImplementedException: Span");
421421
} else if (js_type == "object") {

0 commit comments

Comments
 (0)