Bug 1070962 part 6 - IonBailoutIterator no longer inherit from JitFrameIterator. r=jandem
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Mon, 13 Oct 2014 17:34:01 +0200
changeset 210195 bd068c8342fc9f49df74a230842b245e0900ef27
parent 210194 3fe372c4fe4e1f89e234bd2f19eb198d7baa9c3a
child 210196 ebcb03acce644efd2f399944cf5e2f6f2b6f1eb6
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjandem
bugs1070962
milestone35.0a1
Bug 1070962 part 6 - IonBailoutIterator no longer inherit from JitFrameIterator. r=jandem
js/src/jit/Bailouts.cpp
js/src/jit/Bailouts.h
js/src/jit/BaselineBailouts.cpp
js/src/jit/BaselineJIT.h
js/src/jit/IonFrames.cpp
js/src/jit/JitFrameIterator.h
js/src/jit/ParallelFunctions.cpp
js/src/jit/arm/Bailouts-arm.cpp
js/src/jit/mips/Bailouts-mips.cpp
js/src/jit/none/Trampoline-none.cpp
js/src/jit/x64/Bailouts-x64.cpp
js/src/jit/x86/Bailouts-x86.cpp
js/src/vm/ForkJoin.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -19,90 +19,42 @@
 #include "vm/Probes-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::IsInRange;
 
-// These constructor are exactly the same except for the type of the iterator
-// which is given to the SnapshotIterator constructor. Doing so avoid the
-// creation of virtual functions for the IonIterator but may introduce some
-// weirdness as IonInlineIterator is using a JitFrameIterator reference.
-//
-// If a function relies on ionScript() or to use OsiIndex(), due to the
-// lack of virtual, these functions will use the JitFrameIterator reference
-// contained in the InlineFrameIterator and thus are not able to recover
-// correctly the data stored in IonBailoutIterator.
-//
-// Currently, such cases should not happen because our only use case of the
-// JitFrameIterator within InlineFrameIterator is to read the frame content, or
-// to clone it to find the parent scripted frame.  Both use cases are fine and
-// should not cause any issue since the only potential issue is to read the
-// bailed out frame.
-
-SnapshotIterator::SnapshotIterator(const IonBailoutIterator &iter)
-  : snapshot_(iter.ionScript()->snapshots(),
-              iter.snapshotOffset(),
-              iter.ionScript()->snapshotsRVATableSize(),
-              iter.ionScript()->snapshotsListSize()),
-    recover_(snapshot_,
-             iter.ionScript()->recovers(),
-             iter.ionScript()->recoversSize()),
-    fp_(iter.jsFrame()),
-    machine_(iter.machineState()),
-    ionScript_(iter.ionScript()),
-    instructionResults_(nullptr)
-{
-}
-
-void
-IonBailoutIterator::dump() const
-{
-    if (type_ == JitFrame_IonJS) {
-        InlineFrameIterator frames(GetJSContextFromJitCode(), this);
-        for (;;) {
-            frames.dump();
-            if (!frames.more())
-                break;
-            ++frames;
-        }
-    } else {
-        JitFrameIterator::dump();
-    }
-}
-
 uint32_t
 jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
 {
     JSContext *cx = GetJSContextFromJitCode();
     MOZ_ASSERT(bailoutInfo);
 
     // We don't have an exit frame.
     MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
                IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000),
                "Fake jitTop pointer should be within the first page.");
     cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
     gc::AutoSuppressGC suppress(cx);
 
     JitActivationIterator jitActivations(cx->runtime());
-    IonBailoutIterator iter(jitActivations, sp);
-    JitActivation *activation = jitActivations->asJit();
-    JitActivation::RegisterBailoutIterator registerIterator(*activation, &iter);
+    BailoutFrameInfo bailoutData(jitActivations, sp);
+    JitFrameIterator iter(jitActivations);
 
     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
     TraceLogTimestamp(logger, TraceLogger::Bailout);
 
     JitSpew(JitSpew_IonBailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());
 
     MOZ_ASSERT(IsBaselineEnabled(cx));
 
     *bailoutInfo = nullptr;
-    uint32_t retval = BailoutIonToBaseline(cx, activation, iter, false, bailoutInfo);
+    uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, false, bailoutInfo);
     MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
                retval == BAILOUT_RETURN_FATAL_ERROR ||
                retval == BAILOUT_RETURN_OVERRECURSED);
     MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
 
     if (retval != BAILOUT_RETURN_OK) {
         // If the bailout failed, then bailout trampoline will pop the
         // current frame and jump straight to exception handling code when
@@ -134,32 +86,31 @@ jit::InvalidationBailout(InvalidationBai
 
     JSContext *cx = GetJSContextFromJitCode();
 
     // We don't have an exit frame.
     cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
     gc::AutoSuppressGC suppress(cx);
 
     JitActivationIterator jitActivations(cx->runtime());
-    IonBailoutIterator iter(jitActivations, sp);
-    JitActivation *activation = jitActivations->asJit();
-    JitActivation::RegisterBailoutIterator registerIterator(*activation, &iter);
+    BailoutFrameInfo bailoutData(jitActivations, sp);
+    JitFrameIterator iter(jitActivations);
 
     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
     TraceLogTimestamp(logger, TraceLogger::Invalidation);
 
     JitSpew(JitSpew_IonBailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());
 
     // Note: the frame size must be computed before we return from this function.
-    *frameSizeOut = iter.topFrameSize();
+    *frameSizeOut = iter.frameSize();
 
     MOZ_ASSERT(IsBaselineEnabled(cx));
 
     *bailoutInfo = nullptr;
-    uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, bailoutInfo);
+    uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, bailoutInfo);
     MOZ_ASSERT(retval == BAILOUT_RETURN_OK ||
                retval == BAILOUT_RETURN_FATAL_ERROR ||
                retval == BAILOUT_RETURN_OVERRECURSED);
     MOZ_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
 
     if (retval != BAILOUT_RETURN_OK) {
         // If the bailout failed, then bailout trampoline will pop the
         // current frame and jump straight to exception handling code when
@@ -192,29 +143,26 @@ jit::InvalidationBailout(InvalidationBai
         JitSpew(JitSpew_IonInvalidate, "   new  ra %p", (void *) frame->returnAddress());
     }
 
     iter.ionScript()->decref(cx->runtime()->defaultFreeOp());
 
     return retval;
 }
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       const JitFrameIterator &frame)
-  : JitFrameIterator(activations),
-    machine_(frame.machineState())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   const JitFrameIterator &frame)
+  : machine_(frame.machineState())
 {
-    kind_ = Kind_BailoutIterator;
-    returnAddressToFp_ = frame.returnAddressToFp();
+    framePointer_ = (uint8_t *) frame.fp();
+    topFrameSize_ = frame.frameSize();
     topIonScript_ = frame.ionScript();
+    attachOnJitActivation(activations);
+
     const OsiIndex *osiIndex = frame.osiIndex();
-
-    current_ = (uint8_t *) frame.fp();
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = frame.frameSize();
     snapshotOffset_ = osiIndex->snapshotOffset();
 }
 
 uint32_t
 jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
                              ResumeFromException *rfe,
                              const ExceptionBailoutInfo &excInfo,
                              bool *overrecursed)
@@ -223,22 +171,21 @@ jit::ExceptionHandlerBailout(JSContext *
     // actual exception pending. For instance, when we return false from an
     // operation callback like a timeout handler.
     MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending());
 
     cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
     gc::AutoSuppressGC suppress(cx);
 
     JitActivationIterator jitActivations(cx->runtime());
-    IonBailoutIterator iter(jitActivations, frame.frame());
-    JitActivation *activation = jitActivations->asJit();
-    JitActivation::RegisterBailoutIterator registerIterator(*activation, &iter);
+    BailoutFrameInfo bailoutData(jitActivations, frame.frame());
+    JitFrameIterator iter(jitActivations);
 
     BaselineBailoutInfo *bailoutInfo = nullptr;
-    uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, &bailoutInfo, &excInfo);
+    uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, &bailoutInfo, &excInfo);
 
     if (retval == BAILOUT_RETURN_OK) {
         MOZ_ASSERT(bailoutInfo);
 
         // Overwrite the kind so HandleException after the bailout returns
         // false, jumping directly to the exception tail.
         if (excInfo.propagatingIonExceptionForDebugMode())
             bailoutInfo->bailoutKind = Bailout_IonExceptionDebugMode;
@@ -295,8 +242,21 @@ jit::CheckFrequentBailouts(JSContext *cx
 
             if (!Invalidate(cx, script))
                 return false;
         }
     }
 
     return true;
 }
+
+void
+BailoutFrameInfo::attachOnJitActivation(const JitActivationIterator &jitActivations)
+{
+    MOZ_ASSERT(jitActivations.jitTop() == FAKE_JIT_TOP_FOR_BAILOUT);
+    activation_ = jitActivations->asJit();
+    activation_->setBailoutData(this);
+}
+
+BailoutFrameInfo::~BailoutFrameInfo()
+{
+    activation_->cleanBailoutData();
+}
--- a/js/src/jit/Bailouts.h
+++ b/js/src/jit/Bailouts.h
@@ -108,54 +108,54 @@ class JitCompartment;
 
 // BailoutStack is an architecture specific pointer to the stack, given by the
 // bailout handler.
 class BailoutStack;
 class InvalidationBailoutStack;
 
 // Must be implemented by each architecture.
 
-// This iterator is constructed at a time where there is no exit frame at the
-// moment. They must be initialized to the first JS frame instead of the exit
-// frame as usually done with JitFrameIterator.
-class IonBailoutIterator : public JitFrameIterator
+// This structure is constructed before recovering the baseline frames for a
+// bailout. It records all information extracted from the stack, and which are
+// needed for the JitFrameIterator.
+class BailoutFrameInfo
 {
     MachineState machine_;
-    uint32_t snapshotOffset_;
+    uint8_t *framePointer_;
     size_t topFrameSize_;
     IonScript *topIonScript_;
+    uint32_t snapshotOffset_;
+    JitActivation *activation_;
+
+    void attachOnJitActivation(const JitActivationIterator &activations);
 
   public:
-    IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *sp);
-    IonBailoutIterator(const JitActivationIterator &activations, InvalidationBailoutStack *sp);
-    IonBailoutIterator(const JitActivationIterator &activations, const JitFrameIterator &frame);
+    BailoutFrameInfo(const JitActivationIterator &activations, BailoutStack *sp);
+    BailoutFrameInfo(const JitActivationIterator &activations, InvalidationBailoutStack *sp);
+    BailoutFrameInfo(const JitActivationIterator &activations, const JitFrameIterator &frame);
+    ~BailoutFrameInfo();
 
+    uint8_t *fp() const {
+        return framePointer_;
+    }
     SnapshotOffset snapshotOffset() const {
-        if (topIonScript_)
-            return snapshotOffset_;
-        return osiIndex()->snapshotOffset();
+        return snapshotOffset_;
     }
     const MachineState machineState() const {
-        if (topIonScript_)
-            return machine_;
-        return JitFrameIterator::machineState();
+        return machine_;
     }
     size_t topFrameSize() const {
-        MOZ_ASSERT(topIonScript_);
         return topFrameSize_;
     }
     IonScript *ionScript() const {
-        if (topIonScript_)
-            return topIonScript_;
-        return JitFrameIterator::ionScript();
+        return topIonScript_;
     }
-
-    IonBailoutIterator &operator++() MOZ_DELETE;
-
-    void dump() const;
+    JitActivation *activation() const {
+        return activation_;
+    }
 };
 
 bool EnsureHasScopeObjects(JSContext *cx, AbstractFramePtr fp);
 
 struct BaselineBailoutInfo;
 
 // Called from a bailout thunk. Returns a BAILOUT_* error code.
 uint32_t Bailout(BailoutStack *sp, BaselineBailoutInfo **info);
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -69,41 +69,42 @@ class BufferPointer
  * needs to be enlarged to accomodate new data.  Similarly to the C stack, the
  * data that's written to the reconstructed stack grows from high to low in memory.
  *
  * The lowest region of the allocated memory contains a BaselineBailoutInfo structure that
  * points to the start and end of the written data.
  */
 struct BaselineStackBuilder
 {
-    IonBailoutIterator &iter_;
+    JitFrameIterator &iter_;
     IonJSFrameLayout *frame_;
 
     static size_t HeaderSize() {
         return AlignBytes(sizeof(BaselineBailoutInfo), sizeof(void *));
     }
     size_t bufferTotal_;
     size_t bufferAvail_;
     size_t bufferUsed_;
     uint8_t *buffer_;
     BaselineBailoutInfo *header_;
 
     size_t framePushed_;
 
-    BaselineStackBuilder(IonBailoutIterator &iter, size_t initialSize)
+    BaselineStackBuilder(JitFrameIterator &iter, size_t initialSize)
       : iter_(iter),
         frame_(static_cast<IonJSFrameLayout*>(iter.current())),
         bufferTotal_(initialSize),
         bufferAvail_(0),
         bufferUsed_(0),
         buffer_(nullptr),
         header_(nullptr),
         framePushed_(0)
     {
         MOZ_ASSERT(bufferTotal_ >= HeaderSize());
+        MOZ_ASSERT(iter.isBailoutJS());
     }
 
     ~BaselineStackBuilder() {
         js_free(buffer_);
     }
 
     bool init() {
         MOZ_ASSERT(!buffer_);
@@ -382,20 +383,21 @@ struct BaselineStackBuilder
 // Ensure that all value locations are readable from the SnapshotIterator.
 // Remove RInstructionResults from the JitActivation if the frame got recovered
 // ahead of the bailout.
 class SnapshotIteratorForBailout : public SnapshotIterator
 {
     RInstructionResults results_;
   public:
 
-    SnapshotIteratorForBailout(const IonBailoutIterator &iter)
+    SnapshotIteratorForBailout(const JitFrameIterator &iter)
       : SnapshotIterator(iter),
         results_(iter.jsFrame())
     {
+        MOZ_ASSERT(iter.isBailoutJS());
     }
 
     // Take previously computed result out of the activation, or compute the
     // results of all recover instructions contained in the snapshot.
     bool init(JSContext *cx, JitActivation *activation) {
         activation->maybeTakeIonFrameRecovery(fp_, &results_);
         if (!results_.isInitialized() && !computeInstructionResults(cx, &results_))
             return false;
@@ -1282,17 +1284,17 @@ InitFromBailout(JSContext *cx, HandleScr
     MOZ_ASSERT(rectReturnAddr);
     if (!builder.writePtr(rectReturnAddr, "ReturnAddr"))
         return false;
 
     return true;
 }
 
 uint32_t
-jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &iter,
+jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter,
                           bool invalidate, BaselineBailoutInfo **bailoutInfo,
                           const ExceptionBailoutInfo *excInfo)
 {
     // The Baseline frames we will reconstruct on the heap are not rooted, so GC
     // must be suppressed here.
     MOZ_ASSERT(cx->mainThread().suppressGC);
 
     MOZ_ASSERT(bailoutInfo != nullptr);
@@ -1302,17 +1304,17 @@ jit::BailoutIonToBaseline(JSContext *cx,
     TraceLogStopEvent(logger, TraceLogger::IonMonkey);
     TraceLogStartEvent(logger, TraceLogger::Baseline);
 
     // The caller of the top frame must be one of the following:
     //      IonJS - Ion calling into Ion.
     //      BaselineStub - Baseline calling into Ion.
     //      Entry - Interpreter or other calling into Ion.
     //      Rectifier - Arguments rectifier calling into Ion.
-    MOZ_ASSERT(iter.isIonJS());
+    MOZ_ASSERT(iter.isBailoutJS());
     FrameType prevFrameType = iter.prevType();
     MOZ_ASSERT(prevFrameType == JitFrame_IonJS ||
                prevFrameType == JitFrame_BaselineStub ||
                prevFrameType == JitFrame_Entry ||
                prevFrameType == JitFrame_Rectifier);
 
     // All incoming frames are going to look like this:
     //
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -432,17 +432,17 @@ struct BaselineBailoutInfo
     // Number of baseline frames to push on the stack.
     uint32_t numFrames;
 
     // The bailout kind.
     BailoutKind bailoutKind;
 };
 
 uint32_t
-BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &iter,
+BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIterator &iter,
                      bool invalidate, BaselineBailoutInfo **bailoutInfo,
                      const ExceptionBailoutInfo *exceptionInfo = nullptr);
 
 // Mark baseline scripts on the stack as active, so that they are not discarded
 // during GC.
 void
 MarkActiveBaselineScripts(Zone *zone);
 
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -81,69 +81,54 @@ ReadFrameBooleanSlot(IonJSFrameLayout *f
 }
 
 JitFrameIterator::JitFrameIterator()
   : current_(nullptr),
     type_(JitFrame_Exit),
     returnAddressToFp_(nullptr),
     frameSize_(0),
     mode_(SequentialExecution),
-    kind_(Kind_FrameIterator),
     cachedSafepointIndex_(nullptr),
     activation_(nullptr)
 {
 }
 
 JitFrameIterator::JitFrameIterator(ThreadSafeContext *cx)
   : current_(cx->perThreadData->jitTop),
     type_(JitFrame_Exit),
     returnAddressToFp_(nullptr),
     frameSize_(0),
     mode_(cx->isForkJoinContext() ? ParallelExecution : SequentialExecution),
-    kind_(Kind_FrameIterator),
     cachedSafepointIndex_(nullptr),
     activation_(cx->perThreadData->activation()->asJit())
 {
     if (activation_->bailoutData()) {
         current_ = activation_->bailoutData()->fp();
+        frameSize_ = activation_->bailoutData()->topFrameSize();
         type_ = JitFrame_Bailout;
     }
 }
 
 JitFrameIterator::JitFrameIterator(const ActivationIterator &activations)
   : current_(activations.jitTop()),
     type_(JitFrame_Exit),
     returnAddressToFp_(nullptr),
     frameSize_(0),
     mode_(activations->asJit()->cx()->isForkJoinContext() ? ParallelExecution
                                                           : SequentialExecution),
-    kind_(Kind_FrameIterator),
     cachedSafepointIndex_(nullptr),
     activation_(activations->asJit())
 {
     if (activation_->bailoutData()) {
         current_ = activation_->bailoutData()->fp();
+        frameSize_ = activation_->bailoutData()->topFrameSize();
         type_ = JitFrame_Bailout;
     }
 }
 
-IonBailoutIterator *
-JitFrameIterator::asBailoutIterator()
-{
-    MOZ_ASSERT(isBailoutIterator());
-    return static_cast<IonBailoutIterator *>(this);
-}
-
-const IonBailoutIterator *
-JitFrameIterator::asBailoutIterator() const
-{
-    MOZ_ASSERT(isBailoutIterator());
-    return static_cast<const IonBailoutIterator *>(this);
-}
-
 bool
 JitFrameIterator::checkInvalidation() const
 {
     IonScript *dummy;
     return checkInvalidation(&dummy);
 }
 
 bool
@@ -1933,17 +1918,17 @@ SnapshotIterator::maybeReadAllocByIndex(
     return s;
 }
 
 IonJSFrameLayout *
 JitFrameIterator::jsFrame() const
 {
     MOZ_ASSERT(isScripted());
     if (isBailoutJS())
-        return activation_->bailoutData()->jsFrame();
+        return (IonJSFrameLayout *) activation_->bailoutData()->fp();
 
     return (IonJSFrameLayout *) fp();
 }
 
 IonScript *
 JitFrameIterator::ionScript() const
 {
     MOZ_ASSERT(isIonScripted());
@@ -2007,41 +1992,25 @@ InlineFrameIterator::InlineFrameIterator
 
 InlineFrameIterator::InlineFrameIterator(JSRuntime *rt, const JitFrameIterator *iter)
   : callee_(rt),
     script_(rt)
 {
     resetOn(iter);
 }
 
-InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const IonBailoutIterator *iter)
-  : frame_(iter),
-    framesRead_(0),
-    frameCount_(UINT32_MAX),
-    callee_(cx),
-    script_(cx)
-{
-    if (iter) {
-        start_ = SnapshotIterator(*iter);
-        findNextFrame();
-    }
-}
-
 InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const InlineFrameIterator *iter)
   : frame_(iter ? iter->frame_ : nullptr),
     framesRead_(0),
     frameCount_(iter ? iter->frameCount_ : UINT32_MAX),
     callee_(cx),
     script_(cx)
 {
     if (frame_) {
-        if (frame_->isBailoutIterator())
-            start_ = SnapshotIterator(*frame_->asBailoutIterator());
-        else
-            start_ = SnapshotIterator(*frame_);
+        start_ = SnapshotIterator(*frame_);
 
         // findNextFrame will iterate to the next frame and init. everything.
         // Therefore to settle on the same frame, we report one frame less readed.
         framesRead_ = iter->framesRead_ - 1;
         findNextFrame();
     }
 }
 
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -75,52 +75,41 @@ enum ReadFrameArgsBehavior {
 
     // Read all args (i.e. [0 ... numActuals()])
     ReadFrame_Actuals
 };
 
 class IonCommonFrameLayout;
 class IonJSFrameLayout;
 class IonExitFrameLayout;
-class IonBailoutIterator;
 
 class BaselineFrame;
 
 class JitActivation;
 
 class JitFrameIterator
 {
   protected:
     uint8_t *current_;
     FrameType type_;
     uint8_t *returnAddressToFp_;
     size_t frameSize_;
     ExecutionMode mode_;
-    enum Kind {
-        Kind_FrameIterator,
-        Kind_BailoutIterator
-    } kind_;
 
   private:
     mutable const SafepointIndex *cachedSafepointIndex_;
     const JitActivation *activation_;
 
     void dumpBaseline() const;
 
   public:
     explicit JitFrameIterator();
     explicit JitFrameIterator(ThreadSafeContext *cx);
     explicit JitFrameIterator(const ActivationIterator &activations);
 
-    bool isBailoutIterator() const {
-        return kind_ == Kind_BailoutIterator;
-    }
-    IonBailoutIterator *asBailoutIterator();
-    const IonBailoutIterator *asBailoutIterator() const;
-
     // Current frame information.
     FrameType type() const {
         return type_;
     }
     uint8_t *fp() const {
         return current_;
     }
     const JitActivation *activation() const {
@@ -475,17 +464,16 @@ class SnapshotIterator
 
   public:
     // Connect all informations about the current script in order to recover the
     // content of baseline frames.
 
     SnapshotIterator(IonScript *ionScript, SnapshotOffset snapshotOffset,
                      IonJSFrameLayout *fp, const MachineState &machine);
     explicit SnapshotIterator(const JitFrameIterator &iter);
-    explicit SnapshotIterator(const IonBailoutIterator &iter);
     SnapshotIterator();
 
     Value read() {
         return allocationValue(readAllocation());
     }
 
     Value maybeRead(MaybeReadFallback &fallback) {
         RValueAllocation a = readAllocation();
@@ -590,17 +578,16 @@ class InlineFrameIterator
 
   private:
     void findNextFrame();
     JSObject *computeScopeChain(Value scopeChainValue) const;
 
   public:
     InlineFrameIterator(ThreadSafeContext *cx, const JitFrameIterator *iter);
     InlineFrameIterator(JSRuntime *rt, const JitFrameIterator *iter);
-    InlineFrameIterator(ThreadSafeContext *cx, const IonBailoutIterator *iter);
     InlineFrameIterator(ThreadSafeContext *cx, const InlineFrameIterator *iter);
 
     bool more() const {
         return frame_ && framesRead_ < frameCount_;
     }
     JSFunction *callee() const {
         MOZ_ASSERT(callee_);
         return callee_;
--- a/js/src/jit/ParallelFunctions.cpp
+++ b/js/src/jit/ParallelFunctions.cpp
@@ -539,18 +539,17 @@ jit::BailoutPar(BailoutStack *sp, uint8_
 
     // We don't have an exit frame.
     MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
                IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(IonCommonFrameLayout), 0, 0x1000),
                "Fake jitTop pointer should be within the first page.");
     cx->perThreadData->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
 
     JitActivationIterator jitActivations(cx->perThreadData);
-    IonBailoutIterator bailoutData(jitActivations, sp);
-    JitActivation::RegisterBailoutIterator registerIterator(*jitActivations->asJit(), &bailoutData);
+    BailoutFrameInfo bailoutData(jitActivations, sp);
     JitFrameIterator frameIter(jitActivations);
     SnapshotIterator snapIter(frameIter);
 
     cx->bailoutRecord->setIonBailoutKind(snapIter.bailoutKind());
     cx->bailoutRecord->rematerializeFrames(cx, frameIter);
 
     MOZ_ASSERT(frameIter.done());
     *entryFramePointer = frameIter.fp();
--- a/js/src/jit/arm/Bailouts-arm.cpp
+++ b/js/src/jit/arm/Bailouts-arm.cpp
@@ -64,63 +64,59 @@ class BailoutStack
 };
 
 // Make sure the compiler doesn't add extra padding.
 static_assert((sizeof(BailoutStack) % 8) == 0, "BailoutStack should be 8-byte aligned.");
 
 } // namespace jit
 } // namespace js
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       BailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   BailoutStack *bailout)
+  : machine_(bailout->machine())
 {
     uint8_t *sp = bailout->parentStackPointer();
-    uint8_t *fp = sp + bailout->frameSize();
+    framePointer_ = sp + bailout->frameSize();
+    topFrameSize_ = framePointer_ - sp;
 
-    kind_ = Kind_BailoutIterator;
-    current_ = fp;
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - sp;
-    switch (mode_) {
-      case SequentialExecution: topIonScript_ = script()->ionScript(); break;
-      case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break;
-      default: MOZ_CRASH("No such execution mode");
-    }
+    JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
+    JitActivation *activation = activations.activation()->asJit();
+    if (activation->cx()->isForkJoinContext())
+        topIonScript_ = script->parallelIonScript();
+    else
+        topIonScript_ = script->ionScript();
+
+    attachOnJitActivation(activations);
 
     if (bailout->frameClass() == FrameSizeClass::None()) {
         snapshotOffset_ = bailout->snapshotOffset();
         return;
     }
 
     // Compute the snapshot offset from the bailout ID.
-    JitActivation *activation = activations.activation()->asJit();
     JSRuntime *rt = activation->compartment()->runtimeFromMainThread();
     JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass());
     uintptr_t tableOffset = bailout->tableOffset();
     uintptr_t tableStart = reinterpret_cast<uintptr_t>(Assembler::BailoutTableStart(code->raw()));
 
     MOZ_ASSERT(tableOffset >= tableStart &&
                tableOffset < tableStart + code->instructionsSize());
     MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
 
     uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
     MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE);
 
     snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId);
 }
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       InvalidationBailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   InvalidationBailoutStack *bailout)
+  : machine_(bailout->machine())
 {
-    kind_ = Kind_BailoutIterator;
-    returnAddressToFp_ = bailout->osiPointReturnAddress();
+    framePointer_ = (uint8_t*) bailout->fp();
+    topFrameSize_ = framePointer_ - bailout->sp();
     topIonScript_ = bailout->ionScript();
+    attachOnJitActivation(activations);
+
+    uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress();
     const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
-
-    current_ = (uint8_t*) bailout->fp();
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - bailout->sp();
     snapshotOffset_ = osiIndex->snapshotOffset();
 }
--- a/js/src/jit/mips/Bailouts-mips.cpp
+++ b/js/src/jit/mips/Bailouts-mips.cpp
@@ -7,63 +7,59 @@
 #include "jit/mips/Bailouts-mips.h"
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 
 using namespace js;
 using namespace js::jit;
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       BailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   BailoutStack *bailout)
+  : machine_(bailout->machine())
 {
     uint8_t *sp = bailout->parentStackPointer();
-    uint8_t *fp = sp + bailout->frameSize();
+    framePointer_ = sp + bailout->frameSize();
+    topFrameSize_ = framePointer_ - sp;
 
-    kind_ = Kind_BailoutIterator;
-    current_ = fp;
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - sp;
-    switch (mode_) {
-      case SequentialExecution: topIonScript_ = script()->ionScript(); break;
-      case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break;
-      default: MOZ_CRASH("No such execution mode");
-    }
+    JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
+    JitActivation *activation = activations.activation()->asJit();
+    if (activation->cx()->isForkJoinContext())
+        topIonScript_ = script->parallelIonScript();
+    else
+        topIonScript_ = script->ionScript();
+
+    attachOnJitActivation(activations);
 
     if (bailout->frameClass() == FrameSizeClass::None()) {
         snapshotOffset_ = bailout->snapshotOffset();
         return;
     }
 
     // Compute the snapshot offset from the bailout ID.
-    JitActivation *activation = activations.activation()->asJit();
     JSRuntime *rt = activation->compartment()->runtimeFromMainThread();
     JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass());
     uintptr_t tableOffset = bailout->tableOffset();
     uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw());
 
     MOZ_ASSERT(tableOffset >= tableStart &&
-              tableOffset < tableStart + code->instructionsSize());
+               tableOffset < tableStart + code->instructionsSize());
     MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
 
     uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
     MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE);
 
     snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId);
 }
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       InvalidationBailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   InvalidationBailoutStack *bailout)
+  : machine_(bailout->machine())
 {
-    kind_ = Kind_BailoutIterator;
-    returnAddressToFp_ = bailout->osiPointReturnAddress();
+    framePointer_ = (uint8_t*) bailout->fp();
+    topFrameSize_ = framePointer_ - bailout->sp();
     topIonScript_ = bailout->ionScript();
+    attachOnJitActivation(activations);
+
+    uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress();
     const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
-
-    current_ = (uint8_t*) bailout->fp();
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - bailout->sp();
     snapshotOffset_ = osiIndex->snapshotOffset();
 }
--- a/js/src/jit/none/Trampoline-none.cpp
+++ b/js/src/jit/none/Trampoline-none.cpp
@@ -42,24 +42,22 @@ void MacroAssembler::alignFrameForICArgu
 void MacroAssembler::restoreFrameAlignmentForICArguments(AfterICSaveLive &) { MOZ_CRASH(); }
 
 const Register ABIArgGenerator::NonArgReturnReg0 = { 0 };
 const Register ABIArgGenerator::NonArgReturnReg1 = { 0 };
 const Register ABIArgGenerator::NonArg_VolatileReg = { 0 };
 const Register ABIArgGenerator::NonReturn_VolatileReg0 = { 0 };
 const Register ABIArgGenerator::NonReturn_VolatileReg1 = { 0 };
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &iter, BailoutStack *bailout)
-  : JitFrameIterator(iter)
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &iter, BailoutStack *bailout)
 {
     MOZ_CRASH();
 }
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &iter, InvalidationBailoutStack *bailout)
-  : JitFrameIterator(iter)
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &iter, InvalidationBailoutStack *bailout)
 {
     MOZ_CRASH();
 }
 
 bool ICCompare_Int32::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); }
 bool ICCompare_Double::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); }
 bool ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); }
 bool ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler &) { MOZ_CRASH(); }
--- a/js/src/jit/x64/Bailouts-x64.cpp
+++ b/js/src/jit/x64/Bailouts-x64.cpp
@@ -40,43 +40,40 @@ class BailoutStack
 
 } // namespace jit
 } // namespace js
 
 #if defined(_WIN32)
 # pragma pack(pop)
 #endif
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       BailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machineState())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   BailoutStack *bailout)
+  : machine_(bailout->machineState())
 {
     uint8_t *sp = bailout->parentStackPointer();
-    uint8_t *fp = sp + bailout->frameSize();
+    framePointer_ = sp + bailout->frameSize();
+    topFrameSize_ = framePointer_ - sp;
 
-    kind_ = Kind_BailoutIterator;
-    current_ = fp;
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - sp;
-    switch (mode_) {
-      case SequentialExecution: topIonScript_ = script()->ionScript(); break;
-      case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break;
-      default: MOZ_CRASH("No such execution mode");
-    }
+    JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
+    JitActivation *activation = activations.activation()->asJit();
+    if (activation->cx()->isForkJoinContext())
+        topIonScript_ = script->parallelIonScript();
+    else
+        topIonScript_ = script->ionScript();
+
+    attachOnJitActivation(activations);
     snapshotOffset_ = bailout->snapshotOffset();
 }
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       InvalidationBailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   InvalidationBailoutStack *bailout)
+  : machine_(bailout->machine())
 {
-    kind_ = Kind_BailoutIterator;
-    returnAddressToFp_ = bailout->osiPointReturnAddress();
+    framePointer_ = (uint8_t*) bailout->fp();
+    topFrameSize_ = framePointer_ - bailout->sp();
     topIonScript_ = bailout->ionScript();
+    attachOnJitActivation(activations);
+
+    uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress();
     const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
-
-    current_ = (uint8_t*) bailout->fp();
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - bailout->sp();
     snapshotOffset_ = osiIndex->snapshotOffset();
 }
--- a/js/src/jit/x86/Bailouts-x86.cpp
+++ b/js/src/jit/x86/Bailouts-x86.cpp
@@ -60,63 +60,59 @@ class BailoutStack
 
 } // namespace jit
 } // namespace js
 
 #if defined(_WIN32)
 # pragma pack(pop)
 #endif
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       BailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   BailoutStack *bailout)
+  : machine_(bailout->machine())
 {
     uint8_t *sp = bailout->parentStackPointer();
-    uint8_t *fp = sp + bailout->frameSize();
+    framePointer_ = sp + bailout->frameSize();
+    topFrameSize_ = framePointer_ - sp;
 
-    kind_ = Kind_BailoutIterator;
-    current_ = fp;
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - sp;
-    switch (mode_) {
-      case SequentialExecution: topIonScript_ = script()->ionScript(); break;
-      case ParallelExecution: topIonScript_ = script()->parallelIonScript(); break;
-      default: MOZ_CRASH("No such execution mode");
-    }
+    JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
+    JitActivation *activation = activations.activation()->asJit();
+    if (activation->cx()->isForkJoinContext())
+        topIonScript_ = script->parallelIonScript();
+    else
+        topIonScript_ = script->ionScript();
+
+    attachOnJitActivation(activations);
 
     if (bailout->frameClass() == FrameSizeClass::None()) {
         snapshotOffset_ = bailout->snapshotOffset();
         return;
     }
 
     // Compute the snapshot offset from the bailout ID.
-    JitActivation *activation = activations.activation()->asJit();
     JSRuntime *rt = activation->compartment()->runtimeFromMainThread();
     JitCode *code = rt->jitRuntime()->getBailoutTable(bailout->frameClass());
     uintptr_t tableOffset = bailout->tableOffset();
     uintptr_t tableStart = reinterpret_cast<uintptr_t>(code->raw());
 
     MOZ_ASSERT(tableOffset >= tableStart &&
                tableOffset < tableStart + code->instructionsSize());
     MOZ_ASSERT((tableOffset - tableStart) % BAILOUT_TABLE_ENTRY_SIZE == 0);
 
     uint32_t bailoutId = ((tableOffset - tableStart) / BAILOUT_TABLE_ENTRY_SIZE) - 1;
     MOZ_ASSERT(bailoutId < BAILOUT_TABLE_SIZE);
 
     snapshotOffset_ = topIonScript_->bailoutToSnapshot(bailoutId);
 }
 
-IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
-                                       InvalidationBailoutStack *bailout)
-  : JitFrameIterator(activations),
-    machine_(bailout->machine())
+BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
+                                   InvalidationBailoutStack *bailout)
+  : machine_(bailout->machine())
 {
-    kind_ = Kind_BailoutIterator;
-    returnAddressToFp_ = bailout->osiPointReturnAddress();
+    framePointer_ = (uint8_t*) bailout->fp();
+    topFrameSize_ = framePointer_ - bailout->sp();
     topIonScript_ = bailout->ionScript();
+    attachOnJitActivation(activations);
+
+    uint8_t *returnAddressToFp_ = bailout->osiPointReturnAddress();
     const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
-
-    current_ = (uint8_t*) bailout->fp();
-    type_ = JitFrame_IonJS;
-    topFrameSize_ = current_ - bailout->sp();
     snapshotOffset_ = osiIndex->snapshotOffset();
 }
--- a/js/src/vm/ForkJoin.h
+++ b/js/src/vm/ForkJoin.h
@@ -321,17 +321,16 @@ enum ParallelBailoutCause {
     // parallel.
     ParallelBailoutRequestedGC,
     ParallelBailoutRequestedZoneGC
 };
 
 namespace jit {
 class BailoutStack;
 class JitFrameIterator;
-class IonBailoutIterator;
 class RematerializedFrame;
 }
 
 // See "Bailouts" section in comment above.
 struct ParallelBailoutRecord
 {
     // Captured Ion frames at the point of bailout. Stored younger-to-older,
     // i.e., the 0th frame is the youngest frame.
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1400,70 +1400,70 @@ js::CheckLocalUnaliased(MaybeCheckAliasi
 }
 #endif
 
 jit::JitActivation::JitActivation(JSContext *cx, bool active)
   : Activation(cx, Jit),
     active_(active),
     rematerializedFrames_(nullptr),
     ionRecovery_(cx),
-    ionBailoutIterator_(nullptr)
+    bailoutData_(nullptr)
 {
     if (active) {
         prevJitTop_ = cx->mainThread().jitTop;
         prevJitJSContext_ = cx->mainThread().jitJSContext;
         cx->mainThread().jitJSContext = cx;
     } else {
         prevJitTop_ = nullptr;
         prevJitJSContext_ = nullptr;
     }
 }
 
 jit::JitActivation::JitActivation(ForkJoinContext *cx)
   : Activation(cx, Jit),
     active_(true),
     rematerializedFrames_(nullptr),
     ionRecovery_(cx),
-    ionBailoutIterator_(nullptr)
+    bailoutData_(nullptr)
 {
     prevJitTop_ = cx->perThreadData->jitTop;
     prevJitJSContext_ = cx->perThreadData->jitJSContext;
     cx->perThreadData->jitJSContext = nullptr;
 }
 
 jit::JitActivation::~JitActivation()
 {
     if (active_) {
         cx_->perThreadData->jitTop = prevJitTop_;
         cx_->perThreadData->jitJSContext = prevJitJSContext_;
     }
 
     // All reocvered value are taken from activation during the bailout.
     MOZ_ASSERT(ionRecovery_.empty());
 
-    // The Ion Bailout Iterator should have unregistered itself from the
+    // The BailoutFrameInfo should have unregistered itself from the
     // JitActivations.
-    MOZ_ASSERT(!ionBailoutIterator_);
+    MOZ_ASSERT(!bailoutData_);
 
     clearRematerializedFrames();
     js_delete(rematerializedFrames_);
 }
 
-jit::JitActivation::RegisterBailoutIterator::RegisterBailoutIterator(JitActivation &activation,
-                                                                     IonBailoutIterator *iter)
-  : activation_(activation)
+void
+jit::JitActivation::setBailoutData(jit::BailoutFrameInfo *bailoutData)
 {
-    MOZ_ASSERT(!activation_.ionBailoutIterator_);
-    activation_.ionBailoutIterator_ = iter;
+    MOZ_ASSERT(!bailoutData_);
+    bailoutData_ = bailoutData;
 }
 
-jit::JitActivation::RegisterBailoutIterator::~RegisterBailoutIterator()
+void
+jit::JitActivation::cleanBailoutData()
 {
-    MOZ_ASSERT(activation_.ionBailoutIterator_);
-    activation_.ionBailoutIterator_ = nullptr;
+    MOZ_ASSERT(bailoutData_);
+    bailoutData_ = nullptr;
 }
 
 // setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so
 // changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable
 // and disable activation instruction sequences.
 void
 jit::JitActivation::setActive(JSContext *cx, bool active)
 {
@@ -1502,19 +1502,18 @@ jit::JitActivation::clearRematerializedF
         return;
 
     for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront()) {
         RematerializedFrame::FreeInVector(e.front().value());
         e.removeFront();
     }
 }
 
-template <class T>
 jit::RematerializedFrame *
-jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, const T &iter, size_t inlineDepth)
+jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, const JitFrameIterator &iter, size_t inlineDepth)
 {
     // Only allow rematerializing from the same thread.
     MOZ_ASSERT(cx->perThreadData == cx_->perThreadData);
     MOZ_ASSERT(iter.activation() == this);
     MOZ_ASSERT(iter.isIonScripted());
 
     if (!rematerializedFrames_) {
         rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx);
@@ -1539,25 +1538,16 @@ jit::JitActivation::getRematerializedFra
         InlineFrameIterator inlineIter(cx, &iter);
         if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, p->value()))
             return nullptr;
     }
 
     return p->value()[inlineDepth];
 }
 
-template jit::RematerializedFrame *
-jit::JitActivation::getRematerializedFrame<jit::JitFrameIterator>(ThreadSafeContext *cx,
-                                                                  const jit::JitFrameIterator &iter,
-                                                                  size_t inlineDepth);
-template jit::RematerializedFrame *
-jit::JitActivation::getRematerializedFrame<jit::IonBailoutIterator>(ThreadSafeContext *cx,
-                                                                    const jit::IonBailoutIterator &iter,
-                                                                    size_t inlineDepth);
-
 jit::RematerializedFrame *
 jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth)
 {
     if (!rematerializedFrames_)
         return nullptr;
     if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top))
         return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr;
     return nullptr;
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1296,16 +1296,18 @@ class ActivationIterator
     }
     bool done() const {
         return activation_ == nullptr;
     }
 };
 
 namespace jit {
 
+class BailoutFrameInfo;
+
 // A JitActivation is used for frames running in Baseline or Ion.
 class JitActivation : public Activation
 {
     uint8_t *prevJitTop_;
     JSContext *prevJitJSContext_;
     bool active_;
 
     // Rematerialized Ion frames which has info copied out of snapshots. Maps
@@ -1323,19 +1325,21 @@ class JitActivation : public Activation
     // RInstructionResults are appended into this vector when Snapshot values
     // have to be read, or when the evaluation has to run before some mutating
     // code.  Each RInstructionResults belongs to one frame which has to bailout
     // as soon as we get back to it.
     typedef Vector<RInstructionResults, 1> IonRecoveryMap;
     IonRecoveryMap ionRecovery_;
 
     // If we are bailing out from Ion, then this field should be a non-null
-    // pointer which references the IonBailoutIterator used to walk the inner
-    // frames.
-    IonBailoutIterator  *ionBailoutIterator_;
+    // pointer which references the BailoutFrameInfo used to walk the inner
+    // frames. This field is used for all newly constructed JitFrameIterators to
+    // read the innermost frame information from this bailout data instead of
+    // reading it from the stack.
+    BailoutFrameInfo *bailoutData_;
 
     void clearRematerializedFrames();
 
 #ifdef CHECK_OSIPOINT_REGISTERS
   protected:
     // Used to verify that live registers don't change between a VM call and
     // the OsiPoint that follows it. Protected to silence Clang warning.
     uint32_t checkRegs_;
@@ -1382,21 +1386,18 @@ class JitActivation : public Activation
     }
 #endif
 
     // Look up a rematerialized frame keyed by the fp, rematerializing the
     // frame if one doesn't already exist. A frame can only be rematerialized
     // if an IonFrameIterator pointing to the nearest uninlined frame can be
     // provided, as values need to be read out of snapshots.
     //
-    // T is either JitFrameIterator or IonBailoutIterator.
-    //
     // The inlineDepth must be within bounds of the frame pointed to by iter.
-    template <class T>
-    RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, const T &iter,
+    RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, const JitFrameIterator &iter,
                                                 size_t inlineDepth = 0);
 
     // Look up a rematerialized frame by the fp. If inlineDepth is out of
     // bounds of what has been rematerialized, nullptr is returned.
     RematerializedFrame *lookupRematerializedFrame(uint8_t *top, size_t inlineDepth = 0);
 
     bool hasRematerializedFrame(uint8_t *top, size_t inlineDepth = 0) {
         return !!lookupRematerializedFrame(top, inlineDepth);
@@ -1416,27 +1417,24 @@ class JitActivation : public Activation
 
     // If an Ion frame recovery exists for the |fp| frame exists on the
     // activation, then move its content to the |results| argument, and remove
     // it from the activation.
     void maybeTakeIonFrameRecovery(IonJSFrameLayout *fp, RInstructionResults *results);
 
     void markIonRecovery(JSTracer *trc);
 
-    class RegisterBailoutIterator
-    {
-        JitActivation &activation_;
+    // Return the bailout information if it is registered.
+    const BailoutFrameInfo *bailoutData() const { return bailoutData_; }
 
-      public:
-        RegisterBailoutIterator(JitActivation &activation, IonBailoutIterator *iter);
-        ~RegisterBailoutIterator();
-    };
+    // Register the bailout data when it is constructed.
+    void setBailoutData(BailoutFrameInfo *bailoutData);
 
-    // Return the bailout information if it is registered.
-    const IonBailoutIterator *bailoutData() const { return ionBailoutIterator_; }
+    // Unregister the bailout data when the frame is reconstructed.
+    void cleanBailoutData();
 };
 
 // A filtering of the ActivationIterator to only stop at JitActivations.
 class JitActivationIterator : public ActivationIterator
 {
     void settle() {
         while (!done() && !activation_->isJit())
             ActivationIterator::operator++();