diff --git a/js/src/jit/Bailouts.cpp b/js/src/jit/Bailouts.cpp index 00d35450c9a1..284f29585b3b 100644 --- a/js/src/jit/Bailouts.cpp +++ b/js/src/jit/Bailouts.cpp @@ -40,6 +40,7 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo) JitActivationIterator jitActivations(cx->runtime()); BailoutFrameInfo bailoutData(jitActivations, sp); JitFrameIterator iter(jitActivations); + MOZ_ASSERT(!iter.ionScript()->invalidated()); TraceLogger *logger = TraceLoggerForMainThread(cx->runtime()); TraceLogTimestamp(logger, TraceLogger::Bailout); @@ -78,6 +79,17 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo) EnsureExitFrame(iter.jsFrame()); } + // This condition was wrong when we entered this bailout function, but it + // might be true now. A GC might have reclaimed all the Jit code and + // invalidated all frames which are currently on the stack. As we are + // already in a bailout, we could not switch to an invalidation + // bailout. When the code of an IonScript which is on the stack is + // invalidated (see InvalidateActivation), we remove references to it and + // increment the reference counter for each activation that appear on the + // stack. As the bailed frame is one of them, we have to decrement it now. + if (iter.ionScript()->invalidated()) + iter.ionScript()->decref(cx->runtime()->defaultFreeOp()); + return retval; } diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 5ecd91d4f725..59f60ac57f05 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -2683,7 +2683,7 @@ InvalidateActivation(FreeOp *fop, const JitActivationIterator &activations, bool size_t frameno = 1; for (JitFrameIterator it(activations); !it.done(); ++it, ++frameno) { - MOZ_ASSERT_IF(frameno == 1, it.type() == JitFrame_Exit); + MOZ_ASSERT_IF(frameno == 1, it.type() == JitFrame_Exit || it.type() == JitFrame_Bailout); #ifdef DEBUG switch (it.type()) { @@ -2725,7 +2725,7 @@ InvalidateActivation(FreeOp *fop, const JitActivationIterator &activations, bool } #endif - if (!it.isIonJS()) + if (!it.isIonScripted()) continue; bool calledFromLinkStub = false; @@ -2793,8 +2793,9 @@ InvalidateActivation(FreeOp *fop, const JitActivationIterator &activations, bool } ionCode->setInvalidated(); - // Don't adjust OSI points in the linkStub (which don't exist). - if (calledFromLinkStub) + // Don't adjust OSI points in the linkStub (which don't exist), or in a + // bailout path. + if (calledFromLinkStub || it.isBailoutJS()) continue; // Write the delta (from the return address offset to the diff --git a/js/src/jit/IonFrames.cpp b/js/src/jit/IonFrames.cpp index 53fd943c1e79..fbfc919e2f59 100644 --- a/js/src/jit/IonFrames.cpp +++ b/js/src/jit/IonFrames.cpp @@ -140,8 +140,13 @@ JitFrameIterator::checkInvalidation() const bool JitFrameIterator::checkInvalidation(IonScript **ionScriptOut) const { - uint8_t *returnAddr = returnAddressToFp(); JSScript *script = this->script(); + if (isBailoutJS()) { + *ionScriptOut = activation_->bailoutData()->ionScript(); + return !script->hasIonScript() || script->ionScript() != *ionScriptOut; + } + + uint8_t *returnAddr = returnAddressToFp(); // N.B. the current IonScript is not the same as the frame's // IonScript if the frame has since been invalidated. bool invalidated;