Bug 1566427 - Improved compiler availability computation. r=bbouvier

This patch cleans up wasm compiler selection and a few related things
with as few semantic changes as possible.  The intent is to centralize
compiler availability computation so that all parts of the system stay
in sync and it is easy to change compiler selection policy.

First, we introduce new predicates <Compiler>Available(cx) to test for
the actual availability of a compiler.  These predicates take into
account whether a compiler is compiled into the executable, whether it
supports the hardware, whether it is (currently) selected by
options/switches, and whether it can be used as a result of the
runtime environment (for example, Ion and Cranelift are not available
if the debugger is observing the page or if the GC feature is enabled;
Cranelift is not available if shared memory and atomics are enabled).
We switch to using these predicates almost everywhere that used
<Compiler>CanCompile() or cx->options().wasm<Compiler>(), since those
don't tell the full story.

Second, we implement a priority order of the optimizing compilers and
make it easy to change this order (see comments in code).  At the
moment, Cranelift is prioritized over Ion since Ion is enabled by
default and Cranelift is not; thus the desire of somebody flipping the
pref for Cranelift is to deselect Ion.  The priority order may change
in the future or may become platform-dependent.  The default compiler
selection in both browser and shell remains Baseline+Ion.

Third, we rename HasCompilerSupport() as HasPlatformSupport(), since
the predicate does not test whether compilers are available, only
whether they are present in the executable and support the hardware.
And to make that more sensible, <Compiler>CanCompile() is renamed
as <Compiler>PlatformSupport().

Fourth, we remove some redundant testing predicates (we don't need
both wasmDebugSupport and wasmDebuggingIsSupported, nor do we need
wasmUsesCranelift because wasmCompileMode is more reliable).

Fifth, we introduce a few new test cases that try to ensure that
compiler selection works as it should.  These are white-box and may
need to change if the compiler priority order changes.

Sixth, we rename the internal wasm::Has<Feature>Support() predicates
as wasm::<Feature>Available(), since they all actually test for
compiler availability.

Differential Revision: https://phabricator.services.mozilla.com/D64946

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Lars T Hansen 2020-03-11 07:53:03 +00:00
Родитель bc5a3e6d09
Коммит 23854fd5a5
34 изменённых файлов: 481 добавлений и 258 удалений

Просмотреть файл

@ -474,6 +474,9 @@ set_define('MOZ_RUST_SIMD', rust_simd)
# Experimental support for wasm code generation with Cranelift # Experimental support for wasm code generation with Cranelift
#
# Note, you may have to disable features not supported by Cranelift
# (multi-value, threads) to make Cranelift actually available
# ============================================================== # ==============================================================
js_option('--enable-cranelift', js_option('--enable-cranelift',
@ -590,6 +593,7 @@ set_define('WASM_PRIVATE_REFTYPES', depends_if('--enable-wasm-private-reftypes')
# Support for the WebAssembly multi-value proposal. # Support for the WebAssembly multi-value proposal.
# Do not remove until Cranelift supports multi-value.
# ===================================================== # =====================================================
@depends(milestone.is_nightly, building_js) @depends(milestone.is_nightly, building_js)
@ -604,6 +608,23 @@ js_option('--enable-wasm-multi-value',
set_config('ENABLE_WASM_MULTI_VALUE', depends_if('--enable-wasm-multi-value')(lambda x: True)) set_config('ENABLE_WASM_MULTI_VALUE', depends_if('--enable-wasm-multi-value')(lambda x: True))
set_define('ENABLE_WASM_MULTI_VALUE', depends_if('--enable-wasm-multi-value')(lambda x: True)) set_define('ENABLE_WASM_MULTI_VALUE', depends_if('--enable-wasm-multi-value')(lambda x: True))
# Support for WebAssembly shared memory and atomics.
#
# This affects the JS shell only and here to allow the use of
# Cranelift in the shell. Once Cranelift supports shared memory
# and atomics it can go away.
# =====================================================
js_option('--enable-wasm-threads',
default=True,
help='{Enable|Disable} WebAssembly shared memory and atomics')
set_config('ENABLE_WASM_THREADS', depends_if('--enable-wasm-threads')(lambda x: True))
set_define('ENABLE_WASM_THREADS', depends_if('--enable-wasm-threads')(lambda x: True))
# Initial support for new regexp engine # Initial support for new regexp engine
# ================================================== # ==================================================

Просмотреть файл

@ -85,7 +85,9 @@
#include "vm/TraceLogging.h" #include "vm/TraceLogging.h"
#include "wasm/AsmJS.h" #include "wasm/AsmJS.h"
#include "wasm/WasmBaselineCompile.h" #include "wasm/WasmBaselineCompile.h"
#include "wasm/WasmCraneliftCompile.h"
#include "wasm/WasmInstance.h" #include "wasm/WasmInstance.h"
#include "wasm/WasmIonCompile.h"
#include "wasm/WasmJS.h" #include "wasm/WasmJS.h"
#include "wasm/WasmModule.h" #include "wasm/WasmModule.h"
#include "wasm/WasmSignalHandlers.h" #include "wasm/WasmSignalHandlers.h"
@ -718,25 +720,25 @@ static bool WasmIsSupported(JSContext* cx, unsigned argc, Value* vp) {
static bool WasmIsSupportedByHardware(JSContext* cx, unsigned argc, Value* vp) { static bool WasmIsSupportedByHardware(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::HasCompilerSupport(cx)); args.rval().setBoolean(wasm::HasPlatformSupport(cx));
return true; return true;
} }
static bool WasmDebuggingIsSupported(JSContext* cx, unsigned argc, Value* vp) { static bool WasmDebuggingIsSupported(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::HasSupport(cx) && cx->options().wasmBaseline()); args.rval().setBoolean(wasm::HasSupport(cx) && wasm::BaselineAvailable(cx));
return true; return true;
} }
static bool WasmStreamingIsSupported(JSContext* cx, unsigned argc, Value* vp) { static bool WasmStreamingIsSupported(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::HasStreamingSupport(cx)); args.rval().setBoolean(wasm::StreamingCompilationAvailable(cx));
return true; return true;
} }
static bool WasmCachingIsSupported(JSContext* cx, unsigned argc, Value* vp) { static bool WasmCachingIsSupported(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::HasCachingSupport(cx)); args.rval().setBoolean(wasm::CodeCachingAvailable(cx));
return true; return true;
} }
@ -750,26 +752,9 @@ static bool WasmHugeMemoryIsSupported(JSContext* cx, unsigned argc, Value* vp) {
return true; return true;
} }
static bool WasmUsesCranelift(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
#ifdef ENABLE_WASM_CRANELIFT
bool usesCranelift = cx->options().wasmCranelift();
#else
bool usesCranelift = false;
#endif
args.rval().setBoolean(usesCranelift);
return true;
}
static bool WasmThreadsSupported(JSContext* cx, unsigned argc, Value* vp) { static bool WasmThreadsSupported(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
bool isSupported = wasm::HasSupport(cx); args.rval().setBoolean(wasm::ThreadsAvailable(cx));
#ifdef ENABLE_WASM_CRANELIFT
if (cx->options().wasmCranelift()) {
isSupported = false;
}
#endif
args.rval().setBoolean(isSupported);
return true; return true;
} }
@ -787,47 +772,69 @@ static bool WasmBulkMemSupported(JSContext* cx, unsigned argc, Value* vp) {
static bool WasmReftypesEnabled(JSContext* cx, unsigned argc, Value* vp) { static bool WasmReftypesEnabled(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::HasReftypesSupport(cx)); args.rval().setBoolean(wasm::ReftypesAvailable(cx));
return true; return true;
} }
static bool WasmGcEnabled(JSContext* cx, unsigned argc, Value* vp) { static bool WasmGcEnabled(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::HasGcSupport(cx)); args.rval().setBoolean(wasm::GcTypesAvailable(cx));
return true; return true;
} }
static bool WasmMultiValueEnabled(JSContext* cx, unsigned argc, Value* vp) { static bool WasmMultiValueEnabled(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::HasMultiValueSupport(cx)); args.rval().setBoolean(wasm::MultiValuesAvailable(cx));
return true; return true;
} }
static bool WasmBigIntEnabled(JSContext* cx, unsigned argc, Value* vp) { static bool WasmBigIntEnabled(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::HasI64BigIntSupport(cx)); args.rval().setBoolean(wasm::I64BigIntConversionAvailable(cx));
return true; return true;
} }
static bool WasmDebugSupport(JSContext* cx, unsigned argc, Value* vp) { static bool WasmCompilersPresent(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(cx->options().wasmBaseline() &&
wasm::BaselineCanCompile()); char buf[256];
*buf = 0;
if (wasm::BaselinePlatformSupport()) {
strcat(buf, "baseline");
}
if (wasm::IonPlatformSupport()) {
if (*buf) {
strcat(buf, ",");
}
strcat(buf, "ion");
}
if (wasm::CraneliftPlatformSupport()) {
if (*buf) {
strcat(buf, ",");
}
strcat(buf, "cranelift");
}
JSString* result = JS_NewStringCopyZ(cx, buf);
if (!result) {
return false;
}
args.rval().setString(result);
return true; return true;
} }
static bool WasmCompileMode(JSContext* cx, unsigned argc, Value* vp) { static bool WasmCompileMode(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
bool baseline = cx->options().wasmBaseline(); // This triplet of predicates will select zero or one baseline compiler and
bool ion = cx->options().wasmIon(); // zero or one optimizing compiler.
#ifdef ENABLE_WASM_CRANELIFT bool baseline = wasm::BaselineAvailable(cx);
bool cranelift = cx->options().wasmCranelift(); bool ion = wasm::IonAvailable(cx);
#else bool cranelift = wasm::CraneliftAvailable(cx);
bool cranelift = false;
#endif MOZ_ASSERT(!(ion && cranelift));
// We default to ion if nothing is enabled, as does the Wasm compiler.
JSString* result; JSString* result;
if (!wasm::HasSupport(cx)) { if (!wasm::HasSupport(cx)) {
result = JS_NewStringCopyZ(cx, "none"); result = JS_NewStringCopyZ(cx, "none");
@ -851,6 +858,45 @@ static bool WasmCompileMode(JSContext* cx, unsigned argc, Value* vp) {
return true; return true;
} }
static bool WasmCraneliftDisabledByFeatures(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
bool isDisabled = false;
JSStringBuilder reason(cx);
if (!wasm::CraneliftDisabledByFeatures(cx, &isDisabled, &reason)) {
return false;
}
if (isDisabled) {
JSString* result = reason.finishString();
if (!result) {
return false;
}
args.rval().setString(result);
} else {
args.rval().setBoolean(false);
}
return true;
}
static bool WasmIonDisabledByFeatures(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
bool isDisabled = false;
JSStringBuilder reason(cx);
if (!wasm::IonDisabledByFeatures(cx, &isDisabled, &reason)) {
return false;
}
if (isDisabled) {
JSString* result = reason.finishString();
if (!result) {
return false;
}
args.rval().setString(result);
} else {
args.rval().setBoolean(false);
}
return true;
}
static bool WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp) { static bool WasmTextToBinary(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
RootedObject callee(cx, &args.callee()); RootedObject callee(cx, &args.callee());
@ -6629,12 +6675,6 @@ gc::ZealModeHelpText),
" Returns a boolean indicating whether WebAssembly supports using a large" " Returns a boolean indicating whether WebAssembly supports using a large"
" virtual memory reservation in order to elide bounds checks on this platform."), " virtual memory reservation in order to elide bounds checks on this platform."),
JS_FN_HELP("wasmUsesCranelift", WasmUsesCranelift, 0, 0,
"wasmUsesCranelift()",
" Returns a boolean indicating whether Cranelift is currently enabled for backend\n"
" compilation. This doesn't necessarily mean a module will be compiled with \n"
" Cranelift (e.g. when baseline is also enabled)."),
JS_FN_HELP("wasmThreadsSupported", WasmThreadsSupported, 0, 0, JS_FN_HELP("wasmThreadsSupported", WasmThreadsSupported, 0, 0,
"wasmThreadsSupported()", "wasmThreadsSupported()",
" Returns a boolean indicating whether the WebAssembly threads proposal is\n" " Returns a boolean indicating whether the WebAssembly threads proposal is\n"
@ -6645,10 +6685,31 @@ gc::ZealModeHelpText),
" Returns a boolean indicating whether the WebAssembly bulk memory proposal is\n" " Returns a boolean indicating whether the WebAssembly bulk memory proposal is\n"
" supported on the current device."), " supported on the current device."),
JS_FN_HELP("wasmCompilersPresent", WasmCompilersPresent, 0, 0,
"wasmCompilersPresent()",
" Returns a string indicating the present wasm compilers: a comma-separated list\n"
" of 'baseline', 'ion', and 'cranelift'. A compiler is present in the executable\n"
" if it is compiled in and can generate code for the current architecture."),
JS_FN_HELP("wasmCompileMode", WasmCompileMode, 0, 0, JS_FN_HELP("wasmCompileMode", WasmCompileMode, 0, 0,
"wasmCompileMode()", "wasmCompileMode()",
" Returns a string indicating the available compile policy: 'baseline', 'ion',\n" " Returns a string indicating the available wasm compilers: 'baseline', 'ion',\n"
" 'baseline-or-ion', or 'disabled' (if wasm is not available at all)."), " 'cranelift', 'baseline+ion', 'baseline+cranelift', or 'none'. A compiler is\n"
" available if it is present in the executable and not disabled by switches\n"
" or runtime conditions. At most one baseline and one optimizing compiler can\n"
" be available."),
JS_FN_HELP("wasmCraneliftDisabledByFeatures", WasmCraneliftDisabledByFeatures, 0, 0,
"wasmCraneliftDisabledByFeatures()",
" If some feature is enabled at compile-time or run-time that prevents Cranelift\n"
" from being used then this returns a truthy string describing the features that\n."
" are disabling it. Otherwise it returns false."),
JS_FN_HELP("wasmIonDisabledByFeatures", WasmIonDisabledByFeatures, 0, 0,
"wasmIonDisabledByFeatures()",
" If some feature is enabled at compile-time or run-time that prevents Ion\n"
" from being used then this returns a truthy string describing the features that\n."
" are disabling it. Otherwise it returns false."),
JS_FN_HELP("wasmTextToBinary", WasmTextToBinary, 1, 0, JS_FN_HELP("wasmTextToBinary", WasmTextToBinary, 1, 0,
"wasmTextToBinary(str)", "wasmTextToBinary(str)",
@ -6693,10 +6754,6 @@ gc::ZealModeHelpText),
"wasmBigIntEnabled()", "wasmBigIntEnabled()",
" Returns a boolean indicating whether the WebAssembly I64 to BigInt proposal is enabled."), " Returns a boolean indicating whether the WebAssembly I64 to BigInt proposal is enabled."),
JS_FN_HELP("wasmDebugSupport", WasmDebugSupport, 1, 0,
"wasmDebugSupport()",
" Returns a boolean indicating whether the WebAssembly compilers support debugging."),
JS_FN_HELP("isLazyFunction", IsLazyFunction, 1, 0, JS_FN_HELP("isLazyFunction", IsLazyFunction, 1, 0,
"isLazyFunction(fun)", "isLazyFunction(fun)",
" True if fun is a lazy JSFunction."), " True if fun is a lazy JSFunction."),

Просмотреть файл

@ -139,16 +139,20 @@ static int testWasmFuzz(const uint8_t* buf, size_t size) {
// overwritten later on. // overwritten later on.
uint8_t optByte = (uint8_t)buf[currentIndex]; uint8_t optByte = (uint8_t)buf[currentIndex];
// Note that IonPlatformSupport() and CraneliftPlatformSupport() do not
// take into account whether those compilers support particular features
// that may have been enabled.
bool enableWasmBaseline = ((optByte & 0xF0) == (1 << 7)); bool enableWasmBaseline = ((optByte & 0xF0) == (1 << 7));
bool enableWasmIon = IonCanCompile() && ((optByte & 0xF0) == (1 << 6)); bool enableWasmIon =
IonPlatformSupport() && ((optByte & 0xF0) == (1 << 6));
bool enableWasmCranelift = false; bool enableWasmCranelift = false;
#ifdef ENABLE_WASM_CRANELIFT #ifdef ENABLE_WASM_CRANELIFT
enableWasmCranelift = enableWasmCranelift =
CraneliftCanCompile() && ((optByte & 0xF0) == (1 << 5)); CraneliftPlatformSupport() && ((optByte & 0xF0) == (1 << 5));
#endif #endif
bool enableWasmAwaitTier2 = (IonCanCompile() bool enableWasmAwaitTier2 = (IonPlatformSupport()
#ifdef ENABLE_WASM_CRANELIFT #ifdef ENABLE_WASM_CRANELIFT
|| CraneliftCanCompile() || CraneliftPlatformSupport()
#endif #endif
) && ) &&
((optByte & 0xF) == (1 << 3)); ((optByte & 0xF) == (1 << 3));
@ -158,7 +162,7 @@ static int testWasmFuzz(const uint8_t* buf, size_t size) {
// more platform specific JIT code. However, on some platforms, // more platform specific JIT code. However, on some platforms,
// e.g. ARM64, we do not have Ion available, so we need to switch // e.g. ARM64, we do not have Ion available, so we need to switch
// to baseline instead. // to baseline instead.
if (IonCanCompile()) { if (IonPlatformSupport()) {
enableWasmIon = true; enableWasmIon = true;
} else { } else {
enableWasmBaseline = true; enableWasmBaseline = true;

Просмотреть файл

@ -1,4 +1,4 @@
// |jit-test| skip-if: !wasmDebugSupport() // |jit-test| skip-if: !wasmDebuggingIsSupported()
// Tests that wasm module scripts has inspectable globals and memory. // Tests that wasm module scripts has inspectable globals and memory.
load(libdir + "wasm.js"); load(libdir + "wasm.js");

Просмотреть файл

@ -1,4 +1,4 @@
// |jit-test| skip-if: !wasmDebugSupport() // |jit-test| skip-if: !wasmDebuggingIsSupported()
// Tests that JS can be evaluated on wasm module scripts frames. // Tests that JS can be evaluated on wasm module scripts frames.
load(libdir + "wasm.js"); load(libdir + "wasm.js");

Просмотреть файл

@ -3054,8 +3054,14 @@ const cacheEntry = streamCacheEntry(bytecode);
runBox2d(cacheEntry); runBox2d(cacheEntry);
while (!wasmHasTier2CompilationCompleted(cacheEntry.module)) sleep(1); while (!wasmHasTier2CompilationCompleted(cacheEntry.module))
assertEq(cacheEntry.cached, wasmCachingIsSupported()); sleep(1);
// Cranelift code cannot yet be cached, but cranelift tier2 compilation will
// still populate the cacheEntry.
if (!wasmCompileMode().match("cranelift")) {
assertEq(cacheEntry.cached, wasmCachingIsSupported());
}
runBox2d(cacheEntry); runBox2d(cacheEntry);

Просмотреть файл

@ -0,0 +1,3 @@
// |jit-test| skip-if: !wasmCompilersPresent().match("ion") || wasmIonDisabledByFeatures(); --wasm-compiler=ion
assertEq(wasmCompileMode(), "ion");

Просмотреть файл

@ -0,0 +1,3 @@
// |jit-test| skip-if: !wasmCompilersPresent().match("baseline"); --wasm-compiler=baseline
assertEq(wasmCompileMode(), "baseline");

Просмотреть файл

@ -0,0 +1,3 @@
// |jit-test| --wasm-compiler=cranelift; skip-if: !wasmCompilersPresent().match("cranelift") || wasmCraneliftDisabledByFeatures()
assertEq(wasmCompileMode(), "cranelift");

Просмотреть файл

@ -526,7 +526,7 @@ if (wasmBulkMemSupported()) {
// element segment is completely OOB. // element segment is completely OOB.
assertEq(typeof tbl.get(0), "function"); assertEq(typeof tbl.get(0), "function");
assertEq(tbl.get(1), null); assertEq(tbl.get(1), null);
} else if (!wasmUsesCranelift()) { } else if (!wasmCompileMode().match("cranelift")) {
assertEq(tbl.get(0), null); assertEq(tbl.get(0), null);
assertEq(tbl.get(1), null); assertEq(tbl.get(1), null);
} }
@ -543,7 +543,7 @@ if (wasmBulkMemSupported()) {
assertEq(typeof tbl.get(0), "function"); assertEq(typeof tbl.get(0), "function");
assertEq(typeof tbl.get(1), "function"); assertEq(typeof tbl.get(1), "function");
assertEq(mem8[0], 1); assertEq(mem8[0], 1);
} else if (!wasmUsesCranelift()) { } else if (!wasmCompileMode().match("cranelift")) {
assertEq(tbl.get(0), null); assertEq(tbl.get(0), null);
assertEq(tbl.get(1), null); assertEq(tbl.get(1), null);
assertEq(mem8[0], 0); assertEq(mem8[0], 0);

Просмотреть файл

@ -1,4 +1,4 @@
// |jit-test| skip-if: !wasmDebugSupport() // |jit-test| skip-if: !wasmDebuggingIsSupported()
var g = newGlobal({newCompartment: true}); var g = newGlobal({newCompartment: true});
g.parent = this; g.parent = this;
g.eval("Debugger(parent).onExceptionUnwind = function () {};"); g.eval("Debugger(parent).onExceptionUnwind = function () {};");

Просмотреть файл

@ -1,4 +1,4 @@
// |jit-test| skip-if: !wasmDebugSupport() // |jit-test| skip-if: !wasmDebuggingIsSupported()
var g = newGlobal({newCompartment: true}); var g = newGlobal({newCompartment: true});
var dbg = new g.Debugger(this); var dbg = new g.Debugger(this);
var dbg = new Debugger; var dbg = new Debugger;

Просмотреть файл

@ -1,4 +1,4 @@
// |jit-test| skip-if: !wasmDebugSupport() // |jit-test| skip-if: !wasmDebuggingIsSupported()
var evalInFrame = (function(global) { var evalInFrame = (function(global) {
var dbgGlobal = newGlobal({newCompartment: true}); var dbgGlobal = newGlobal({newCompartment: true});
var dbg = new dbgGlobal.Debugger(); var dbg = new dbgGlobal.Debugger();

Просмотреть файл

@ -1,4 +1,4 @@
// |jit-test| skip-if: !wasmDebugSupport() // |jit-test| skip-if: !wasmDebuggingIsSupported()
// //
var mod = new WebAssembly.Module(wasmTextToBinary(` var mod = new WebAssembly.Module(wasmTextToBinary(`
(module (module

Просмотреть файл

@ -1,4 +1,4 @@
// |jit-test| skip-if: !wasmDebugSupport() // |jit-test| skip-if: !wasmDebuggingIsSupported()
g = newGlobal({newCompartment: true}); g = newGlobal({newCompartment: true});
g.parent = this; g.parent = this;
g.eval("(" + function() { g.eval("(" + function() {

Просмотреть файл

@ -1,4 +1,4 @@
// |jit-test| skip-if: !wasmDebugSupport() // |jit-test| skip-if: !wasmDebuggingIsSupported()
g = newGlobal({newCompartment: true}); g = newGlobal({newCompartment: true});
g.parent = this; g.parent = this;
g.eval("(" + function() { g.eval("(" + function() {

Просмотреть файл

@ -1,4 +1,4 @@
// |jit-test| skip-if: !wasmIsSupported() || !wasmDebugSupport(); exitstatus:3 // |jit-test| skip-if: !wasmDebuggingIsSupported(); exitstatus:3
function userError() {}; function userError() {};

Просмотреть файл

@ -862,7 +862,7 @@ void LIRGenerator::visitWasmCompareExchangeHeap(MWasmCompareExchangeHeap* ins) {
} }
MOZ_ASSERT(ins->access().type() < Scalar::Float32); MOZ_ASSERT(ins->access().type() < Scalar::Float32);
MOZ_ASSERT(HasLDSTREXBHD(), "by HasCompilerSupport() constraints"); MOZ_ASSERT(HasLDSTREXBHD(), "by HasPlatformSupport() constraints");
LWasmCompareExchangeHeap* lir = new (alloc()) LWasmCompareExchangeHeap* lir = new (alloc())
LWasmCompareExchangeHeap(useRegister(base), useRegister(ins->oldValue()), LWasmCompareExchangeHeap(useRegister(base), useRegister(ins->oldValue()),
@ -885,7 +885,7 @@ void LIRGenerator::visitWasmAtomicExchangeHeap(MWasmAtomicExchangeHeap* ins) {
} }
MOZ_ASSERT(ins->access().type() < Scalar::Float32); MOZ_ASSERT(ins->access().type() < Scalar::Float32);
MOZ_ASSERT(HasLDSTREXBHD(), "by HasCompilerSupport() constraints"); MOZ_ASSERT(HasLDSTREXBHD(), "by HasPlatformSupport() constraints");
const LAllocation base = useRegister(ins->base()); const LAllocation base = useRegister(ins->base());
const LAllocation value = useRegister(ins->value()); const LAllocation value = useRegister(ins->value());
@ -905,7 +905,7 @@ void LIRGenerator::visitWasmAtomicBinopHeap(MWasmAtomicBinopHeap* ins) {
} }
MOZ_ASSERT(ins->access().type() < Scalar::Float32); MOZ_ASSERT(ins->access().type() < Scalar::Float32);
MOZ_ASSERT(HasLDSTREXBHD(), "by HasCompilerSupport() constraints"); MOZ_ASSERT(HasLDSTREXBHD(), "by HasPlatformSupport() constraints");
MDefinition* base = ins->base(); MDefinition* base = ins->base();
MOZ_ASSERT(base->type() == MIRType::Int32); MOZ_ASSERT(base->type() == MIRType::Int32);

Просмотреть файл

@ -208,7 +208,11 @@ static const size_t gMaxStackSize = 128 * sizeof(size_t) * 1024;
static const double MAX_TIMEOUT_SECONDS = 1800.0; static const double MAX_TIMEOUT_SECONDS = 1800.0;
// Not necessarily in sync with the browser // Not necessarily in sync with the browser
#define SHARED_MEMORY_DEFAULT 1 #ifdef ENABLE_WASM_THREADS
# define SHARED_MEMORY_DEFAULT 1
#else
# define SHARED_MEMORY_DEFAULT 0
#endif
// Fuzzing support for JS runtime fuzzing // Fuzzing support for JS runtime fuzzing
#ifdef FUZZING_INTERFACES #ifdef FUZZING_INTERFACES
@ -4657,6 +4661,10 @@ static bool SetJitCompilerOption(JSContext* cx, unsigned argc, Value* vp) {
// Throw if trying to disable all the Wasm compilers. The logic here is that // Throw if trying to disable all the Wasm compilers. The logic here is that
// if we're trying to disable a compiler that is currently enabled and that is // if we're trying to disable a compiler that is currently enabled and that is
// the last compiler enabled then we must throw. // the last compiler enabled then we must throw.
//
// Note that this check does not prevent an error from being thrown later.
// Actual compiler availability is dynamic and depends on other conditions,
// such as other options set and whether a debugger is present.
if ((opt == JSJITCOMPILER_WASM_JIT_BASELINE || if ((opt == JSJITCOMPILER_WASM_JIT_BASELINE ||
opt == JSJITCOMPILER_WASM_JIT_ION || opt == JSJITCOMPILER_WASM_JIT_ION ||
opt == JSJITCOMPILER_WASM_JIT_CRANELIFT) && opt == JSJITCOMPILER_WASM_JIT_CRANELIFT) &&
@ -6292,7 +6300,7 @@ static bool CompileAndSerializeInSeparateProcess(JSContext* cx,
} }
static bool WasmCompileAndSerialize(JSContext* cx) { static bool WasmCompileAndSerialize(JSContext* cx) {
MOZ_ASSERT(wasm::HasCachingSupport(cx)); MOZ_ASSERT(wasm::CodeCachingAvailable(cx));
#ifdef XP_WIN #ifdef XP_WIN
// See CompileAndSerializeInSeparateProcess for why we've had to smuggle // See CompileAndSerializeInSeparateProcess for why we've had to smuggle
@ -6342,7 +6350,7 @@ static bool WasmCompileAndSerialize(JSContext* cx) {
static bool WasmCompileInSeparateProcess(JSContext* cx, unsigned argc, static bool WasmCompileInSeparateProcess(JSContext* cx, unsigned argc,
Value* vp) { Value* vp) {
if (!wasm::HasCachingSupport(cx)) { if (!wasm::CodeCachingAvailable(cx)) {
JS_ReportErrorASCII(cx, "WebAssembly caching not supported"); JS_ReportErrorASCII(cx, "WebAssembly caching not supported");
return false; return false;
} }

Просмотреть файл

@ -6843,10 +6843,10 @@ static bool TryInstantiate(JSContext* cx, CallArgs args, const Module& module,
HandleValue importVal = args.get(1); HandleValue importVal = args.get(1);
HandleValue bufferVal = args.get(2); HandleValue bufferVal = args.get(2);
// Re-check HasCompilerSupport(cx) since this varies per-thread and // Re-check HasPlatformSupport(cx) since this varies per-thread and
// 'module' may have been produced on a parser thread. // 'module' may have been produced on a parser thread.
if (!HasCompilerSupport(cx)) { if (!HasPlatformSupport(cx)) {
return LinkFail(cx, "no compiler support"); return LinkFail(cx, "no platform support");
} }
Rooted<ImportValues> imports(cx); Rooted<ImportValues> imports(cx);
@ -7039,7 +7039,7 @@ static bool TypeFailureWarning(frontend::ParserBase& parser, const char* str) {
// asm.js requires Ion to be available on the current hardware/OS and to be // asm.js requires Ion to be available on the current hardware/OS and to be
// enabled for wasm, since asm.js compilation goes via wasm. // enabled for wasm, since asm.js compilation goes via wasm.
static bool IsAsmJSCompilerAvailable(JSContext* cx) { static bool IsAsmJSCompilerAvailable(JSContext* cx) {
return HasCompilerSupport(cx) && IonCanCompile() && cx->options().wasmIon(); return HasPlatformSupport(cx) && IonAvailable(cx);
} }
static bool EstablishPreconditions(JSContext* cx, static bool EstablishPreconditions(JSContext* cx,

Просмотреть файл

@ -12918,7 +12918,7 @@ FuncOffsets BaseCompiler::finish() {
} // namespace wasm } // namespace wasm
} // namespace js } // namespace js
bool js::wasm::BaselineCanCompile() { bool js::wasm::BaselinePlatformSupport() {
#if defined(JS_CODEGEN_ARM) #if defined(JS_CODEGEN_ARM)
// Simplifying assumption: require SDIV and UDIV. // Simplifying assumption: require SDIV and UDIV.
// //

Просмотреть файл

@ -25,8 +25,9 @@ namespace js {
namespace wasm { namespace wasm {
// Return whether BaselineCompileFunction can generate code on the current // Return whether BaselineCompileFunction can generate code on the current
// device. // device. Usually you do *not* want to call this, you want
bool BaselineCanCompile(); // BaselineAvailable().
MOZ_MUST_USE bool BaselinePlatformSupport();
// Generate adequate code quickly. // Generate adequate code quickly.
MOZ_MUST_USE bool BaselineCompileFunctions(const ModuleEnvironment& env, MOZ_MUST_USE bool BaselineCompileFunctions(const ModuleEnvironment& env,

Просмотреть файл

@ -78,25 +78,12 @@ uint32_t wasm::ObservedCPUFeatures() {
SharedCompileArgs CompileArgs::build(JSContext* cx, SharedCompileArgs CompileArgs::build(JSContext* cx,
ScriptedCaller&& scriptedCaller) { ScriptedCaller&& scriptedCaller) {
bool baseline = BaselineCanCompile() && cx->options().wasmBaseline(); bool baseline = BaselineAvailable(cx);
bool ion = IonCanCompile() && cx->options().wasmIon(); bool ion = IonAvailable(cx);
#ifdef ENABLE_WASM_CRANELIFT bool cranelift = CraneliftAvailable(cx);
bool cranelift = CraneliftCanCompile() && cx->options().wasmCranelift();
#else
bool cranelift = false;
#endif
#ifdef ENABLE_WASM_GC // At most one optimizing compiler.
bool gc = cx->options().wasmGc(); MOZ_RELEASE_ASSERT(!(ion && cranelift));
#else
bool gc = false;
#endif
#ifdef ENABLE_WASM_BIGINT
bool bigInt = cx->options().isWasmBigIntEnabled();
#else
bool bigInt = false;
#endif
// Debug information such as source view or debug traps will require // Debug information such as source view or debug traps will require
// additional memory and permanently stay in baseline code, so we try to // additional memory and permanently stay in baseline code, so we try to
@ -104,39 +91,23 @@ SharedCompileArgs CompileArgs::build(JSContext* cx,
// is open. // is open.
bool debug = cx->realm()->debuggerObservesAsmJS(); bool debug = cx->realm()->debuggerObservesAsmJS();
bool sharedMemory =
cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled();
bool forceTiering = bool forceTiering =
cx->options().testWasmAwaitTier2() || JitOptions.wasmDelayTier2; cx->options().testWasmAwaitTier2() || JitOptions.wasmDelayTier2;
if (debug || gc) { // The <Compiler>Available() predicates should ensure this.
if (!baseline) { MOZ_RELEASE_ASSERT(!(debug && (ion || cranelift)));
JS_ReportErrorASCII(cx, "can't use wasm debug/gc without baseline");
return nullptr;
}
ion = false;
cranelift = false;
}
if (forceTiering && (!baseline || (!cranelift && !ion))) { if (forceTiering && !(baseline && (cranelift || ion))) {
// This can happen only in testing, and in this case we don't have a // This can happen only in testing, and in this case we don't have a
// proper way to signal the error, so just silently override the default, // proper way to signal the error, so just silently override the default,
// instead of adding a skip-if directive to every test using debug/gc. // instead of adding a skip-if directive to every test using debug/gc.
forceTiering = false; forceTiering = false;
} }
#ifdef ENABLE_WASM_CRANELIFT if (!(baseline || ion || cranelift)) {
if (!baseline && !ion && !cranelift) { JS_ReportErrorASCII(cx, "no WebAssembly compiler available");
if (cx->options().wasmCranelift() && !CraneliftCanCompile()) { return nullptr;
// We're forcing to use Cranelift on a platform that doesn't support it.
JS_ReportErrorASCII(cx, "cranelift isn't supported on this platform");
return nullptr;
}
} }
#endif
// HasCompilerSupport() should prevent failure here.
MOZ_RELEASE_ASSERT(baseline || ion || cranelift);
CompileArgs* target = cx->new_<CompileArgs>(std::move(scriptedCaller)); CompileArgs* target = cx->new_<CompileArgs>(std::move(scriptedCaller));
if (!target) { if (!target) {
@ -147,11 +118,17 @@ SharedCompileArgs CompileArgs::build(JSContext* cx,
target->ionEnabled = ion; target->ionEnabled = ion;
target->craneliftEnabled = cranelift; target->craneliftEnabled = cranelift;
target->debugEnabled = debug; target->debugEnabled = debug;
target->sharedMemoryEnabled = sharedMemory; target->sharedMemoryEnabled =
cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled();
target->forceTiering = forceTiering; target->forceTiering = forceTiering;
target->gcEnabled = gc; target->gcEnabled = wasm::GcTypesAvailable(cx);
target->hugeMemory = wasm::IsHugeMemoryEnabled(); target->hugeMemory = wasm::IsHugeMemoryEnabled();
target->bigIntEnabled = bigInt; target->bigIntEnabled = wasm::I64BigIntConversionAvailable(cx);
target->multiValuesEnabled = wasm::MultiValuesAvailable(cx);
Log(cx, "available wasm compilers: tier1=%s tier2=%s",
baseline ? "baseline" : "none",
ion ? "ion" : (cranelift ? "cranelift" : "none"));
return target; return target;
} }
@ -486,13 +463,15 @@ void CompilerEnvironment::computeParameters(Decoder& d, bool gcFeatureOptIn) {
bool forceTiering = args_->forceTiering; bool forceTiering = args_->forceTiering;
bool hugeMemory = args_->hugeMemory; bool hugeMemory = args_->hugeMemory;
bool bigIntEnabled = args_->bigIntEnabled; bool bigIntEnabled = args_->bigIntEnabled;
bool multiValuesEnabled = args_->multiValuesEnabled;
bool hasSecondTier = ionEnabled || craneliftEnabled; bool hasSecondTier = ionEnabled || craneliftEnabled;
MOZ_ASSERT_IF(gcEnabled || debugEnabled, baselineEnabled); MOZ_ASSERT_IF(debugEnabled, baselineEnabled);
MOZ_ASSERT_IF(forceTiering, baselineEnabled && hasSecondTier); MOZ_ASSERT_IF(forceTiering, baselineEnabled && hasSecondTier);
// HasCompilerSupport() should prevent failure here // Various constraints in various places should prevent failure here.
MOZ_RELEASE_ASSERT(baselineEnabled || ionEnabled || craneliftEnabled); MOZ_RELEASE_ASSERT(baselineEnabled || ionEnabled || craneliftEnabled);
MOZ_RELEASE_ASSERT(!(ionEnabled && craneliftEnabled));
uint32_t codeSectionSize = 0; uint32_t codeSectionSize = 0;
@ -516,13 +495,10 @@ void CompilerEnvironment::computeParameters(Decoder& d, bool gcFeatureOptIn) {
debug_ = debugEnabled ? DebugEnabled::True : DebugEnabled::False; debug_ = debugEnabled ? DebugEnabled::True : DebugEnabled::False;
gcTypes_ = gcEnabled; gcTypes_ = gcEnabled;
refTypes_ = true; refTypes_ = true;
#ifdef ENABLE_WASM_MULTI_VALUE multiValues_ = multiValuesEnabled;
multiValues_ = !craneliftEnabled;
#else
multiValues_ = false;
#endif
hugeMemory_ = hugeMemory; hugeMemory_ = hugeMemory;
bigInt_ = bigIntEnabled && !craneliftEnabled; bigInt_ = bigIntEnabled;
multiValues_ = multiValuesEnabled;
state_ = Computed; state_ = Computed;
} }
@ -627,12 +603,8 @@ void wasm::CompileTier2(const CompileArgs& args, const Bytes& bytecode,
#else #else
bool refTypesConfigured = false; bool refTypesConfigured = false;
#endif #endif
#ifdef ENABLE_WASM_MULTI_VALUE bool multiValueConfigured = args.multiValuesEnabled;
bool multiValueConfigured = !args.craneliftEnabled; bool bigIntConfigured = args.bigIntEnabled;
#else
bool multiValueConfigured = false;
#endif
bool bigIntConfigured = args.bigIntEnabled && !args.craneliftEnabled;
OptimizedBackend optimizedBackend = args.craneliftEnabled OptimizedBackend optimizedBackend = args.craneliftEnabled
? OptimizedBackend::Cranelift ? OptimizedBackend::Cranelift

Просмотреть файл

@ -59,6 +59,7 @@ struct CompileArgs : ShareableBase<CompileArgs> {
bool gcEnabled; bool gcEnabled;
bool hugeMemory; bool hugeMemory;
bool bigIntEnabled; bool bigIntEnabled;
bool multiValuesEnabled;
// CompileArgs has two constructors: // CompileArgs has two constructors:
// //
@ -82,7 +83,8 @@ struct CompileArgs : ShareableBase<CompileArgs> {
forceTiering(false), forceTiering(false),
gcEnabled(false), gcEnabled(false),
hugeMemory(false), hugeMemory(false),
bigIntEnabled(false) {} bigIntEnabled(false),
multiValuesEnabled(false) {}
}; };
// Return the estimated compiled (machine) code size for the given bytecode size // Return the estimated compiled (machine) code size for the given bytecode size

Просмотреть файл

@ -36,7 +36,7 @@ using namespace js;
using namespace js::jit; using namespace js::jit;
using namespace js::wasm; using namespace js::wasm;
bool wasm::CraneliftCanCompile() { bool wasm::CraneliftPlatformSupport() {
#ifdef JS_CODEGEN_X64 #ifdef JS_CODEGEN_X64
return true; return true;
#else #else
@ -427,7 +427,7 @@ bool wasm::CraneliftCompileFunctions(const ModuleEnvironment& env,
LifoAlloc& lifo, LifoAlloc& lifo,
const FuncCompileInputVector& inputs, const FuncCompileInputVector& inputs,
CompiledCode* code, UniqueChars* error) { CompiledCode* code, UniqueChars* error) {
MOZ_RELEASE_ASSERT(CraneliftCanCompile()); MOZ_RELEASE_ASSERT(CraneliftPlatformSupport());
MOZ_ASSERT(env.tier() == Tier::Optimized); MOZ_ASSERT(env.tier() == Tier::Optimized);
MOZ_ASSERT(env.optimizedBackend() == OptimizedBackend::Cranelift); MOZ_ASSERT(env.optimizedBackend() == OptimizedBackend::Cranelift);

Просмотреть файл

@ -27,16 +27,25 @@ namespace js {
namespace wasm { namespace wasm {
#ifdef ENABLE_WASM_CRANELIFT #ifdef ENABLE_WASM_CRANELIFT
MOZ_MUST_USE bool CraneliftCanCompile(); // Return whether CraneliftCompileFunction() can generate code on the current
#else // device. Usually you do *not* want this, you want CraneliftAvailable().
MOZ_MUST_USE inline bool CraneliftCanCompile() { return false; } MOZ_MUST_USE bool CraneliftPlatformSupport();
#endif
// Generates code with Cranelift. // Generates code with Cranelift.
MOZ_MUST_USE bool CraneliftCompileFunctions( MOZ_MUST_USE bool CraneliftCompileFunctions(
const ModuleEnvironment& env, LifoAlloc& lifo, const ModuleEnvironment& env, LifoAlloc& lifo,
const FuncCompileInputVector& inputs, CompiledCode* code, const FuncCompileInputVector& inputs, CompiledCode* code,
UniqueChars* error); UniqueChars* error);
#else
MOZ_MUST_USE inline bool CraneliftPlatformSupport() { return false; }
MOZ_MUST_USE inline bool CraneliftCompileFunctions(
const ModuleEnvironment& env, LifoAlloc& lifo,
const FuncCompileInputVector& inputs, CompiledCode* code,
UniqueChars* error) {
MOZ_CRASH("Should not happen");
}
#endif
} // namespace wasm } // namespace wasm
} // namespace js } // namespace js

Просмотреть файл

@ -724,19 +724,19 @@ static bool ExecuteCompileTask(CompileTask* task, UniqueChars* error) {
switch (task->env.tier()) { switch (task->env.tier()) {
case Tier::Optimized: case Tier::Optimized:
#ifdef ENABLE_WASM_CRANELIFT switch (task->env.optimizedBackend()) {
if (task->env.optimizedBackend() == OptimizedBackend::Cranelift) { case OptimizedBackend::Cranelift:
if (!CraneliftCompileFunctions(task->env, task->lifo, task->inputs, if (!CraneliftCompileFunctions(task->env, task->lifo, task->inputs,
&task->output, error)) { &task->output, error)) {
return false; return false;
} }
break; break;
} case OptimizedBackend::Ion:
#endif if (!IonCompileFunctions(task->env, task->lifo, task->inputs,
MOZ_ASSERT(task->env.optimizedBackend() == OptimizedBackend::Ion); &task->output, error)) {
if (!IonCompileFunctions(task->env, task->lifo, task->inputs, return false;
&task->output, error)) { }
return false; break;
} }
break; break;
case Tier::Baseline: case Tier::Baseline:

Просмотреть файл

@ -117,7 +117,7 @@ bool Instance::callImport(JSContext* cx, uint32_t funcImportIndex,
return false; return false;
} }
if (fi.funcType().hasI64ArgOrRet() && !HasI64BigIntSupport(cx)) { if (fi.funcType().hasI64ArgOrRet() && !I64BigIntConversionAvailable(cx)) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_I64_TYPE); JSMSG_WASM_BAD_I64_TYPE);
return false; return false;
@ -132,7 +132,7 @@ bool Instance::callImport(JSContext* cx, uint32_t funcImportIndex,
} }
case ValType::I64: { case ValType::I64: {
#ifdef ENABLE_WASM_BIGINT #ifdef ENABLE_WASM_BIGINT
MOZ_ASSERT(HasI64BigIntSupport(cx)); MOZ_ASSERT(I64BigIntConversionAvailable(cx));
// If bi is manipulated other than test & storing, it would need // If bi is manipulated other than test & storing, it would need
// to be rooted here. // to be rooted here.
BigInt* bi = BigInt::createFromInt64(cx, *(int64_t*)&argv[i]); BigInt* bi = BigInt::createFromInt64(cx, *(int64_t*)&argv[i]);
@ -1692,7 +1692,7 @@ bool Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args) {
return false; return false;
} }
if (funcType->hasI64ArgOrRet() && !HasI64BigIntSupport(cx)) { if (funcType->hasI64ArgOrRet() && !I64BigIntConversionAvailable(cx)) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_I64_TYPE); JSMSG_WASM_BAD_I64_TYPE);
return false; return false;
@ -1729,7 +1729,7 @@ bool Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args) {
break; break;
case ValType::I64: { case ValType::I64: {
#ifdef ENABLE_WASM_BIGINT #ifdef ENABLE_WASM_BIGINT
MOZ_ASSERT(HasI64BigIntSupport(cx), MOZ_ASSERT(I64BigIntConversionAvailable(cx),
"unexpected i64 flowing into callExport"); "unexpected i64 flowing into callExport");
RootedBigInt bigint(cx, ToBigInt(cx, v)); RootedBigInt bigint(cx, ToBigInt(cx, v));
if (!bigint) { if (!bigint) {
@ -1848,7 +1848,7 @@ bool Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args) {
break; break;
case ValType::I64: { case ValType::I64: {
#ifdef ENABLE_WASM_BIGINT #ifdef ENABLE_WASM_BIGINT
MOZ_ASSERT(HasI64BigIntSupport(cx), MOZ_ASSERT(I64BigIntConversionAvailable(cx),
"unexpected i64 flowing from callExport"); "unexpected i64 flowing from callExport");
// If bi is manipulated other than test & storing, it would need // If bi is manipulated other than test & storing, it would need
// to be rooted here. // to be rooted here.

Просмотреть файл

@ -4745,7 +4745,7 @@ bool wasm::IonCompileFunctions(const ModuleEnvironment& env, LifoAlloc& lifo,
return code->swap(masm); return code->swap(masm);
} }
bool js::wasm::IonCanCompile() { bool js::wasm::IonPlatformSupport() {
#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || \ #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || \
defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || \ defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || \
defined(JS_CODEGEN_MIPS64) defined(JS_CODEGEN_MIPS64)

Просмотреть файл

@ -27,7 +27,8 @@ namespace js {
namespace wasm { namespace wasm {
// Return whether IonCompileFunction() can generate code on the current device. // Return whether IonCompileFunction() can generate code on the current device.
bool IonCanCompile(); // Usually you do *not* want this, you want IonAvailable().
MOZ_MUST_USE bool IonPlatformSupport();
// Generates very fast code at the expense of compilation time. // Generates very fast code at the expense of compilation time.
MOZ_MUST_USE bool IonCompileFunctions(const ModuleEnvironment& env, MOZ_MUST_USE bool IonCompileFunctions(const ModuleEnvironment& env,

Просмотреть файл

@ -64,33 +64,7 @@ using mozilla::RangedPtr;
extern mozilla::Atomic<bool> fuzzingSafe; extern mozilla::Atomic<bool> fuzzingSafe;
bool wasm::HasReftypesSupport(JSContext* cx) { static inline bool WasmMultiValueFlag(JSContext* cx) {
#ifdef ENABLE_WASM_REFTYPES
return true;
#else
return false;
#endif
}
bool wasm::HasGcSupport(JSContext* cx) {
#ifdef ENABLE_WASM_CRANELIFT
if (cx->options().wasmCranelift()) {
return false;
}
#endif
#ifdef ENABLE_WASM_GC
return cx->options().wasmGc() && cx->options().wasmBaseline();
#else
return false;
#endif
}
bool wasm::HasMultiValueSupport(JSContext* cx) {
#ifdef ENABLE_WASM_CRANELIFT
if (cx->options().wasmCranelift()) {
return false;
}
#endif
#ifdef ENABLE_WASM_MULTI_VALUE #ifdef ENABLE_WASM_MULTI_VALUE
return true; return true;
#else #else
@ -98,12 +72,132 @@ bool wasm::HasMultiValueSupport(JSContext* cx) {
#endif #endif
} }
bool wasm::HasI64BigIntSupport(JSContext* cx) { // Compiler availability predicates. These must be kept in sync with the
#ifdef ENABLE_WASM_CRANELIFT // feature predicates in the next section below.
if (cx->options().wasmCranelift()) { //
// These can't call the feature predicates since the feature predicates call
// back to these predicates. So there will be a small amount of duplicated
// logic here, but as compilers reach feature parity that duplication will go
// away.
//
// There's a static precedence order between the optimizing compilers. This
// order currently ranks Cranelift over Ion on all platforms because Cranelift
// is disabled by default on all platforms: anyone who has enabled Cranelift
// will wish to use it instead of Ion.
//
// The precedence order is implemented by guards in IonAvailable() and
// CraneliftAvailable(). We expect that it will become more complex as the
// default settings change. But it should remain static.
bool wasm::BaselineAvailable(JSContext* cx) {
// Baseline supports every feature supported by any compiler.
return cx->options().wasmBaseline() && BaselinePlatformSupport();
}
bool wasm::IonAvailable(JSContext* cx) {
if (!cx->options().wasmIon() || !IonPlatformSupport()) {
return false; return false;
} }
bool isDisabled = false;
MOZ_ALWAYS_TRUE(IonDisabledByFeatures(cx, &isDisabled));
return !isDisabled && !CraneliftAvailable(cx);
}
template <size_t ArrayLength>
static inline bool Append(JSStringBuilder* reason, const char (&s)[ArrayLength],
char* sep) {
if ((*sep && !reason->append(*sep)) || !reason->append(s)) {
return false;
}
*sep = ',';
return true;
}
bool wasm::IonDisabledByFeatures(JSContext* cx, bool* isDisabled,
JSStringBuilder* reason) {
// Ion has no debugging support, no gc support.
bool debug = cx->realm() && cx->realm()->debuggerObservesAsmJS();
bool gc = cx->options().wasmGc();
if (reason) {
char sep = 0;
if (debug && !Append(reason, "debug", &sep)) {
return false;
}
if (gc && !Append(reason, "gc", &sep)) {
return false;
}
}
*isDisabled = debug || gc;
return true;
}
bool wasm::CraneliftAvailable(JSContext* cx) {
if (!cx->options().wasmCranelift() || !CraneliftPlatformSupport()) {
return false;
}
bool isDisabled = false;
MOZ_ALWAYS_TRUE(CraneliftDisabledByFeatures(cx, &isDisabled));
return !isDisabled;
}
bool wasm::CraneliftDisabledByFeatures(JSContext* cx, bool* isDisabled,
JSStringBuilder* reason) {
// Cranelift has no debugging support, no gc support, no multi-value support,
// no threads.
bool debug = cx->realm() && cx->realm()->debuggerObservesAsmJS();
bool gc = cx->options().wasmGc();
bool multiValue = WasmMultiValueFlag(cx);
bool threads =
cx->realm() &&
cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled();
if (reason) {
char sep = 0;
if (debug && !Append(reason, "debug", &sep)) {
return false;
}
if (gc && !Append(reason, "gc", &sep)) {
return false;
}
if (multiValue && !Append(reason, "multi-value", &sep)) {
return false;
}
if (threads && !Append(reason, "threads", &sep)) {
return false;
}
}
*isDisabled = debug || gc || multiValue || threads;
return true;
}
// Feature predicates. These must be kept in sync with the predicates in the
// section above.
//
// The meaning of these predicates is tricky: A predicate is true for a feature
// if the feature is enabled and/or compiled-in *and* we have *at least one*
// compiler that can support the feature. Subsequent compiler selection must
// ensure that only compilers that actually support the feature are used.
bool wasm::ReftypesAvailable(JSContext* cx) {
// All compilers support reference types.
#ifdef ENABLE_WASM_REFTYPES
return true;
#else
return false;
#endif #endif
}
bool wasm::GcTypesAvailable(JSContext* cx) {
// Cranelift and Ion do not support GC.
return cx->options().wasmGc() && BaselineAvailable(cx);
}
bool wasm::MultiValuesAvailable(JSContext* cx) {
// Cranelift does not support multi-value.
return WasmMultiValueFlag(cx) && (BaselineAvailable(cx) || IonAvailable(cx));
}
bool wasm::I64BigIntConversionAvailable(JSContext* cx) {
// All compilers support int64<->bigint conversion.
#ifdef ENABLE_WASM_BIGINT #ifdef ENABLE_WASM_BIGINT
return cx->options().isWasmBigIntEnabled(); return cx->options().isWasmBigIntEnabled();
#else #else
@ -111,7 +205,14 @@ bool wasm::HasI64BigIntSupport(JSContext* cx) {
#endif #endif
} }
bool wasm::HasCompilerSupport(JSContext* cx) { bool wasm::ThreadsAvailable(JSContext* cx) {
// Cranelift does not support atomics.
return cx->realm() &&
cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled() &&
(BaselineAvailable(cx) || IonAvailable(cx));
}
bool wasm::HasPlatformSupport(JSContext* cx) {
#if !MOZ_LITTLE_ENDIAN() || defined(JS_CODEGEN_NONE) #if !MOZ_LITTLE_ENDIAN() || defined(JS_CODEGEN_NONE)
return false; return false;
#endif #endif
@ -143,22 +244,10 @@ bool wasm::HasCompilerSupport(JSContext* cx) {
} }
#endif #endif
return BaselineCanCompile() || IonCanCompile() || CraneliftCanCompile(); // Test only whether the compilers are supported on the hardware, not whether
} // they are enabled.
return BaselinePlatformSupport() || IonPlatformSupport() ||
bool wasm::HasOptimizedCompilerTier(JSContext* cx) { CraneliftPlatformSupport();
return (cx->options().wasmIon() && IonCanCompile())
#ifdef ENABLE_WASM_CRANELIFT
|| (cx->options().wasmCranelift() && CraneliftCanCompile())
#endif
;
}
// Return whether wasm compilation is allowed by prefs. This check
// only makes sense if HasCompilerSupport() is true.
static bool HasAvailableCompilerTier(JSContext* cx) {
return (cx->options().wasmBaseline() && BaselineCanCompile()) ||
HasOptimizedCompilerTier(cx);
} }
bool wasm::HasSupport(JSContext* cx) { bool wasm::HasSupport(JSContext* cx) {
@ -170,10 +259,11 @@ bool wasm::HasSupport(JSContext* cx) {
cx->realm()->principals() && cx->realm()->principals() &&
cx->realm()->principals()->isSystemOrAddonPrincipal(); cx->realm()->principals()->isSystemOrAddonPrincipal();
} }
return prefEnabled && HasCompilerSupport(cx) && HasAvailableCompilerTier(cx); return prefEnabled && HasPlatformSupport(cx) &&
(BaselineAvailable(cx) || IonAvailable(cx) || CraneliftAvailable(cx));
} }
bool wasm::HasStreamingSupport(JSContext* cx) { bool wasm::StreamingCompilationAvailable(JSContext* cx) {
// This should match EnsureStreamSupport(). // This should match EnsureStreamSupport().
return HasSupport(cx) && return HasSupport(cx) &&
cx->runtime()->offThreadPromiseState.ref().initialized() && cx->runtime()->offThreadPromiseState.ref().initialized() &&
@ -181,8 +271,12 @@ bool wasm::HasStreamingSupport(JSContext* cx) {
cx->runtime()->reportStreamErrorCallback; cx->runtime()->reportStreamErrorCallback;
} }
bool wasm::HasCachingSupport(JSContext* cx) { bool wasm::CodeCachingAvailable(JSContext* cx) {
return HasStreamingSupport(cx) && HasOptimizedCompilerTier(cx); // At the moment, we require Ion support for code caching. The main reason
// for this is that wasm::CompileAndSerialize() does not have access to
// information about which optimizing compiler it should use. See comments in
// CompileAndSerialize(), below.
return StreamingCompilationAvailable(cx) && IonAvailable(cx);
} }
bool wasm::CheckRefType(JSContext* cx, RefType::Kind targetTypeKind, bool wasm::CheckRefType(JSContext* cx, RefType::Kind targetTypeKind,
@ -242,7 +336,7 @@ static bool ToWebAssemblyValue(JSContext* cx, ValType targetType, HandleValue v,
} }
case ValType::I64: { case ValType::I64: {
#ifdef ENABLE_WASM_BIGINT #ifdef ENABLE_WASM_BIGINT
if (HasI64BigIntSupport(cx)) { if (I64BigIntConversionAvailable(cx)) {
BigInt* bigint = ToBigInt(cx, v); BigInt* bigint = ToBigInt(cx, v);
if (!bigint) { if (!bigint) {
return false; return false;
@ -289,7 +383,7 @@ static bool ToJSValue(JSContext* cx, const Val& val, MutableHandleValue out) {
return true; return true;
case ValType::I64: { case ValType::I64: {
#ifdef ENABLE_WASM_BIGINT #ifdef ENABLE_WASM_BIGINT
if (HasI64BigIntSupport(cx)) { if (I64BigIntConversionAvailable(cx)) {
BigInt* bi = BigInt::createFromInt64(cx, val.i64()); BigInt* bi = BigInt::createFromInt64(cx, val.i64());
if (!bi) { if (!bi) {
return false; return false;
@ -442,7 +536,7 @@ bool js::wasm::GetImports(JSContext* cx, const Module& module,
obj->val(&val); obj->val(&val);
} else { } else {
if (IsNumberType(global.type())) { if (IsNumberType(global.type())) {
if (HasI64BigIntSupport(cx)) { if (I64BigIntConversionAvailable(cx)) {
if (global.type() == ValType::I64 && v.isNumber()) { if (global.type() == ValType::I64 && v.isNumber()) {
return ThrowBadImportType(cx, import.field.get(), "BigInt"); return ThrowBadImportType(cx, import.field.get(), "BigInt");
} }
@ -591,10 +685,15 @@ bool wasm::CompileAndSerialize(const ShareableBytes& bytecode,
return false; return false;
} }
// The caller has ensured HasCachingSupport(). Moreover, we want to ensure // The caller has ensured CodeCachingAvailable(). Moreover, we want to ensure
// we go straight to tier-2 so that we synchronously call // we go straight to tier-2 so that we synchronously call
// JS::OptimizedEncodingListener::storeOptimizedEncoding(). // JS::OptimizedEncodingListener::storeOptimizedEncoding().
compileArgs->baselineEnabled = false; compileArgs->baselineEnabled = false;
// We always pick Ion here, and we depend on CodeCachingAvailable() having
// determined that Ion is available, see comments at CodeCachingAvailable().
// To do better, we need to pass information about which compiler that should
// be used into CompileAndSerialize().
compileArgs->ionEnabled = true; compileArgs->ionEnabled = true;
// The caller must ensure that huge memory support is configured the same in // The caller must ensure that huge memory support is configured the same in
@ -2277,7 +2376,7 @@ bool WasmTableObject::construct(JSContext* cx, unsigned argc, Value* vp) {
#ifdef ENABLE_WASM_REFTYPES #ifdef ENABLE_WASM_REFTYPES
} else if (StringEqualsLiteral(elementLinearStr, "anyref") || } else if (StringEqualsLiteral(elementLinearStr, "anyref") ||
StringEqualsLiteral(elementLinearStr, "nullref")) { StringEqualsLiteral(elementLinearStr, "nullref")) {
if (!HasReftypesSupport(cx)) { if (!ReftypesAvailable(cx)) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_ELEMENT); JSMSG_WASM_BAD_ELEMENT);
return false; return false;
@ -2735,18 +2834,18 @@ bool WasmGlobalObject::construct(JSContext* cx, unsigned argc, Value* vp) {
} else if (StringEqualsLiteral(typeLinearStr, "f64")) { } else if (StringEqualsLiteral(typeLinearStr, "f64")) {
globalType = ValType::F64; globalType = ValType::F64;
#ifdef ENABLE_WASM_BIGINT #ifdef ENABLE_WASM_BIGINT
} else if (HasI64BigIntSupport(cx) && } else if (I64BigIntConversionAvailable(cx) &&
StringEqualsLiteral(typeLinearStr, "i64")) { StringEqualsLiteral(typeLinearStr, "i64")) {
globalType = ValType::I64; globalType = ValType::I64;
#endif #endif
#ifdef ENABLE_WASM_REFTYPES #ifdef ENABLE_WASM_REFTYPES
} else if (HasReftypesSupport(cx) && } else if (ReftypesAvailable(cx) &&
StringEqualsLiteral(typeLinearStr, "funcref")) { StringEqualsLiteral(typeLinearStr, "funcref")) {
globalType = RefType::func(); globalType = RefType::func();
} else if (HasReftypesSupport(cx) && } else if (ReftypesAvailable(cx) &&
StringEqualsLiteral(typeLinearStr, "anyref")) { StringEqualsLiteral(typeLinearStr, "anyref")) {
globalType = RefType::any(); globalType = RefType::any();
} else if (HasReftypesSupport(cx) && } else if (ReftypesAvailable(cx) &&
StringEqualsLiteral(typeLinearStr, "nullref")) { StringEqualsLiteral(typeLinearStr, "nullref")) {
globalType = RefType::null(); globalType = RefType::null();
#endif #endif
@ -2822,7 +2921,7 @@ bool WasmGlobalObject::valueGetterImpl(JSContext* cx, const CallArgs& args) {
return true; return true;
case ValType::I64: case ValType::I64:
#ifdef ENABLE_WASM_BIGINT #ifdef ENABLE_WASM_BIGINT
if (HasI64BigIntSupport(cx)) { if (I64BigIntConversionAvailable(cx)) {
return args.thisv().toObject().as<WasmGlobalObject>().value( return args.thisv().toObject().as<WasmGlobalObject>().value(
cx, args.rval()); cx, args.rval());
} }
@ -2866,7 +2965,7 @@ bool WasmGlobalObject::valueSetterImpl(JSContext* cx, const CallArgs& args) {
return false; return false;
} }
if (global->type() == ValType::I64 && !HasI64BigIntSupport(cx)) { if (global->type() == ValType::I64 && !I64BigIntConversionAvailable(cx)) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_I64_TYPE); JSMSG_WASM_BAD_I64_TYPE);
return false; return false;
@ -2890,7 +2989,7 @@ bool WasmGlobalObject::valueSetterImpl(JSContext* cx, const CallArgs& args) {
break; break;
case ValType::I64: case ValType::I64:
#ifdef ENABLE_WASM_BIGINT #ifdef ENABLE_WASM_BIGINT
MOZ_ASSERT(HasI64BigIntSupport(cx), MOZ_ASSERT(I64BigIntConversionAvailable(cx),
"expected BigInt support for setting I64 global"); "expected BigInt support for setting I64 global");
cell->i64 = val.get().i64(); cell->i64 = val.get().i64();
#endif #endif
@ -3368,7 +3467,7 @@ static bool WebAssembly_validate(JSContext* cx, unsigned argc, Value* vp) {
} }
static bool EnsureStreamSupport(JSContext* cx) { static bool EnsureStreamSupport(JSContext* cx) {
// This should match wasm::HasStreamingSupport(). // This should match wasm::StreamingCompilationAvailable().
if (!EnsurePromiseSupport(cx)) { if (!EnsurePromiseSupport(cx)) {
return false; return false;

Просмотреть файл

@ -27,6 +27,7 @@
namespace js { namespace js {
class ArrayBufferObjectMaybeShared; class ArrayBufferObjectMaybeShared;
class JSStringBuilder;
class StructTypeDescr; class StructTypeDescr;
class TypedArrayObject; class TypedArrayObject;
class WasmFunctionScope; class WasmFunctionScope;
@ -35,48 +36,81 @@ class SharedArrayRawBuffer;
namespace wasm { namespace wasm {
// Return whether WebAssembly can be compiled on this platform. // Return whether WebAssembly can in principle be compiled on this platform (ie
// This must be checked and must be true to call any of the top-level wasm // combination of hardware and OS), assuming at least one of the compilers that
// eval/compile methods. // supports the platform is not disabled by other settings.
//
// This predicate must be checked and must be true to call any of the top-level
// wasm eval/compile methods.
bool HasCompilerSupport(JSContext* cx); bool HasPlatformSupport(JSContext* cx);
// Return whether WebAssembly has support for an optimized compiler backend.
bool HasOptimizedCompilerTier(JSContext* cx);
// Return whether WebAssembly is supported on this platform. This determines // Return whether WebAssembly is supported on this platform. This determines
// whether the WebAssembly object is exposed to JS and takes into account // whether the WebAssembly object is exposed to JS and takes into account
// configuration options that disable various modes. // configuration options that disable various modes. It also checks that at
// least one compiler is (currently) available.
bool HasSupport(JSContext* cx); bool HasSupport(JSContext* cx);
// Return whether WebAssembly streaming/caching is supported on this platform. // Predicates for compiler availability.
// This takes into account prefs and necessary embedding callbacks. //
// These three predicates together select zero or one baseline compiler and zero
// or one optimizing compiler, based on: what's compiled into the executable,
// what's supported on the current platform, what's selected by options, and the
// current run-time environment. As it is possible for the computed values to
// change (when a value changes in about:config or the debugger pane is shown or
// hidden), it is inadvisable to cache these values in such a way that they
// could become invalid. Generally it is cheap always to recompute them.
bool HasStreamingSupport(JSContext* cx); bool BaselineAvailable(JSContext* cx);
bool IonAvailable(JSContext* cx);
bool CraneliftAvailable(JSContext* cx);
bool HasCachingSupport(JSContext* cx); // Predicates for white-box compiler disablement testing.
//
// These predicates determine whether the optimizing compilers were disabled by
// features that are enabled at compile-time or run-time. They do not consider
// the hardware platform on whether other compilers are enabled.
//
// If `reason` is not null then it is populated with a string that describes
// the specific features that disable the compiler.
//
// Returns false on OOM (which happens only when a reason is requested),
// otherwise true, with the result in `*isDisabled` and optionally the reason in
// `*reason`.
// Returns true if WebAssembly as configured by compile-time flags and run-time bool IonDisabledByFeatures(JSContext* cx, bool* isDisabled,
// options can support reference types and stack walking. JSStringBuilder* reason = nullptr);
bool CraneliftDisabledByFeatures(JSContext* cx, bool* isDisabled,
JSStringBuilder* reason = nullptr);
bool HasReftypesSupport(JSContext* cx); // Predicates for feature availability.
//
// The following predicates check whether particular wasm features are enabled,
// and for each, whether at least one compiler is (currently) available that
// supports the feature.
// Returns true if WebAssembly as configured by compile-time flags and run-time // Streaming compilation.
// options can support (ref T) types and structure types, etc (evolving). bool StreamingCompilationAvailable(JSContext* cx);
bool HasGcSupport(JSContext* cx); // Caching of optimized code. Implies both streaming compilation and an
// optimizing compiler tier.
bool CodeCachingAvailable(JSContext* cx);
// Returns true if WebAssembly as configured by compile-time flags and run-time // General reference types (anyref, funcref, nullref) and operations on them.
// options can support multi-value block and function returns (evolving). bool ReftypesAvailable(JSContext* cx);
bool HasMultiValueSupport(JSContext* cx); // Experimental (ref T) types and structure types.
bool GcTypesAvailable(JSContext* cx);
// Returns true if WebAssembly as configured by compile-time flags and run-time // Multi-value block and function returns.
// options can support I64 to BigInt conversion. bool MultiValuesAvailable(JSContext* cx);
bool HasI64BigIntSupport(JSContext* cx); // I64<->BigInt interconversion at the wasm/JS boundary.
bool I64BigIntConversionAvailable(JSContext* cx);
// Shared memory and atomics.
bool ThreadsAvailable(JSContext* cx);
// Compiles the given binary wasm module given the ArrayBufferObject // Compiles the given binary wasm module given the ArrayBufferObject
// and links the module's imports with the given import object. // and links the module's imports with the given import object.

Просмотреть файл

@ -45,7 +45,7 @@ void EnsureEagerProcessSignalHandlers();
// this function performs the full installation of signal handlers which must // this function performs the full installation of signal handlers which must
// be performed per-thread/JSContext. This operation may incur some overhead and // be performed per-thread/JSContext. This operation may incur some overhead and
// so should be done only when needed to use wasm. Currently, this is done in // so should be done only when needed to use wasm. Currently, this is done in
// wasm::HasCompilerSupport() which is called when deciding whether to expose // wasm::HasPlatformSupport() which is called when deciding whether to expose
// the 'WebAssembly' object on the global object. // the 'WebAssembly' object on the global object.
bool EnsureFullSignalHandlers(JSContext* cx); bool EnsureFullSignalHandlers(JSContext* cx);

Просмотреть файл

@ -2986,11 +2986,11 @@ bool wasm::Validate(JSContext* cx, const ShareableBytes& bytecode,
UniqueChars* error) { UniqueChars* error) {
Decoder d(bytecode.bytes, 0, error); Decoder d(bytecode.bytes, 0, error);
bool gcTypesConfigured = HasGcSupport(cx); bool gcTypesConfigured = GcTypesAvailable(cx);
bool refTypesConfigured = HasReftypesSupport(cx); bool refTypesConfigured = ReftypesAvailable(cx);
bool multiValueConfigured = HasMultiValueSupport(cx); bool multiValueConfigured = MultiValuesAvailable(cx);
bool hugeMemory = false; bool hugeMemory = false;
bool bigIntConfigured = HasI64BigIntSupport(cx); bool bigIntConfigured = I64BigIntConversionAvailable(cx);
CompilerEnvironment compilerEnv( CompilerEnvironment compilerEnv(
CompileMode::Once, Tier::Optimized, OptimizedBackend::Ion, CompileMode::Once, Tier::Optimized, OptimizedBackend::Ion,