Backed out changeset 66a520c18efe (bug 1008590) for octane-mandreel regression.
authorHannes Verschore <hv1989@gmail.com>
Fri, 16 May 2014 21:21:10 +0200
changeset 183627 b729d9a177120d70ba2ec462d4006709bffaf532
parent 183626 ecf17dd38106132b5359575e6a728f66932c3a1b
child 183628 af5e255b4dee2908eec9f25eefca69fadf34ea31
push id6844
push userphilringnalda@gmail.com
push dateSun, 18 May 2014 01:12:08 +0000
treeherderfx-team@41a54c8add09 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1008590
milestone32.0a1
backs out66a520c18efefa844b682465a833960c754d00a6
Backed out changeset 66a520c18efe (bug 1008590) for octane-mandreel regression.
js/src/jit/CodeGenerator.cpp
js/src/jit/Ion.cpp
js/src/jit/Ion.h
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/MIR.h
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3346,17 +3346,16 @@ CodeGenerator::emitDebugResultChecks(LIn
       case MIRType_Object:
       case MIRType_String:
         return emitObjectOrStringResultChecks(ins, mir);
       case MIRType_Value:
         return emitValueResultChecks(ins, mir);
       default:
         return true;
     }
-    return true;
 }
 #endif
 
 bool
 CodeGenerator::generateBody()
 {
     IonScriptCounts *counts = maybeCreateScriptCounts();
 
@@ -6523,28 +6522,20 @@ CodeGenerator::link(JSContext *cx, types
                         /* resetUses */ false, /* cancelOffThread*/ false))
         {
             return false;
         }
     }
 
     // Check to make sure we didn't have a mid-build invalidation. If so, we
     // will trickle to jit::Compile() and return Method_Skipped.
-    uint32_t useCount = script->getUseCount();
     types::RecompileInfo recompileInfo;
     if (!types::FinishCompilation(cx, script, executionMode, constraints, &recompileInfo))
         return true;
 
-    // IonMonkey could have inferred better type information during
-    // compilation. Since adding the new information to the actual type
-    // information can reset the usecount, increase it back to what it was
-    // before.
-    if (useCount > script->getUseCount())
-        script->incUseCount(useCount - script->getUseCount());
-
     uint32_t scriptFrameSize = frameClass_ == FrameSizeClass::None()
                            ? frameDepth_
                            : FrameSizeClass::FromDepth(frameDepth_).frameSize();
 
     // We encode safepoints after the OSI-point offsets have been determined.
     encodeSafepoints();
 
     // List of possible scripts that this graph may call. Currently this is
@@ -8665,41 +8656,28 @@ CodeGenerator::visitAssertRangeV(LAssert
     masm.assumeUnreachable("Incorrect range for Value.");
     masm.bind(&done);
     return true;
 }
 
 typedef bool (*RecompileFn)(JSContext *);
 static const VMFunction RecompileFnInfo = FunctionInfo<RecompileFn>(Recompile);
 
-typedef bool (*ForcedRecompileFn)(JSContext *);
-static const VMFunction ForcedRecompileFnInfo = FunctionInfo<ForcedRecompileFn>(ForcedRecompile);
-
 bool
 CodeGenerator::visitRecompileCheck(LRecompileCheck *ins)
 {
     Label done;
     Register tmp = ToRegister(ins->scratch());
-    OutOfLineCode *ool;
-    if (ins->mir()->forceRecompilation())
-        ool = oolCallVM(ForcedRecompileFnInfo, ins, (ArgList()), StoreRegisterTo(tmp));
-    else
-        ool = oolCallVM(RecompileFnInfo, ins, (ArgList()), StoreRegisterTo(tmp));
+    OutOfLineCode *ool = oolCallVM(RecompileFnInfo, ins, (ArgList()), StoreRegisterTo(tmp));
 
     // Check if usecount is high enough.
-    AbsoluteAddress useCount = AbsoluteAddress(ins->mir()->script()->addressOfUseCount());
-    if (ins->mir()->increaseUseCount()) {
-        masm.load32(useCount, tmp);
-        masm.add32(Imm32(1), tmp);
-        masm.store32(tmp, useCount);
-        masm.branch32(Assembler::BelowOrEqual, tmp, Imm32(ins->mir()->recompileThreshold()), &done);
-    } else {
-        masm.branch32(Assembler::BelowOrEqual, useCount, Imm32(ins->mir()->recompileThreshold()),
-                      &done);
-    }
+    masm.movePtr(ImmPtr(ins->mir()->script()->addressOfUseCount()), tmp);
+    Address ptr(tmp, 0);
+    masm.add32(Imm32(1), tmp);
+    masm.branch32(Assembler::BelowOrEqual, ptr, Imm32(ins->mir()->recompileThreshold()), &done);
 
     // Check if not yet recompiling.
     CodeOffsetLabel label = masm.movWithPatch(ImmWord(uintptr_t(-1)), tmp);
     if (!ionScriptLabels_.append(label))
         return false;
     masm.branch32(Assembler::Equal,
                   Address(tmp, IonScript::offsetOfRecompiling()),
                   Imm32(0),
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2072,17 +2072,17 @@ GetOptimizationLevel(HandleScript script
 
     JS_ASSERT(executionMode == SequentialExecution);
 
     return js_IonOptimizations.levelForScript(script, pc);
 }
 
 static MethodStatus
 Compile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
-        bool constructing, ExecutionMode executionMode, bool forceRecompile = false)
+        bool constructing, ExecutionMode executionMode)
 {
     JS_ASSERT(jit::IsIonEnabled(cx));
     JS_ASSERT(jit::IsBaselineEnabled(cx));
     JS_ASSERT_IF(osrPc != nullptr, LoopEntryCanIonOsr(osrPc));
     JS_ASSERT_IF(executionMode == ParallelExecution, !osrFrame && !osrPc);
     JS_ASSERT_IF(executionMode == ParallelExecution, !HasIonScript(script, executionMode));
 
     if (!script->hasBaselineScript())
@@ -2109,27 +2109,45 @@ Compile(JSContext *cx, HandleScript scri
     if (optimizationLevel == Optimization_DontCompile)
         return Method_Skipped;
 
     IonScript *scriptIon = GetIonScript(script, executionMode);
     if (scriptIon) {
         if (!scriptIon->method())
             return Method_CantCompile;
 
+        MethodStatus failedState = Method_Compiled;
+
+        // If we keep failing to enter the script due to an OSR pc mismatch,
+        // recompile with the right pc.
+        if (osrPc && script->ionScript()->osrPc() != osrPc) {
+            uint32_t count = script->ionScript()->incrOsrPcMismatchCounter();
+            if (count <= js_JitOptions.osrPcMismatchesBeforeRecompile)
+                return Method_Skipped;
+
+            failedState = Method_Skipped;
+        }
+
         // Don't recompile/overwrite higher optimized code,
         // with a lower optimization level.
-        if (optimizationLevel <= scriptIon->optimizationLevel() && !forceRecompile)
-            return Method_Compiled;
+        if (optimizationLevel < scriptIon->optimizationLevel())
+            return failedState;
+
+        if (optimizationLevel == scriptIon->optimizationLevel() &&
+            (!osrPc || script->ionScript()->osrPc() == osrPc))
+        {
+            return failedState;
+        }
 
         // Don't start compiling if already compiling
         if (scriptIon->isRecompiling())
-            return Method_Compiled;
+            return failedState;
 
         if (osrPc)
-            scriptIon->resetOsrPcMismatchCounter();
+            script->ionScript()->resetOsrPcMismatchCounter();
 
         recompile = true;
     }
 
     AbortReason reason = IonCompile(cx, script, osrFrame, osrPc, constructing, executionMode,
                                     recompile, optimizationLevel);
     if (reason == AbortReason_Error)
         return Method_Error;
@@ -2138,18 +2156,21 @@ Compile(JSContext *cx, HandleScript scri
         return Method_CantCompile;
 
     if (reason == AbortReason_Alloc) {
         js_ReportOutOfMemory(cx);
         return Method_Error;
     }
 
     // Compilation succeeded or we invalidated right away or an inlining/alloc abort
-    if (HasIonScript(script, executionMode))
+    if (HasIonScript(script, executionMode)) {
+        if (osrPc && script->ionScript()->osrPc() != osrPc)
+            return Method_Skipped;
         return Method_Compiled;
+    }
     return Method_Skipped;
 }
 
 } // namespace jit
 } // namespace js
 
 // Decide if a transition from interpreter execution to Ion code should occur.
 // May compile or recompile the target JSScript.
@@ -2178,45 +2199,29 @@ jit::CanEnterAtBranch(JSContext *cx, JSS
         return Method_Skipped;
 
     // Mark as forbidden if frame can't be handled.
     if (!CheckFrame(osrFrame)) {
         ForbidCompilation(cx, script);
         return Method_CantCompile;
     }
 
-    // By default a recompilation doesn't happen on osr mismatch.
-    // Decide if we want to force a recompilation if this happens too much.
-    bool force = false;
-    if (script->hasIonScript() && pc != script->ionScript()->osrPc()) {
-        uint32_t count = script->ionScript()->incrOsrPcMismatchCounter();
-        if (count <= js_JitOptions.osrPcMismatchesBeforeRecompile)
-            return Method_Skipped;
-        force = true;
-    }
-
     // Attempt compilation.
     // - Returns Method_Compiled if the right ionscript is present
     //   (Meaning it was present or a sequantial compile finished)
+    // - Returns Method_Skipped if pc doesn't match
+    //   (This means a background thread compilation with that pc could have started or not.)
     RootedScript rscript(cx, script);
-    MethodStatus status =
-        Compile(cx, rscript, osrFrame, pc, isConstructing, SequentialExecution, force);
+    MethodStatus status = Compile(cx, rscript, osrFrame, pc, isConstructing, SequentialExecution);
     if (status != Method_Compiled) {
         if (status == Method_CantCompile)
             ForbidCompilation(cx, script);
         return status;
     }
 
-    // Return the compilation was skipped when the osr pc wasn't adjusted.
-    // This can happen when there was still an IonScript available and a
-    // background compilation started, but hasn't finished yet.
-    // Or when we didn't force a recompile.
-    if (pc != script->ionScript()->osrPc())
-        return Method_Skipped;
-
     return Method_Compiled;
 }
 
 MethodStatus
 jit::CanEnter(JSContext *cx, RunState &state)
 {
     JS_ASSERT(jit::IsIonEnabled(cx));
 
@@ -2317,24 +2322,24 @@ jit::CompileFunctionForBaseline(JSContex
         return status;
     }
 
     return Method_Compiled;
 }
 
 MethodStatus
 jit::Recompile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
-               bool constructing, bool force)
+               bool constructing)
 {
     JS_ASSERT(script->hasIonScript());
     if (script->ionScript()->isRecompiling())
         return Method_Compiled;
 
     MethodStatus status =
-        Compile(cx, script, osrFrame, osrPc, constructing, SequentialExecution, force);
+        Compile(cx, script, osrFrame, osrPc, constructing, SequentialExecution);
     if (status != Method_Compiled) {
         if (status == Method_CantCompile)
             ForbidCompilation(cx, script);
         return status;
     }
 
     return Method_Compiled;
 }
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -90,17 +90,17 @@ MethodStatus CanEnter(JSContext *cx, Run
 MethodStatus CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFrame *frame,
                                         bool isConstructing);
 MethodStatus CanEnterUsingFastInvoke(JSContext *cx, HandleScript script, uint32_t numActualArgs);
 
 MethodStatus CanEnterInParallel(JSContext *cx, HandleScript script);
 
 MethodStatus
 Recompile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
-          bool constructing, bool force);
+          bool constructing);
 
 enum IonExecStatus
 {
     // The method call had to be aborted due to a stack limit check. This
     // error indicates that Ion never attempted to clean up frames.
     IonExec_Aborted,
 
     // The method call resulted in an error, and IonMonkey has cleaned up
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -4171,19 +4171,17 @@ IonBuilder::makeInliningDecision(JSFunct
             return DontInline(targetScript, "Vetoed: callee excessively large");
 
         // Callee must have been called a few times to have somewhat stable
         // type information, except for definite properties analysis,
         // as the caller has not run yet.
         if (targetScript->getUseCount() < optimizationInfo().usesBeforeInlining() &&
             info().executionMode() != DefinitePropertiesAnalysis)
         {
-            IonSpew(IonSpew_Inlining, "Cannot inline %s:%u: callee is insufficiently hot.",
-                    targetScript->filename(), targetScript->lineno());
-            return InliningDecision_UseCountTooLow;
+            return DontInline(targetScript, "Vetoed: callee is insufficiently hot.");
         }
     }
 
     // TI calls ObjectStateChange to trigger invalidation of the caller.
     types::TypeObjectKey *targetType = types::TypeObjectKey::get(target);
     targetType->watchStateChangeForInlinedCall(constraints());
 
     return InliningDecision_Inline;
@@ -4208,17 +4206,16 @@ IonBuilder::selectInliningTargets(Object
     for (size_t i = 0; i < targets.length(); i++) {
         JSFunction *target = &targets[i]->as<JSFunction>();
         bool inlineable;
         InliningDecision decision = makeInliningDecision(target, callInfo);
         switch (decision) {
           case InliningDecision_Error:
             return false;
           case InliningDecision_DontInline:
-          case InliningDecision_UseCountTooLow:
             inlineable = false;
             break;
           case InliningDecision_Inline:
             inlineable = true;
             break;
           default:
             MOZ_ASSUME_UNREACHABLE("Unhandled InliningDecision value!");
         }
@@ -4329,18 +4326,16 @@ IonBuilder::inlineCallsite(ObjectVector 
     if (!propCache && targets.length() == 1) {
         JSFunction *target = &targets[0]->as<JSFunction>();
         InliningDecision decision = makeInliningDecision(target, callInfo);
         switch (decision) {
           case InliningDecision_Error:
             return InliningStatus_Error;
           case InliningDecision_DontInline:
             return InliningStatus_NotInlined;
-          case InliningDecision_UseCountTooLow:
-            return InliningStatus_UseCountTooLow;
           case InliningDecision_Inline:
             break;
         }
 
         // Inlining will elminate uses of the original callee, but it needs to
         // be preserved in phis if we bail out.  Mark the old callee definition as
         // implicitly used to ensure this happens.
         callInfo.fun()->setImplicitlyUsedUnchecked();
@@ -4955,17 +4950,16 @@ IonBuilder::jsop_funcall(uint32_t argc)
 
     // Try to inline the call.
     if (!zeroArguments) {
         InliningDecision decision = makeInliningDecision(target, callInfo);
         switch (decision) {
           case InliningDecision_Error:
             return false;
           case InliningDecision_DontInline:
-          case InliningDecision_UseCountTooLow:
             break;
           case InliningDecision_Inline:
             if (target->isInterpreted())
                 return inlineScriptedCall(callInfo, target);
             break;
         }
     }
 
@@ -5096,17 +5090,16 @@ IonBuilder::jsop_funapplyarguments(uint3
     nativeFunc->setImplicitlyUsedUnchecked();
 
     // Try to inline the call.
     InliningDecision decision = makeInliningDecision(target, callInfo);
     switch (decision) {
       case InliningDecision_Error:
         return false;
       case InliningDecision_DontInline:
-      case InliningDecision_UseCountTooLow:
         break;
       case InliningDecision_Inline:
         if (target->isInterpreted())
             return inlineScriptedCall(callInfo, target);
     }
 
     return makeCall(target, callInfo, false);
 }
@@ -5167,23 +5160,16 @@ IonBuilder::jsop_call(uint32_t argc, boo
     if (status == InliningStatus_Error)
         return false;
 
     // No inline, just make the call.
     JSFunction *target = nullptr;
     if (targets.length() == 1)
         target = &targets[0]->as<JSFunction>();
 
-    if (target && status == InliningStatus_UseCountTooLow) {
-        MRecompileCheck *check = MRecompileCheck::New(alloc(), target->nonLazyScript(),
-                                                      optimizationInfo().usesBeforeInlining(),
-                                                      MRecompileCheck::RecompileCheck_Inlining);
-        current->add(check);
-    }
-
     return makeCall(target, callInfo, hasClones);
 }
 
 MDefinition *
 IonBuilder::makeCallsiteClone(JSFunction *target, MDefinition *fun)
 {
     // Bake in the clone eagerly if we have a known target. We have arrived here
     // because TI told us that the known target is a should-clone-at-callsite
@@ -6146,20 +6132,17 @@ IonBuilder::insertRecompileCheck()
     while (topBuilder->callerBuilder_)
         topBuilder = topBuilder->callerBuilder_;
 
     // Add recompile check to recompile when the usecount reaches the usecount
     // of the next optimization level.
     OptimizationLevel nextLevel = js_IonOptimizations.nextLevel(curLevel);
     const OptimizationInfo *info = js_IonOptimizations.get(nextLevel);
     uint32_t useCount = info->usesBeforeCompile(topBuilder->script());
-
-    MRecompileCheck *check = MRecompileCheck::New(alloc(), topBuilder->script(), useCount,
-                                MRecompileCheck::RecompileCheck_OptimizationLevel);
-    current->add(check);
+    current->add(MRecompileCheck::New(alloc(), topBuilder->script(), useCount));
 }
 
 JSObject *
 IonBuilder::testSingletonProperty(JSObject *obj, PropertyName *name)
 {
     // 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
@@ -8881,17 +8864,16 @@ IonBuilder::getPropTryCommonGetter(bool 
     // Inline if we can, otherwise, forget it and just generate a call.
     bool inlineable = false;
     if (commonGetter->isInterpreted()) {
         InliningDecision decision = makeInliningDecision(commonGetter, callInfo);
         switch (decision) {
           case InliningDecision_Error:
             return false;
           case InliningDecision_DontInline:
-          case InliningDecision_UseCountTooLow:
             break;
           case InliningDecision_Inline:
             inlineable = true;
             break;
         }
     }
 
     if (inlineable) {
@@ -9298,17 +9280,16 @@ IonBuilder::setPropTryCommonSetter(bool 
 
     // Inline the setter if we can.
     if (commonSetter->isInterpreted()) {
         InliningDecision decision = makeInliningDecision(commonSetter, callInfo);
         switch (decision) {
           case InliningDecision_Error:
             return false;
           case InliningDecision_DontInline:
-          case InliningDecision_UseCountTooLow:
             break;
           case InliningDecision_Inline:
             if (!inlineScriptedCall(callInfo, commonSetter))
                 return false;
             *emitted = true;
             return true;
         }
     }
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -628,26 +628,24 @@ class IonBuilder : public MIRGenerator
     bool jsop_setaliasedvar(ScopeCoordinate sc);
 
     /* Inlining. */
 
     enum InliningStatus
     {
         InliningStatus_Error,
         InliningStatus_NotInlined,
-        InliningStatus_UseCountTooLow,
         InliningStatus_Inlined
     };
 
     enum InliningDecision
     {
         InliningDecision_Error,
         InliningDecision_Inline,
-        InliningDecision_DontInline,
-        InliningDecision_UseCountTooLow
+        InliningDecision_DontInline
     };
 
     static InliningDecision DontInline(JSScript *targetScript, const char *reason);
 
     // Oracles.
     InliningDecision canInlineTarget(JSFunction *target, CallInfo &callInfo);
     InliningDecision makeInliningDecision(JSFunction *target, CallInfo &callInfo);
     bool selectInliningTargets(ObjectVector &targets, CallInfo &callInfo,
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -9864,73 +9864,41 @@ class MHasClass
     }
 };
 
 // Increase the usecount of the provided script upon execution and test if
 // the usecount surpasses the threshold. Upon hit it will recompile the
 // outermost script (i.e. not the inlined script).
 class MRecompileCheck : public MNullaryInstruction
 {
-  public:
-    enum RecompileCheckType {
-        RecompileCheck_OptimizationLevel,
-        RecompileCheck_Inlining
-    };
-
-  private:
     JSScript *script_;
     uint32_t recompileThreshold_;
-    bool forceRecompilation_;
-    bool increaseUseCount_;
-
-    MRecompileCheck(JSScript *script, uint32_t recompileThreshold, RecompileCheckType type)
+
+    MRecompileCheck(JSScript *script, uint32_t recompileThreshold)
       : script_(script),
         recompileThreshold_(recompileThreshold)
     {
-        switch (type) {
-          case RecompileCheck_OptimizationLevel:
-            forceRecompilation_ = false;
-            increaseUseCount_ = true;
-            break;
-          case RecompileCheck_Inlining:
-            forceRecompilation_ = true;
-            increaseUseCount_ = false;
-            break;
-          default:
-            MOZ_ASSUME_UNREACHABLE("Unexpected recompile check type");
-        }
-
         setGuard();
     }
 
   public:
     INSTRUCTION_HEADER(RecompileCheck);
 
-    static MRecompileCheck *New(TempAllocator &alloc, JSScript *script_,
-                                uint32_t useCount, RecompileCheckType type)
-    {
-        return new(alloc) MRecompileCheck(script_, useCount, type);
+    static MRecompileCheck *New(TempAllocator &alloc, JSScript *script_, uint32_t useCount) {
+        return new(alloc) MRecompileCheck(script_, useCount);
     }
 
     JSScript *script() const {
         return script_;
     }
 
     uint32_t recompileThreshold() const {
         return recompileThreshold_;
     }
 
-    bool forceRecompilation() const {
-        return forceRecompilation_;
-    }
-
-    bool increaseUseCount() const {
-        return increaseUseCount_;
-    }
-
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MAsmJSNeg : public MUnaryInstruction
 {
     MAsmJSNeg(MDefinition *op, MIRType type)
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1018,53 +1018,41 @@ StringReplace(JSContext *cx, HandleStrin
 
     RootedValue rval(cx);
     if (!str_replace_string_raw(cx, string, pattern, repl, &rval))
         return nullptr;
 
     return rval.toString();
 }
 
-static bool
-RecompileImpl(JSContext *cx, bool force)
+bool
+Recompile(JSContext *cx)
 {
     JS_ASSERT(cx->currentlyRunningInJit());
     JitActivationIterator activations(cx->runtime());
     JitFrameIterator iter(activations);
 
     JS_ASSERT(iter.type() == JitFrame_Exit);
     ++iter;
 
     bool isConstructing = iter.isConstructing();
     RootedScript script(cx, iter.script());
     JS_ASSERT(script->hasIonScript());
 
     if (!IsIonEnabled(cx))
         return true;
 
-    MethodStatus status = Recompile(cx, script, nullptr, nullptr, isConstructing, force);
+    MethodStatus status = Recompile(cx, script, nullptr, nullptr, isConstructing);
     if (status == Method_Error)
         return false;
 
     return true;
 }
 
 bool
-ForcedRecompile(JSContext *cx)
-{
-    return RecompileImpl(cx, /* force = */ true);
-}
-
-bool
-Recompile(JSContext *cx)
-{
-    return RecompileImpl(cx, /* force = */ false);
-}
-
-bool
 SetDenseElement(JSContext *cx, HandleObject 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, has no indexed properties
     // and we can use setDenseElement instead of setDenseElementWithType.
 
     MOZ_ASSERT(obj->isNative());
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -671,17 +671,16 @@ bool InitBaselineFrameForOsr(BaselineFra
                              uint32_t numStackValues);
 
 JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject descr,
                                 HandleObject owner, int32_t offset);
 
 bool ArraySpliceDense(JSContext *cx, HandleObject obj, uint32_t start, uint32_t deleteCount);
 
 bool Recompile(JSContext *cx);
-bool ForcedRecompile(JSContext *cx);
 JSString *RegExpReplace(JSContext *cx, HandleString string, HandleObject regexp,
                         HandleString repl);
 JSString *StringReplace(JSContext *cx, HandleString string, HandleString pattern,
                         HandleString repl);
 
 bool SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue value,
                      bool strict);