From 0a751a2ff2381cc097da664aae0308047c244e88 Mon Sep 17 00:00:00 2001 From: Ioanna Dimitriou Date: Fri, 4 Dec 2020 22:47:29 +0000 Subject: [PATCH] Bug 1335652 - wasm exceptions part 1: configuration & flags r=rhunt Adds compile-time and run-time flags for wasm exception handling. Differential Revision: https://phabricator.services.mozilla.com/D96680 --- js/moz.configure | 23 ++++++++++++++++++++++ js/public/ContextOptions.h | 6 ++++++ js/src/builtin/TestingFunctions.cpp | 10 ++++++++++ js/src/jsapi.cpp | 7 +++++++ js/src/shell/js.cpp | 19 ++++++++++++++++++ js/src/shell/jsshell.h | 3 +++ js/src/wasm/WasmJS.cpp | 30 ++++++++++++++++++++++++++--- js/src/wasm/WasmJS.h | 4 ++++ 8 files changed, 99 insertions(+), 3 deletions(-) diff --git a/js/moz.configure b/js/moz.configure index 688bbfb99223..8ffc28ce9a90 100644 --- a/js/moz.configure +++ b/js/moz.configure @@ -958,3 +958,26 @@ set_define( "ENABLE_WASM_TYPE_REFLECTIONS", depends_if("--enable-wasm-type-reflections")(lambda x: True), ) + +# Support for WebAssembly exceptions +# ================================== + + +@depends(milestone.is_nightly, "--enable-wasm-multi-value") +def default_wasm_exceptions(is_nightly, multi_value): + if multi_value and is_nightly: + return True + + +option( + "--enable-wasm-exceptions", + default=default_wasm_exceptions, + help="{Enable|Disable} WebAssembly exceptions", +) + +set_config( + "ENABLE_WASM_EXCEPTIONS", depends_if("--enable-wasm-exceptions")(lambda x: True) +) +set_define( + "ENABLE_WASM_EXCEPTIONS", depends_if("--enable-wasm-exceptions")(lambda x: True) +) diff --git a/js/public/ContextOptions.h b/js/public/ContextOptions.h index 61199c63d3bf..075cffcecc09 100644 --- a/js/public/ContextOptions.h +++ b/js/public/ContextOptions.h @@ -30,6 +30,7 @@ class JS_PUBLIC_API ContextOptions { wasmGc_(false), wasmMultiValue_(false), wasmSimd_(false), + wasmExceptions_(false), testWasmAwaitTier2_(false), throwOnAsmJSValidationFailure_(false), disableIon_(false), @@ -126,6 +127,10 @@ class JS_PUBLIC_API ContextOptions { // Defined out-of-line because it depends on a compile-time option ContextOptions& setWasmSimd(bool flag); + bool wasmExceptions() const { return wasmExceptions_; } + // Defined out-of-line because it depends on a compile-time option + ContextOptions& setWasmExceptions(bool flag); + bool throwOnAsmJSValidationFailure() const { return throwOnAsmJSValidationFailure_; } @@ -258,6 +263,7 @@ class JS_PUBLIC_API ContextOptions { bool wasmGc_ : 1; bool wasmMultiValue_ : 1; bool wasmSimd_ : 1; + bool wasmExceptions_ : 1; bool testWasmAwaitTier2_ : 1; bool throwOnAsmJSValidationFailure_ : 1; bool disableIon_ : 1; diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index b51b485401e4..f18b8a4f1d04 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -852,6 +852,12 @@ static bool WasmGcEnabled(JSContext* cx, unsigned argc, Value* vp) { return true; } +static bool WasmExceptionsEnabled(JSContext* cx, unsigned argc, Value* vp) { + CallArgs args = CallArgsFromVp(argc, vp); + args.rval().setBoolean(wasm::ExceptionsAvailable(cx)); + return true; +} + static bool WasmMultiValueEnabled(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); args.rval().setBoolean(wasm::MultiValuesAvailable(cx)); @@ -6774,6 +6780,10 @@ gc::ZealModeHelpText), "wasmMultiValueEnabled()", " Returns a boolean indicating whether the WebAssembly multi-value proposal is enabled."), + JS_FN_HELP("wasmExceptionsEnabled", WasmExceptionsEnabled, 1, 0, +"wasmExceptionsEnabled()", +" Returns a boolean indicating whether the WebAssembly exceptions proposal is enabled."), + #if defined(ENABLE_WASM_SIMD) && defined(DEBUG) JS_FN_HELP("wasmSimdAnalysis", WasmSimdAnalysis, 1, 0, "wasmSimdAnalysis(...)", diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 85427d15f0b5..46cf889ff05c 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -459,6 +459,13 @@ JS::ContextOptions& JS::ContextOptions::setWasmSimd(bool flag) { return *this; } +JS::ContextOptions& JS::ContextOptions::setWasmExceptions(bool flag) { +#ifdef ENABLE_WASM_EXCEPTIONS + wasmExceptions_ = flag; +#endif + return *this; +} + JS::ContextOptions& JS::ContextOptions::setFuzzing(bool flag) { #ifdef FUZZING fuzzing_ = flag; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index da002395a55d..2babc124fd10 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -519,6 +519,9 @@ bool shell::enableWasmSimd = true; bool shell::enableWasmVerbose = false; bool shell::enableTestWasmAwaitTier2 = false; bool shell::enableSourcePragmas = true; +#ifdef ENABLE_WASM_EXCEPTIONS +bool shell::enableWasmExceptions = false; +#endif bool shell::enableAsyncStacks = false; bool shell::enableAsyncStackCaptureDebuggeeOnly = false; bool shell::enableStreams = false; @@ -10408,6 +10411,9 @@ static bool SetContextOptions(JSContext* cx, const OptionParser& op) { #endif #ifdef ENABLE_WASM_SIMD enableWasmSimd = !op.getBoolOption("no-wasm-simd"); +#endif +#ifdef ENABLE_WASM_EXCEPTIONS + enableWasmExceptions = op.getBoolOption("wasm-exceptions"); #endif enableWasmVerbose = op.getBoolOption("wasm-verbose"); enableTestWasmAwaitTier2 = op.getBoolOption("test-wasm-await-tier2"); @@ -10453,6 +10459,9 @@ static bool SetContextOptions(JSContext* cx, const OptionParser& op) { #endif #ifdef ENABLE_WASM_SIMD .setWasmSimd(enableWasmSimd) +#endif +#ifdef ENABLE_WASM_EXCEPTIONS + .setWasmExceptions(enableWasmExceptions) #endif .setWasmVerbose(enableWasmVerbose) .setTestWasmAwaitTier2(enableTestWasmAwaitTier2) @@ -10842,6 +10851,9 @@ static void SetWorkerContextOptions(JSContext* cx) { #endif #ifdef ENABLE_WASM_SIMD .setWasmSimd(enableWasmSimd) +#endif +#ifdef ENABLE_WASM_EXCEPTIONS + .setWasmExceptions(enableWasmExceptions) #endif .setWasmReftypes(enableWasmReftypes) .setWasmVerbose(enableWasmVerbose) @@ -11288,6 +11300,13 @@ int main(int argc, char** argv, char** envp) { #else !op.addBoolOption('\0', "no-wasm-simd", "No-op") || #endif +#ifdef ENABLE_WASM_EXCEPTIONS + !op.addBoolOption('\0', "wasm-exceptions", + "Enable wasm exceptions features") || +#else + !op.addBoolOption('\0', "wasm-exceptions", "No-op") || +#endif + !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation") || !op.addIntOption( diff --git a/js/src/shell/jsshell.h b/js/src/shell/jsshell.h index c1c0aaff11d4..375da2f4ceb6 100644 --- a/js/src/shell/jsshell.h +++ b/js/src/shell/jsshell.h @@ -123,6 +123,9 @@ extern bool enableWasmMultiValue; #ifdef ENABLE_WASM_SIMD extern bool enableWasmSimd; #endif +#ifdef ENABLE_WASM_EXCEPTIONS +extern bool enableWasmExceptions; +#endif extern bool enableWasmVerbose; extern bool enableTestWasmAwaitTier2; extern bool enableSourcePragmas; diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp index 92f59ab58ef3..29e72133d408 100644 --- a/js/src/wasm/WasmJS.cpp +++ b/js/src/wasm/WasmJS.cpp @@ -156,6 +156,14 @@ static inline bool WasmThreadsFlag(JSContext* cx) { cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled(); } +static inline bool WasmExceptionsFlag(JSContext* cx) { +#ifdef ENABLE_WASM_EXCEPTIONS + return cx->options().wasmExceptions(); +#else + return false; +#endif +} + static inline bool WasmDebuggerActive(JSContext* cx) { if (IsFuzzingIon(cx) || IsFuzzingCranelift(cx)) { return false; @@ -291,6 +299,7 @@ bool wasm::IonDisabledByFeatures(JSContext* cx, bool* isDisabled, bool debug = WasmDebuggerActive(cx); bool functionReferences = WasmFunctionReferencesFlag(cx); bool gc = WasmGcFlag(cx); + bool exn = WasmExceptionsFlag(cx); if (reason) { char sep = 0; if (debug && !Append(reason, "debug", &sep)) { @@ -302,8 +311,11 @@ bool wasm::IonDisabledByFeatures(JSContext* cx, bool* isDisabled, if (gc && !Append(reason, "gc", &sep)) { return false; } + if (exn && !Append(reason, "exceptions", &sep)) { + return false; + } } - *isDisabled = debug || functionReferences || gc; + *isDisabled = debug || functionReferences || gc || exn; return true; } @@ -318,7 +330,8 @@ bool wasm::CraneliftAvailable(JSContext* cx) { bool wasm::CraneliftDisabledByFeatures(JSContext* cx, bool* isDisabled, JSStringBuilder* reason) { - // Cranelift has no debugging support, no gc support, no simd. + // Cranelift has no debugging support, no gc support, no simd, and + // no exceptions support. bool debug = WasmDebuggerActive(cx); bool functionReferences = WasmFunctionReferencesFlag(cx); bool gc = WasmGcFlag(cx); @@ -328,6 +341,7 @@ bool wasm::CraneliftDisabledByFeatures(JSContext* cx, bool* isDisabled, #else bool simdOnNonAarch64 = WasmSimdFlag(cx); #endif + bool exn = WasmExceptionsFlag(cx); if (reason) { char sep = 0; if (debug && !Append(reason, "debug", &sep)) { @@ -342,8 +356,11 @@ bool wasm::CraneliftDisabledByFeatures(JSContext* cx, bool* isDisabled, if (simdOnNonAarch64 && !Append(reason, "simd", &sep)) { return false; } + if (exn && !Append(reason, "exceptions", &sep)) { + return false; + } } - *isDisabled = debug || functionReferences || gc || simdOnNonAarch64; + *isDisabled = debug || functionReferences || gc || simdOnNonAarch64 || exn; return true; } @@ -388,6 +405,13 @@ bool wasm::ThreadsAvailable(JSContext* cx) { return WasmThreadsFlag(cx) && AnyCompilerAvailable(cx); } +bool wasm::ExceptionsAvailable(JSContext* cx) { + // Ion & Cranelift do not support Exceptions (for now). + // Exceptions require multi-value. + return WasmExceptionsFlag(cx) && MultiValuesAvailable(cx) && + BaselineAvailable(cx); +} + bool wasm::HasPlatformSupport(JSContext* cx) { #if !MOZ_LITTLE_ENDIAN() || defined(JS_CODEGEN_NONE) return false; diff --git a/js/src/wasm/WasmJS.h b/js/src/wasm/WasmJS.h index 463c52618a5d..cdf407f5fc6d 100644 --- a/js/src/wasm/WasmJS.h +++ b/js/src/wasm/WasmJS.h @@ -129,6 +129,10 @@ bool SimdAvailable(JSContext* cx); void ReportSimdAnalysis(const char* data); #endif +// Returns true if WebAssembly as configured by compile-time flags and run-time +// options can support try/catch, throw, rethrow, and branch_on_exn (evolving). +bool ExceptionsAvailable(JSContext* cx); + // Compiles the given binary wasm module given the ArrayBufferObject // and links the module's imports with the given import object.