Bug 1370696: Add an option to trigger an interrupt every single instruction in the simulator; r=luke

MozReview-Commit-ID: CbJnep4vYXR

--HG--
extra : rebase_source : 17a9977cba9074680f5541f8f8ec0b2ac0e5a86c
This commit is contained in:
Benjamin Bouvier 2017-06-08 19:02:46 +02:00
Родитель 0179001ce3
Коммит 43892c612c
9 изменённых файлов: 63 добавлений и 21 удалений

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

@ -26,6 +26,7 @@ var outer = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`(m
)
)`)), {imports:{tbl}});
setJitCompilerOption('simulator.always-interrupt', 1);
timeout(1, () => { tbl.set(0, null); gc() });
outer.exports.run();
assertEq(true, false);

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

@ -28,5 +28,6 @@ outer = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`
call_indirect $v2v)
)`)), { imports: { t } });
setJitCompilerOption('simulator.always-interrupt', 1);
timeout(1);
outer.exports.run();

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

@ -185,6 +185,10 @@ DefaultJitOptions::DefaultJitOptions()
// pc-relative jump and call instructions.
SET_DEFAULT(jumpThreshold, UINT32_MAX);
// Whether the (ARM) simulators should always interrupt before executing any
// instruction.
SET_DEFAULT(simulatorAlwaysInterrupt, false);
// Branch pruning heuristic is based on a scoring system, which is look at
// different metrics and provide a score. The score is computed as a
// projection where each factor defines the weight of each metric. Then this

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

@ -77,6 +77,7 @@ struct DefaultJitOptions
bool wasmAlwaysCheckBounds;
bool wasmFoldOffsets;
bool ionInterruptWithoutSignals;
bool simulatorAlwaysInterrupt;
uint32_t baselineWarmUpThreshold;
uint32_t exceptionBailoutThreshold;
uint32_t frequentBailoutThreshold;

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

@ -4782,6 +4782,19 @@ Simulator::disable_single_stepping()
single_step_callback_arg_ = nullptr;
}
static void
FakeInterruptHandler()
{
JSContext* cx = TlsContext.get();
uint8_t* pc = cx->simulator()->get_pc_as<uint8_t*>();
const wasm::CodeSegment* cs = nullptr;
if (!wasm::InInterruptibleCode(cx, pc, &cs))
return;
cx->simulator()->trigger_wasm_interrupt();
}
template<bool EnableStopSimAt>
void
Simulator::execute()
@ -4801,6 +4814,8 @@ Simulator::execute()
} else {
if (single_stepping_)
single_step_callback_(single_step_callback_arg_, this, (void*)program_counter);
if (MOZ_UNLIKELY(JitOptions.simulatorAlwaysInterrupt))
FakeInterruptHandler();
SimInstruction* instr = reinterpret_cast<SimInstruction*>(program_counter);
instructionDecode(instr);
icount_++;

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

@ -6767,6 +6767,9 @@ JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t v
}
jit::JitOptions.jumpThreshold = value;
break;
case JSJITCOMPILER_SIMULATOR_ALWAYS_INTERRUPT:
jit::JitOptions.simulatorAlwaysInterrupt = !!value;
break;
case JSJITCOMPILER_ASMJS_ATOMICS_ENABLE:
jit::JitOptions.asmJSAtomicsEnable = !!value;
break;

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

@ -6053,20 +6053,21 @@ JS_SetParallelParsingEnabled(JSContext* cx, bool enabled);
extern JS_PUBLIC_API(void)
JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled);
#define JIT_COMPILER_OPTIONS(Register) \
Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \
Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \
Register(ION_GVN_ENABLE, "ion.gvn.enable") \
Register(ION_FORCE_IC, "ion.forceinlineCaches") \
Register(ION_ENABLE, "ion.enable") \
#define JIT_COMPILER_OPTIONS(Register) \
Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \
Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \
Register(ION_GVN_ENABLE, "ion.gvn.enable") \
Register(ION_FORCE_IC, "ion.forceinlineCaches") \
Register(ION_ENABLE, "ion.enable") \
Register(ION_INTERRUPT_WITHOUT_SIGNAL, "ion.interrupt-without-signals") \
Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \
Register(BASELINE_ENABLE, "baseline.enable") \
Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \
Register(FULL_DEBUG_CHECKS, "jit.full-debug-checks") \
Register(JUMP_THRESHOLD, "jump-threshold") \
Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \
Register(WASM_TEST_MODE, "wasm.test-mode") \
Register(ION_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \
Register(BASELINE_ENABLE, "baseline.enable") \
Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \
Register(FULL_DEBUG_CHECKS, "jit.full-debug-checks") \
Register(JUMP_THRESHOLD, "jump-threshold") \
Register(SIMULATOR_ALWAYS_INTERRUPT, "simulator.always-interrupt") \
Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \
Register(WASM_TEST_MODE, "wasm.test-mode") \
Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets")
typedef enum JSJitCompilerOption {

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

@ -1337,6 +1337,19 @@ RedirectIonBackedgesToInterruptCheck(JSContext* cx)
}
}
bool
wasm::InInterruptibleCode(JSContext* cx, uint8_t* pc, const CodeSegment** cs)
{
// Only interrupt in function code so that the frame iterators have the
// invariant that resumePC always has a function CodeRange and we can't
// get into any weird interrupt-during-interrupt-stub cases.
if (!cx->compartment())
return false;
const Code* code = cx->compartment()->wasm.lookupCode(pc, cs);
return code && (*cs)->containsFunctionPC(pc);
}
// The return value indicates whether the PC was changed, not whether there was
// a failure.
static bool
@ -1358,14 +1371,8 @@ RedirectJitCodeToInterruptCheck(JSContext* cx, CONTEXT* context)
uint8_t* pc = *ContextToPC(context);
#endif
// Only interrupt in function code so that the frame iterators have the
// invariant that resumePC always has a function CodeRange and we can't
// get into any weird interrupt-during-interrupt-stub cases.
if (!cx->compartment())
return false;
const CodeSegment* codeSegment;
const Code* code = cx->compartment()->wasm.lookupCode(pc, &codeSegment);
if (!code || !codeSegment->containsFunctionPC(pc))
const CodeSegment* codeSegment = nullptr;
if (!InInterruptibleCode(cx, pc, &codeSegment))
return false;
// Only probe cx->activation() via ActivationIfInnermost after we know the

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

@ -35,6 +35,8 @@ namespace js {
extern void
InterruptRunningJitCode(JSContext* cx);
class WasmActivation;
namespace wasm {
// Ensure the given JSRuntime is set up to use signals. Failure to enable signal
@ -48,6 +50,13 @@ EnsureSignalHandlers(JSContext* cx);
bool
HaveSignalHandlers();
class CodeSegment;
// Returns true if wasm code is on top of the activation stack (and fills out
// the code segment outparam in this case), or false otherwise.
bool
InInterruptibleCode(JSContext* cx, uint8_t* pc, const CodeSegment** cs);
#if defined(XP_DARWIN)
// On OSX we are forced to use the lower-level Mach exception mechanism instead
// of Unix signals. Mach exceptions are not handled on the victim's stack but