diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 63528a42f2..acb408c419 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -5291,8 +5291,10 @@ CodeGenerator::generateBody() extendTrackedOptimizationsEntry(iter->mirRaw()->trackedOptimizations()); #ifdef DEBUG - if (!counts) - emitDebugResultChecks(*iter); + if (!counts) { + if (JitOptions.fullDebugChecks) + emitDebugResultChecks(*iter); + } #endif } if (masm.oom()) diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 8e28a93c0e..c7a4f36b12 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -1833,6 +1833,7 @@ OptimizeMIR(MIRGenerator* mir) if (mir->shouldCancel("Make loops contiguous")) return false; } + AssertExtendedGraphCoherency(graph, /* underValueNumberer = */ false, /* force = */ true); // Passes after this point must not move instructions; these analyses // depend on knowing the final order in which instructions will execute. @@ -1875,6 +1876,8 @@ OptimizeMIR(MIRGenerator* mir) gs.spewPass("Redundant Bounds Check Elimination"); AssertGraphCoherency(graph); } + + AssertGraphCoherency(graph, /* force = */ true); DumpMIRExpressions(graph); @@ -1919,8 +1922,10 @@ GenerateLIR(MIRGenerator* mir) case RegisterAllocator_Backtracking: case RegisterAllocator_Testbed: { #ifdef DEBUG - if (!integrity.record()) - return nullptr; + if (JitOptions.fullDebugChecks) { + if (!integrity.record()) + return nullptr; + } #endif BacktrackingAllocator regalloc(mir, &lirgen, *lir, @@ -1929,8 +1934,10 @@ GenerateLIR(MIRGenerator* mir) return nullptr; #ifdef DEBUG - if (!integrity.check(false)) - return nullptr; + if (JitOptions.fullDebugChecks) { + if (!integrity.check(false)) + return nullptr; + } #endif gs.spewPass("Allocate Registers [Backtracking]"); diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index f774114ef4..0e511e07d0 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -2407,9 +2407,12 @@ AssertOperandsBeforeSafeInsertTop(MResumePoint* resume) #endif // DEBUG void -jit::AssertBasicGraphCoherency(MIRGraph& graph) +jit::AssertBasicGraphCoherency(MIRGraph& graph, bool force) { #ifdef DEBUG + if (!JitOptions.fullDebugChecks && !force) + return; + MOZ_ASSERT(graph.entryBlock()->numPredecessors() == 0); MOZ_ASSERT(graph.entryBlock()->phisEmpty()); MOZ_ASSERT(!graph.entryBlock()->unreachable()); @@ -2592,12 +2595,14 @@ AssertDominatorTree(MIRGraph& graph) #endif void -jit::AssertGraphCoherency(MIRGraph& graph) +jit::AssertGraphCoherency(MIRGraph& graph, bool force) { #ifdef DEBUG if (!JitOptions.checkGraphConsistency) return; - AssertBasicGraphCoherency(graph); + if (!JitOptions.fullDebugChecks && !force) + return; + AssertBasicGraphCoherency(graph, force); AssertReversePostorder(graph); #endif } @@ -2682,7 +2687,7 @@ AssertResumePointDominatedByOperands(MResumePoint* resume) #endif // DEBUG void -jit::AssertExtendedGraphCoherency(MIRGraph& graph, bool underValueNumberer) +jit::AssertExtendedGraphCoherency(MIRGraph& graph, bool underValueNumberer, bool force) { // Checks the basic GraphCoherency but also other conditions that // do not hold immediately (such as the fact that critical edges @@ -2691,8 +2696,10 @@ jit::AssertExtendedGraphCoherency(MIRGraph& graph, bool underValueNumberer) #ifdef DEBUG if (!JitOptions.checkGraphConsistency) return; + if (!JitOptions.fullDebugChecks && !force) + return; - AssertGraphCoherency(graph); + AssertGraphCoherency(graph, force); AssertDominatorTree(graph); diff --git a/js/src/jit/IonAnalysis.h b/js/src/jit/IonAnalysis.h index e6b7fa2aa2..1b7f952a9a 100644 --- a/js/src/jit/IonAnalysis.h +++ b/js/src/jit/IonAnalysis.h @@ -78,13 +78,13 @@ MOZ_MUST_USE bool BuildPhiReverseMapping(MIRGraph& graph); void -AssertBasicGraphCoherency(MIRGraph& graph); +AssertBasicGraphCoherency(MIRGraph& graph, bool force = false); void -AssertGraphCoherency(MIRGraph& graph); +AssertGraphCoherency(MIRGraph& graph, bool force = false); void -AssertExtendedGraphCoherency(MIRGraph& graph, bool underValueNumberer = false); +AssertExtendedGraphCoherency(MIRGraph& graph, bool underValueNumberer = false, bool force = false); MOZ_MUST_USE bool EliminateRedundantChecks(MIRGraph& graph); diff --git a/js/src/jit/JitOptions.cpp b/js/src/jit/JitOptions.cpp index 2e799740b7..245e78987a 100644 --- a/js/src/jit/JitOptions.cpp +++ b/js/src/jit/JitOptions.cpp @@ -160,6 +160,9 @@ DefaultJitOptions::DefaultJitOptions() // JSScript::hadFrequentBailouts and invalidate. SET_DEFAULT(frequentBailoutThreshold, 10); + // Whether to run all debug checks in debug builds. + // Disabling might make it more enjoyable to run JS in debug builds. + SET_DEFAULT(fullDebugChecks, true); // How many actual arguments are accepted on the C stack. SET_DEFAULT(maxStackArgs, 4096); diff --git a/js/src/jit/JitOptions.h b/js/src/jit/JitOptions.h index 0fbfc99829..00ef3a2121 100644 --- a/js/src/jit/JitOptions.h +++ b/js/src/jit/JitOptions.h @@ -66,6 +66,7 @@ struct DefaultJitOptions bool disableSink; bool eagerCompilation; bool forceInlineCaches; + bool fullDebugChecks; bool limitScriptSize; bool osr; bool asmJSAtomicsEnable; diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 7514d4d2c7..660a9f7b9f 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -299,7 +299,7 @@ class MNode : public TempObject protected: // Need visibility on getUseFor to avoid O(n^2) complexity. - friend void AssertBasicGraphCoherency(MIRGraph& graph); + friend void AssertBasicGraphCoherency(MIRGraph& graph, bool force); // Gets the MUse corresponding to given operand. virtual MUse* getUseFor(size_t index) = 0; @@ -11905,7 +11905,7 @@ class MResumePoint final : private: friend class MBasicBlock; - friend void AssertBasicGraphCoherency(MIRGraph& graph); + friend void AssertBasicGraphCoherency(MIRGraph& graph, bool force); // List of stack slots needed to reconstruct the frame corresponding to the // function which is compiled by IonBuilder. diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 57eec17bd5..0fbb0d40e8 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -7119,6 +7119,11 @@ JS_SetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t v case JSJITCOMPILER_ION_INLINING: jit::JitOptions.disableInlining = !value; break; +#ifdef DEBUG + case JSJITCOMPILER_FULL_DEBUG_CHECKS: + jit::JitOptions.fullDebugChecks = !!value; + break; +#endif default: break; } @@ -7166,6 +7171,11 @@ JS_GetGlobalJitCompilerOption(JSContext* cx, JSJitCompilerOption opt, uint32_t* case JSJITCOMPILER_ION_INTERRUPT_WITHOUT_SIGNAL: *valueOut = jit::JitOptions.ionInterruptWithoutSignals ? 1 : 0; break; +#ifdef DEBUG + case JSJITCOMPILER_FULL_DEBUG_CHECKS: + *valueOut = jit::JitOptions.fullDebugChecks ? 1 : 0; + break; +#endif default: return false; } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index cae2297ae4..d8b2a03a5d 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -5316,7 +5316,8 @@ JS_SetOffthreadIonCompilationEnabled(JSContext* cx, bool enabled); 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(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \ + Register(FULL_DEBUG_CHECKS, "jit.full-debug-checks") \ Register(JUMP_THRESHOLD, "jump-threshold") \ Register(UNBOXED_OBJECTS, "unboxed_objects") \ Register(ASMJS_ATOMICS_ENABLE, "asmjs.atomics.enable") \ diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index 3ca3da6b8b..a1dcd4dcc0 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -1492,7 +1492,10 @@ ReloadPrefsCallback(const char* pref, void* data) JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_BASELINE_WARMUP_TRIGGER, baselineWarmUpThreshold); JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_WARMUP_TRIGGER, - ionWarmUpThreshold); + useIonEager ? 0 : ionThreshold); +#ifdef DEBUG + JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_FULL_DEBUG_CHECKS, fullJitDebugChecks); +#endif JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_UNBOXED_OBJECTS, unboxedObjects); JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_INLINING, diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 74a843de40..aed22011f9 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1285,6 +1285,9 @@ pref("javascript.options.parallel_parsing", true); pref("javascript.options.asyncstack", false); pref("javascript.options.throw_on_asmjs_validation_failure", false); pref("javascript.options.ion.offthread_compilation", true); +#ifdef DEBUG +pref("javascript.options.jit.full_debug_checks", true); +#endif // This preference instructs the JS engine to discard the // source of any privileged JS after compilation. This saves // memory, but makes things like Function.prototype.toSource()