Bug 1541404 part 24 - Fix JSScript::resetWarmUpCounter() calls to not affect Baseline. r=tcampbell
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 08 May 2019 10:04:19 +0000
changeset 534923 2bea789487b771c178585c365496b61d51fbaa6e
parent 534922 5822c9d23ff717f637b5cd9c2c24a8e2d223fcb8
child 534924 cee398776b835ecb955e0ff7af1a457898808637
push id2082
push userffxbld-merge
push dateMon, 01 Jul 2019 08:34:18 +0000
treeherdermozilla-release@2fb19d0466d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1541404
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1541404 part 24 - Fix JSScript::resetWarmUpCounter() calls to not affect Baseline. r=tcampbell Most of the script->resetWarmUpCounter() calls are heuristics to delay Ion compilation. This patch adds resetWarmUpCounterToDelayIonCompilation to make that more explicit. This method does nothing if the script is not warm enough for Baseline compilation, to ensure scripts never get stuck in the (Baseline) interpreter. Differential Revision: https://phabricator.services.mozilla.com/D29990
js/src/gc/Zone.cpp
js/src/jit-test/lib/jitopts.js
js/src/jit/Ion.cpp
js/src/jit/JitFrames.cpp
js/src/vm/JSScript.cpp
js/src/vm/JSScript.h
js/src/vm/TypeInference.cpp
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -236,17 +236,17 @@ void Zone::discardJitCode(FreeOp* fop,
       } else {
         jit::FinishDiscardBaselineScript(fop, script);
       }
     }
 
     // Warm-up counter for scripts are reset on GC. After discarding code we
     // need to let it warm back up to get information such as which
     // opcodes are setting array holes or accessing getter properties.
-    script->resetWarmUpCounter();
+    script->resetWarmUpCounterForGC();
 
     // Clear the BaselineScript's control flow graph. The LifoAlloc is purged
     // below.
     if (script->hasBaselineScript()) {
       script->baselineScript()->setControlFlowGraph(nullptr);
     }
 
     // Try to release the script's TypeScript. This should happen after
--- a/js/src/jit-test/lib/jitopts.js
+++ b/js/src/jit-test/lib/jitopts.js
@@ -51,18 +51,18 @@ var Opts_IonEagerNoOffthreadCompilation 
       'baseline.enable': 1,
       'baseline.warmup.trigger': 0,
       'offthread-compilation.enable': 0,
     };
 
 var Opts_Ion2NoOffthreadCompilation =
     {
       'ion.enable': 1,
-      'ion.warmup.trigger': 2,
-      'ion.full.warmup.trigger': 2,
+      'ion.warmup.trigger': 3,
+      'ion.full.warmup.trigger': 3,
       'baseline.enable': 1,
       'baseline.warmup.trigger': 1,
       'offthread-compilation.enable': 0
     };
 
 var Opts_NoJits =
     {
       'ion.enable': 0,
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2247,17 +2247,17 @@ static MethodStatus Compile(JSContext* c
 
   bool recompile = false;
   OptimizationLevel optimizationLevel = GetOptimizationLevel(script, osrPc);
   if (optimizationLevel == OptimizationLevel::DontCompile) {
     return Method_Skipped;
   }
 
   if (!CanLikelyAllocateMoreExecutableMemory()) {
-    script->resetWarmUpCounter();
+    script->resetWarmUpCounterToDelayIonCompilation();
     return Method_Skipped;
   }
 
   if (script->baselineScript()->hasPendingIonBuilder()) {
     LinkIonScript(cx, script);
   }
 
   if (script->hasIonScript()) {
@@ -2508,17 +2508,17 @@ bool jit::IonCompileScriptForBaseline(JS
   bool isLoopEntry = JSOp(*pc) == JSOP_LOOPENTRY;
 
   MOZ_ASSERT(!isLoopEntry || LoopEntryCanIonOsr(pc));
 
   if (!script->canIonCompile()) {
     // TODO: ASSERT that ion-compilation-disabled checker stub doesn't exist.
     // TODO: Clear all optimized stubs.
     // TODO: Add a ion-compilation-disabled checker IC stub
-    script->resetWarmUpCounter();
+    script->resetWarmUpCounterToDelayIonCompilation();
     return true;
   }
 
   MOZ_ASSERT(!script->isIonCompilingOffThread());
 
   // If Ion script exists, but PC is not at a loop entry, then Ion will be
   // entered for this script at an appropriate LOOPENTRY or the next time this
   // function is called.
@@ -2571,17 +2571,17 @@ bool jit::IonCompileScriptForBaseline(JS
     // warm-up counter entirely, instead of resetting it.
     bool bailoutExpected =
         script->hasIonScript() && script->ionScript()->bailoutExpected();
     if (stat == Method_CantCompile || bailoutExpected) {
       JitSpew(JitSpew_BaselineOSR,
               "  Reset WarmUpCounter cantCompile=%s bailoutExpected=%s!",
               stat == Method_CantCompile ? "yes" : "no",
               bailoutExpected ? "yes" : "no");
-      script->resetWarmUpCounter();
+      script->resetWarmUpCounterToDelayIonCompilation();
     }
     return true;
   }
 
   return true;
 }
 
 MethodStatus jit::Recompile(JSContext* cx, HandleScript script,
@@ -2794,17 +2794,17 @@ void jit::InvalidateAll(FreeOp* fop, Zon
 static void ClearIonScriptAfterInvalidation(JSContext* cx, JSScript* script,
                                             bool resetUses) {
   script->setIonScript(cx->runtime(), nullptr);
 
   // Wait for the scripts to get warm again before doing another
   // compile, unless we are recompiling *because* a script got hot
   // (resetUses is false).
   if (resetUses) {
-    script->resetWarmUpCounter();
+    script->resetWarmUpCounterToDelayIonCompilation();
   }
 }
 
 void jit::Invalidate(TypeZone& types, FreeOp* fop,
                      const RecompileInfoVector& invalid, bool resetUses,
                      bool cancelOffThread) {
   JitSpew(JitSpew_IonInvalidate, "Start invalidation.");
 
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -210,17 +210,17 @@ static void HandleExceptionIon(JSContext
         CloseLiveIteratorIon(cx, frame, tn);
         break;
 
       case JSTRY_CATCH:
         if (cx->isExceptionPending()) {
           // Ion can compile try-catch, but bailing out to catch
           // exceptions is slow. Reset the warm-up counter so that if we
           // catch many exceptions we won't Ion-compile the script.
-          script->resetWarmUpCounter();
+          script->resetWarmUpCounterToDelayIonCompilation();
 
           if (*hitBailoutException) {
             break;
           }
 
           // Bailout at the start of the catch block.
           jsbytecode* catchPC = script->offsetToPC(tn->start + tn->length);
           ExceptionBailoutInfo excInfo(frame.frameNo(), catchPC,
@@ -368,17 +368,17 @@ static bool ProcessTryNotesBaseline(JSCo
           break;
         }
 
         SettleOnTryNote(cx, tn, frame, ei, rfe, pc);
 
         // Ion can compile try-catch, but bailing out to catch
         // exceptions is slow. Reset the warm-up counter so that if we
         // catch many exceptions we won't Ion-compile the script.
-        script->resetWarmUpCounter();
+        script->resetWarmUpCounterToDelayIonCompilation();
 
         // Resume at the start of the catch block.
         rfe->kind = ResumeFromException::RESUME_CATCH;
         if (frame.baselineFrame()->runningInInterpreter()) {
           const BaselineInterpreter& interp =
               cx->runtime()->jitRuntime()->baselineInterpreter();
           frame.baselineFrame()->setInterpreterPC(*pc);
           rfe->target = interp.interpretOpAddr().value;
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -31,16 +31,17 @@
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/SharedContext.h"
 #include "gc/FreeOp.h"
 #include "jit/BaselineJIT.h"
 #include "jit/Ion.h"
 #include "jit/IonCode.h"
+#include "jit/JitOptions.h"
 #include "jit/JitRealm.h"
 #include "js/CompileOptions.h"
 #include "js/MemoryMetrics.h"
 #include "js/Printf.h"
 #include "js/SourceText.h"
 #include "js/UniquePtr.h"
 #include "js/Utility.h"
 #include "js/Wrapper.h"
@@ -5460,16 +5461,28 @@ bool JSScript::hasLoops() {
   }
   return false;
 }
 
 bool JSScript::mayReadFrameArgsDirectly() {
   return argumentsHasVarBinding() || hasRest();
 }
 
+void JSScript::resetWarmUpCounterToDelayIonCompilation() {
+  // Reset the warm-up count only if it's greater than the BaselineCompiler
+  // threshold. We do this to ensure this has no effect on Baseline compilation
+  // because we don't want scripts to get stuck in the (Baseline) interpreter in
+  // pathological cases.
+
+  if (warmUpCount > jit::JitOptions.baselineWarmUpThreshold) {
+    incWarmUpResetCounter();
+    warmUpCount = jit::JitOptions.baselineWarmUpThreshold;
+  }
+}
+
 void JSScript::AutoDelazify::holdScript(JS::HandleFunction fun) {
   if (fun) {
     if (fun->realm()->isSelfHostingRealm()) {
       // The self-hosting realm is shared across runtimes, so we can't use
       // JSAutoRealm: it could cause races. Functions in the self-hosting
       // realm will never be lazy, so we can safely assume we don't have
       // to delazify.
       script_ = fun->nonLazyScript();
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -2657,21 +2657,23 @@ class JSScript : public js::gc::TenuredC
     return warmUpCount += amount;
   }
   uint32_t* addressOfWarmUpCounter() {
     return reinterpret_cast<uint32_t*>(&warmUpCount);
   }
   static size_t offsetOfWarmUpCounter() {
     return offsetof(JSScript, warmUpCount);
   }
-  void resetWarmUpCounter() {
+  void resetWarmUpCounterForGC() {
     incWarmUpResetCounter();
     warmUpCount = 0;
   }
 
+  void resetWarmUpCounterToDelayIonCompilation();
+
   unsigned getWarmUpResetCount() const {
     constexpr uint32_t MASK = uint32_t(MutableFlags::WarmupResets_MASK);
     return mutableFlags_ & MASK;
   }
   void incWarmUpResetCounter() {
     constexpr uint32_t MASK = uint32_t(MutableFlags::WarmupResets_MASK);
     uint32_t newCount = getWarmUpResetCount() + 1;
     if (newCount <= MASK) {
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -1564,17 +1564,17 @@ bool js::FinishCompilation(JSContext* cx
     }
 
     if (succeeded) {
       types->setHasFreezeConstraints(sweep);
     }
   }
 
   if (!succeeded) {
-    script->resetWarmUpCounter();
+    script->resetWarmUpCounterToDelayIonCompilation();
     *isValidOut = false;
     return true;
   }
 
   *isValidOut = true;
   return true;
 }
 
@@ -2674,19 +2674,17 @@ void TypeZone::addPendingRecompile(JSCon
 }
 
 void TypeZone::addPendingRecompile(JSContext* cx, JSScript* script) {
   MOZ_ASSERT(script);
 
   CancelOffThreadIonCompile(script);
 
   // Let the script warm up again before attempting another compile.
-  if (jit::IsBaselineEnabled(cx)) {
-    script->resetWarmUpCounter();
-  }
+  script->resetWarmUpCounterToDelayIonCompilation();
 
   if (script->hasIonScript()) {
     addPendingRecompile(
         cx, RecompileInfo(script, script->ionScript()->compilationId()));
   }
 
   // Trigger recompilation of any callers inlining this script.
   if (TypeScript* types = script->types()) {