Bug 1276029 - Baldr: use process-wide signal-handling-support query (r=bbouvier)

MozReview-Commit-ID: 3bS2f00Xcu

--HG--
extra : rebase_source : 28522b8a179e8528999ea0c3bd55abf3509d4b1e
This commit is contained in:
Luke Wagner 2016-07-15 12:26:40 -05:00
Родитель 9c830edcb0
Коммит 70d041e484
25 изменённых файлов: 122 добавлений и 125 удалений

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

@ -8388,7 +8388,7 @@ LookupAsmJSModuleInCache(ExclusiveContext* cx, AsmJSParser& parser, bool* loaded
return true;
Assumptions assumptions;
if (!assumptions.init(SignalUsage(cx), cx->buildIdOp()))
if (!assumptions.init(cx->buildIdOp()))
return true;
if (assumptions != (*module)->metadata().assumptions)

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

@ -1389,7 +1389,7 @@ bool
CompileArgs::init(ExclusiveContext* cx)
{
alwaysBaseline = cx->options().wasmAlwaysBaseline();
if (!assumptions.init(SignalUsage(cx), cx->buildIdOp())) {
if (!assumptions.init(cx->buildIdOp())) {
ReportOutOfMemory(cx);
return false;
}

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

@ -567,7 +567,7 @@ WasmMemoryObject::construct(JSContext* cx, unsigned argc, Value* vp)
}
uint32_t bytes = uint32_t(initialDbl) * PageSize;
bool signalsForOOB = SignalUsage(cx).forOOB;
bool signalsForOOB = SignalUsage().forOOB;
RootedArrayBufferObject buffer(cx, ArrayBufferObject::createForWasm(cx, bytes, signalsForOOB));
if (!buffer)
return false;

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

@ -1261,24 +1261,21 @@ JitInterruptHandler(int signum, siginfo_t* info, void* context)
}
#endif
bool
wasm::EnsureSignalHandlersInstalled(JSRuntime* rt)
static bool
ProcessHasSignalHandlers()
{
#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS)
// On OSX, each JSRuntime gets its own handler thread.
if (!rt->wasmMachExceptionHandler.installed() && !rt->wasmMachExceptionHandler.install(rt))
return false;
#endif
// All the rest of the handlers are process-wide and thus must only be
// installed once. We assume that there are no races creating the first
// JSRuntime of the process.
// We assume that there are no races creating the first JSRuntime of the process.
static bool sTried = false;
static bool sResult = false;
if (sTried)
return sResult;
sTried = true;
// Developers might want to forcibly disable signals to avoid seeing
// spurious SIGSEGVs in the debugger.
if (getenv("JS_DISABLE_SLOW_SCRIPT_SIGNALS") || getenv("JS_NO_SIGNALS"))
return false;
#if defined(ANDROID)
// Before Android 4.4 (SDK version 19), there is a bug
// https://android-review.googlesource.com/#/c/52333
@ -1357,6 +1354,39 @@ wasm::EnsureSignalHandlersInstalled(JSRuntime* rt)
return true;
}
bool
wasm::EnsureSignalHandlers(JSRuntime* rt)
{
// Nothing to do if the platform doesn't support it.
if (!ProcessHasSignalHandlers())
return true;
#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS)
// On OSX, each JSRuntime gets its own handler thread.
if (!rt->wasmMachExceptionHandler.installed() && !rt->wasmMachExceptionHandler.install(rt))
return false;
#endif
return true;
}
static bool sHandlersSuppressedForTesting = false;
bool
wasm::HaveSignalHandlers()
{
if (!ProcessHasSignalHandlers())
return false;
return !sHandlersSuppressedForTesting;
}
void
wasm::SuppressSignalHandlersForTesting(bool suppress)
{
sHandlersSuppressedForTesting = suppress;
}
// JSRuntime::requestInterrupt sets interrupt_ (which is checked frequently by
// C++ code at every Baseline JIT loop backedge) and jitStackLimit_ (which is
// checked at every Baseline and Ion JIT function prologue). The remaining
@ -1371,7 +1401,7 @@ js::InterruptRunningJitCode(JSRuntime* rt)
{
// If signal handlers weren't installed, then Ion and wasm emit normal
// interrupt checks and don't need asynchronous interruption.
if (!rt->canUseSignalHandlers())
if (!HaveSignalHandlers())
return;
// Do nothing if we're already handling an interrupt here, to avoid races

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

@ -37,12 +37,21 @@ InterruptRunningJitCode(JSRuntime* rt);
namespace wasm {
// Set up any signal/exception handlers needed to execute code in the given
// runtime. Return whether runtime can:
// - rely on fault handler support for avoiding asm.js heap bounds checks
// - rely on InterruptRunningJitCode to halt running Ion/asm.js from any thread
// Ensure the given JSRuntime is set up to use signals. Failure to enable signal
// handlers indicates some catastrophic failure and creation of the runtime must
// fail.
MOZ_MUST_USE bool
EnsureSignalHandlersInstalled(JSRuntime* rt);
EnsureSignalHandlers(JSRuntime* rt);
// Return whether signals can be used in this process for interrupts or, ifdef
// ASMJS_MAY_USE_SIGNAL_HANDLERS, asm.js/wasm out-of-bounds. This value can
// change over time solely due to DisableSignalHandlersForTesting.
bool
HaveSignalHandlers();
// Artificially suppress signal handler support, for testing purposes.
void
SuppressSignalHandlersForTesting(bool suppress);
#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS)
// On OSX we are forced to use the lower-level Mach exception mechanism instead

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

@ -25,6 +25,7 @@
#include "asmjs/WasmInstance.h"
#include "asmjs/WasmSerialize.h"
#include "asmjs/WasmSignalHandlers.h"
#include "jit/MacroAssembler.h"
#include "js/Conversions.h"
#include "vm/Interpreter.h"
@ -272,18 +273,18 @@ wasm::AddressOf(SymbolicAddress imm, ExclusiveContext* cx)
MOZ_CRASH("Bad SymbolicAddress");
}
SignalUsage::SignalUsage(ExclusiveContext* cx)
SignalUsage::SignalUsage()
:
#ifdef ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB
// Signal-handling is only used to eliminate bounds checks when the OS page
// size is an even divisor of the WebAssembly page size.
forOOB(cx->canUseSignalHandlers() &&
forOOB(HaveSignalHandlers() &&
gc::SystemPageSize() <= PageSize &&
PageSize % gc::SystemPageSize() == 0),
#else
forOOB(false),
#endif
forInterrupt(cx->canUseSignalHandlers())
forInterrupt(HaveSignalHandlers())
{}
bool
@ -330,10 +331,8 @@ GetCPUID(uint32_t* cpuId)
}
MOZ_MUST_USE bool
Assumptions::init(SignalUsage usesSignal, JS::BuildIdOp buildIdOp)
Assumptions::init(JS::BuildIdOp buildIdOp)
{
this->usesSignal = usesSignal;
if (!GetCPUID(&cpuId))
return false;

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

@ -801,8 +801,7 @@ struct SignalUsage
bool forOOB;
bool forInterrupt;
SignalUsage() = default;
explicit SignalUsage(ExclusiveContext* cx);
SignalUsage();
bool operator==(SignalUsage rhs) const;
bool operator!=(SignalUsage rhs) const { return !(*this == rhs); }
};
@ -818,8 +817,8 @@ struct Assumptions
JS::BuildIdCharVector buildId;
bool newFormat;
Assumptions() : cpuId(0), newFormat(false) {}
MOZ_MUST_USE bool init(SignalUsage usesSignal, JS::BuildIdOp buildIdOp);
Assumptions() : usesSignal(), cpuId(0), newFormat(false) {}
MOZ_MUST_USE bool init(JS::BuildIdOp buildIdOp);
bool operator==(const Assumptions& rhs) const;
bool operator!=(const Assumptions& rhs) const { return !(*this == rhs); }

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

@ -23,6 +23,7 @@
#include "asmjs/WasmBinaryToExperimentalText.h"
#include "asmjs/WasmBinaryToText.h"
#include "asmjs/WasmJS.h"
#include "asmjs/WasmSignalHandlers.h"
#include "asmjs/WasmTextToBinary.h"
#include "builtin/Promise.h"
#include "builtin/SelfHostingDefines.h"
@ -515,7 +516,21 @@ static bool
WasmUsesSignalForOOB(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(wasm::SignalUsage(cx).forOOB);
args.rval().setBoolean(wasm::SignalUsage().forOOB);
return true;
}
static bool
SuppressSignalHandlers(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!args.requireAtLeast(cx, "suppressSignalHandlers", 1))
return false;
wasm::SuppressSignalHandlersForTesting(ToBoolean(args[0]));
args.rval().setUndefined();
return true;
}
@ -3786,6 +3801,11 @@ gc::ZealModeHelpText),
"wasmUsesSignalForOOB()",
" Return whether wasm and asm.js use a signal handler for detecting out-of-bounds."),
JS_FN_HELP("suppressSignalHandlers", SuppressSignalHandlers, 1, 0,
"suppressSignalHandlers(suppress)",
" This function allows artificially suppressing signal handler support, even if the underlying "
" platform supports it."),
JS_FN_HELP("wasmTextToBinary", WasmTextToBinary, 1, 0,
"wasmTextToBinary(str)",
" Translates the given text wasm module into its binary encoding."),

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

@ -26,29 +26,24 @@ assertEq(f(0xff),-1);
assertEq(f(0x100),0);
// Test signal handlers deactivation
(function() {
var jco = getJitCompilerOptions();
var signalHandlersBefore = jco["signals.enable"];
if (signalHandlersBefore == 1) {
setJitCompilerOption("signals.enable", 0);
if (wasmUsesSignalForOOB()) {
suppressSignalHandlers(true);
assertEq(wasmUsesSignalForOOB(), false);
var buf = new ArrayBuffer(BUF_MIN);
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + '/* not a clone */ function f(i) {i=i|0; i32[0] = i; return i8[0]|0}; return f');
var f = asmLink(code, this, null, buf);
assertEq(f(0),0);
assertEq(f(0x7f),0x7f);
assertEq(f(0xff),-1);
assertEq(f(0x100),0);
var buf = new ArrayBuffer(BUF_MIN);
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + '/* not a clone */ function f(i) {i=i|0; i32[0] = i; return i8[0]|0}; return f');
var f = asmLink(code, this, null, buf);
assertEq(f(0),0);
assertEq(f(0x7f),0x7f);
assertEq(f(0xff),-1);
assertEq(f(0x100),0);
// Bug 1088655
assertEq(asmLink(asmCompile('stdlib', 'foreign', 'heap', USE_ASM + 'var i32=new stdlib.Int32Array(heap); function f(i) {i=i|0;var j=0x10000;return (i32[j>>2] = i)|0 } return f'), this, null, buf)(1), 1);
// Bug 1088655
assertEq(asmLink(asmCompile('stdlib', 'foreign', 'heap', USE_ASM + 'var i32=new stdlib.Int32Array(heap); function f(i) {i=i|0;var j=0x10000;return (i32[j>>2] = i)|0 } return f'), this, null, buf)(1), 1);
setJitCompilerOption("signals.enable", 1);
}
jco = getJitCompilerOptions();
var signalHandlersAfter = jco["signals.enable"];
assertEq(signalHandlersBefore, signalHandlersAfter);
})();
suppressSignalHandlers(false);
assertEq(wasmUsesSignalForOOB(), true);
}
setCachingEnabled(false);

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

@ -8,7 +8,7 @@ fatFunc += "function f100() { return 42 }\n";
fatFunc += "return f0";
for (var signals = 0; signals <= 1; signals++) {
setJitCompilerOption("signals.enable", signals);
suppressSignalHandlers(Boolean(signals));
for (let threshold of [0, 50, 100, 5000, -1]) {
setJitCompilerOption("jump-threshold", threshold);

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

@ -5,12 +5,12 @@ load(libdir + "asm.js");
setCachingEnabled(true);
var jco = getJitCompilerOptions();
if (jco["signals.enable"] === 0 || !isCachingEnabled() || !isAsmJSCompilationAvailable())
if (!isCachingEnabled() || !isAsmJSCompilationAvailable())
quit(6);
// Modules compiled without signal handlers should still work even if signal
// handlers have been reactivated.
setJitCompilerOption("signals.enable", 0);
suppressSignalHandlers(true);
var code = USE_ASM + "function f() {} function g() { while(1) { f() } } return g";
@ -18,7 +18,7 @@ var m = asmCompile(code);
assertEq(isAsmJSModule(m), true);
assertEq(isAsmJSModuleLoadedFromCache(m), false);
setJitCompilerOption("signals.enable", 1);
suppressSignalHandlers(false);
var m = asmCompile(code);
assertEq(isAsmJSModule(m), true);

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

@ -2,7 +2,7 @@
load(libdir + "asm.js");
setJitCompilerOption("signals.enable", 0);
suppressSignalHandlers(true);
var g = asmLink(asmCompile(USE_ASM + "function f() {} function g() { while(1) { f() } } return g"));
timeout(1);
g();

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

@ -2,7 +2,7 @@
load(libdir + "asm.js");
setJitCompilerOption("signals.enable", 0);
suppressSignalHandlers(true);
var g = asmLink(asmCompile(USE_ASM + "function g() { while(1) {} } return g"));
timeout(1);
g();

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

@ -2,7 +2,7 @@
load(libdir + "asm.js");
setJitCompilerOption("signals.enable", 0);
suppressSignalHandlers(true);
var f = asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; if (!i) return; f((i-1)|0); f((i-1)|0); f((i-1)|0); f((i-1)|0); f((i-1)|0); } return f"));
timeout(1);
f(100);

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

@ -2,7 +2,7 @@
load(libdir + "asm.js");
setJitCompilerOption("signals.enable", 0);
suppressSignalHandlers(true);
var g = asmLink(asmCompile(USE_ASM + "function f(d) { d=+d; d=d*.1; d=d/.4; return +d } function g() { while(1) { +f(1.1) } } return g"));
timeout(1);
g();

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

@ -1,5 +1,5 @@
// |jit-test| exitstatus: 6;
setJitCompilerOption('signals.enable', 0);
suppressSignalHandlers(true);
timeout(1);
for(;;);

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

@ -8,31 +8,22 @@ const textToBinary = str => wasmTextToBinary(str, 'new-format');
if (!wasmUsesSignalForOOB())
quit();
function enable() {
assertEq(getJitCompilerOptions()["signals.enable"], 0);
setJitCompilerOption("signals.enable", 1);
}
function disable() {
assertEq(getJitCompilerOptions()["signals.enable"], 1);
setJitCompilerOption("signals.enable", 0);
}
const Module = WebAssembly.Module;
const Instance = WebAssembly.Instance;
const Memory = WebAssembly.Memory;
const code = textToBinary('(module (import "x" "y" (memory 1 1)))');
disable();
suppressSignalHandlers(true);
var mem = new Memory({initial:1});
enable();
suppressSignalHandlers(false);
var m = new Module(code);
disable();
suppressSignalHandlers(true);
assertErrorMessage(() => new Instance(m, {x:{y:mem}}), Error, /signals/);
var m = new Module(code);
enable();
suppressSignalHandlers(false);
assertEq(new Instance(m, {x:{y:mem}}) instanceof Instance, true);
var mem = new Memory({initial:1});
disable();
suppressSignalHandlers(true);
var m = new Module(code);
enable();
suppressSignalHandlers(false);
assertEq(new Instance(m, {x:{y:mem}}) instanceof Instance, true);

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

@ -112,12 +112,6 @@ CompileRuntime::spsProfiler()
return runtime()->spsProfiler;
}
bool
CompileRuntime::canUseSignalHandlers()
{
return runtime()->canUseSignalHandlers();
}
bool
CompileRuntime::jitSupportsFloatingPoint()
{

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

@ -69,7 +69,6 @@ class CompileRuntime
// Compilation does not occur off thread when the SPS profiler is enabled.
SPSProfiler& spsProfiler();
bool canUseSignalHandlers();
bool jitSupportsFloatingPoint();
bool hadOutOfMemory();
bool profilingScripts();

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

@ -8,6 +8,7 @@
#include "mozilla/DebugOnly.h"
#include "asmjs/WasmSignalHandlers.h"
#include "jit/JitSpewer.h"
#include "jit/LIR.h"
#include "jit/MIR.h"
@ -93,7 +94,7 @@ static void
TryToUseImplicitInterruptCheck(MIRGraph& graph, MBasicBlock* backedge)
{
// Implicit interrupt checks require asm.js signal handlers to be installed.
if (!GetJitContext()->runtime->canUseSignalHandlers())
if (!wasm::HaveSignalHandlers())
return;
// To avoid triggering expensive interrupts (backedge patching) in

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

@ -6107,15 +6107,6 @@ JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t v
JitSpew(js::jit::JitSpew_IonScripts, "Disable offthread compilation");
}
break;
case JSJITCOMPILER_SIGNALS_ENABLE:
if (value == 1) {
rt->setCanUseSignalHandlers(true);
JitSpew(js::jit::JitSpew_IonScripts, "Enable signals");
} else if (value == 0) {
rt->setCanUseSignalHandlers(false);
JitSpew(js::jit::JitSpew_IonScripts, "Disable signals");
}
break;
case JSJITCOMPILER_JUMP_THRESHOLD:
if (value == uint32_t(-1)) {
jit::DefaultJitOptions defaultValues;
@ -6151,8 +6142,6 @@ JS_GetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt)
return JS::ContextOptionsRef(cx).baseline();
case JSJITCOMPILER_OFFTHREAD_COMPILATION_ENABLE:
return rt->canUseOffthreadIonCompilation();
case JSJITCOMPILER_SIGNALS_ENABLE:
return rt->canUseSignalHandlers();
case JSJITCOMPILER_WASM_TEST_MODE:
return jit::JitOptions.wasmTestMode ? 1 : 0;
default:

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

@ -5541,7 +5541,6 @@ JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled);
Register(ION_ENABLE, "ion.enable") \
Register(BASELINE_ENABLE, "baseline.enable") \
Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \
Register(SIGNALS_ENABLE, "signals.enable") \
Register(JUMP_THRESHOLD, "jump-threshold") \
Register(WASM_TEST_MODE, "wasm.test-mode")

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

@ -218,7 +218,6 @@ class ExclusiveContext : public ContextFriendFields,
void* stackLimitAddressForJitCode(StackKind kind);
uintptr_t stackLimit(StackKind kind) { return runtime_->mainThread.nativeStackLimit[kind]; }
size_t gcSystemPageSize() { return gc::SystemPageSize(); }
bool canUseSignalHandlers() const { return runtime_->canUseSignalHandlers(); }
bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; }
bool jitSupportsUnalignedAccesses() const { return runtime_->jitSupportsUnalignedAccesses; }
bool jitSupportsSimd() const { return runtime_->jitSupportsSimd; }

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

@ -209,8 +209,6 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
#endif
allowRelazificationForTesting(false),
data(nullptr),
signalHandlersInstalled_(false),
canUseSignalHandlers_(false),
defaultFreeOp_(thisFromCtor()),
debuggerMutations(0),
securityCallbacks(&NullSecurityCallbacks),
@ -269,14 +267,6 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
lcovOutput.init();
}
static bool
SignalBasedTriggersDisabled()
{
// Don't bother trying to cache the getenv lookup; this should be called
// infrequently.
return !!getenv("JS_DISABLE_SLOW_SCRIPT_SIGNALS") || !!getenv("JS_NO_SIGNALS");
}
bool
JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
{
@ -354,8 +344,8 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
jitSupportsUnalignedAccesses = js::jit::JitSupportsUnalignedAccesses();
jitSupportsSimd = js::jit::JitSupportsSimd();
signalHandlersInstalled_ = wasm::EnsureSignalHandlersInstalled(this);
canUseSignalHandlers_ = signalHandlersInstalled_ && !SignalBasedTriggersDisabled();
if (!wasm::EnsureSignalHandlers(this))
return false;
if (!spsProfiler.init())
return false;

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

@ -977,23 +977,6 @@ struct JSRuntime : public JS::shadow::Runtime,
js::wasm::MachExceptionHandler wasmMachExceptionHandler;
#endif
private:
// Whether EnsureSignalHandlersInstalled succeeded in installing all the
// relevant handlers for this platform.
bool signalHandlersInstalled_;
// Whether we should use them or they have been disabled for making
// debugging easier. If signal handlers aren't installed, it is set to false.
bool canUseSignalHandlers_;
public:
bool canUseSignalHandlers() const {
return canUseSignalHandlers_;
}
void setCanUseSignalHandlers(bool enable) {
canUseSignalHandlers_ = signalHandlersInstalled_ && enable;
}
private:
js::FreeOp defaultFreeOp_;