diff --git a/src/mono/CMakeLists.txt b/src/mono/CMakeLists.txt
index 6909e62fcf0bd0..7ed11e8c699d70 100644
--- a/src/mono/CMakeLists.txt
+++ b/src/mono/CMakeLists.txt
@@ -655,7 +655,12 @@ if(LLVM_PREFIX)
# llvm-config --cflags
set(llvm_cflags "-I${LLVM_PREFIX}/include -D__STDC_CONSTANT_MACROS -D__STD_FORMAT_MACROS -D__STDC_LIMIT_MACROS")
- set(llvm_cxxflags "-I${LLVM_PREFIX}/include ${MONO_cxx_include} ${MONO_cxx_std_version} ${MONO_stdlib} -fno-exceptions -fno-rtti -D__STDC_CONSTANT_MACROS -D__STD_FORMAT_MACROS -D__STDC_LIMIT_MACROS")
+
+ if (HOST_BROWSER)
+ set(llvm_cxxflags "-I${LLVM_PREFIX}/include ${MONO_cxx_include} ${MONO_cxx_std_version} ${MONO_stdlib} -fno-rtti -D__STDC_CONSTANT_MACROS -D__STD_FORMAT_MACROS -D__STDC_LIMIT_MACROS")
+ else()
+ set(llvm_cxxflags "-I${LLVM_PREFIX}/include ${MONO_cxx_include} ${MONO_cxx_std_version} ${MONO_stdlib} -fno-exceptions -fno-rtti -D__STDC_CONSTANT_MACROS -D__STD_FORMAT_MACROS -D__STDC_LIMIT_MACROS")
+ endif()
set(llvm_includedir "${LLVM_PREFIX}/include")
if(HOST_LINUX)
@@ -694,6 +699,10 @@ if(LLVM_PREFIX)
string(REPLACE "/EHs-c-" "" llvm_cxxflags "${llvm_cxxflags}")
# /GR- already enabled and inherited from LLVM flags. Corresponds to -fno-rtti.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${llvm_cxxflags}")
+ elseif(HOST_BROWSER)
+ # emscripten's handling of the different exception modes is complex, so having multiple flags
+ # passed during a single compile is undesirable. we need to set them elsewhere.
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${llvm_cxxflags} -fno-rtti")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${llvm_cxxflags} -fexceptions -fno-rtti")
endif()
diff --git a/src/mono/mono.proj b/src/mono/mono.proj
index 26c7c470b3447d..789544b8a4bdc7 100644
--- a/src/mono/mono.proj
+++ b/src/mono/mono.proj
@@ -207,7 +207,7 @@
%(_ActualVersionLines.Identity)
%(_ExpectedVersionLines.Identity)
-
@@ -416,10 +416,8 @@
<_MonoCMakeArgs Include="-DENABLE_ICALL_EXPORT=1"/>
<_MonoCMakeArgs Include="-DENABLE_LAZY_GC_THREAD_CREATION=1"/>
<_MonoCMakeArgs Include="-DENABLE_WEBCIL=1"/>
- <_MonoCFLAGS Include="-fexceptions"/>
<_MonoCFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="-pthread"/>
<_MonoCFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="-D_GNU_SOURCE=1" />
- <_MonoCXXFLAGS Include="-fexceptions"/>
<_MonoCXXFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="-pthread"/>
<_MonoCXXFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="-D_GNU_SOURCE=1" />
@@ -433,8 +431,8 @@
-
<_MonoCFLAGS Include="$(EscapedQuoteW)-I$([MSBuild]::NormalizePath('$(MonoProjectRoot)', 'wasi', 'include').Replace('\','/'))$(EscapedQuoteW)"/>
diff --git a/src/mono/mono/mini/CMakeLists.txt b/src/mono/mono/mini/CMakeLists.txt
index cca4fea9ca493b..b7d7b6d029a594 100644
--- a/src/mono/mono/mini/CMakeLists.txt
+++ b/src/mono/mono/mini/CMakeLists.txt
@@ -503,10 +503,14 @@ if(HOST_BROWSER)
# This is the only source file which contains a c++ throw or catch
add_library(mono-wasm-eh-js STATIC llvm-runtime.cpp)
target_link_libraries (mono-wasm-eh-js PRIVATE monoapi eglib_api)
+ set_target_properties(mono-wasm-eh-js PROPERTIES COMPILE_FLAGS "-fexceptions")
+ set_target_properties(mono-wasm-eh-js PROPERTIES LINK_FLAGS "-fexceptions -s EXPORT_EXCEPTION_HANDLING_HELPERS=1")
install(TARGETS mono-wasm-eh-js LIBRARY)
+
add_library(mono-wasm-eh-wasm STATIC llvm-runtime.cpp)
target_link_libraries (mono-wasm-eh-wasm PRIVATE monoapi eglib_api)
set_target_properties(mono-wasm-eh-wasm PROPERTIES COMPILE_FLAGS "-fwasm-exceptions")
+ set_target_properties(mono-wasm-eh-wasm PROPERTIES LINK_FLAGS "-fwasm-exceptions -s EXPORT_EXCEPTION_HANDLING_HELPERS=1")
install(TARGETS mono-wasm-eh-wasm LIBRARY)
endif()
diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c
index 463c25a7972bd9..35c3021dcee13c 100644
--- a/src/mono/mono/mini/interp/interp.c
+++ b/src/mono/mono/mini/interp/interp.c
@@ -2707,21 +2707,8 @@ do_jit_call (ThreadContext *context, stackval *ret_sp, stackval *sp, InterpFrame
interp_push_lmf (&ext, frame);
if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
-#if JITERPRETER_ENABLE_SPECIALIZED_JIT_CALL
- /*
- * invoke jit_call_cb via a single indirect function call that dispatches to
- * either a specialized JS implementation or a specialized WASM EH version
- * see jiterpreter-jit-call.ts and do-jit-call.wat
- * NOTE: the first argument must ALWAYS be jit_call_cb for the specialization.
- * the actual implementation cannot verify this at runtime, so get it right
- * this is faster than mono_llvm_cpp_catch_exception by avoiding the use of
- * emscripten invoke_vi to find and invoke jit_call_cb indirectly
- */
- jiterpreter_do_jit_call (jit_call_cb, &cb_data, &thrown);
-#else
/* Catch the exception thrown by the native code using a try-catch */
mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
-#endif
} else {
jit_call_cb (&cb_data);
}
diff --git a/src/mono/mono/mini/interp/jiterpreter.c b/src/mono/mono/mini/interp/jiterpreter.c
index 0dd3175cfb74ab..ceb6a66679647e 100644
--- a/src/mono/mono/mini/interp/jiterpreter.c
+++ b/src/mono/mono/mini/interp/jiterpreter.c
@@ -60,10 +60,6 @@ void jiterp_preserve_module (void);
static gint32 jiterpreter_abort_counts[MINT_LASTOP + 1] = { 0 };
static int64_t jiterp_trace_bailout_counts[256] = { 0 };
-// This function pointer is used by interp.c to invoke jit_call_cb for exception handling purposes
-// See jiterpreter-jit-call.ts mono_jiterp_do_jit_call_indirect
-WasmDoJitCall jiterpreter_do_jit_call = mono_jiterp_do_jit_call_indirect;
-
// We disable this diagnostic because EMSCRIPTEN_KEEPALIVE makes it a false alarm, the keepalive
// functions are being used externally. Having a bunch of prototypes is pointless since these
// functions are not consumed by C anywhere else
@@ -1021,20 +1017,6 @@ mono_jiterp_get_options_as_json ()
return mono_options_get_as_json ();
}
-EMSCRIPTEN_KEEPALIVE void
-mono_jiterp_update_jit_call_dispatcher (WasmDoJitCall dispatcher)
-{
- // If we received a 0 dispatcher that means the TS side failed to compile
- // any kind of dispatcher - this likely indicates that content security policy
- // blocked the use of Module.addFunction
- if (!dispatcher)
- dispatcher = (WasmDoJitCall)mono_llvm_cpp_catch_exception;
- else if (((int)(void*)dispatcher)==-1)
- dispatcher = mono_jiterp_do_jit_call_indirect;
-
- jiterpreter_do_jit_call = dispatcher;
-}
-
EMSCRIPTEN_KEEPALIVE int
mono_jiterp_object_has_component_size (MonoObject ** ppObj)
{
diff --git a/src/mono/mono/mini/interp/jiterpreter.h b/src/mono/mono/mini/interp/jiterpreter.h
index 643f2c05478289..26b05f64a0c85f 100644
--- a/src/mono/mono/mini/interp/jiterpreter.h
+++ b/src/mono/mono/mini/interp/jiterpreter.h
@@ -5,12 +5,8 @@
#ifdef DISABLE_THREADS
#define JITERPRETER_ENABLE_JIT_CALL_TRAMPOLINES 1
-// enables specialized mono_llvm_cpp_catch_exception replacement (see jiterpreter-jit-call.ts)
-// works even if the jiterpreter is otherwise disabled.
-#define JITERPRETER_ENABLE_SPECIALIZED_JIT_CALL 1
#else
#define JITERPRETER_ENABLE_JIT_CALL_TRAMPOLINES 0
-#define JITERPRETER_ENABLE_SPECIALIZED_JIT_CALL 0
#endif // DISABLE_THREADS
// mono_interp_tier_prepare_jiterpreter will return these special values if it doesn't
@@ -49,9 +45,8 @@ __attribute__ ((__packed__, __aligned__(2)))
// Keep in sync with JiterpreterTable in jiterpreter-enums.ts
enum {
JITERPRETER_TABLE_TRACE = 0,
- JITERPRETER_TABLE_DO_JIT_CALL = 1,
- JITERPRETER_TABLE_JIT_CALL = 2,
- JITERPRETER_TABLE_INTERP_ENTRY_STATIC_0 = 3,
+ JITERPRETER_TABLE_JIT_CALL = 1,
+ JITERPRETER_TABLE_INTERP_ENTRY_STATIC_0 = 2,
JITERPRETER_TABLE_INTERP_ENTRY_STATIC_1,
JITERPRETER_TABLE_INTERP_ENTRY_STATIC_2,
JITERPRETER_TABLE_INTERP_ENTRY_STATIC_3,
@@ -165,11 +160,6 @@ mono_interp_invoke_wasm_jit_call_trampoline (
void *ftndesc, gboolean *thrown
);
-extern void
-mono_jiterp_do_jit_call_indirect (
- gpointer cb, gpointer arg, gboolean *out_thrown
-);
-
#ifdef __MONO_MINI_INTERPRETER_INTERNALS_H__
extern void
@@ -247,8 +237,6 @@ mono_jiterp_tlqueue_purge_all (gpointer item);
#endif // __MONO_MINI_INTERPRETER_INTERNALS_H__
-extern WasmDoJitCall jiterpreter_do_jit_call;
-
#endif // HOST_BROWSER
#endif // __MONO_MINI_JITERPRETER_H__
diff --git a/src/mono/mono/mini/llvm-runtime.cpp b/src/mono/mono/mini/llvm-runtime.cpp
index a14b26bd739cf4..8159020ea9fe88 100644
--- a/src/mono/mono/mini/llvm-runtime.cpp
+++ b/src/mono/mono/mini/llvm-runtime.cpp
@@ -47,4 +47,22 @@ mono_llvm_cpp_catch_exception (MonoLLVMInvokeCallback cb, gpointer arg, gboolean
}
}
+#ifdef HOST_WASM
+
+// https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
+void *__cxa_begin_catch (void *exceptionObject);
+void __cxa_end_catch (void);
+
+EMSCRIPTEN_KEEPALIVE void
+mono_jiterp_begin_catch (void *exception_object) {
+ __cxa_begin_catch (exception_object);
+}
+
+EMSCRIPTEN_KEEPALIVE void
+mono_jiterp_end_catch (void) {
+ return __cxa_end_catch ();
+}
+
+#endif
+
}
diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets
index 557db242b43fa2..d9595b16c2eb42 100644
--- a/src/mono/wasm/build/WasmApp.Native.targets
+++ b/src/mono/wasm/build/WasmApp.Native.targets
@@ -26,6 +26,8 @@
_ReadEmccProps
+ <_EmccDefaultFlags Condition="'$(WasmEnableExceptionHandling)' == 'false'">-fexceptions
+ <_EmccDefaultFlags Condition="'$(WasmEnableExceptionHandling)' != 'false'">-fwasm-exceptions
<_EmccDefaultFlags Condition="'$(WasmEnableSIMD)' == 'true'">-msimd128
<_ExeExt Condition="$([MSBuild]::IsOSPlatform('WINDOWS'))">.exe
true
@@ -254,6 +256,7 @@
<_EmccLDFlags Include="$(EmccLinkOptimizationFlag)" />
<_EmccLDFlags Include="@(_EmccCommonFlags)" />
<_EmccLDFlags Include="-s EXPORT_ES6=1" />
+ <_EmccLDFlags Condition="'$(WasmEnableExceptionHandling)' != 'false'" Include="-s EXPORT_EXCEPTION_HANDLING_HELPERS=1" />
<_DriverCDependencies Include="$(_WasmPInvokeHPath);$(_WasmICallTablePath)" />
<_DriverCDependencies Include="$(_DriverGenCPath)" Condition="'$(_DriverGenCNeeded)' == 'true'" />
diff --git a/src/mono/wasm/runtime/cwraps.ts b/src/mono/wasm/runtime/cwraps.ts
index f8c283eae52cf1..e2ddc4b41b3853 100644
--- a/src/mono/wasm/runtime/cwraps.ts
+++ b/src/mono/wasm/runtime/cwraps.ts
@@ -118,7 +118,6 @@ const fn_signatures: SigLine[] = [
[true, "mono_jiterp_adjust_abort_count", "number", ["number", "number"]],
[true, "mono_jiterp_register_jit_call_thunk", "void", ["number", "number"]],
[true, "mono_jiterp_type_get_raw_value_size", "number", ["number"]],
- [true, "mono_jiterp_update_jit_call_dispatcher", "void", ["number"]],
[true, "mono_jiterp_get_signature_has_this", "number", ["number"]],
[true, "mono_jiterp_get_signature_return_type", "number", ["number"]],
[true, "mono_jiterp_get_signature_param_count", "number", ["number"]],
@@ -147,6 +146,8 @@ const fn_signatures: SigLine[] = [
[true, "mono_jiterp_tlqueue_next", "number", ["number"]],
[true, "mono_jiterp_tlqueue_add", "number", ["number", "number"]],
[true, "mono_jiterp_tlqueue_clear", "void", ["number"]],
+ [true, "mono_jiterp_begin_catch", "void", ["number"]],
+ [true, "mono_jiterp_end_catch", "void", []],
...diagnostics_cwraps,
...legacy_interop_cwraps
@@ -259,7 +260,6 @@ export interface t_Cwraps {
mono_jiterp_get_options_version(): number;
mono_jiterp_adjust_abort_count(opcode: number, delta: number): number;
mono_jiterp_register_jit_call_thunk(cinfo: number, func: number): void;
- mono_jiterp_update_jit_call_dispatcher(fn: number): void;
mono_jiterp_get_signature_has_this(sig: VoidPtr): number;
mono_jiterp_get_signature_return_type(sig: VoidPtr): MonoType;
mono_jiterp_get_signature_param_count(sig: VoidPtr): number;
@@ -291,6 +291,8 @@ export interface t_Cwraps {
// returns new size of queue after add
mono_jiterp_tlqueue_add(queue: number, value: VoidPtr): number;
mono_jiterp_tlqueue_clear(queue: number): void;
+ mono_jiterp_begin_catch(ptr: number): void;
+ mono_jiterp_end_catch(): void;
}
const wrapped_c_functions: t_Cwraps = {};
diff --git a/src/mono/wasm/runtime/exports-binding.ts b/src/mono/wasm/runtime/exports-binding.ts
index e3143c04f973be..8e856c35fa4c53 100644
--- a/src/mono/wasm/runtime/exports-binding.ts
+++ b/src/mono/wasm/runtime/exports-binding.ts
@@ -10,7 +10,7 @@ import { mono_wasm_bind_cs_function } from "./invoke-cs";
import { mono_wasm_bind_js_function, mono_wasm_invoke_bound_function, mono_wasm_invoke_import } from "./invoke-js";
import { mono_interp_tier_prepare_jiterpreter, mono_jiterp_free_method_data_js } from "./jiterpreter";
import { mono_interp_jit_wasm_entry_trampoline, mono_interp_record_interp_entry } from "./jiterpreter-interp-entry";
-import { mono_interp_jit_wasm_jit_call_trampoline, mono_interp_invoke_wasm_jit_call_trampoline, mono_interp_flush_jitcall_queue, mono_jiterp_do_jit_call_indirect } from "./jiterpreter-jit-call";
+import { mono_interp_jit_wasm_jit_call_trampoline, mono_interp_invoke_wasm_jit_call_trampoline, mono_interp_flush_jitcall_queue } from "./jiterpreter-jit-call";
import { mono_wasm_marshal_promise } from "./marshal-to-js";
import { mono_wasm_eventloop_has_unsettled_interop_promises } from "./pthreads/shared/eventloop";
import { mono_wasm_pthread_on_pthread_attached, mono_wasm_pthread_on_pthread_detached } from "./pthreads/worker";
@@ -88,7 +88,6 @@ export const mono_wasm_imports = [
mono_interp_jit_wasm_jit_call_trampoline,
mono_interp_invoke_wasm_jit_call_trampoline,
mono_interp_flush_jitcall_queue,
- mono_jiterp_do_jit_call_indirect,
mono_jiterp_free_method_data_js,
mono_wasm_profiler_enter,
diff --git a/src/mono/wasm/runtime/jiterpreter-enums.ts b/src/mono/wasm/runtime/jiterpreter-enums.ts
index 1c98615cc57d27..1e65f7b3cec39e 100644
--- a/src/mono/wasm/runtime/jiterpreter-enums.ts
+++ b/src/mono/wasm/runtime/jiterpreter-enums.ts
@@ -56,10 +56,9 @@ export const enum JiterpNumberMode {
// keep in sync with jiterpreter.h
export const enum JiterpreterTable {
- Trace,
- DoJitCall,
- JitCall,
- InterpEntryStatic0,
+ Trace = 0,
+ JitCall = 1,
+ InterpEntryStatic0 = 2,
InterpEntryStatic1,
InterpEntryStatic2,
InterpEntryStatic3,
diff --git a/src/mono/wasm/runtime/jiterpreter-feature-detect.ts b/src/mono/wasm/runtime/jiterpreter-feature-detect.ts
deleted file mode 100644
index b17f78483da444..00000000000000
--- a/src/mono/wasm/runtime/jiterpreter-feature-detect.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import {
- WasmValtype, WasmOpcode, WasmSimdOpcode
-} from "./jiterpreter-opcodes";
-import {
- WasmBuilder,
-} from "./jiterpreter-support";
-
-export function compileDoJitCall () : WebAssembly.Module {
- const builder = new WasmBuilder(0);
- builder.defineType("jit_call_cb", {
- "cb_data": WasmValtype.i32,
- }, WasmValtype.void, true);
- builder.defineType("do_jit_call", {
- "unused": WasmValtype.i32,
- "cb_data": WasmValtype.i32,
- "thrown": WasmValtype.i32,
- }, WasmValtype.void, true);
- builder.defineImportedFunction("i", "jit_call_cb", "jit_call_cb", true);
- builder.defineFunction({
- type: "do_jit_call",
- name: "do_jit_call_indirect",
- export: true,
- locals: {}
- }, () => {
- builder.block(WasmValtype.void, WasmOpcode.try_);
- builder.local("cb_data");
- builder.callImport("jit_call_cb");
- builder.appendU8(WasmOpcode.catch_all);
- builder.local("thrown");
- builder.i32_const(1);
- builder.appendU8(WasmOpcode.i32_store);
- builder.appendMemarg(0, 0);
- builder.endBlock();
- builder.appendU8(WasmOpcode.end);
- });
- // Magic number and version
- builder.appendU32(0x6d736100);
- builder.appendU32(1);
- builder.generateTypeSection();
- builder.emitImportsAndFunctions(false);
- const buffer = builder.getArrayView();
- return new WebAssembly.Module(buffer);
-}
-
-export function compileSimdFeatureDetect () : WebAssembly.Module {
- const builder = new WasmBuilder(0);
- builder.defineType("test", {}, WasmValtype.void, true);
- builder.defineFunction({
- type: "test",
- name: "test",
- export: true,
- locals: {}
- }, () => {
- builder.i32_const(0);
- builder.appendSimd(WasmSimdOpcode.i32x4_splat);
- builder.appendU8(WasmOpcode.drop);
- builder.appendU8(WasmOpcode.end);
- });
- // Magic number and version
- builder.appendU32(0x6d736100);
- builder.appendU32(1);
- builder.generateTypeSection();
- builder.emitImportsAndFunctions(false);
- const buffer = builder.getArrayView();
- return new WebAssembly.Module(buffer);
-}
diff --git a/src/mono/wasm/runtime/jiterpreter-jit-call.ts b/src/mono/wasm/runtime/jiterpreter-jit-call.ts
index 1af011764e7d8e..1b6514fa64fae1 100644
--- a/src/mono/wasm/runtime/jiterpreter-jit-call.ts
+++ b/src/mono/wasm/runtime/jiterpreter-jit-call.ts
@@ -1,9 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-import MonoWasmThreads from "consts:monoWasmThreads";
import { MonoType, MonoMethod } from "./types/internal";
-import { NativePointer, Int32Ptr, VoidPtr } from "./types/emscripten";
+import { NativePointer, VoidPtr } from "./types/emscripten";
import { Module, mono_assert, runtimeHelpers } from "./globals";
import {
getU8, getI32_unaligned, getU32_unaligned, setU32_unchecked, receiveWorkerHeapViews
@@ -14,12 +13,9 @@ import {
_now, getWasmFunctionTable, applyOptions,
recordFailure, getOptions,
getCounter, modifyCounter,
- jiterpreter_allocate_tables
+ getRawCwrap
} from "./jiterpreter-support";
import { JiterpreterTable, JiterpCounter, JitQueue } from "./jiterpreter-enums";
-import {
- compileDoJitCall
-} from "./jiterpreter-feature-detect";
import cwraps from "./cwraps";
import { mono_log_error, mono_log_info } from "./logging";
import { utf8ToString } from "./strings";
@@ -189,9 +185,33 @@ export function mono_interp_invoke_wasm_jit_call_trampoline(
const thunk = getWasmTableEntry(thunkIndex);
try {
thunk(ret_sp, sp, ftndesc, thrown);
- } catch (exc) {
+ } catch (exc: any) {
receiveWorkerHeapViews();
- setU32_unchecked(thrown, 1);
+ const exceptionTag = (Module)["asm"]["__cpp_exception"];
+ const haveTag = exceptionTag instanceof (WebAssembly).Tag;
+ if (
+ !haveTag || (
+ (exc instanceof (WebAssembly).Exception) &&
+ exc.is(exceptionTag)
+ )
+ ) {
+ setU32_unchecked(thrown, 1);
+
+ // Call begin_catch and then end_catch to clean it up.
+ if (haveTag) {
+ // Wasm EH is enabled, so we know that the current exception is a C++ exception
+ const ptr = exc.getArg(exceptionTag, 0);
+ cwraps.mono_jiterp_begin_catch(ptr);
+ cwraps.mono_jiterp_end_catch();
+ } else if (typeof (exc) === "number") {
+ // emscripten JS exception
+ cwraps.mono_jiterp_begin_catch(exc);
+ cwraps.mono_jiterp_end_catch();
+ } else
+ throw exc;
+ } else {
+ throw exc;
+ }
}
}
@@ -256,97 +276,18 @@ export function mono_interp_jit_wasm_jit_call_trampoline(
mono_interp_flush_jitcall_queue();
}
-let doJitCallModule: WebAssembly.Module | undefined = undefined;
-
function getIsWasmEhSupported(): boolean {
if (wasmEhSupported !== undefined)
return wasmEhSupported;
// Probe whether the current environment can handle wasm exceptions
- try {
- doJitCallModule = compileDoJitCall();
- wasmEhSupported = true;
- } catch (exc) {
- mono_log_info("Disabling WASM EH support due to JIT failure", exc);
- wasmEhSupported = false;
- }
+ wasmEhSupported = runtimeHelpers.featureWasmEh === true;
+ if (!wasmEhSupported)
+ mono_log_info("Disabling Jiterpreter Exception Handling");
return wasmEhSupported;
}
-// this is the generic entry point for do_jit_call that is registered by default at runtime startup.
-// its job is to do initialization for the optimized do_jit_call path, which will either use a jitted
-// wasm trampoline or will use a specialized JS function.
-export function mono_jiterp_do_jit_call_indirect(
- jit_call_cb: number, cb_data: VoidPtr, thrown: Int32Ptr
-): void {
- mono_assert(!runtimeHelpers.storeMemorySnapshotPending, "Attempting to set function into table during creation of memory snapshot");
- const table = getWasmFunctionTable();
- const jitCallCb = table.get(jit_call_cb);
-
- // This should perform better than the regular mono_llvm_cpp_catch_exception because the call target
- // is statically known, not being pulled out of a table.
- const do_jit_call_indirect_js = function (unused: number, _cb_data: VoidPtr, _thrown: Int32Ptr) {
- try {
- jitCallCb(_cb_data);
- } catch (exc) {
- receiveWorkerHeapViews();
- setU32_unchecked(_thrown, 1);
- }
- };
-
- let failed = !getIsWasmEhSupported();
- if (!failed) {
- // Wasm EH is supported which means doJitCallModule was loaded and compiled.
- // Now that we have jit_call_cb, we can instantiate it.
- try {
- const instance = new WebAssembly.Instance(doJitCallModule!, {
- i: {
- jit_call_cb: jitCallCb,
- },
- m: {
- h: (Module).getMemory()
- },
- });
- const impl = instance.exports.do_jit_call_indirect;
- if (typeof (impl) !== "function")
- throw new Error("Did not find exported do_jit_call handler");
-
- // Make sure we've allocated the jiterpreter tables first because we need to use them
- jiterpreter_allocate_tables(Module);
- // We successfully instantiated it so we can register it as the new do_jit_call handler
- const result = addWasmFunctionPointer(JiterpreterTable.DoJitCall, impl);
- cwraps.mono_jiterp_update_jit_call_dispatcher(result);
- failed = false;
- } catch (exc) {
- mono_log_error("failed to compile do_jit_call handler", exc);
- failed = true;
- }
- // If wasm EH support was detected, a native wasm implementation of the dispatcher was already registered.
- }
-
- if (failed) {
- // This means that either wasm EH is unavailable or we failed to JIT the handler somehow
- try {
- // HACK: It's not safe to use Module.addFunction in a multithreaded scenario
- if (MonoWasmThreads) {
- // Use mono_llvm_cpp_catch_exception instead
- cwraps.mono_jiterp_update_jit_call_dispatcher(0);
- } else {
- // Use the JS helper function defined up above
- const result = Module.addFunction(do_jit_call_indirect_js, "viii");
- cwraps.mono_jiterp_update_jit_call_dispatcher(result);
- }
- } catch {
- // CSP policy or some other problem could break Module.addFunction, so in that case, pass 0
- // This will cause the runtime to use mono_llvm_cpp_catch_exception
- cwraps.mono_jiterp_update_jit_call_dispatcher(0);
- }
- }
-
- do_jit_call_indirect_js(jit_call_cb, cb_data, thrown);
-}
-
export function mono_interp_flush_jitcall_queue(): void {
const jitQueue : TrampolineInfo[] = [];
let methodPtr = 0;
@@ -378,6 +319,14 @@ export function mono_interp_flush_jitcall_queue(): void {
"thrown": WasmValtype.i32,
}, WasmValtype.void, true
);
+ builder.defineType("begin_catch", {
+ "ptr": WasmValtype.i32,
+ }, WasmValtype.void, true);
+ builder.defineType("end_catch", {
+ }, WasmValtype.void, true);
+
+ builder.defineImportedFunction("i", "begin_catch", "begin_catch", true, getRawCwrap("mono_jiterp_begin_catch"));
+ builder.defineImportedFunction("i", "end_catch", "end_catch", true, getRawCwrap("mono_jiterp_end_catch"));
} else
builder.clear(0);
@@ -451,6 +400,9 @@ export function mono_interp_flush_jitcall_queue(): void {
for (let i = 0; i < trampImports.length; i++)
builder.markImportAsUsed(trampImports[i][0]);
+ builder.markImportAsUsed("begin_catch");
+ builder.markImportAsUsed("end_catch");
+
builder._generateImportSection(false);
// Function section
@@ -830,7 +782,10 @@ function generate_wasm_body(
// If the call threw a JS or wasm exception, set the thrown flag
if (builder.options.enableWasmEh) {
- builder.appendU8(WasmOpcode.catch_all);
+ builder.appendU8(WasmOpcode.catch_);
+ builder.appendULeb(builder.getTypeIndex("__cpp_exception"));
+ builder.callImport("begin_catch");
+ builder.callImport("end_catch");
builder.local("thrown");
builder.i32_const(1);
builder.appendU8(WasmOpcode.i32_store);
diff --git a/src/mono/wasm/runtime/jiterpreter-support.ts b/src/mono/wasm/runtime/jiterpreter-support.ts
index 06e1e6569ffc8e..ab828d5dc3a54a 100644
--- a/src/mono/wasm/runtime/jiterpreter-support.ts
+++ b/src/mono/wasm/runtime/jiterpreter-support.ts
@@ -112,6 +112,7 @@ export class WasmBuilder {
this.stack = [new BlobBuilder()];
this.clear(constantSlotCount);
this.cfg = new Cfg(this);
+ this.defineType("__cpp_exception", { "ptr": WasmValtype.i32 }, WasmValtype.void, true);
}
clear(constantSlotCount: number) {
@@ -176,14 +177,31 @@ export class WasmBuilder {
return current.getArrayView(false).slice(0, current.size);
}
+ setImportFunction(name: string, value: Function) {
+ const imp = this.importedFunctions[name];
+ if (!imp)
+ throw new Error("No import named " + name);
+ imp.func = value;
+ }
+
+ getExceptionTag(): any {
+ const exceptionTag = (Module)["asm"]["__cpp_exception"];
+ if (typeof (exceptionTag) !== "undefined")
+ mono_assert(exceptionTag instanceof (WebAssembly).Tag, () => `expected __cpp_exception export from dotnet.wasm to be WebAssembly.Tag but was ${exceptionTag}`);
+ return exceptionTag;
+ }
+
getWasmImports(): WebAssembly.Imports {
const memory = (Module).getMemory();
mono_assert(memory instanceof WebAssembly.Memory, () => `expected heap import to be WebAssembly.Memory but was ${memory}`);
+ const exceptionTag = this.getExceptionTag();
const result: any = {
c: this.getConstants(),
m: { h: memory },
};
+ if (exceptionTag)
+ result.x = { e: exceptionTag };
const importsToEmit = this.getImportsToEmit();
@@ -463,10 +481,14 @@ export class WasmBuilder {
if (includeFunctionTable !== false)
throw new Error("function table imports are disabled");
+ const enableWasmEh = this.getExceptionTag() !== undefined;
+
// Import section
this.beginSection(2);
this.appendULeb(
- 1 + importsToEmit.length + this.constantSlots.length +
+ 1 + // memory
+ (enableWasmEh ? 1 : 0) + // c++ exception tag
+ importsToEmit.length + this.constantSlots.length +
((includeFunctionTable !== false) ? 1 : 0)
);
@@ -488,6 +510,7 @@ export class WasmBuilder {
this.appendU8(0x00); // constant
}
+ // import the native heap
this.appendName("m");
this.appendName("h");
if (MonoWasmThreads) {
@@ -505,6 +528,18 @@ export class WasmBuilder {
this.appendULeb(0x01);
}
+ if (enableWasmEh) {
+ // import the c++ exception tag
+ this.appendName("x");
+ this.appendName("e");
+ // tagtype
+ this.appendU8(0x04);
+ // attribute (exception)
+ this.appendU8(0x0);
+ // signature
+ this.appendULeb(this.getTypeIndex("__cpp_exception"));
+ }
+
if (includeFunctionTable !== false) {
this.appendName("f");
this.appendName("f");
@@ -555,6 +590,13 @@ export class WasmBuilder {
func.index = this.importedFunctionCount++;
}
+ getTypeIndex(name: string) {
+ const type = this.functionTypes[name];
+ if (!type)
+ throw new Error("No type named " + name);
+ return type[0];
+ }
+
defineFunction(
options: {
type: string,
@@ -567,7 +609,7 @@ export class WasmBuilder {
index: this.functions.length,
name: options.name,
typeName: options.type,
- typeIndex: this.functionTypes[options.type][0],
+ typeIndex: this.getTypeIndex(options.type),
export: options.export,
locals: options.locals,
generator,
@@ -1990,8 +2032,6 @@ export function jiterpreter_allocate_tables(module: any) {
if (options.enableStats)
mono_log_info(`Allocated ${totalSize} function table entries for jiterpreter, bringing total table size to ${wasmTable.length}`);
base = jiterpreter_allocate_table(JiterpreterTable.Trace, base, traceTableSize, getRawCwrap("mono_jiterp_placeholder_trace"));
- // FIXME: Install mono_jiterp_do_jit_call_indirect somehow.
- base = jiterpreter_allocate_table(JiterpreterTable.DoJitCall, base, 1, getRawCwrap("mono_llvm_cpp_catch_exception"));
base = jiterpreter_allocate_table(JiterpreterTable.JitCall, base, jitCallTableSize, getRawCwrap("mono_jiterp_placeholder_jit_call"));
for (let table = JiterpreterTable.InterpEntryStatic0; table <= JiterpreterTable.LAST; table++)
base = jiterpreter_allocate_table(table, base, interpEntryTableSize, wasmTable.get(cwraps.mono_jiterp_get_interp_entry_func(table)));
diff --git a/src/mono/wasm/runtime/jiterpreter-trace-generator.ts b/src/mono/wasm/runtime/jiterpreter-trace-generator.ts
index 2c7bb17ef9e82c..616792ffec25ba 100644
--- a/src/mono/wasm/runtime/jiterpreter-trace-generator.ts
+++ b/src/mono/wasm/runtime/jiterpreter-trace-generator.ts
@@ -28,7 +28,6 @@ import {
getMemberOffset, isZeroPageReserved, CfgBranchType,
append_safepoint, modifyCounter, simdFallbackCounters,
} from "./jiterpreter-support";
-import { compileSimdFeatureDetect } from "./jiterpreter-feature-detect";
import {
sizeOfDataItem, sizeOfV128, sizeOfStackval,
@@ -57,7 +56,7 @@ import {
simdLoadTable, simdStoreTable,
} from "./jiterpreter-tables";
import { mono_log_error, mono_log_info } from "./logging";
-import { mono_assert } from "./globals";
+import { mono_assert, runtimeHelpers } from "./globals";
// indexPlusOne so that ip[1] in the interpreter becomes getArgU16(ip, 1)
function getArgU16(ip: MintOpcodePtr, indexPlusOne: number) {
@@ -3268,15 +3267,9 @@ function getIsWasmSimdSupported(): boolean {
if (wasmSimdSupported !== undefined)
return wasmSimdSupported;
- // Probe whether the current environment can handle wasm v128 opcodes.
- try {
- // Load and compile a test module that uses i32x4.splat. See wasm-simd-feature-detect.wat/wasm
- const module = compileSimdFeatureDetect();
- wasmSimdSupported = !!module;
- } catch (exc) {
- mono_log_info("Disabling WASM SIMD support due to JIT failure", exc);
- wasmSimdSupported = false;
- }
+ wasmSimdSupported = runtimeHelpers.featureWasmSimd === true;
+ if (!wasmSimdSupported)
+ mono_log_info("Disabling Jiterpreter SIMD");
return wasmSimdSupported;
}
diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts
index 028df7aa069a22..d481f3b72d9f06 100644
--- a/src/mono/wasm/runtime/startup.ts
+++ b/src/mono/wasm/runtime/startup.ts
@@ -503,11 +503,13 @@ async function instantiate_wasm_module(
}
async function ensureUsedWasmFeatures() {
+ runtimeHelpers.featureWasmSimd = await loaderHelpers.simd();
+ runtimeHelpers.featureWasmEh = await loaderHelpers.exceptions();
if (linkerWasmEnableSIMD) {
- mono_assert(await loaderHelpers.simd(), "This browser/engine doesn't support WASM SIMD. Please use a modern version. See also https://aka.ms/dotnet-wasm-features");
+ mono_assert(runtimeHelpers.featureWasmSimd, "This browser/engine doesn't support WASM SIMD. Please use a modern version. See also https://aka.ms/dotnet-wasm-features");
}
if (linkerWasmEnableEH) {
- mono_assert(await loaderHelpers.exceptions(), "This browser/engine doesn't support WASM exception handling. Please use a modern version. See also https://aka.ms/dotnet-wasm-features");
+ mono_assert(runtimeHelpers.featureWasmEh, "This browser/engine doesn't support WASM exception handling. Please use a modern version. See also https://aka.ms/dotnet-wasm-features");
}
}
@@ -532,10 +534,6 @@ async function mono_wasm_before_memory_snapshot() {
else
throw new Error(`Expected environment variable '${k}' to be a string but it was ${typeof v}: '${v}'`);
}
- if (runtimeHelpers.config.startupMemoryCache) {
- // disable the trampoline for now, we will re-enable it after we stored the snapshot
- cwraps.mono_jiterp_update_jit_call_dispatcher(0);
- }
if (runtimeHelpers.config.runtimeOptions)
mono_wasm_set_runtime_options(runtimeHelpers.config.runtimeOptions);
@@ -560,8 +558,6 @@ async function mono_wasm_before_memory_snapshot() {
// we didn't have snapshot yet and the feature is enabled. Take snapshot now.
if (runtimeHelpers.config.startupMemoryCache) {
- // this would install the mono_jiterp_do_jit_call_indirect
- cwraps.mono_jiterp_update_jit_call_dispatcher(-1);
await storeMemorySnapshot(localHeapViewU8().buffer);
runtimeHelpers.storeMemorySnapshotPending = false;
}
diff --git a/src/mono/wasm/runtime/types/internal.ts b/src/mono/wasm/runtime/types/internal.ts
index 751f2795e45452..cb980969a2bf02 100644
--- a/src/mono/wasm/runtime/types/internal.ts
+++ b/src/mono/wasm/runtime/types/internal.ts
@@ -203,6 +203,9 @@ export type RuntimeHelpers = {
afterOnRuntimeInitialized: PromiseAndController,
afterPostRun: PromiseAndController,
+ featureWasmEh: boolean,
+ featureWasmSimd: boolean,
+
//core
stringify_as_error_with_stack?: (error: any) => string,
instantiate_asset: (asset: AssetEntry, url: string, bytes: Uint8Array) => void,
diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj
index 539def55f13130..818641337c2d27 100644
--- a/src/mono/wasm/wasm.proj
+++ b/src/mono/wasm/wasm.proj
@@ -365,6 +365,7 @@
$(ArtifactsObjDir)wasm/pinvoke-table.h
$(ArtifactsObjDir)wasm/wasm_m2n_invoke.g.h
+
-g -Os -s -DDEBUG=1 -DENABLE_AOT_PROFILER=1 -DENABLE_BROWSER_PROFILER=1
-Oz -DENABLE_BROWSER_PROFILER=1