Backed out 8 changesets (bug 1382650) for spidermonkey bustages on js.cpp . a=backout
authorNarcis Beleuzu <nbeleuzu@mozilla.com>
Sun, 07 Apr 2019 17:06:38 +0300
changeset 526010 a330a98357513bce14a5764b8866aaf9843b9c3a
parent 526009 c0c2da9127f3a5112d18df9e029a3a0bc8107d1e
child 526011 78075f5bf04a65a4665dc2c44f250b2de8a35f8e
push id2032
push userffxbld-merge
push dateMon, 13 May 2019 09:36:57 +0000
treeherdermozilla-release@455c1065dcbe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1382650
milestone67.0
backs out353c9e1559f09f75eafcb6f7897b21a75777e64a
dfde2a76520d0f0539a4ee1b377c34f5d410d9a3
e099b8601dc77a26fbaaf6cfef7254cb4a9d5247
0e0e954b3cdc98870700da9e8d76b2f5b142fdb0
9d3bcd768496b23e1423f41a15e78e6d35ff1ff6
a0419e61efcd9bc2b2a8f1a7d8f40ad2cc55fe94
02cdde2f8dbd674f0ec37b666be214f883bf27e7
7feb497c2ffe0d7a4c7b695fd1e2b423fb6e0b5c
Backed out 8 changesets (bug 1382650) for spidermonkey bustages on js.cpp . a=backout Backed out changeset 353c9e1559f0 (bug 1382650) Backed out changeset dfde2a76520d (bug 1382650) Backed out changeset e099b8601dc7 (bug 1382650) Backed out changeset 0e0e954b3cdc (bug 1382650) Backed out changeset 9d3bcd768496 (bug 1382650) Backed out changeset a0419e61efcd (bug 1382650) Backed out changeset 02cdde2f8dbd (bug 1382650) Backed out changeset 7feb497c2ffe (bug 1382650)
js/src/jit-test/lib/jitopts.js
js/src/jit-test/tests/asm.js/testBug1125561.js
js/src/jit-test/tests/cacheir/bug1500255.js
js/src/jit-test/tests/cacheir/bug1526872.js
js/src/jit-test/tests/debug/Frame-eval-20.js
js/src/jit-test/tests/debug/bug1263899.js
js/src/jit-test/tests/debug/bug1302432.js
js/src/jit-test/tests/ion/bug1526840.js
js/src/jit-test/tests/ion/dce-with-rinstructions.js
js/src/jit-test/tests/ion/recover-lambdas.js
js/src/jit/CodeGenerator.cpp
js/src/jit/Ion.cpp
js/src/jit/IonAnalysis.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/IonOptimizationLevels.cpp
js/src/jit/IonOptimizationLevels.h
js/src/jit/JitOptions.cpp
js/src/jit/JitOptions.h
js/src/jit/Lowering.cpp
js/src/jit/MIR.h
js/src/jit/VMFunctionList-inl.h
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
js/src/jit/arm64/MacroAssembler-arm64-inl.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/shell/fuzz-flags.txt
js/src/shell/js.cpp
js/xpconnect/src/XPCJSContext.cpp
modules/libpref/init/all.js
--- a/js/src/jit-test/lib/jitopts.js
+++ b/js/src/jit-test/lib/jitopts.js
@@ -28,41 +28,38 @@ function withJitOptions(opts, fn) {
 // N.B. Ion opts *must come before* baseline opts because there's some kind of
 // "undo eager compilation" logic. If we don't set the baseline warmup-counter
 // *after* the Ion warmup-counter we end up setting the baseline warmup-counter
 // to be the default if we hit the "undo eager compilation" logic.
 var Opts_BaselineEager =
     {
       'ion.enable': 1,
       'ion.warmup.trigger': 100,
-      'ion.full.warmup.trigger': 100,
       'baseline.enable': 1,
       'baseline.warmup.trigger': 0,
       'offthread-compilation.enable': 1
     };
 
 // Checking for offthread compilation being off is often helpful if the test
 // requires a function be Ion compiled. Each individual test will usually
 // finish before the Ion compilation thread has a chance to attach the
 // compiled code.
 var Opts_IonEagerNoOffthreadCompilation =
     {
       'ion.enable': 1,
       'ion.warmup.trigger': 0,
-      'ion.full.warmup.trigger': 0,
       '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,
       'baseline.enable': 1,
       'baseline.warmup.trigger': 1,
       'offthread-compilation.enable': 0
     };
 
 var Opts_NoJits =
     {
       'ion.enable': 0,
--- a/js/src/jit-test/tests/asm.js/testBug1125561.js
+++ b/js/src/jit-test/tests/asm.js/testBug1125561.js
@@ -1,11 +1,11 @@
 load(libdir + "asm.js");
 
-setJitCompilerOption("ion.full.warmup.trigger", 0);
+setJitCompilerOption("ion.warmup.trigger", 0);
 setJitCompilerOption("baseline.warmup.trigger", 0);
 setJitCompilerOption("offthread-compilation.enable", 0);
 
 function ffi1() { assertJitStackInvariants() }
 function ffi2() { return { valueOf() { assertJitStackInvariants() } } }
 
 // FFI with no coercion
 var m = asmCompile('stdlib', 'foreign', `
--- a/js/src/jit-test/tests/cacheir/bug1500255.js
+++ b/js/src/jit-test/tests/cacheir/bug1500255.js
@@ -1,11 +1,10 @@
 
 setJitCompilerOption("offthread-compilation.enable", 0);
-setJitCompilerOption("baseline.warmup.trigger", 0);
 setJitCompilerOption("ion.warmup.trigger", 0);
 
 foo();
 
 function foo() {
     Array.prototype.__proto__ = null;
     Array.prototype[1] = 'bar';
 }
--- a/js/src/jit-test/tests/cacheir/bug1526872.js
+++ b/js/src/jit-test/tests/cacheir/bug1526872.js
@@ -1,11 +1,10 @@
 
 setJitCompilerOption("offthread-compilation.enable", 0);
-setJitCompilerOption("baseline.warmup.trigger", 0);
 setJitCompilerOption("ion.warmup.trigger", 0);
 
 for (var i = 0; i < 5; i++) {
     assertEq(foo(1n), false);
 }
 
 function foo(x) {
     return x == null || x == undefined;
--- a/js/src/jit-test/tests/debug/Frame-eval-20.js
+++ b/js/src/jit-test/tests/debug/Frame-eval-20.js
@@ -1,10 +1,8 @@
-// |jit-test| --ion-osr=off
-
 // Eval-in-frame with different type on non-youngest Ion frame.
 
 load(libdir + "jitopts.js");
 
 if (!jitTogglesMatch(Opts_Ion2NoOffthreadCompilation))
   quit(0);
 
 withJitOptions(Opts_Ion2NoOffthreadCompilation, function () {
--- a/js/src/jit-test/tests/debug/bug1263899.js
+++ b/js/src/jit-test/tests/debug/bug1263899.js
@@ -1,16 +1,15 @@
 try {
   evaluate(` 
     function runTestCase() $ERROR()
     function $ERROR() {
       throw Error
     }
     Object.defineProperty(this, "x", { value: 0 });
-    setJitCompilerOption("baseline.warmup.trigger", 0);
     setJitCompilerOption("ion.warmup.trigger", 0)
   `)
   evaluate(`function f() {} f(x)`)
   runTestCase()
 } catch (exc) {}
 evaluate(`
   g = newGlobal({newCompartment: true})
   g.parent = this
--- a/js/src/jit-test/tests/debug/bug1302432.js
+++ b/js/src/jit-test/tests/debug/bug1302432.js
@@ -1,9 +1,8 @@
-setJitCompilerOption("baseline.warmup.trigger", 0);
 setJitCompilerOption('ion.warmup.trigger', 0);
 gczeal(7, 1);
 var dbgGlobal = newGlobal({newCompartment: true});
 var dbg = new dbgGlobal.Debugger();
 dbg.addDebuggee(this);
 function f(x, await = () => Array.isArray(revocable.proxy), ...get) {
     dbg.getNewestFrame().older.eval("print(a)");
 }
--- a/js/src/jit-test/tests/ion/bug1526840.js
+++ b/js/src/jit-test/tests/ion/bug1526840.js
@@ -1,11 +1,10 @@
 
 setJitCompilerOption("offthread-compilation.enable", 0);
-setJitCompilerOption("baseline.warmup.trigger", 0);
 setJitCompilerOption("ion.warmup.trigger", 0);
 
 for (let j = 0; j < 2; ++j) {
     let z = j ? 0n : 1;
     if (z) {
         z = 0;
     } else {
         z = 0;
--- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js
+++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js
@@ -1,11 +1,10 @@
 setJitCompilerOption("baseline.warmup.trigger", 10);
 setJitCompilerOption("ion.warmup.trigger", 20);
-setJitCompilerOption("ion.full.warmup.trigger", 20);
 var i;
 
 var config = getBuildConfiguration();
 var max = 200;
 
 // Check that we are able to remove the operation inside recover test functions (denoted by "rop..."),
 // when we inline the first version of uceFault, and ensure that the bailout is correct
 // when uceFault is replaced (which cause an invalidation bailout)
--- a/js/src/jit-test/tests/ion/recover-lambdas.js
+++ b/js/src/jit-test/tests/ion/recover-lambdas.js
@@ -1,13 +1,11 @@
-// |jit-test| --ion-osr=off
 
 var max = 40;
 setJitCompilerOption("ion.warmup.trigger", max - 10);
-setJitCompilerOption("ion.full.warmup.trigger", max - 10);
 
 // This function is used to escape "g" which is a non-escaped inner function.
 // As it is not escaped within "f", the lambda for "g" would be computed on the
 // bailout path. Resolving the first ".caller" implies that we have to recover
 // the lambda. Resolving the second ".caller" is needed such as we can build the
 // test case without explicitly escaping "g", which would prevent this
 // optimization.
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -13434,56 +13434,47 @@ void CodeGenerator::visitWasmLoadTls(LWa
     default:
       MOZ_CRASH("MIRType not supported in WasmLoadTls");
   }
 }
 
 void CodeGenerator::visitRecompileCheck(LRecompileCheck* ins) {
   Label done;
   Register tmp = ToRegister(ins->scratch());
-
-  OutOfLineCode* ool = nullptr;
-  if (ins->mir()->checkCounter()) {
-    using Fn = bool (*)(JSContext*);
-    if (ins->mir()->forceInvalidation()) {
-      ool =
-          oolCallVM<Fn, IonForcedInvalidation>(ins, ArgList(), StoreNothing());
-    } else if (ins->mir()->forceRecompilation()) {
-      ool = oolCallVM<Fn, IonForcedRecompile>(ins, ArgList(), StoreNothing());
-    } else {
-      ool = oolCallVM<Fn, IonRecompile>(ins, ArgList(), StoreNothing());
-    }
+  OutOfLineCode* ool;
+
+  using Fn = bool (*)(JSContext*);
+  if (ins->mir()->forceRecompilation()) {
+    ool = oolCallVM<Fn, IonForcedRecompile>(ins, ArgList(), StoreNothing());
+  } else {
+    ool = oolCallVM<Fn, IonRecompile>(ins, ArgList(), StoreNothing());
   }
 
   // Check if warm-up counter is high enough.
   AbsoluteAddress warmUpCount =
       AbsoluteAddress(ins->mir()->script()->addressOfWarmUpCounter());
   if (ins->mir()->increaseWarmUpCounter()) {
     masm.load32(warmUpCount, tmp);
     masm.add32(Imm32(1), tmp);
     masm.store32(tmp, warmUpCount);
-    if (ins->mir()->checkCounter()) {
-      masm.branch32(Assembler::BelowOrEqual, tmp,
-                    Imm32(ins->mir()->recompileThreshold()), &done);
-    }
+    masm.branch32(Assembler::BelowOrEqual, tmp,
+                  Imm32(ins->mir()->recompileThreshold()), &done);
   } else {
     masm.branch32(Assembler::BelowOrEqual, warmUpCount,
                   Imm32(ins->mir()->recompileThreshold()), &done);
   }
 
   // Check if not yet recompiling.
-  if (ins->mir()->checkCounter()) {
-    CodeOffset label = masm.movWithPatch(ImmWord(uintptr_t(-1)), tmp);
-    masm.propagateOOM(ionScriptLabels_.append(label));
-    masm.branch32(Assembler::Equal,
-                  Address(tmp, IonScript::offsetOfRecompiling()), Imm32(0),
-                  ool->entry());
-    masm.bind(ool->rejoin());
-    masm.bind(&done);
-  }
+  CodeOffset label = masm.movWithPatch(ImmWord(uintptr_t(-1)), tmp);
+  masm.propagateOOM(ionScriptLabels_.append(label));
+  masm.branch32(Assembler::Equal,
+                Address(tmp, IonScript::offsetOfRecompiling()), Imm32(0),
+                ool->entry());
+  masm.bind(ool->rejoin());
+  masm.bind(&done);
 }
 
 void CodeGenerator::visitLexicalCheck(LLexicalCheck* ins) {
   ValueOperand inputValue = ToValue(ins, LLexicalCheck::Input);
   Label bail;
   masm.branchTestMagicValue(Assembler::Equal, inputValue,
                             JS_UNINITIALIZED_LEXICAL, &bail);
   bailoutFrom(&bail, ins->snapshot());
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2233,20 +2233,16 @@ static MethodStatus Compile(JSContext* c
     return Method_Skipped;
   }
 
   if (!CanLikelyAllocateMoreExecutableMemory()) {
     script->resetWarmUpCounter();
     return Method_Skipped;
   }
 
-  if (script->baselineScript()->hasPendingIonBuilder()) {
-    LinkIonScript(cx, script);
-  }
-
   if (script->hasIonScript()) {
     IonScript* scriptIon = script->ionScript();
     if (!scriptIon->method()) {
       return Method_CantCompile;
     }
 
     // Don't recompile/overwrite higher optimized code,
     // with a lower optimization level.
@@ -2262,16 +2258,26 @@ static MethodStatus Compile(JSContext* c
 
     if (osrPc) {
       scriptIon->resetOsrPcMismatchCounter();
     }
 
     recompile = true;
   }
 
+  if (script->baselineScript()->hasPendingIonBuilder()) {
+    IonBuilder* buildIon = script->baselineScript()->pendingIonBuilder();
+    if (optimizationLevel <= buildIon->optimizationInfo().level() &&
+        !forceRecompile) {
+      return Method_Compiled;
+    }
+
+    recompile = true;
+  }
+
   AbortReason reason =
       IonCompile(cx, script, osrFrame, osrPc, recompile, optimizationLevel);
   if (reason == AbortReason::Error) {
     MOZ_ASSERT(cx->isExceptionPending());
     return Method_Error;
   }
 
   if (reason == AbortReason::Disable) {
@@ -2341,17 +2347,17 @@ MethodStatus jit::CanEnterIon(JSContext*
       TrackAndSpewIonAbort(cx, script, "too many args");
       ForbidCompilation(cx, script);
       return Method_CantCompile;
     }
   }
 
   // If --ion-eager is used, compile with Baseline first, so that we
   // can directly enter IonMonkey.
-  if (JitOptions.eagerIonCompilation() && !script->hasBaselineScript()) {
+  if (JitOptions.eagerCompilation && !script->hasBaselineScript()) {
     MethodStatus status = CanEnterBaselineMethod(cx, state);
     if (status != Method_Compiled) {
       return status;
     }
   }
 
   MOZ_ASSERT(!script->isIonCompilingOffThread());
   MOZ_ASSERT(script->canIonCompile());
@@ -2568,18 +2574,16 @@ bool jit::IonCompileScriptForBaseline(JS
 MethodStatus jit::Recompile(JSContext* cx, HandleScript script,
                             BaselineFrame* osrFrame, jsbytecode* osrPc,
                             bool force) {
   MOZ_ASSERT(script->hasIonScript());
   if (script->ionScript()->isRecompiling()) {
     return Method_Compiled;
   }
 
-  MOZ_ASSERT(!script->baselineScript()->hasPendingIonBuilder());
-
   MethodStatus status = Compile(cx, script, osrFrame, osrPc, force);
   if (status != Method_Compiled) {
     if (status == Method_CantCompile) {
       ForbidCompilation(cx, script);
     }
     return status;
   }
 
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -4571,17 +4571,17 @@ bool jit::AnalyzeNewScriptDefiniteProper
     return false;
   }
 
   CompileInfo info(CompileRuntime::get(cx->runtime()), script, fun,
                    /* osrPc = */ nullptr, Analysis_DefiniteProperties,
                    script->needsArgsObj(), inlineScriptTree);
 
   const OptimizationInfo* optimizationInfo =
-      IonOptimizations.get(OptimizationLevel::Full);
+      IonOptimizations.get(OptimizationLevel::Normal);
 
   CompilerConstraintList* constraints = NewCompilerConstraintList(temp);
   if (!constraints) {
     ReportOutOfMemory(cx);
     return false;
   }
 
   BaselineInspector inspector(script);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -480,29 +480,16 @@ IonBuilder::InliningDecision IonBuilder:
   }
 
   // Don't inline functions which don't have baseline scripts.
   if (!inlineScript->hasBaselineScript()) {
     trackOptimizationOutcome(TrackedOutcome::CantInlineNoBaseline);
     return DontInline(inlineScript, "No baseline jitcode");
   }
 
-  // Don't inline functions with a higher optimization level.
-  if (!isHighestOptimizationLevel()) {
-    OptimizationLevel level = optimizationLevel();
-    if (inlineScript->hasIonScript() &&
-        (inlineScript->ionScript()->isRecompiling() ||
-         inlineScript->ionScript()->optimizationLevel() > level)) {
-      return DontInline(inlineScript, "More optimized");
-    }
-    if (IonOptimizations.levelForScript(inlineScript, nullptr) > level) {
-      return DontInline(inlineScript, "Should be more optimized");
-    }
-  }
-
   if (TooManyFormalArguments(target->nargs())) {
     trackOptimizationOutcome(TrackedOutcome::CantInlineTooManyArgs);
     return DontInline(inlineScript, "Too many args");
   }
 
   // We check the number of actual arguments against the maximum number of
   // formal arguments as we do not want to encode all actual arguments in the
   // callerResumePoint.
@@ -785,20 +772,17 @@ AbortReasonOr<Ok> IonBuilder::build() {
 #ifdef JS_STRUCTURED_SPEW
   if (!info().isAnalysis()) {
     JitSpewBaselineICStats(script(), "To-Be-Compiled");
   }
 #endif
 
   MOZ_TRY(init());
 
-  // The BaselineScript-based inlining heuristics only affect the highest
-  // optimization level. Other levels do almost no inlining and we don't want to
-  // overwrite data from the highest optimization tier.
-  if (script()->hasBaselineScript() && isHighestOptimizationLevel()) {
+  if (script()->hasBaselineScript()) {
     script()->baselineScript()->resetMaxInliningDepth();
   }
 
   MBasicBlock* entry;
   MOZ_TRY_VAR(entry, newBlock(info().firstStackSlot(), pc));
   MOZ_TRY(setCurrentAndSpecializePhis(entry));
 
 #ifdef JS_JITSPEW
@@ -808,17 +792,17 @@ AbortReasonOr<Ok> IonBuilder::build() {
             (void*)script(), AnalysisModeString(info().analysisMode()));
   } else {
     JitSpew(JitSpew_IonScripts,
             "%sompiling script %s:%u:%u (%p) (warmup-counter=%" PRIu32
             ", level=%s)",
             (script()->hasIonScript() ? "Rec" : "C"), script()->filename(),
             script()->lineno(), script()->column(), (void*)script(),
             script()->getWarmUpCount(),
-            OptimizationLevelString(optimizationLevel()));
+            OptimizationLevelString(optimizationInfo().level()));
   }
 #endif
 
   MOZ_TRY(initParameters());
   initLocals();
 
   // Initialize something for the env chain. We can bail out before the
   // start instruction, but the snapshot is encoded *at* the start
@@ -921,17 +905,17 @@ AbortReasonOr<Ok> IonBuilder::build() {
 
   auto clearLastPriorResumePoint = mozilla::MakeScopeExit([&] {
     // Discard unreferenced & pre-allocated resume points.
     replaceMaybeFallbackFunctionGetter(nullptr);
   });
 
   MOZ_TRY(traverseBytecode());
 
-  if (isHighestOptimizationLevel() && script_->hasBaselineScript() &&
+  if (script_->hasBaselineScript() &&
       inlinedBytecodeLength_ >
           script_->baselineScript()->inlinedBytecodeLength()) {
     script_->baselineScript()->setInlinedBytecodeLength(inlinedBytecodeLength_);
   }
 
   MOZ_TRY(maybeAddOsrTypeBarriers());
   MOZ_TRY(processIterators());
 
@@ -4380,20 +4364,17 @@ IonBuilder::InliningDecision IonBuilder:
 
   BaselineScript* outerBaseline =
       outermostBuilder()->script()->baselineScript();
   if (inliningDepth_ >= maxInlineDepth) {
     // We hit the depth limit and won't inline this function. Give the
     // outermost script a max inlining depth of 0, so that it won't be
     // inlined in other scripts. This heuristic is currently only used
     // when we're inlining scripts with loops, see the comment below.
-    // These heuristics only apply to the highest optimization level.
-    if (isHighestOptimizationLevel()) {
-      outerBaseline->setMaxInliningDepth(0);
-    }
+    outerBaseline->setMaxInliningDepth(0);
 
     trackOptimizationOutcome(TrackedOutcome::CantInlineExceededDepth);
     return DontInline(targetScript, "Vetoed: exceeding allowed inline depth");
   }
 
   // Inlining functions with loops can be complicated. For instance, if we're
   // close to the inlining depth limit and we inline the function f below, we
   // can no longer inline the call to g:
@@ -4406,31 +4387,27 @@ IonBuilder::InliningDecision IonBuilder:
   //
   // If the loop has many iterations, it's more efficient to call f and inline
   // g in f.
   //
   // To avoid this problem, we record a separate max inlining depth for each
   // script, indicating at which depth we won't be able to inline all functions
   // we inlined this time. This solves the issue above, because we will only
   // inline f if it means we can also inline g.
-  //
-  // These heuristics only apply to the highest optimization level: other tiers
-  // do very little inlining and performance is not as much of a concern there.
-  if (isHighestOptimizationLevel() && targetScript->hasLoops() &&
+  if (targetScript->hasLoops() &&
       inliningDepth_ >= targetScript->baselineScript()->maxInliningDepth()) {
     trackOptimizationOutcome(TrackedOutcome::CantInlineExceededDepth);
     return DontInline(targetScript,
                       "Vetoed: exceeding allowed script inline depth");
   }
 
   // Update the max depth at which we can inline the outer script.
   MOZ_ASSERT(maxInlineDepth > inliningDepth_);
   uint32_t scriptInlineDepth = maxInlineDepth - inliningDepth_ - 1;
-  if (scriptInlineDepth < outerBaseline->maxInliningDepth() &&
-      isHighestOptimizationLevel()) {
+  if (scriptInlineDepth < outerBaseline->maxInliningDepth()) {
     outerBaseline->setMaxInliningDepth(scriptInlineDepth);
   }
 
   // End of heuristics, we will inline this function.
 
   outerBuilder->inlinedBytecodeLength_ += targetScript->length();
 
   return InliningDecision_Inline;
@@ -5973,22 +5950,22 @@ AbortReasonOr<Ok> IonBuilder::jsop_call(
       }
       if (!callTargets->append(&target.target->as<JSFunction>())) {
         return abort(AbortReason::Alloc);
       }
     }
   }
 
   if (status == InliningStatus_WarmUpCountTooLow && callTargets &&
-      callTargets->length() == 1 && isHighestOptimizationLevel()) {
+      callTargets->length() == 1) {
     JSFunction* target = callTargets.ref()[0];
     MRecompileCheck* check =
         MRecompileCheck::New(alloc(), target->nonLazyScript(),
                              optimizationInfo().inliningRecompileThreshold(),
-                             MRecompileCheck::RecompileCheckType::Inlining);
+                             MRecompileCheck::RecompileCheck_Inlining);
     current->add(check);
   }
 
   return makeCall(callTargets, callInfo);
 }
 
 AbortReasonOr<bool> IonBuilder::testShouldDOMCall(TypeSet* inTypes,
                                                   JSFunction* func,
@@ -7649,46 +7626,37 @@ static bool ObjectHasExtraOwnProperty(Co
   }
 
   // Resolve hooks can install new properties on objects on demand.
   JSObject* singleton = object->isSingleton() ? object->singleton() : nullptr;
   return ClassMayResolveId(realm->runtime()->names(), clasp, id, singleton);
 }
 
 void IonBuilder::insertRecompileCheck() {
-  MOZ_ASSERT(pc == script()->code() || *pc == JSOP_LOOPENTRY);
-
-  // No need for recompile checks if this is the highest optimization level or
-  // if we're performing an analysis instead of compilation.
-  OptimizationLevel curLevel = optimizationLevel();
-  if (IonOptimizations.isLastLevel(curLevel) || info().isAnalysis()) {
+  // No need for recompile checks if this is the highest optimization level.
+  OptimizationLevel curLevel = optimizationInfo().level();
+  if (IonOptimizations.isLastLevel(curLevel)) {
     return;
   }
 
-  MOZ_ASSERT(!JitOptions.disableOptimizationLevels);
-
-  // Add recompile check. See MRecompileCheck::RecompileCheckType for how this
-  // works.
-
-  MRecompileCheck::RecompileCheckType type;
-  if (*pc == JSOP_LOOPENTRY) {
-    type = MRecompileCheck::RecompileCheckType::OptimizationLevelOSR;
-  } else if (this != outermostBuilder()) {
-    type = MRecompileCheck::RecompileCheckType::OptimizationLevelInlined;
-  } else {
-    type = MRecompileCheck::RecompileCheckType::OptimizationLevel;
-  }
+  // Add recompile check.
+
+  // Get the topmost builder. The topmost script will get recompiled when
+  // warm-up counter is high enough to justify a higher optimization level.
+  IonBuilder* topBuilder = outermostBuilder();
 
   // Add recompile check to recompile when the warm-up count reaches the
   // threshold of the next optimization level.
   OptimizationLevel nextLevel = IonOptimizations.nextLevel(curLevel);
   const OptimizationInfo* info = IonOptimizations.get(nextLevel);
-  uint32_t warmUpThreshold = info->recompileWarmUpThreshold(script(), pc);
+  uint32_t warmUpThreshold =
+      info->compilerWarmUpThreshold(topBuilder->script());
   MRecompileCheck* check =
-      MRecompileCheck::New(alloc(), script(), warmUpThreshold, type);
+      MRecompileCheck::New(alloc(), topBuilder->script(), warmUpThreshold,
+                           MRecompileCheck::RecompileCheck_OptimizationLevel);
   current->add(check);
 }
 
 JSObject* IonBuilder::testSingletonProperty(JSObject* obj, jsid id) {
   // We would like to completely no-op property/global accesses which can
   // produce only a particular JSObject. When indicating the access result is
   // definitely an object, type inference does not account for the
   // possibility that the property is entirely missing from the input object
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -699,23 +699,16 @@ class IonBuilder : public MIRGenerator,
   // Oracles.
   InliningDecision canInlineTarget(JSFunction* target, CallInfo& callInfo);
   InliningDecision makeInliningDecision(JSObject* target, CallInfo& callInfo);
   AbortReasonOr<Ok> selectInliningTargets(const InliningTargets& targets,
                                           CallInfo& callInfo,
                                           BoolVector& choiceSet,
                                           uint32_t* numInlineable);
 
-  OptimizationLevel optimizationLevel() const {
-    return optimizationInfo().level();
-  }
-  bool isHighestOptimizationLevel() const {
-    return IonOptimizations.isLastLevel(optimizationLevel());
-  }
-
   // Native inlining helpers.
   // The typeset for the return value of our function.  These are
   // the types it's been observed returning in the past.
   TemporaryTypeSet* getInlineReturnTypeSet();
   // The known MIR type of getInlineReturnTypeSet.
   MIRType getInlineReturnType();
 
   // Array natives.
--- a/js/src/jit/IonOptimizationLevels.cpp
+++ b/js/src/jit/IonOptimizationLevels.cpp
@@ -12,58 +12,53 @@
 using namespace js;
 using namespace js::jit;
 
 namespace js {
 namespace jit {
 
 const OptimizationLevelInfo IonOptimizations;
 
+// Duplicated in all.js - ensure both match.
+const uint32_t OptimizationInfo::CompilerWarmupThreshold = 1000;
+const uint32_t OptimizationInfo::CompilerSmallFunctionWarmupThreshold =
+    CompilerWarmupThreshold;
+
 void OptimizationInfo::initNormalOptimizationInfo() {
   level_ = OptimizationLevel::Normal;
 
   autoTruncate_ = true;
   eaa_ = true;
   edgeCaseAnalysis_ = true;
   eliminateRedundantChecks_ = true;
   inlineInterpreted_ = true;
   inlineNative_ = true;
   licm_ = true;
   gvn_ = true;
   rangeAnalysis_ = true;
   reordering_ = true;
-  scalarReplacement_ = true;
   sincos_ = true;
   sink_ = true;
 
   registerAllocator_ = RegisterAllocator_Backtracking;
 
-  inlineMaxBytecodePerCallSiteMainThread_ = 200;
-  inlineMaxBytecodePerCallSiteHelperThread_ = 400;
+  inlineMaxBytecodePerCallSiteMainThread_ = 550;
+  inlineMaxBytecodePerCallSiteHelperThread_ = 1100;
   inlineMaxCalleeInlinedBytecodeLength_ = 3550;
   inlineMaxTotalBytecodeLength_ = 85000;
   inliningMaxCallerBytecodeLength_ = 1600;
-  maxInlineDepth_ = 0;
-  smallFunctionMaxInlineDepth_ = 1;
-  inliningWarmUpThresholdFactor_ = 0.5;
+  maxInlineDepth_ = 3;
+  scalarReplacement_ = true;
+  smallFunctionMaxInlineDepth_ = 10;
+  compilerWarmUpThreshold_ = CompilerWarmupThreshold;
+  compilerSmallFunctionWarmUpThreshold_ = CompilerSmallFunctionWarmupThreshold;
+  inliningWarmUpThresholdFactor_ = 0.125;
   inliningRecompileThresholdFactor_ = 4;
 }
 
-void OptimizationInfo::initFullOptimizationInfo() {
-  initNormalOptimizationInfo();
-
-  level_ = OptimizationLevel::Full;
-
-  inlineMaxBytecodePerCallSiteMainThread_ = 550;
-  inlineMaxBytecodePerCallSiteHelperThread_ = 1100;
-  maxInlineDepth_ = 3;
-  smallFunctionMaxInlineDepth_ = 10;
-  inliningWarmUpThresholdFactor_ = 0.125;
-}
-
 void OptimizationInfo::initWasmOptimizationInfo() {
   // The Wasm optimization level
   // Disables some passes that don't work well with wasm.
 
   // Take normal option values for not specified values.
   initNormalOptimizationInfo();
 
   level_ = OptimizationLevel::Wasm;
@@ -81,68 +76,54 @@ uint32_t OptimizationInfo::compilerWarmU
                                                    jsbytecode* pc) const {
   MOZ_ASSERT(pc == nullptr || pc == script->code() ||
              JSOp(*pc) == JSOP_LOOPENTRY);
 
   if (pc == script->code()) {
     pc = nullptr;
   }
 
-  uint32_t warmUpThreshold = baseCompilerWarmUpThreshold();
+  uint32_t warmUpThreshold = JitOptions.forcedDefaultIonWarmUpThreshold.valueOr(
+      compilerWarmUpThreshold_);
+
+  if (JitOptions.isSmallFunction(script)) {
+    warmUpThreshold =
+        JitOptions.forcedDefaultIonSmallFunctionWarmUpThreshold.valueOr(
+            compilerSmallFunctionWarmUpThreshold_);
+  }
 
   // If the script is too large to compile on the main thread, we can still
   // compile it off thread. In these cases, increase the warm-up counter
   // threshold to improve the compilation's type information and hopefully
   // avoid later recompilation.
 
   if (script->length() > MAX_MAIN_THREAD_SCRIPT_SIZE) {
     warmUpThreshold *= (script->length() / double(MAX_MAIN_THREAD_SCRIPT_SIZE));
   }
 
   uint32_t numLocalsAndArgs = NumLocalsAndArgs(script);
   if (numLocalsAndArgs > MAX_MAIN_THREAD_LOCALS_AND_ARGS) {
     warmUpThreshold *=
         (numLocalsAndArgs / double(MAX_MAIN_THREAD_LOCALS_AND_ARGS));
   }
 
-  if (!pc || JitOptions.eagerIonCompilation()) {
+  if (!pc || JitOptions.eagerCompilation) {
     return warmUpThreshold;
   }
 
   // It's more efficient to enter outer loops, rather than inner loops, via OSR.
   // To accomplish this, we use a slightly higher threshold for inner loops.
   // Note that the loop depth is always > 0 so we will prefer non-OSR over OSR.
   uint32_t loopDepth = LoopEntryDepthHint(pc);
   MOZ_ASSERT(loopDepth > 0);
-  return warmUpThreshold + loopDepth * (baseCompilerWarmUpThreshold() / 10);
-}
-
-uint32_t OptimizationInfo::recompileWarmUpThreshold(JSScript* script,
-                                                    jsbytecode* pc) const {
-  MOZ_ASSERT(pc == script->code() || *pc == JSOP_LOOPENTRY);
-
-  uint32_t threshold = compilerWarmUpThreshold(script, pc);
-  if (*pc != JSOP_LOOPENTRY || JitOptions.eagerIonCompilation()) {
-    return threshold;
-  }
-
-  // If we're stuck in a long-running loop at a low optimization level, we have
-  // to invalidate to be able to tier up. This is worse than recompiling at
-  // function entry (because in that case we can use the lazy link mechanism and
-  // avoid invalidation completely). Use a very high recompilation threshold for
-  // loop edges so that this only affects very long-running loops.
-
-  uint32_t loopDepth = LoopEntryDepthHint(pc);
-  MOZ_ASSERT(loopDepth > 0);
-  return threshold + loopDepth * (baseCompilerWarmUpThreshold() / 10);
+  return warmUpThreshold + loopDepth * 100;
 }
 
 OptimizationLevelInfo::OptimizationLevelInfo() {
   infos_[OptimizationLevel::Normal].initNormalOptimizationInfo();
-  infos_[OptimizationLevel::Full].initFullOptimizationInfo();
   infos_[OptimizationLevel::Wasm].initWasmOptimizationInfo();
 
 #ifdef DEBUG
   OptimizationLevel level = firstLevel();
   while (!isLastLevel(level)) {
     OptimizationLevel next = nextLevel(level);
     MOZ_ASSERT_IF(level != OptimizationLevel::DontCompile, level < next);
     level = next;
@@ -152,31 +133,28 @@ OptimizationLevelInfo::OptimizationLevel
 
 OptimizationLevel OptimizationLevelInfo::nextLevel(
     OptimizationLevel level) const {
   MOZ_ASSERT(!isLastLevel(level));
   switch (level) {
     case OptimizationLevel::DontCompile:
       return OptimizationLevel::Normal;
     case OptimizationLevel::Normal:
-      return OptimizationLevel::Full;
-    case OptimizationLevel::Full:
     case OptimizationLevel::Wasm:
-    case OptimizationLevel::Count:
-      break;
+    case OptimizationLevel::Count:;
   }
   MOZ_CRASH("Unknown optimization level.");
 }
 
 OptimizationLevel OptimizationLevelInfo::firstLevel() const {
   return nextLevel(OptimizationLevel::DontCompile);
 }
 
 bool OptimizationLevelInfo::isLastLevel(OptimizationLevel level) const {
-  return level == OptimizationLevel::Full;
+  return level == OptimizationLevel::Normal;
 }
 
 OptimizationLevel OptimizationLevelInfo::levelForScript(JSScript* script,
                                                         jsbytecode* pc) const {
   OptimizationLevel prev = OptimizationLevel::DontCompile;
 
   while (!isLastLevel(prev)) {
     OptimizationLevel level = nextLevel(prev);
--- a/js/src/jit/IonOptimizationLevels.h
+++ b/js/src/jit/IonOptimizationLevels.h
@@ -12,61 +12,35 @@
 #include "jstypes.h"
 
 #include "jit/JitOptions.h"
 #include "js/TypeDecls.h"
 
 namespace js {
 namespace jit {
 
-// [SMDOC] Ion Optimization Levels
-//
-// Ion can do aggressive inlining, but inlining a lot of code will have a
-// negative effect on compilation time and memory usage. It also means we spend
-// more time in the slower Baseline code while compiling the Ion code
-// off-thread or after an invalidation.
-//
-// To address this, Ion consists of two tiers:
-//
-// * Normal: the first tier (warm-up threshold of 1,000) only inlines small
-//           functions one level deep. This tier also has recompile checks to
-//           recompile the script when it becomes very hot.
-//
-// * Full: the second tier (warm-up threshold of 100,000) is only used for very
-//         hot code so we can afford inlining a lot more code.
-//
-// See MRecompileCheck::RecompileCheckType for more info.
-
-enum class OptimizationLevel : uint8_t {
-  Normal,
-  Full,
-  Wasm,
-  Count,
-  DontCompile
-};
+enum class OptimizationLevel : uint8_t { Normal, Wasm, Count, DontCompile };
 
 #ifdef JS_JITSPEW
 inline const char* OptimizationLevelString(OptimizationLevel level) {
   switch (level) {
     case OptimizationLevel::DontCompile:
       return "Optimization_DontCompile";
     case OptimizationLevel::Normal:
       return "Optimization_Normal";
-    case OptimizationLevel::Full:
-      return "Optimization_Full";
     case OptimizationLevel::Wasm:
       return "Optimization_Wasm";
     case OptimizationLevel::Count:;
   }
   MOZ_CRASH("Invalid OptimizationLevel");
 }
 #endif
 
-// Class representing the Ion optimization settings for an OptimizationLevel.
 class OptimizationInfo {
+ public:
   OptimizationLevel level_;
 
   // Toggles whether Effective Address Analysis is performed.
   bool eaa_;
 
   // Toggles whether Alignment Mask Analysis is performed.
   bool ama_;
 
@@ -132,45 +106,39 @@ class OptimizationInfo {
   // The maximum inlining depth for functions.
   //
   // Inlining small functions has almost no compiling overhead
   // and removes the otherwise needed call overhead.
   // The value is currently very low.
   // Actually it is only needed to make sure we don't blow out the stack.
   uint32_t smallFunctionMaxInlineDepth_;
 
+  // How many invocations or loop iterations are needed before functions
+  // are compiled.
+  uint32_t compilerWarmUpThreshold_;
+
+  // Default compiler warmup threshold, unless it is overridden.
+  static const uint32_t CompilerWarmupThreshold;
+
+  // How many invocations or loop iterations are needed before small functions
+  // are compiled.
+  uint32_t compilerSmallFunctionWarmUpThreshold_;
+
+  // Default small function compiler warmup threshold, unless it is overridden.
+  static const uint32_t CompilerSmallFunctionWarmupThreshold;
+
   // How many invocations or loop iterations are needed before calls
   // are inlined, as a fraction of compilerWarmUpThreshold.
   double inliningWarmUpThresholdFactor_;
 
   // How many invocations or loop iterations are needed before a function
   // is hot enough to recompile the outerScript to inline that function,
   // as a multiplication of inliningWarmUpThreshold.
   uint32_t inliningRecompileThresholdFactor_;
 
-  uint32_t baseCompilerWarmUpThreshold() const {
-    switch (level_) {
-      case OptimizationLevel::Normal:
-        return JitOptions.normalIonWarmUpThreshold;
-      case OptimizationLevel::Full:
-        if (!JitOptions.disableOptimizationLevels) {
-          return JitOptions.fullIonWarmUpThreshold;
-        }
-        // Use the 'normal' threshold so Ion uses a single optimization level,
-        // OptimizationLevel::Full.
-        return JitOptions.normalIonWarmUpThreshold;
-      case OptimizationLevel::DontCompile:
-      case OptimizationLevel::Wasm:
-      case OptimizationLevel::Count:
-        break;
-    }
-    MOZ_CRASH("Unexpected optimization level");
-  }
-
- public:
   constexpr OptimizationInfo()
       : level_(OptimizationLevel::Normal),
         eaa_(false),
         ama_(false),
         edgeCaseAnalysis_(false),
         eliminateRedundantChecks_(false),
         inlineInterpreted_(false),
         inlineNative_(false),
@@ -185,38 +153,37 @@ class OptimizationInfo {
         inlineMaxBytecodePerCallSiteHelperThread_(0),
         inlineMaxBytecodePerCallSiteMainThread_(0),
         inlineMaxCalleeInlinedBytecodeLength_(0),
         inlineMaxTotalBytecodeLength_(0),
         inliningMaxCallerBytecodeLength_(0),
         maxInlineDepth_(0),
         scalarReplacement_(false),
         smallFunctionMaxInlineDepth_(0),
+        compilerWarmUpThreshold_(0),
+        compilerSmallFunctionWarmUpThreshold_(0),
         inliningWarmUpThresholdFactor_(0.0),
         inliningRecompileThresholdFactor_(0) {}
 
   void initNormalOptimizationInfo();
-  void initFullOptimizationInfo();
   void initWasmOptimizationInfo();
 
   OptimizationLevel level() const { return level_; }
 
   bool inlineInterpreted() const {
     return inlineInterpreted_ && !JitOptions.disableInlining;
   }
 
   bool inlineNative() const {
     return inlineNative_ && !JitOptions.disableInlining;
   }
 
   uint32_t compilerWarmUpThreshold(JSScript* script,
                                    jsbytecode* pc = nullptr) const;
 
-  uint32_t recompileWarmUpThreshold(JSScript* script, jsbytecode* pc) const;
-
   bool gvnEnabled() const { return gvn_ && !JitOptions.disableGvn; }
 
   bool licmEnabled() const { return licm_ && !JitOptions.disableLicm; }
 
   bool rangeAnalysisEnabled() const {
     return rangeAnalysis_ && !JitOptions.disableRangeAnalysis;
   }
 
@@ -274,17 +241,20 @@ class OptimizationInfo {
     return inlineMaxTotalBytecodeLength_;
   }
 
   uint32_t inliningMaxCallerBytecodeLength() const {
     return inliningMaxCallerBytecodeLength_;
   }
 
   uint32_t inliningWarmUpThreshold() const {
-    return baseCompilerWarmUpThreshold() * inliningWarmUpThresholdFactor_;
+    uint32_t compilerWarmUpThreshold =
+        JitOptions.forcedDefaultIonWarmUpThreshold.valueOr(
+            compilerWarmUpThreshold_);
+    return compilerWarmUpThreshold * inliningWarmUpThresholdFactor_;
   }
 
   uint32_t inliningRecompileThreshold() const {
     return inliningWarmUpThreshold() * inliningRecompileThresholdFactor_;
   }
 };
 
 class OptimizationLevelInfo {
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -131,19 +131,18 @@ DefaultJitOptions::DefaultJitOptions() {
   SET_DEFAULT(disableSincos, false);
 #else
   SET_DEFAULT(disableSincos, true);
 #endif
 
   // Toggles whether sink code motion is globally disabled.
   SET_DEFAULT(disableSink, true);
 
-  // Toggles whether the use of multiple Ion optimization levels is globally
-  // disabled.
-  SET_DEFAULT(disableOptimizationLevels, false);
+  // Whether functions are compiled immediately.
+  SET_DEFAULT(eagerCompilation, false);
 
   // Whether IonBuilder should prefer IC generation above specialized MIR.
   SET_DEFAULT(forceInlineCaches, false);
 
   // Toggles whether large scripts are rejected.
   SET_DEFAULT(limitScriptSize, true);
 
   // Toggles whether functions may be entered at loop headers.
@@ -152,26 +151,16 @@ DefaultJitOptions::DefaultJitOptions() {
   // Whether to enable extra code to perform dynamic validations.
   SET_DEFAULT(runExtraChecks, false);
 
   // How many invocations or loop iterations are needed before functions
   // are compiled with the baseline compiler.
   // Duplicated in all.js - ensure both match.
   SET_DEFAULT(baselineWarmUpThreshold, 10);
 
-  // How many invocations or loop iterations are needed before functions
-  // are compiled with the Ion compiler at OptimizationLevel::Normal.
-  // Duplicated in all.js - ensure both match.
-  SET_DEFAULT(normalIonWarmUpThreshold, 1000);
-
-  // How many invocations or loop iterations are needed before functions
-  // are compiled with the Ion compiler at OptimizationLevel::Full.
-  // Duplicated in all.js - ensure both match.
-  SET_DEFAULT(fullIonWarmUpThreshold, 100'000);
-
   // Number of exception bailouts (resuming into catch/finally block) before
   // we invalidate and forbid Ion compilation.
   SET_DEFAULT(exceptionBailoutThreshold, 10);
 
   // Number of bailouts without invalidation before we set
   // JSScript::hadFrequentBailouts and invalidate.
   // Duplicated in all.js - ensure both match.
   SET_DEFAULT(frequentBailoutThreshold, 10);
@@ -200,16 +189,43 @@ DefaultJitOptions::DefaultJitOptions() {
   // score is compared against a threshold to prevent a branch from being
   // removed.
   SET_DEFAULT(branchPruningHitCountFactor, 1);
   SET_DEFAULT(branchPruningInstFactor, 10);
   SET_DEFAULT(branchPruningBlockSpanFactor, 100);
   SET_DEFAULT(branchPruningEffectfulInstFactor, 3500);
   SET_DEFAULT(branchPruningThreshold, 4000);
 
+  // Force how many invocation or loop iterations are needed before compiling
+  // a function with the highest ionmonkey optimization level.
+  // (i.e. OptimizationLevel_Normal)
+  const char* forcedDefaultIonWarmUpThresholdEnv =
+      "JIT_OPTION_forcedDefaultIonWarmUpThreshold";
+  if (const char* env = getenv(forcedDefaultIonWarmUpThresholdEnv)) {
+    Maybe<int> value = ParseInt(env);
+    if (value.isSome()) {
+      forcedDefaultIonWarmUpThreshold.emplace(value.ref());
+    } else {
+      Warn(forcedDefaultIonWarmUpThresholdEnv, env);
+    }
+  }
+
+  // Same but for compiling small functions.
+  const char* forcedDefaultIonSmallFunctionWarmUpThresholdEnv =
+      "JIT_OPTION_forcedDefaultIonSmallFunctionWarmUpThreshold";
+  if (const char* env =
+          getenv(forcedDefaultIonSmallFunctionWarmUpThresholdEnv)) {
+    Maybe<int> value = ParseInt(env);
+    if (value.isSome()) {
+      forcedDefaultIonSmallFunctionWarmUpThreshold.emplace(value.ref());
+    } else {
+      Warn(forcedDefaultIonSmallFunctionWarmUpThresholdEnv, env);
+    }
+  }
+
   // Force the used register allocator instead of letting the optimization
   // pass decide.
   const char* forcedRegisterAllocatorEnv = "JIT_OPTION_forcedRegisterAllocator";
   if (const char* env = getenv(forcedRegisterAllocatorEnv)) {
     forcedRegisterAllocator = LookupRegisterAllocator(env);
     if (!forcedRegisterAllocator.isSome()) {
       Warn(forcedRegisterAllocatorEnv, env);
     }
@@ -268,42 +284,44 @@ DefaultJitOptions::DefaultJitOptions() {
 }
 
 bool DefaultJitOptions::isSmallFunction(JSScript* script) const {
   return script->length() <= smallFunctionMaxBytecodeLength_;
 }
 
 void DefaultJitOptions::enableGvn(bool enable) { disableGvn = !enable; }
 
-void DefaultJitOptions::setEagerIonCompilation() {
+void DefaultJitOptions::setEagerCompilation() {
+  eagerCompilation = true;
   baselineWarmUpThreshold = 0;
-  normalIonWarmUpThreshold = 0;
-  fullIonWarmUpThreshold = 0;
+  forcedDefaultIonWarmUpThreshold.reset();
+  forcedDefaultIonWarmUpThreshold.emplace(0);
+  forcedDefaultIonSmallFunctionWarmUpThreshold.reset();
+  forcedDefaultIonSmallFunctionWarmUpThreshold.emplace(0);
 }
 
-void DefaultJitOptions::setNormalIonWarmUpThreshold(uint32_t warmUpThreshold) {
-  normalIonWarmUpThreshold = warmUpThreshold;
+void DefaultJitOptions::setCompilerWarmUpThreshold(uint32_t warmUpThreshold) {
+  forcedDefaultIonWarmUpThreshold.reset();
+  forcedDefaultIonWarmUpThreshold.emplace(warmUpThreshold);
+  forcedDefaultIonSmallFunctionWarmUpThreshold.reset();
+  forcedDefaultIonSmallFunctionWarmUpThreshold.emplace(warmUpThreshold);
 
-  if (fullIonWarmUpThreshold < normalIonWarmUpThreshold) {
-    fullIonWarmUpThreshold = normalIonWarmUpThreshold;
+  // Undo eager compilation
+  if (eagerCompilation && warmUpThreshold != 0) {
+    jit::DefaultJitOptions defaultValues;
+    eagerCompilation = false;
+    baselineWarmUpThreshold = defaultValues.baselineWarmUpThreshold;
   }
 }
 
-void DefaultJitOptions::setFullIonWarmUpThreshold(uint32_t warmUpThreshold) {
-  fullIonWarmUpThreshold = warmUpThreshold;
-
-  if (normalIonWarmUpThreshold > fullIonWarmUpThreshold) {
-    setNormalIonWarmUpThreshold(fullIonWarmUpThreshold);
-  }
-}
+void DefaultJitOptions::resetCompilerWarmUpThreshold() {
+  forcedDefaultIonWarmUpThreshold.reset();
 
-void DefaultJitOptions::resetNormalIonWarmUpThreshold() {
-  jit::DefaultJitOptions defaultValues;
-  setNormalIonWarmUpThreshold(defaultValues.normalIonWarmUpThreshold);
-}
-
-void DefaultJitOptions::resetFullIonWarmUpThreshold() {
-  jit::DefaultJitOptions defaultValues;
-  setFullIonWarmUpThreshold(defaultValues.fullIonWarmUpThreshold);
+  // Undo eager compilation
+  if (eagerCompilation) {
+    jit::DefaultJitOptions defaultValues;
+    eagerCompilation = false;
+    baselineWarmUpThreshold = defaultValues.baselineWarmUpThreshold;
+  }
 }
 
 }  // namespace jit
 }  // namespace js
--- a/js/src/jit/JitOptions.h
+++ b/js/src/jit/JitOptions.h
@@ -60,17 +60,17 @@ struct DefaultJitOptions {
   bool disableInstructionReordering;
   bool disableRangeAnalysis;
   bool disableRecoverIns;
   bool disableScalarReplacement;
   bool disableCacheIR;
   bool disableCacheIRBinaryArith;
   bool disableSincos;
   bool disableSink;
-  bool disableOptimizationLevels;
+  bool eagerCompilation;
   bool forceInlineCaches;
   bool fullDebugChecks;
   bool limitScriptSize;
   bool osr;
   bool wasmFoldOffsets;
   bool wasmDelayTier2;
 #ifdef JS_TRACE_LOGGING
   bool enableTraceLogger;
@@ -78,31 +78,31 @@ struct DefaultJitOptions {
 #ifdef WASM_CODEGEN_DEBUG
   bool enableWasmJitExit;
   bool enableWasmJitEntry;
   bool enableWasmIonFastCalls;
   bool enableWasmImportCallSpew;
   bool enableWasmFuncCallSpew;
 #endif
   uint32_t baselineWarmUpThreshold;
-  uint32_t normalIonWarmUpThreshold;
-  uint32_t fullIonWarmUpThreshold;
   uint32_t exceptionBailoutThreshold;
   uint32_t frequentBailoutThreshold;
   uint32_t maxStackArgs;
   uint32_t osrPcMismatchesBeforeRecompile;
   uint32_t smallFunctionMaxBytecodeLength_;
   uint32_t jumpThreshold;
   uint32_t branchPruningHitCountFactor;
   uint32_t branchPruningInstFactor;
   uint32_t branchPruningBlockSpanFactor;
   uint32_t branchPruningEffectfulInstFactor;
   uint32_t branchPruningThreshold;
   uint32_t wasmBatchIonThreshold;
   uint32_t wasmBatchBaselineThreshold;
+  mozilla::Maybe<uint32_t> forcedDefaultIonWarmUpThreshold;
+  mozilla::Maybe<uint32_t> forcedDefaultIonSmallFunctionWarmUpThreshold;
   mozilla::Maybe<IonRegisterAllocator> forcedRegisterAllocator;
 
   // Spectre mitigation flags. Each mitigation has its own flag in order to
   // measure the effectiveness of each mitigation with various proof of
   // concept.
   bool spectreIndexMasking;
   bool spectreObjectMitigationsBarriers;
   bool spectreObjectMitigationsMisc;
@@ -110,26 +110,20 @@ struct DefaultJitOptions {
   bool spectreValueMasking;
   bool spectreJitToCxxCalls;
 
   // The options below affect the rest of the VM, and not just the JIT.
   bool disableUnboxedObjects;
 
   DefaultJitOptions();
   bool isSmallFunction(JSScript* script) const;
-  void setEagerIonCompilation();
-  void setNormalIonWarmUpThreshold(uint32_t warmUpThreshold);
-  void setFullIonWarmUpThreshold(uint32_t warmUpThreshold);
-  void resetNormalIonWarmUpThreshold();
-  void resetFullIonWarmUpThreshold();
+  void setEagerCompilation();
+  void setCompilerWarmUpThreshold(uint32_t warmUpThreshold);
+  void resetCompilerWarmUpThreshold();
   void enableGvn(bool val);
-
-  bool eagerIonCompilation() const {
-    return normalIonWarmUpThreshold == 0;
-  }
 };
 
 extern DefaultJitOptions JitOptions;
 
 }  // namespace jit
 }  // namespace js
 
 #endif /* jit_JitOptions_h */
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -537,17 +537,17 @@ void LIRGenerator::visitEncodeSnapshot(M
   assignSnapshot(lir, Bailout_Inevitable);
   add(lir, mir);
 }
 
 void LIRGenerator::visitAssertFloat32(MAssertFloat32* assertion) {
   MIRType type = assertion->input()->type();
   DebugOnly<bool> checkIsFloat32 = assertion->mustBeFloat32();
 
-  if (type != MIRType::Value && !JitOptions.eagerIonCompilation()) {
+  if (type != MIRType::Value && !JitOptions.eagerCompilation) {
     MOZ_ASSERT_IF(checkIsFloat32, type == MIRType::Float32);
     MOZ_ASSERT_IF(!checkIsFloat32, type != MIRType::Float32);
   }
 }
 
 void LIRGenerator::visitAssertRecoveredOnBailout(
     MAssertRecoveredOnBailout* assertion) {
   MOZ_CRASH("AssertRecoveredOnBailout nodes are always recovered on bailouts.");
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -10972,80 +10972,59 @@ class MCheckReturn : public MBinaryInstr
   NAMED_OPERANDS((0, returnValue), (1, thisValue))
 };
 
 // Increase the warm-up counter of the provided script upon execution and test
 // if the warm-up counter surpasses the threshold. Upon hit it will recompile
 // the outermost script (i.e. not the inlined script).
 class MRecompileCheck : public MNullaryInstruction {
  public:
-  enum class RecompileCheckType : uint8_t {
-    // If we're not at the highest optimization level, keep incrementing the
-    // warm-up counter for the outermost script on entry. The warmup check will
-    // trigger recompilation to tier up. The lazy link mechanism will be used to
-    // tier up once recompilation is done.
-    OptimizationLevel,
-
-    // If we're not at the highest optimization level, keep incrementing the
-    // warm-up counter at loop edges. This check will trigger invalidation for
-    // very long-running loops to ensure we still tier up even if we don't
-    // invoke the lazy link stub.
-    OptimizationLevelOSR,
-
-    // If we're not at the highest optimization level, keep incrementing the
-    // warm-up counter for inlined scripts. This check does not trigger any
-    // recompilation or invalidation, it exists to ensure inlined scripts have
-    // an accurate warm-up count.
-    OptimizationLevelInlined,
-
-    // Used at the last optimization level for callees that weren't hot enough
-    // to be inlined. If a callee becomes hot enough we force recompilation of
-    // the caller's Ion script.
-    Inlining
+  enum RecompileCheckType {
+    RecompileCheck_OptimizationLevel,
+    RecompileCheck_Inlining
   };
 
  private:
   JSScript* script_;
   uint32_t recompileThreshold_;
-  RecompileCheckType type_;
+  bool forceRecompilation_;
+  bool increaseWarmUpCounter_;
 
   MRecompileCheck(JSScript* script, uint32_t recompileThreshold,
                   RecompileCheckType type)
       : MNullaryInstruction(classOpcode),
         script_(script),
-        recompileThreshold_(recompileThreshold),
-        type_(type) {
+        recompileThreshold_(recompileThreshold) {
+    switch (type) {
+      case RecompileCheck_OptimizationLevel:
+        forceRecompilation_ = false;
+        increaseWarmUpCounter_ = true;
+        break;
+      case RecompileCheck_Inlining:
+        forceRecompilation_ = true;
+        increaseWarmUpCounter_ = false;
+        break;
+      default:
+        MOZ_CRASH("Unexpected recompile check type");
+    }
+
     setGuard();
   }
 
  public:
   INSTRUCTION_HEADER(RecompileCheck)
   TRIVIAL_NEW_WRAPPERS
 
   JSScript* script() const { return script_; }
 
   uint32_t recompileThreshold() const { return recompileThreshold_; }
 
-  bool forceInvalidation() const {
-    return type_ == RecompileCheckType::OptimizationLevelOSR;
-  }
-
-  bool forceRecompilation() const {
-    return type_ == RecompileCheckType::Inlining;
-  }
-
-  bool checkCounter() const {
-    return type_ != RecompileCheckType::OptimizationLevelInlined;
-  }
-
-  bool increaseWarmUpCounter() const {
-    return (type_ == RecompileCheckType::OptimizationLevel ||
-            type_ == RecompileCheckType::OptimizationLevelInlined ||
-            type_ == RecompileCheckType::OptimizationLevelOSR);
-  }
+  bool forceRecompilation() const { return forceRecompilation_; }
+
+  bool increaseWarmUpCounter() const { return increaseWarmUpCounter_; }
 
   AliasSet getAliasSet() const override { return AliasSet::None(); }
 };
 
 class MAtomicIsLockFree : public MUnaryInstruction,
                           public ConvertToInt32Policy<0>::Data {
   explicit MAtomicIsLockFree(MDefinition* value)
       : MUnaryInstruction(classOpcode, value) {
--- a/js/src/jit/VMFunctionList-inl.h
+++ b/js/src/jit/VMFunctionList-inl.h
@@ -133,17 +133,16 @@ namespace jit {
   _(InterpretResume, js::jit::InterpretResume)                                 \
   _(InterruptCheck, js::jit::InterruptCheck)                                   \
   _(InvokeFunction, js::jit::InvokeFunction)                                   \
   _(InvokeFunctionShuffleNewTarget, js::jit::InvokeFunctionShuffleNewTarget)   \
   _(IonBinaryArithICUpdate, js::jit::IonBinaryArithIC::update)                 \
   _(IonBindNameICUpdate, js::jit::IonBindNameIC::update)                       \
   _(IonCompareICUpdate, js::jit::IonCompareIC::update)                         \
   _(IonCompileScriptForBaseline, js::jit::IonCompileScriptForBaseline)         \
-  _(IonForcedInvalidation, js::jit::IonForcedInvalidation)                     \
   _(IonForcedRecompile, js::jit::IonForcedRecompile)                           \
   _(IonGetIteratorICUpdate, js::jit::IonGetIteratorIC::update)                 \
   _(IonGetNameICUpdate, js::jit::IonGetNameIC::update)                         \
   _(IonGetPropSuperICUpdate, js::jit::IonGetPropSuperIC::update)               \
   _(IonGetPropertyICUpdate, js::jit::IonGetPropertyIC::update)                 \
   _(IonHasOwnICUpdate, js::jit::IonHasOwnIC::update)                           \
   _(IonInICUpdate, js::jit::IonInIC::update)                                   \
   _(IonInstanceOfICUpdate, js::jit::IonInstanceOfIC::update)                   \
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1289,37 +1289,16 @@ bool RecompileImpl(JSContext* cx, bool f
 bool IonForcedRecompile(JSContext* cx) {
   return RecompileImpl(cx, /* force = */ true);
 }
 
 bool IonRecompile(JSContext* cx) {
   return RecompileImpl(cx, /* force = */ false);
 }
 
-bool IonForcedInvalidation(JSContext* cx) {
-  MOZ_ASSERT(cx->currentlyRunningInJit());
-  JitActivationIterator activations(cx);
-  JSJitFrameIter frame(activations->asJit());
-
-  MOZ_ASSERT(frame.type() == FrameType::Exit);
-  ++frame;
-
-  RootedScript script(cx, frame.script());
-  MOZ_ASSERT(script->hasIonScript());
-
-  if (script->baselineScript()->hasPendingIonBuilder()) {
-    LinkIonScript(cx, script);
-    return true;
-  }
-
-  Invalidate(cx, script, /* resetUses = */ false,
-             /* cancelOffThread = */ false);
-  return true;
-}
-
 bool SetDenseElement(JSContext* cx, HandleNativeObject obj, int32_t index,
                      HandleValue value, bool strict) {
   // This function is called from Ion code for StoreElementHole's OOL path.
   // In this case we know the object is native and that no type changes are
   // needed.
 
   DenseElementResult result = obj->setOrExtendDenseElements(
       cx, index, value.address(), 1, ShouldUpdateTypes::DontUpdate);
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -988,18 +988,16 @@ MOZ_MUST_USE bool InitBaselineFrameForOs
                                           InterpreterFrame* interpFrame,
                                           uint32_t numStackValues);
 
 JSObject* CreateDerivedTypedObj(JSContext* cx, HandleObject descr,
                                 HandleObject owner, int32_t offset);
 
 MOZ_MUST_USE bool IonRecompile(JSContext* cx);
 MOZ_MUST_USE bool IonForcedRecompile(JSContext* cx);
-MOZ_MUST_USE bool IonForcedInvalidation(JSContext* cx);
-
 JSString* StringReplace(JSContext* cx, HandleString string,
                         HandleString pattern, HandleString repl);
 
 MOZ_MUST_USE bool SetDenseElement(JSContext* cx, HandleNativeObject obj,
                                   int32_t index, HandleValue value,
                                   bool strict);
 
 void AssertValidObjectPtr(JSContext* cx, JSObject* obj);
--- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h
@@ -823,18 +823,18 @@ void MacroAssembler::branch32(Condition 
   movePtr(ImmPtr(lhs.addr), scratch);
   branch32(cond, Address(scratch, 0), rhs, label);
 }
 
 void MacroAssembler::branch32(Condition cond, const AbsoluteAddress& lhs,
                               Imm32 rhs, Label* label) {
   vixl::UseScratchRegisterScope temps(this);
   const Register scratch = temps.AcquireX().asUnsized();
-  load32(lhs, scratch);
-  branch32(cond, scratch, rhs, label);
+  movePtr(ImmPtr(lhs.addr), scratch);
+  branch32(cond, Address(scratch, 0), rhs, label);
 }
 
 void MacroAssembler::branch32(Condition cond, const BaseIndex& lhs, Imm32 rhs,
                               Label* label) {
   vixl::UseScratchRegisterScope temps(this);
   const ARMRegister scratch32 = temps.AcquireW();
   MOZ_ASSERT(scratch32.asUnsized() != lhs.base);
   MOZ_ASSERT(scratch32.asUnsized() != lhs.index);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5470,29 +5470,25 @@ JS_PUBLIC_API void JS_SetGlobalJitCompil
   switch (opt) {
     case JSJITCOMPILER_BASELINE_WARMUP_TRIGGER:
       if (value == uint32_t(-1)) {
         jit::DefaultJitOptions defaultValues;
         value = defaultValues.baselineWarmUpThreshold;
       }
       jit::JitOptions.baselineWarmUpThreshold = value;
       break;
-    case JSJITCOMPILER_ION_NORMAL_WARMUP_TRIGGER:
+    case JSJITCOMPILER_ION_WARMUP_TRIGGER:
       if (value == uint32_t(-1)) {
-        jit::JitOptions.resetNormalIonWarmUpThreshold();
+        jit::JitOptions.resetCompilerWarmUpThreshold();
         break;
       }
-      jit::JitOptions.setNormalIonWarmUpThreshold(value);
-      break;
-    case JSJITCOMPILER_ION_FULL_WARMUP_TRIGGER:
-      if (value == uint32_t(-1)) {
-        jit::JitOptions.resetFullIonWarmUpThreshold();
-        break;
+      jit::JitOptions.setCompilerWarmUpThreshold(value);
+      if (value == 0) {
+        jit::JitOptions.setEagerCompilation();
       }
-      jit::JitOptions.setFullIonWarmUpThreshold(value);
       break;
     case JSJITCOMPILER_ION_GVN_ENABLE:
       if (value == 0) {
         jit::JitOptions.enableGvn(false);
         JitSpew(js::jit::JitSpew_IonScripts, "Disable ion's GVN");
       } else {
         jit::JitOptions.enableGvn(true);
         JitSpew(js::jit::JitSpew_IonScripts, "Enable ion's GVN");
@@ -5608,21 +5604,19 @@ JS_PUBLIC_API bool JS_GetGlobalJitCompil
                                                  uint32_t* valueOut) {
   MOZ_ASSERT(valueOut);
 #ifndef JS_CODEGEN_NONE
   JSRuntime* rt = cx->runtime();
   switch (opt) {
     case JSJITCOMPILER_BASELINE_WARMUP_TRIGGER:
       *valueOut = jit::JitOptions.baselineWarmUpThreshold;
       break;
-    case JSJITCOMPILER_ION_NORMAL_WARMUP_TRIGGER:
-      *valueOut = jit::JitOptions.normalIonWarmUpThreshold;
-      break;
-    case JSJITCOMPILER_ION_FULL_WARMUP_TRIGGER:
-      *valueOut = jit::JitOptions.fullIonWarmUpThreshold;
+    case JSJITCOMPILER_ION_WARMUP_TRIGGER:
+      *valueOut = jit::JitOptions.forcedDefaultIonWarmUpThreshold.valueOr(
+          jit::OptimizationInfo::CompilerWarmupThreshold);
       break;
     case JSJITCOMPILER_ION_FORCE_IC:
       *valueOut = jit::JitOptions.forceInlineCaches;
       break;
     case JSJITCOMPILER_ION_CHECK_RANGE_ANALYSIS:
       *valueOut = jit::JitOptions.checkRangeAnalysis;
       break;
     case JSJITCOMPILER_ION_ENABLE:
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3289,18 +3289,17 @@ extern JS_PUBLIC_API void JS_SetParallel
                                                        bool enabled);
 
 extern JS_PUBLIC_API void JS_SetOffthreadIonCompilationEnabled(JSContext* cx,
                                                                bool enabled);
 
 // clang-format off
 #define JIT_COMPILER_OPTIONS(Register) \
   Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \
-  Register(ION_NORMAL_WARMUP_TRIGGER, "ion.warmup.trigger") \
-  Register(ION_FULL_WARMUP_TRIGGER, "ion.full.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_CHECK_RANGE_ANALYSIS, "ion.check-range-analysis") \
   Register(ION_FREQUENT_BAILOUT_THRESHOLD, "ion.frequent-bailout-threshold") \
   Register(BASELINE_ENABLE, "baseline.enable") \
   Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \
   Register(FULL_DEBUG_CHECKS, "jit.full-debug-checks") \
--- a/js/src/shell/fuzz-flags.txt
+++ b/js/src/shell/fuzz-flags.txt
@@ -31,24 +31,16 @@
 --ion-regalloc=testbed
 --ion-scalar-replacement=off
 --ion-scalar-replacement=on
 --ion-sincos=off
 --ion-sincos=on
 --ion-warmup-threshold=0
 --ion-warmup-threshold=10
 --ion-warmup-threshold=100
---ion-full-warmup-threshold=0
---ion-full-warmup-threshold=10
---ion-full-warmup-threshold=100
---ion-full-warmup-threshold=1000
---ion-full-warmup-threshold=1500
---ion-full-warmup-threshold=5000
---ion-optimization-levels=off
---ion-optimization-levels=on
 --no-native-regexp
 --nursery-strings=off
 --nursery-strings=on
 --spectre-mitigations=off
 --spectre-mitigations=on
 --more-compartments
 
 # Experimental JS language features
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -10324,26 +10324,16 @@ static bool SetContextOptions(JSContext*
       jit::JitOptions.disableSink = false;
     } else if (strcmp(str, "off") == 0) {
       jit::JitOptions.disableSink = true;
     } else {
       return OptionFailure("ion-sink", str);
     }
   }
 
-  if (const char* str = op.getStringOption("ion-optimization-levels")) {
-    if (strcmp(str, "on") == 0) {
-      jit::JitOptions.disableOptimizationLevels = false;
-    } else if (strcmp(str, "off") == 0) {
-      jit::JitOptions.disableOptimizationLevels = true;
-    } else {
-      return OptionFailure("ion-optimization-levels", str);
-    }
-  }
-
   if (const char* str = op.getStringOption("ion-instruction-reordering")) {
     if (strcmp(str, "on") == 0) {
       jit::JitOptions.disableInstructionReordering = false;
     } else if (strcmp(str, "off") == 0) {
       jit::JitOptions.disableInstructionReordering = true;
     } else {
       return OptionFailure("ion-instruction-reordering", str);
     }
@@ -10384,22 +10374,17 @@ static bool SetContextOptions(JSContext*
       jit::JitOptions.limitScriptSize = false;
     } else {
       return OptionFailure("ion-limit-script-size", str);
     }
   }
 
   int32_t warmUpThreshold = op.getIntOption("ion-warmup-threshold");
   if (warmUpThreshold >= 0) {
-    jit::JitOptions.setNormalIonWarmUpThreshold(warmUpThreshold);
-  }
-
-  warmUpThreshold = op.getIntOption("ion-full-warmup-threshold");
-  if (warmUpThreshold >= 0) {
-    jit::JitOptions.setFullIonWarmUpThreshold(warmUpThreshold);
+    jit::JitOptions.setCompilerWarmUpThreshold(warmUpThreshold);
   }
 
   warmUpThreshold = op.getIntOption("baseline-warmup-threshold");
   if (warmUpThreshold >= 0) {
     jit::JitOptions.baselineWarmUpThreshold = warmUpThreshold;
   }
 
   if (op.getBoolOption("baseline-eager")) {
@@ -10409,17 +10394,17 @@ static bool SetContextOptions(JSContext*
   if (const char* str = op.getStringOption("ion-regalloc")) {
     jit::JitOptions.forcedRegisterAllocator = jit::LookupRegisterAllocator(str);
     if (!jit::JitOptions.forcedRegisterAllocator.isSome()) {
       return OptionFailure("ion-regalloc", str);
     }
   }
 
   if (op.getBoolOption("ion-eager")) {
-    jit::JitOptions.setEagerIonCompilation();
+    jit::JitOptions.setEagerCompilation();
   }
 
   offthreadCompilation = true;
   if (const char* str = op.getStringOption("ion-offthread-compile")) {
     if (strcmp(str, "off") == 0) {
       offthreadCompilation = false;
     } else if (strcmp(str, "on") != 0) {
       return OptionFailure("ion-offthread-compile", str);
@@ -10959,19 +10944,16 @@ int main(int argc, char** argv, char** e
              "Replace sin(x)/cos(x) to sincos(x) (default: on, off to disable)")
 #else
       || !op.addStringOption(
              '\0', "ion-sincos", "on/off",
              "Replace sin(x)/cos(x) to sincos(x) (default: off, on to enable)")
 #endif
       || !op.addStringOption('\0', "ion-sink", "on/off",
                              "Sink code motion (default: off, on to enable)") ||
-      !op.addStringOption('\0', "ion-optimization-levels", "on/off",
-                          "Use multiple Ion optimization levels (default: on, "
-                          "off to disable)") ||
       !op.addStringOption('\0', "ion-loop-unrolling", "on/off",
                           "(NOP for fuzzers)") ||
       !op.addStringOption(
           '\0', "ion-instruction-reordering", "on/off",
           "Instruction reordering (default: off, on to enable)") ||
       !op.addBoolOption('\0', "ion-check-range-analysis",
                         "Range analysis checking") ||
       !op.addBoolOption('\0', "ion-extra-checks",
@@ -10982,21 +10964,17 @@ int main(int argc, char** argv, char** e
       !op.addStringOption(
           '\0', "ion-osr", "on/off",
           "On-Stack Replacement (default: on, off to disable)") ||
       !op.addStringOption(
           '\0', "ion-limit-script-size", "on/off",
           "Don't compile very large scripts (default: on, off to disable)") ||
       !op.addIntOption('\0', "ion-warmup-threshold", "COUNT",
                        "Wait for COUNT calls or iterations before compiling "
-                       "at the normal optimization level (default: 1000)",
-                       -1) ||
-      !op.addIntOption('\0', "ion-full-warmup-threshold", "COUNT",
-                       "Wait for COUNT calls or iterations before compiling "
-                       "at the 'full' optimization level (default: 100,000)",
+                       "(default: 1000)",
                        -1) ||
       !op.addStringOption(
           '\0', "ion-regalloc", "[mode]",
           "Specify Ion register allocation:\n"
           "  backtracking: Priority based backtracking register allocation "
           "(default)\n"
           "  testbed: Backtracking allocator with experimental features\n"
           "  stupid: Simple block local register allocation") ||
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -805,20 +805,18 @@ static void ReloadPrefsCallback(const ch
       Preferences::GetBool(JS_OPTIONS_DOT_STR "ion.unsafe_eager_compilation");
 #ifdef DEBUG
   bool fullJitDebugChecks =
       Preferences::GetBool(JS_OPTIONS_DOT_STR "jit.full_debug_checks");
 #endif
 
   int32_t baselineThreshold =
       Preferences::GetInt(JS_OPTIONS_DOT_STR "baselinejit.threshold", -1);
-  int32_t normalIonThreshold =
+  int32_t ionThreshold =
       Preferences::GetInt(JS_OPTIONS_DOT_STR "ion.threshold", -1);
-  int32_t fullIonThreshold =
-      Preferences::GetInt(JS_OPTIONS_DOT_STR "ion.full.threshold", -1);
   int32_t ionFrequentBailoutThreshold = Preferences::GetInt(
       JS_OPTIONS_DOT_STR "ion.frequent_bailout_threshold", -1);
 
   sDiscardSystemSource =
       Preferences::GetBool(JS_OPTIONS_DOT_STR "discardSystemSource");
 
   bool useAsyncStack = Preferences::GetBool(JS_OPTIONS_DOT_STR "asyncstack");
 
@@ -907,20 +905,18 @@ static void ReloadPrefsCallback(const ch
       JS::ContextOptionsRef(cx).disableOptionsForSafeMode();
     }
   }
 
   JS_SetParallelParsingEnabled(cx, parallelParsing);
   JS_SetOffthreadIonCompilationEnabled(cx, offthreadIonCompilation);
   JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_BASELINE_WARMUP_TRIGGER,
                                 useBaselineEager ? 0 : baselineThreshold);
-  JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_NORMAL_WARMUP_TRIGGER,
-                                useIonEager ? 0 : normalIonThreshold);
-  JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_FULL_WARMUP_TRIGGER,
-                                useIonEager ? 0 : fullIonThreshold);
+  JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_WARMUP_TRIGGER,
+                                useIonEager ? 0 : ionThreshold);
   JS_SetGlobalJitCompilerOption(cx,
                                 JSJITCOMPILER_ION_FREQUENT_BAILOUT_THRESHOLD,
                                 ionFrequentBailoutThreshold);
 
 #ifdef DEBUG
   JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_FULL_DEBUG_CHECKS,
                                 fullJitDebugChecks);
 #endif
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1465,17 +1465,16 @@ pref("javascript.options.strict.debug", 
 #endif
 pref("javascript.options.unboxed_objects",  false);
 pref("javascript.options.baselinejit",      true);
 //Duplicated in JitOptions - ensure both match.
 pref("javascript.options.baselinejit.threshold", 10);
 pref("javascript.options.ion",              true);
 //Duplicated in JitOptions - ensure both match.
 pref("javascript.options.ion.threshold",    1000);
-pref("javascript.options.ion.full.threshold", 100000);
 //Duplicated in JitOptions - ensure both match.
 pref("javascript.options.ion.frequent_bailout_threshold", 10);
 pref("javascript.options.asmjs",            true);
 pref("javascript.options.wasm",             true);
 pref("javascript.options.wasm_verbose",     false);
 pref("javascript.options.wasm_ionjit",      true);
 pref("javascript.options.wasm_baselinejit", true);
 #ifdef ENABLE_WASM_CRANELIFT