зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
0179001ce3
Коммит
43892c612c
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче