Backed out 6 changesets (bug 1070962) for bustage
authorWes Kocher <wkocher@mozilla.com>
Mon, 13 Oct 2014 09:31:11 -0700
changeset 210187 4c4092b50ccb733a946076ad344a449b8e816205
parent 210186 e00ce29c8c6716436164bb0fa66fbb641aa21e80
child 210188 d29a91fd9c40ad85d921e2aa76c29f8bf8f7f1c6
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
bugs1070962
milestone35.0a1
backs oute00ce29c8c6716436164bb0fa66fbb641aa21e80
8876a417bd4f0f0045a1bf1a726640b87bc5630f
191e57386752fcf7a849b26a8d980212d8656297
3aac2b77e38f6abe9a5a05001560accd4de08ae7
d4dd598af9ac9615013e9cfecad99e72ae7bc6e0
4b8b34a91096b9048b7dfd27eb16ff6be07b32fa
Backed out 6 changesets (bug 1070962) for bustage Backed out changeset e00ce29c8c67 (bug 1070962) Backed out changeset 8876a417bd4f (bug 1070962) Backed out changeset 191e57386752 (bug 1070962) Backed out changeset 3aac2b77e38f (bug 1070962) Backed out changeset d4dd598af9ac (bug 1070962) Backed out changeset 4b8b34a91096 (bug 1070962)
js/src/jit/Bailouts.cpp
js/src/jit/Bailouts.h
js/src/jit/BaselineBailouts.cpp
js/src/jit/BaselineJIT.h
js/src/jit/Ion.cpp
js/src/jit/IonFrames-inl.h
js/src/jit/IonFrames.cpp
js/src/jit/IonFrames.h
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.cpp
js/src/vm/ForkJoin.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -19,42 +19,89 @@
 #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());
-    BailoutFrameInfo bailoutData(jitActivations, sp);
-    JitFrameIterator iter(jitActivations);
+    IonBailoutIterator iter(jitActivations, sp);
+    JitActivation *activation = jitActivations->asJit();
 
     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, bailoutData.activation(), iter, false, bailoutInfo);
+    uint32_t retval = BailoutIonToBaseline(cx, 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
@@ -86,31 +133,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());
-    BailoutFrameInfo bailoutData(jitActivations, sp);
-    JitFrameIterator iter(jitActivations);
+    IonBailoutIterator iter(jitActivations, sp);
+    JitActivation *activation = jitActivations->asJit();
 
     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.frameSize();
+    *frameSizeOut = iter.topFrameSize();
 
     MOZ_ASSERT(IsBaselineEnabled(cx));
 
     *bailoutInfo = nullptr;
-    uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, bailoutInfo);
+    uint32_t retval = BailoutIonToBaseline(cx, 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
@@ -143,26 +190,29 @@ jit::InvalidationBailout(InvalidationBai
         JitSpew(JitSpew_IonInvalidate, "   new  ra %p", (void *) frame->returnAddress());
     }
 
     iter.ionScript()->decref(cx->runtime()->defaultFreeOp());
 
     return retval;
 }
 
-BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
-                                   const JitFrameIterator &frame)
-  : machine_(frame.machineState())
+IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
+                                       const JitFrameIterator &frame)
+  : JitFrameIterator(activations),
+    machine_(frame.machineState())
 {
-    framePointer_ = (uint8_t *) frame.fp();
-    topFrameSize_ = frame.frameSize();
+    kind_ = Kind_BailoutIterator;
+    returnAddressToFp_ = frame.returnAddressToFp();
     topIonScript_ = frame.ionScript();
-    attachOnJitActivation(activations);
+    const OsiIndex *osiIndex = frame.osiIndex();
 
-    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)
@@ -171,21 +221,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());
-    BailoutFrameInfo bailoutData(jitActivations, frame.frame());
-    JitFrameIterator iter(jitActivations);
+    IonBailoutIterator iter(jitActivations, frame.frame());
+    JitActivation *activation = jitActivations->asJit();
 
     BaselineBailoutInfo *bailoutInfo = nullptr;
-    uint32_t retval = BailoutIonToBaseline(cx, bailoutData.activation(), iter, true, &bailoutInfo, &excInfo);
+    uint32_t retval = BailoutIonToBaseline(cx, 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;
@@ -242,21 +292,8 @@ 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,60 @@ 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 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
+// 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
 {
     MachineState machine_;
-    uint8_t *framePointer_;
+    uint32_t snapshotOffset_;
     size_t topFrameSize_;
     IonScript *topIonScript_;
-    uint32_t snapshotOffset_;
-    JitActivation *activation_;
-
-    void attachOnJitActivation(const JitActivationIterator &activations);
 
   public:
-    BailoutFrameInfo(const JitActivationIterator &activations, BailoutStack *sp);
-    BailoutFrameInfo(const JitActivationIterator &activations, InvalidationBailoutStack *sp);
-    BailoutFrameInfo(const JitActivationIterator &activations, const JitFrameIterator &frame);
-    ~BailoutFrameInfo();
+    IonBailoutIterator(const JitActivationIterator &activations, BailoutStack *sp);
+    IonBailoutIterator(const JitActivationIterator &activations, InvalidationBailoutStack *sp);
+    IonBailoutIterator(const JitActivationIterator &activations, const JitFrameIterator &frame);
 
-    uint8_t *fp() const {
-        return framePointer_;
-    }
     SnapshotOffset snapshotOffset() const {
-        return snapshotOffset_;
+        if (topIonScript_)
+            return snapshotOffset_;
+        return osiIndex()->snapshotOffset();
     }
     const MachineState machineState() const {
-        return machine_;
+        if (topIonScript_)
+            return machine_;
+        return JitFrameIterator::machineState();
     }
     size_t topFrameSize() const {
+        MOZ_ASSERT(topIonScript_);
         return topFrameSize_;
     }
     IonScript *ionScript() const {
-        return topIonScript_;
+        if (topIonScript_)
+            return topIonScript_;
+        return JitFrameIterator::ionScript();
     }
-    JitActivation *activation() const {
-        return activation_;
+
+    IonBailoutIterator &operator++() {
+        JitFrameIterator::operator++();
+        // Clear topIonScript_ now that we've advanced past it, so that
+        // snapshotOffset() and machineState() reflect the current script.
+        topIonScript_ = nullptr;
+        return *this;
     }
+
+    void dump() const;
 };
 
 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,42 +69,41 @@ 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
 {
-    JitFrameIterator &iter_;
+    IonBailoutIterator &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(JitFrameIterator &iter, size_t initialSize)
+    BaselineStackBuilder(IonBailoutIterator &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_);
@@ -383,21 +382,20 @@ 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 JitFrameIterator &iter)
+    SnapshotIteratorForBailout(const IonBailoutIterator &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;
@@ -1284,17 +1282,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, JitFrameIterator &iter,
+jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &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);
@@ -1304,17 +1302,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.isBailoutJS());
+    MOZ_ASSERT(iter.isIonJS());
     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, JitFrameIterator &iter,
+BailoutIonToBaseline(JSContext *cx, JitActivation *activation, IonBailoutIterator &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/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -619,17 +619,17 @@ FinishAllOffThreadCompilations(JSCompart
 }
 
 uint8_t *
 jit::LazyLinkTopActivation(JSContext *cx)
 {
     JitActivationIterator iter(cx->runtime());
 
     // First frame should be an exit frame.
-    JitFrameIterator it(iter);
+    JitFrameIterator it(iter.jitTop(), SequentialExecution);
     MOZ_ASSERT(it.type() == JitFrame_Exit);
 
     // Second frame is the Ion frame.
     ++it;
     MOZ_ASSERT(it.type() == JitFrame_IonJS);
 
     // Get the pending builder from the Ion frame.
     IonBuilder *builder = it.script()->ionScript()->pendingBuilder();
@@ -1879,17 +1879,17 @@ AttachFinishedCompilations(JSContext *cx
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
         // Try to defer linking if the script is on the stack, to postpone
         // invalidating them.
         if (builder->info().executionMode() == SequentialExecution &&
             builder->script()->hasIonScript())
         {
             bool onStack = false;
             for (JitActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
-                for (JitFrameIterator it(iter); !it.done(); ++it) {
+                for (JitFrameIterator it(iter.jitTop(), SequentialExecution); !it.done(); ++it) {
                     if (!it.isIonJS())
                         continue;
                     if (it.checkInvalidation())
                         continue;
 
                     JSScript *script = it.script();
                     if (builder->script() == script) {
                         onStack = true;
@@ -2681,42 +2681,35 @@ jit::FastInvoke(JSContext *cx, HandleFun
 
     args.rval().set(result);
 
     MOZ_ASSERT_IF(result.isMagic(), result.isMagic(JS_ION_ERROR));
     return result.isMagic() ? IonExec_Error : IonExec_Ok;
 }
 
 static void
-InvalidateActivation(FreeOp *fop, const JitActivationIterator &activations, bool invalidateAll)
+InvalidateActivation(FreeOp *fop, uint8_t *jitTop, bool invalidateAll)
 {
     JitSpew(JitSpew_IonInvalidate, "BEGIN invalidating activation");
 
     size_t frameno = 1;
 
-    for (JitFrameIterator it(activations); !it.done(); ++it, ++frameno) {
+    for (JitFrameIterator it(jitTop, SequentialExecution); !it.done(); ++it, ++frameno) {
         MOZ_ASSERT_IF(frameno == 1, it.type() == JitFrame_Exit);
 
 #ifdef DEBUG
         switch (it.type()) {
           case JitFrame_Exit:
             JitSpew(JitSpew_IonInvalidate, "#%d exit frame @ %p", frameno, it.fp());
             break;
           case JitFrame_BaselineJS:
           case JitFrame_IonJS:
-          case JitFrame_Bailout:
           {
             MOZ_ASSERT(it.isScripted());
-            const char *type = "Unknown";
-            if (it.isIonJS())
-                type = "Optimized";
-            else if (it.isBaselineJS())
-                type = "Baseline";
-            else if (it.isBailoutJS())
-                type = "Bailing";
+            const char *type = it.isIonJS() ? "Optimized" : "Baseline";
             JitSpew(JitSpew_IonInvalidate, "#%d %s JS frame @ %p, %s:%d (fun: %p, script: %p, pc %p)",
                     frameno, type, it.fp(), it.script()->filename(), it.script()->lineno(),
                     it.maybeCallee(), (JSScript *)it.script(), it.returnAddressToFp());
             break;
           }
           case JitFrame_BaselineStub:
             JitSpew(JitSpew_IonInvalidate, "#%d baseline stub frame @ %p", frameno, it.fp());
             break;
@@ -2843,17 +2836,17 @@ void
 jit::InvalidateAll(FreeOp *fop, Zone *zone)
 {
     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
         StopAllOffThreadCompilations(comp);
 
     for (JitActivationIterator iter(fop->runtime()); !iter.done(); ++iter) {
         if (iter->compartment()->zone() == zone) {
             JitSpew(JitSpew_IonInvalidate, "Invalidating all frames for GC");
-            InvalidateActivation(fop, iter, true);
+            InvalidateActivation(fop, iter.jitTop(), true);
         }
     }
 }
 
 
 void
 jit::Invalidate(types::TypeZone &types, FreeOp *fop,
                 const Vector<types::RecompileInfo> &invalid, bool resetUses,
@@ -2886,17 +2879,17 @@ jit::Invalidate(types::TypeZone &types, 
     }
 
     if (!numInvalidations) {
         JitSpew(JitSpew_IonInvalidate, " No IonScript invalidation.");
         return;
     }
 
     for (JitActivationIterator iter(fop->runtime()); !iter.done(); ++iter)
-        InvalidateActivation(fop, iter, false);
+        InvalidateActivation(fop, iter.jitTop(), false);
 
     // Drop the references added above. If a script was never active, its
     // IonScript will be immediately destroyed. Otherwise, it will be held live
     // until its last invalidated frame is destroyed.
     for (size_t i = 0; i < invalid.length(); i++) {
         types::CompilerOutput &co = *invalid[i].compilerOutput(types);
         if (!co.isValid())
             continue;
@@ -3352,17 +3345,17 @@ AutoDebugModeInvalidation::~AutoDebugMod
     // mode.
     jit::MarkActiveBaselineScripts(zone);
 
     for (JitActivationIterator iter(rt); !iter.done(); ++iter) {
         JSCompartment *comp = iter->compartment();
         if (comp_ == comp || zone_ == comp->zone()) {
             IonContext ictx(CompileRuntime::get(rt));
             JitSpew(JitSpew_IonInvalidate, "Invalidating frames for debug mode toggle");
-            InvalidateActivation(fop, iter, true);
+            InvalidateActivation(fop, iter.jitTop(), true);
         }
     }
 
     for (gc::ZoneCellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
         JSScript *script = i.get<JSScript>();
         if (script->compartment() == comp_ || zone_) {
             FinishInvalidation<SequentialExecution>(fop, script);
             FinishInvalidation<ParallelExecution>(fop, script);
--- a/js/src/jit/IonFrames-inl.h
+++ b/js/src/jit/IonFrames-inl.h
@@ -75,12 +75,24 @@ GetTopBaselineFrame(JSContext *cx)
     MOZ_ASSERT(iter.type() == JitFrame_Exit);
     ++iter;
     if (iter.isBaselineStub())
         ++iter;
     MOZ_ASSERT(iter.isBaselineJS());
     return iter.baselineFrame();
 }
 
+inline JSScript *
+GetTopIonJSScript(JSContext *cx, void **returnAddrOut = nullptr)
+{
+    return GetTopIonJSScript(cx->mainThread().jitTop, returnAddrOut, SequentialExecution);
+}
+
+inline JSScript *
+GetTopIonJSScript(ForkJoinContext *cx, void **returnAddrOut = nullptr)
+{
+    return GetTopIonJSScript(cx->perThreadData->jitTop, returnAddrOut, ParallelExecution);
+}
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_IonFrames_inl_h */
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -75,58 +75,63 @@ ReadFrameInt32Slot(IonJSFrameLayout *fp,
 }
 
 static inline bool
 ReadFrameBooleanSlot(IonJSFrameLayout *fp, int32_t slot)
 {
     return *(bool *)((char *)fp + OffsetOfFrameSlot(slot));
 }
 
-JitFrameIterator::JitFrameIterator()
-  : current_(nullptr),
-    type_(JitFrame_Exit),
-    returnAddressToFp_(nullptr),
-    frameSize_(0),
-    mode_(SequentialExecution),
-    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())
+    activation_(nullptr)
 {
-    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;
-    }
+}
+
+JitFrameIterator::JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode)
+  : current_((uint8_t *)fp),
+    type_(JitFrame_IonJS),
+    returnAddressToFp_(fp->returnAddress()),
+    frameSize_(fp->prevFrameLocalSize()),
+    mode_(mode),
+    kind_(Kind_FrameIterator)
+{
+}
+
+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);
 }
@@ -263,17 +268,16 @@ JitFrameIterator::actualArgs() const
 static inline size_t
 SizeOfFramePrefix(FrameType type)
 {
     switch (type) {
       case JitFrame_Entry:
         return IonEntryFrameLayout::Size();
       case JitFrame_BaselineJS:
       case JitFrame_IonJS:
-      case JitFrame_Bailout:
       case JitFrame_Unwound_IonJS:
         return IonJSFrameLayout::Size();
       case JitFrame_BaselineStub:
         return IonBaselineStubFrameLayout::Size();
       case JitFrame_Rectifier:
         return IonRectifierFrameLayout::Size();
       case JitFrame_Unwound_Rectifier:
         return IonUnwoundRectifierFrameLayout::Size();
@@ -328,34 +332,26 @@ JitFrameIterator::operator++()
 
 
     return *this;
 }
 
 uintptr_t *
 JitFrameIterator::spillBase() const
 {
-    MOZ_ASSERT(isIonJS());
-
     // Get the base address to where safepoint registers are spilled.
     // Out-of-line calls do not unwind the extra padding space used to
     // aggregate bailout tables, so we use frameSize instead of frameLocals,
     // which would only account for local stack slots.
     return reinterpret_cast<uintptr_t *>(fp() - ionScript()->frameSize());
 }
 
 MachineState
 JitFrameIterator::machineState() const
 {
-    MOZ_ASSERT(isIonScripted());
-
-    // The MachineState is used by GCs for marking call-sites.
-    if (MOZ_UNLIKELY(isBailoutJS()))
-        return activation_->bailoutData()->machineState();
-
     SafepointReader reader(ionScript(), safepoint());
     uintptr_t *spill = spillBase();
 
     MachineState machine;
     for (GeneralRegisterBackwardIterator iter(reader.allGprSpills()); iter.more(); iter++)
         machine.setRegisterLocation(*iter, --spill);
 
     uint8_t *spillAlign = alignDoubleSpillWithOffset(reinterpret_cast<uint8_t *>(spill), 0);
@@ -1034,17 +1030,17 @@ MarkBaselineStubFrame(JSTracer *trc, con
         MOZ_ASSERT(ICStub::CanMakeCalls(stub->kind()));
         stub->trace(trc);
     }
 }
 
 void
 JitActivationIterator::jitStackRange(uintptr_t *&min, uintptr_t *&end)
 {
-    JitFrameIterator frames(*this);
+    JitFrameIterator frames(jitTop(), SequentialExecution);
 
     if (frames.isFakeExitFrame()) {
         min = reinterpret_cast<uintptr_t *>(frames.fp());
     } else {
         IonExitFrameLayout *exitFrame = frames.exitFrame();
         IonExitFooterFrame *footer = exitFrame->footer();
         const VMFunction *f = footer->function();
         if (exitFrame->isWrapperExit() && f->outParam == Type_Handle) {
@@ -1365,18 +1361,17 @@ void UpdateJitActivationsForMinorGC<gc::
 void
 GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
 {
     JitSpew(JitSpew_IonSnapshots, "Recover PC & Script from the last frame.");
 
     JSRuntime *rt = cx->runtime();
 
     // Recover the return address.
-    JitActivationIterator iter(rt);
-    JitFrameIterator it(iter);
+    JitFrameIterator it(rt->mainThread.jitTop, SequentialExecution);
 
     // If the previous frame is a rectifier frame (maybe unwound),
     // skip past it.
     if (it.prevType() == JitFrame_Rectifier || it.prevType() == JitFrame_Unwound_Rectifier) {
         ++it;
         MOZ_ASSERT(it.prevType() == JitFrame_BaselineStub ||
                    it.prevType() == JitFrame_BaselineJS ||
                    it.prevType() == JitFrame_IonJS);
@@ -1529,17 +1524,17 @@ SnapshotIterator::SnapshotIterator(IonSc
     ionScript_(ionScript),
     instructionResults_(nullptr)
 {
     MOZ_ASSERT(snapshotOffset < ionScript->snapshotsListSize());
 }
 
 SnapshotIterator::SnapshotIterator(const JitFrameIterator &iter)
   : snapshot_(iter.ionScript()->snapshots(),
-              iter.snapshotOffset(),
+              iter.osiIndex()->snapshotOffset(),
               iter.ionScript()->snapshotsRVATableSize(),
               iter.ionScript()->snapshotsListSize()),
     recover_(snapshot_,
              iter.ionScript()->recovers(),
              iter.ionScript()->recoversSize()),
     fp_(iter.jsFrame()),
     machine_(iter.machineState()),
     ionScript_(iter.ionScript()),
@@ -1913,77 +1908,54 @@ SnapshotIterator::maybeReadAllocByIndex(
     }
 
     while (moreAllocations())
         skip();
 
     return s;
 }
 
-IonJSFrameLayout *
-JitFrameIterator::jsFrame() const
-{
-    MOZ_ASSERT(isScripted());
-    if (isBailoutJS())
-        return (IonJSFrameLayout *) activation_->bailoutData()->fp();
-
-    return (IonJSFrameLayout *) fp();
-}
-
 IonScript *
 JitFrameIterator::ionScript() const
 {
-    MOZ_ASSERT(isIonScripted());
-    if (isBailoutJS())
-        return activation_->bailoutData()->ionScript();
+    MOZ_ASSERT(type() == JitFrame_IonJS);
 
     IonScript *ionScript = nullptr;
     if (checkInvalidation(&ionScript))
         return ionScript;
     return ionScriptFromCalleeToken();
 }
 
 IonScript *
 JitFrameIterator::ionScriptFromCalleeToken() const
 {
-    MOZ_ASSERT(isIonJS());
+    MOZ_ASSERT(type() == JitFrame_IonJS);
     MOZ_ASSERT(!checkInvalidation());
 
     switch (mode_) {
       case SequentialExecution:
         return script()->ionScript();
       case ParallelExecution:
         return script()->parallelIonScript();
       default:
         MOZ_CRASH("No such execution mode");
     }
 }
 
 const SafepointIndex *
 JitFrameIterator::safepoint() const
 {
-    MOZ_ASSERT(isIonJS());
     if (!cachedSafepointIndex_)
         cachedSafepointIndex_ = ionScript()->getSafepointIndex(returnAddressToFp());
     return cachedSafepointIndex_;
 }
 
-SnapshotOffset
-JitFrameIterator::snapshotOffset() const
-{
-    MOZ_ASSERT(isIonScripted());
-    if (isBailoutJS())
-        return activation_->bailoutData()->snapshotOffset();
-    return osiIndex()->snapshotOffset();
-}
-
 const OsiIndex *
 JitFrameIterator::osiIndex() const
 {
-    MOZ_ASSERT(isIonJS());
     SafepointReader reader(ionScript(), safepoint());
     return ionScript()->getOsiIndex(reader.osiReturnPointOffset());
 }
 
 InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const JitFrameIterator *iter)
   : callee_(cx),
     script_(cx)
 {
@@ -1992,25 +1964,41 @@ 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_) {
-        start_ = SnapshotIterator(*frame_);
+        if (frame_->isBailoutIterator())
+            start_ = SnapshotIterator(*frame_->asBailoutIterator());
+        else
+            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();
     }
 }
 
@@ -2339,17 +2327,16 @@ JitFrameIterator::dump() const
       case JitFrame_BaselineJS:
         dumpBaseline();
         break;
       case JitFrame_BaselineStub:
       case JitFrame_Unwound_BaselineStub:
         fprintf(stderr, " Baseline stub frame\n");
         fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
         break;
-      case JitFrame_Bailout:
       case JitFrame_IonJS:
       {
         InlineFrameIterator frames(GetJSContextFromJitCode(), this);
         for (;;) {
             frames.dump();
             if (!frames.more())
                 break;
             ++frames;
--- a/js/src/jit/IonFrames.h
+++ b/js/src/jit/IonFrames.h
@@ -287,19 +287,19 @@ void UpdateJitActivationsForMinorGC(PerT
 static inline uint32_t
 MakeFrameDescriptor(uint32_t frameSize, FrameType type)
 {
     return (frameSize << FRAMESIZE_SHIFT) | type;
 }
 
 // Returns the JSScript associated with the topmost Ion frame.
 inline JSScript *
-GetTopIonJSScript(ThreadSafeContext *cx, void **returnAddrOut = nullptr)
+GetTopIonJSScript(uint8_t *jitTop, void **returnAddrOut, ExecutionMode mode)
 {
-    JitFrameIterator iter(cx);
+    JitFrameIterator iter(jitTop, mode);
     MOZ_ASSERT(iter.type() == JitFrame_Exit);
     ++iter;
 
     MOZ_ASSERT(iter.returnAddressToFp() != nullptr);
     if (returnAddrOut)
         *returnAddrOut = (void *) iter.returnAddressToFp();
 
     if (iter.isBaselineStub()) {
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -52,63 +52,79 @@ enum FrameType
 
     // An unwound rectifier frame is a rectifier frame signalling that its callee
     // frame has been turned into an exit frame (see EnsureExitFrame).
     JitFrame_Unwound_Rectifier,
 
     // An exit frame is necessary for transitioning from a JS frame into C++.
     // From within C++, an exit frame is always the last frame in any
     // JitActivation.
-    JitFrame_Exit,
-
-    // A bailout frame is a special IonJS jit frame after a bailout, and before
-    // the reconstruction of the BaselineJS frame. From within C++, a bailout
-    // frame is always the last frame in a JitActivation iff the bailout frame
-    // information is recorded on the JitActivation.
-    JitFrame_Bailout
+    JitFrame_Exit
 };
 
 enum ReadFrameArgsBehavior {
     // Only read formals (i.e. [0 ... callee()->nargs]
     ReadFrame_Formals,
 
     // Only read overflown args (i.e. [callee()->nargs ... numActuals()]
     ReadFrame_Overflown,
 
     // 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(uint8_t *top, ExecutionMode mode)
+      : current_(top),
+        type_(JitFrame_Exit),
+        returnAddressToFp_(nullptr),
+        frameSize_(0),
+        mode_(mode),
+        kind_(Kind_FrameIterator),
+        cachedSafepointIndex_(nullptr),
+        activation_(nullptr)
+    { }
+
     explicit JitFrameIterator(ThreadSafeContext *cx);
     explicit JitFrameIterator(const ActivationIterator &activations);
+    explicit JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode);
+
+    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_;
     }
@@ -117,45 +133,40 @@ class JitFrameIterator
     }
 
     IonCommonFrameLayout *current() const {
         return (IonCommonFrameLayout *)current_;
     }
 
     inline uint8_t *returnAddress() const;
 
-    // Return the pointer of the JitFrame, the iterator is assumed to be settled
-    // on a scripted frame.
-    IonJSFrameLayout *jsFrame() const;
+    IonJSFrameLayout *jsFrame() const {
+        MOZ_ASSERT(isScripted());
+        return (IonJSFrameLayout *) fp();
+    }
 
     // Returns true iff this exit frame was created using EnsureExitFrame.
     inline bool isFakeExitFrame() const;
 
     inline IonExitFrameLayout *exitFrame() const;
 
     // Returns whether the JS frame has been invalidated and, if so,
     // places the invalidated Ion script in |ionScript|.
     bool checkInvalidation(IonScript **ionScript) const;
     bool checkInvalidation() const;
 
     bool isScripted() const {
-        return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
+        return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS;
     }
     bool isBaselineJS() const {
         return type_ == JitFrame_BaselineJS;
     }
-    bool isIonScripted() const {
-        return type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
-    }
     bool isIonJS() const {
         return type_ == JitFrame_IonJS;
     }
-    bool isBailoutJS() const {
-        return type_ == JitFrame_Bailout;
-    }
     bool isBaselineStub() const {
         return type_ == JitFrame_BaselineStub;
     }
     bool isBareExit() const;
     template <typename T> bool isExitFrameLayout() const;
 
     bool isEntry() const {
         return type_ == JitFrame_Entry;
@@ -211,20 +222,16 @@ class JitFrameIterator
     // Returns the Safepoint associated with this JS frame. Incurs a lookup
     // overhead.
     const SafepointIndex *safepoint() const;
 
     // Returns the OSI index associated with this JS frame. Incurs a lookup
     // overhead.
     const OsiIndex *osiIndex() const;
 
-    // Returns the Snapshot offset associated with this JS frame. Incurs a
-    // lookup overhead.
-    SnapshotOffset snapshotOffset() const;
-
     uintptr_t *spillBase() const;
     MachineState machineState() const;
 
     template <class Op>
     void unaliasedForEachActual(Op op, ReadFrameArgsBehavior behavior) const {
         MOZ_ASSERT(isBaselineJS());
 
         unsigned nactual = numActualArgs();
@@ -464,16 +471,17 @@ 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();
@@ -578,16 +586,17 @@ 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);
-    BailoutFrameInfo bailoutData(jitActivations, sp);
-    JitFrameIterator frameIter(jitActivations);
+    IonBailoutIterator frameIter(jitActivations, sp);
     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,59 +64,63 @@ 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
 
-BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
-                                   BailoutStack *bailout)
-  : machine_(bailout->machine())
+IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
+                                       BailoutStack *bailout)
+  : JitFrameIterator(activations),
+    machine_(bailout->machine())
 {
     uint8_t *sp = bailout->parentStackPointer();
-    framePointer_ = sp + bailout->frameSize();
-    topFrameSize_ = framePointer_ - sp;
+    uint8_t *fp = sp + bailout->frameSize();
 
-    JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
-    JitActivation *activation = activations.activation()->asJit();
-    if (activation->cx()->isForkJoinContext())
-        topIonScript_ = script->parallelIonScript();
-    else
-        topIonScript_ = script->ionScript();
-
-    attachOnJitActivation(activations);
+    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");
+    }
 
     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);
 }
 
-BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
-                                   InvalidationBailoutStack *bailout)
-  : machine_(bailout->machine())
+IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
+                                       InvalidationBailoutStack *bailout)
+  : JitFrameIterator(activations),
+    machine_(bailout->machine())
 {
-    framePointer_ = (uint8_t*) bailout->fp();
-    topFrameSize_ = framePointer_ - bailout->sp();
+    kind_ = Kind_BailoutIterator;
+    returnAddressToFp_ = bailout->osiPointReturnAddress();
     topIonScript_ = bailout->ionScript();
-    attachOnJitActivation(activations);
+    const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
 
-    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,59 +7,63 @@
 #include "jit/mips/Bailouts-mips.h"
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 
 using namespace js;
 using namespace js::jit;
 
-BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
-                                   BailoutStack *bailout)
-  : machine_(bailout->machine())
+IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
+                                       BailoutStack *bailout)
+  : JitFrameIterator(activations),
+    machine_(bailout->machine())
 {
     uint8_t *sp = bailout->parentStackPointer();
-    framePointer_ = sp + bailout->frameSize();
-    topFrameSize_ = framePointer_ - sp;
+    uint8_t *fp = sp + bailout->frameSize();
 
-    JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
-    JitActivation *activation = activations.activation()->asJit();
-    if (activation->cx()->isForkJoinContext())
-        topIonScript_ = script->parallelIonScript();
-    else
-        topIonScript_ = script->ionScript();
-
-    attachOnJitActivation(activations);
+    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");
+    }
 
     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);
 }
 
-BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
-                                   InvalidationBailoutStack *bailout)
-  : machine_(bailout->machine())
+IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
+                                       InvalidationBailoutStack *bailout)
+  : JitFrameIterator(activations),
+    machine_(bailout->machine())
 {
-    framePointer_ = (uint8_t*) bailout->fp();
-    topFrameSize_ = framePointer_ - bailout->sp();
+    kind_ = Kind_BailoutIterator;
+    returnAddressToFp_ = bailout->osiPointReturnAddress();
     topIonScript_ = bailout->ionScript();
-    attachOnJitActivation(activations);
+    const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
 
-    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,22 +42,24 @@ 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 };
 
-BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &iter, BailoutStack *bailout)
+IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &iter, BailoutStack *bailout)
+  : JitFrameIterator(iter)
 {
     MOZ_CRASH();
 }
 
-BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &iter, InvalidationBailoutStack *bailout)
+IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &iter, InvalidationBailoutStack *bailout)
+  : JitFrameIterator(iter)
 {
     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,40 +40,43 @@ class BailoutStack
 
 } // namespace jit
 } // namespace js
 
 #if defined(_WIN32)
 # pragma pack(pop)
 #endif
 
-BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
-                                   BailoutStack *bailout)
-  : machine_(bailout->machineState())
+IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
+                                       BailoutStack *bailout)
+  : JitFrameIterator(activations),
+    machine_(bailout->machineState())
 {
     uint8_t *sp = bailout->parentStackPointer();
-    framePointer_ = sp + bailout->frameSize();
-    topFrameSize_ = framePointer_ - sp;
+    uint8_t *fp = sp + bailout->frameSize();
 
-    JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
-    JitActivation *activation = activations.activation()->asJit();
-    if (activation->cx()->isForkJoinContext())
-        topIonScript_ = script->parallelIonScript();
-    else
-        topIonScript_ = script->ionScript();
-
-    attachOnJitActivation(activations);
+    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");
+    }
     snapshotOffset_ = bailout->snapshotOffset();
 }
 
-BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
-                                   InvalidationBailoutStack *bailout)
-  : machine_(bailout->machine())
+IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
+                                       InvalidationBailoutStack *bailout)
+  : JitFrameIterator(activations),
+    machine_(bailout->machine())
 {
-    framePointer_ = (uint8_t*) bailout->fp();
-    topFrameSize_ = framePointer_ - bailout->sp();
+    kind_ = Kind_BailoutIterator;
+    returnAddressToFp_ = bailout->osiPointReturnAddress();
     topIonScript_ = bailout->ionScript();
-    attachOnJitActivation(activations);
+    const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
 
-    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,59 +60,63 @@ class BailoutStack
 
 } // namespace jit
 } // namespace js
 
 #if defined(_WIN32)
 # pragma pack(pop)
 #endif
 
-BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
-                                   BailoutStack *bailout)
-  : machine_(bailout->machine())
+IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
+                                       BailoutStack *bailout)
+  : JitFrameIterator(activations),
+    machine_(bailout->machine())
 {
     uint8_t *sp = bailout->parentStackPointer();
-    framePointer_ = sp + bailout->frameSize();
-    topFrameSize_ = framePointer_ - sp;
+    uint8_t *fp = sp + bailout->frameSize();
 
-    JSScript *script = ScriptFromCalleeToken(((IonJSFrameLayout *) framePointer_)->calleeToken());
-    JitActivation *activation = activations.activation()->asJit();
-    if (activation->cx()->isForkJoinContext())
-        topIonScript_ = script->parallelIonScript();
-    else
-        topIonScript_ = script->ionScript();
-
-    attachOnJitActivation(activations);
+    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");
+    }
 
     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);
 }
 
-BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
-                                   InvalidationBailoutStack *bailout)
-  : machine_(bailout->machine())
+IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
+                                       InvalidationBailoutStack *bailout)
+  : JitFrameIterator(activations),
+    machine_(bailout->machine())
 {
-    framePointer_ = (uint8_t*) bailout->fp();
-    topFrameSize_ = framePointer_ - bailout->sp();
+    kind_ = Kind_BailoutIterator;
+    returnAddressToFp_ = bailout->osiPointReturnAddress();
     topIonScript_ = bailout->ionScript();
-    attachOnJitActivation(activations);
+    const OsiIndex *osiIndex = topIonScript_->getOsiIndex(returnAddressToFp_);
 
-    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.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -1876,51 +1876,66 @@ ParallelBailoutRecord::init(JSContext *c
 
 void
 ParallelBailoutRecord::reset()
 {
     RematerializedFrame::FreeInVector(frames());
     cause = ParallelBailoutNone;
 }
 
-void
-ParallelBailoutRecord::rematerializeFrames(ForkJoinContext *cx, JitFrameIterator &frameIter)
+template <class T>
+static void
+RematerializeFramesWithIter(ForkJoinContext *cx, T &frameIter,
+                            Vector<RematerializedFrame *> &frames)
 {
-    // This function is infallible. These are only called when we are already
-    // erroring out. If we OOM here, free what we've allocated and return. Error
-    // reporting is then unable to give the user detailed stack information.
+    // This function as well as |rematerializeFrames| methods below are
+    // infallible. These are only called when we are already erroring out. If
+    // we OOM here, free what we've allocated and return. Error reporting is
+    // then unable to give the user detailed stack information.
 
-    MOZ_ASSERT(frames().empty());
+    MOZ_ASSERT(frames.empty());
 
     for (; !frameIter.done(); ++frameIter) {
         if (!frameIter.isIonJS())
             continue;
 
         InlineFrameIterator inlineIter(cx, &frameIter);
         Vector<RematerializedFrame *> inlineFrames(cx);
 
         if (!RematerializedFrame::RematerializeInlineFrames(cx, frameIter.fp(),
                                                             inlineIter, inlineFrames))
         {
             RematerializedFrame::FreeInVector(inlineFrames);
-            RematerializedFrame::FreeInVector(frames());
+            RematerializedFrame::FreeInVector(frames);
             return;
         }
 
         // Reverse the inline frames into the main vector.
         while (!inlineFrames.empty()) {
-            if (!frames().append(inlineFrames.popCopy())) {
+            if (!frames.append(inlineFrames.popCopy())) {
                 RematerializedFrame::FreeInVector(inlineFrames);
-                RematerializedFrame::FreeInVector(frames());
+                RematerializedFrame::FreeInVector(frames);
                 return;
             }
         }
     }
 }
 
+void
+ParallelBailoutRecord::rematerializeFrames(ForkJoinContext *cx, JitFrameIterator &frameIter)
+{
+    RematerializeFramesWithIter(cx, frameIter, frames());
+}
+
+void
+ParallelBailoutRecord::rematerializeFrames(ForkJoinContext *cx, IonBailoutIterator &frameIter)
+{
+    RematerializeFramesWithIter(cx, frameIter, frames());
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 //
 // Debug spew
 //
 
 #ifdef FORKJOIN_SPEW
 
--- a/js/src/vm/ForkJoin.h
+++ b/js/src/vm/ForkJoin.h
@@ -321,16 +321,17 @@ 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.
@@ -367,16 +368,17 @@ struct ParallelBailoutRecord
     }
 
     void setIonBailoutKind(jit::BailoutKind kind) {
         joinCause(ParallelBailoutExecution);
         ionBailoutKind = kind;
     }
 
     void rematerializeFrames(ForkJoinContext *cx, jit::JitFrameIterator &frameIter);
+    void rematerializeFrames(ForkJoinContext *cx, jit::IonBailoutIterator &frameIter);
 };
 
 class ForkJoinShared;
 
 class ForkJoinContext : public ThreadSafeContext
 {
   public:
     // Bailout record used to record the reason this thread stopped executing
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -346,25 +346,16 @@ FrameIter::unaliasedForEachActual(JSCont
         break;
       case INTERP:
         interpFrame()->unaliasedForEachActual(op);
         return;
       case JIT:
         if (data_.jitFrames_.isIonJS()) {
             jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
             ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, recover);
-        } else if (data_.jitFrames_.isBailoutJS()) {
-            // :TODO: (Bug 1070962) If we are introspecting the frame which is
-            // being bailed, then we might be in the middle of recovering
-            // instructions. Stacking computeInstructionResults implies that we
-            // might be recovering result twice. In the mean time, to avoid
-            // that, we just return Undefined values for instruction results
-            // which are not yet recovered.
-            jit::MaybeReadFallback fallback;
-            ionInlineFrames_.unaliasedForEachActual(cx, op, jit::ReadFrame_Actuals, fallback);
         } else {
             MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
             data_.jitFrames_.unaliasedForEachActual(op, jit::ReadFrame_Actuals);
         }
         return;
     }
     MOZ_CRASH("Unexpected state");
 }
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -623,17 +623,17 @@ FrameIter::Data::Data(ThreadSafeContext 
                       ContextOption contextOption, JSPrincipals *principals)
   : cx_(cx),
     savedOption_(savedOption),
     contextOption_(contextOption),
     principals_(principals),
     pc_(nullptr),
     interpFrames_(nullptr),
     activations_(cx->perThreadData),
-    jitFrames_(),
+    jitFrames_((uint8_t *)nullptr, SequentialExecution),
     ionInlineFrameNo_(0),
     asmJSFrames_()
 {
 }
 
 FrameIter::Data::Data(const FrameIter::Data &other)
   : cx_(other.cx_),
     savedOption_(other.savedOption_),
@@ -674,50 +674,50 @@ FrameIter::FrameIter(JSContext *cx, Cont
     ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
 {
     settleOnActivation();
 }
 
 FrameIter::FrameIter(const FrameIter &other)
   : data_(other.data_),
     ionInlineFrames_(other.data_.cx_,
-                     data_.jitFrames_.isIonScripted() ? &other.ionInlineFrames_ : nullptr)
+                     data_.jitFrames_.isIonJS() ? &other.ionInlineFrames_ : nullptr)
 {
 }
 
 FrameIter::FrameIter(const Data &data)
   : data_(data),
-    ionInlineFrames_(data.cx_, data_.jitFrames_.isIonScripted() ? &data_.jitFrames_ : nullptr)
+    ionInlineFrames_(data.cx_, data_.jitFrames_.isIonJS() ? &data_.jitFrames_ : nullptr)
 {
     MOZ_ASSERT(data.cx_);
 
-    if (data_.jitFrames_.isIonScripted()) {
+    if (data_.jitFrames_.isIonJS()) {
         while (ionInlineFrames_.frameNo() != data.ionInlineFrameNo_)
             ++ionInlineFrames_;
     }
 }
 
 void
 FrameIter::nextJitFrame()
 {
-    if (data_.jitFrames_.isIonScripted()) {
+    if (data_.jitFrames_.isIonJS()) {
         ionInlineFrames_.resetOn(&data_.jitFrames_);
         data_.pc_ = ionInlineFrames_.pc();
     } else {
         MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
         data_.jitFrames_.baselineScriptAndPc(nullptr, &data_.pc_);
     }
 }
 
 void
 FrameIter::popJitFrame()
 {
     MOZ_ASSERT(data_.state_ == JIT);
 
-    if (data_.jitFrames_.isIonScripted() && ionInlineFrames_.more()) {
+    if (data_.jitFrames_.isIonJS() && ionInlineFrames_.more()) {
         ++ionInlineFrames_;
         data_.pc_ = ionInlineFrames_.pc();
         return;
     }
 
     ++data_.jitFrames_;
     while (!data_.jitFrames_.done() && !data_.jitFrames_.isScripted())
         ++data_.jitFrames_;
@@ -784,17 +784,17 @@ FrameIter::operator++()
     return *this;
 }
 
 FrameIter::Data *
 FrameIter::copyData() const
 {
     Data *data = data_.cx_->new_<Data>(data_);
     MOZ_ASSERT(data_.state_ != ASMJS);
-    if (data && data_.jitFrames_.isIonScripted())
+    if (data && data_.jitFrames_.isIonJS())
         data->ionInlineFrameNo_ = ionInlineFrames_.frameNo();
     return data;
 }
 
 AbstractFramePtr
 FrameIter::copyDataAsAbstractFramePtr() const
 {
     AbstractFramePtr frame;
@@ -992,17 +992,17 @@ FrameIter::mutedErrors() const
 bool
 FrameIter::isConstructing() const
 {
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case JIT:
-        if (data_.jitFrames_.isIonScripted())
+        if (data_.jitFrames_.isIonJS())
             return ionInlineFrames_.isConstructing();
         MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
         return data_.jitFrames_.isConstructing();
       case INTERP:
         return interpFrame()->isConstructing();
     }
 
     MOZ_CRASH("Unexpected state");
@@ -1021,17 +1021,17 @@ FrameIter::hasUsableAbstractFramePtr() c
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         return false;
       case JIT:
         if (data_.jitFrames_.isBaselineJS())
             return true;
 
-        MOZ_ASSERT(data_.jitFrames_.isIonScripted());
+        MOZ_ASSERT(data_.jitFrames_.isIonJS());
         return !!activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
                                                                   ionInlineFrames_.frameNo());
         break;
       case INTERP:
         return true;
     }
     MOZ_CRASH("Unexpected state");
 }
@@ -1043,17 +1043,17 @@ FrameIter::abstractFramePtr() const
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case JIT: {
         if (data_.jitFrames_.isBaselineJS())
             return data_.jitFrames_.baselineFrame();
 
-        MOZ_ASSERT(data_.jitFrames_.isIonScripted());
+        MOZ_ASSERT(data_.jitFrames_.isIonJS());
         return activation()->asJit()->lookupRematerializedFrame(data_.jitFrames_.fp(),
                                                                 ionInlineFrames_.frameNo());
         break;
       }
       case INTERP:
         MOZ_ASSERT(interpFrame());
         return AbstractFramePtr(interpFrame());
     }
@@ -1115,17 +1115,17 @@ FrameIter::callee() const
       case ASMJS:
         break;
       case INTERP:
         MOZ_ASSERT(isFunctionFrame());
         return &interpFrame()->callee();
       case JIT:
         if (data_.jitFrames_.isBaselineJS())
             return data_.jitFrames_.callee();
-        MOZ_ASSERT(data_.jitFrames_.isIonScripted());
+        MOZ_ASSERT(data_.jitFrames_.isIonJS());
         return ionInlineFrames_.callee();
     }
     MOZ_CRASH("Unexpected state");
 }
 
 Value
 FrameIter::calleev() const
 {
@@ -1148,17 +1148,17 @@ FrameIter::numActualArgs() const
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case INTERP:
         MOZ_ASSERT(isFunctionFrame());
         return interpFrame()->numActualArgs();
       case JIT:
-        if (data_.jitFrames_.isIonScripted())
+        if (data_.jitFrames_.isIonJS())
             return ionInlineFrames_.numActualArgs();
 
         MOZ_ASSERT(data_.jitFrames_.isBaselineJS());
         return data_.jitFrames_.numActualArgs();
     }
     MOZ_CRASH("Unexpected state");
 }
 
@@ -1177,17 +1177,17 @@ FrameIter::unaliasedActual(unsigned i, M
 JSObject *
 FrameIter::scopeChain() const
 {
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case JIT:
-        if (data_.jitFrames_.isIonScripted())
+        if (data_.jitFrames_.isIonJS())
             return ionInlineFrames_.scopeChain();
         return data_.jitFrames_.baselineFrame()->scopeChain();
       case INTERP:
         return interpFrame()->scopeChain();
     }
     MOZ_CRASH("Unexpected state");
 }
 
@@ -1232,17 +1232,17 @@ FrameIter::computedThisValue() const
 Value
 FrameIter::thisv(JSContext *cx)
 {
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case JIT:
-        if (data_.jitFrames_.isIonScripted()) {
+        if (data_.jitFrames_.isIonJS()) {
             jit::MaybeReadFallback recover(cx, activation()->asJit(), &data_.jitFrames_);
             return ionInlineFrames_.thisValue(recover);
         }
         return data_.jitFrames_.baselineFrame()->thisValue();
       case INTERP:
         return interpFrame()->thisValue();
     }
     MOZ_CRASH("Unexpected state");
@@ -1288,17 +1288,17 @@ FrameIter::setReturnValue(const Value &v
 size_t
 FrameIter::numFrameSlots() const
 {
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case JIT: {
-        if (data_.jitFrames_.isIonScripted()) {
+        if (data_.jitFrames_.isIonJS()) {
             return ionInlineFrames_.snapshotIterator().numAllocations() -
                 ionInlineFrames_.script()->nfixed();
         }
         jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame();
         return frame->numValueSlots() - data_.jitFrames_.script()->nfixed();
       }
       case INTERP:
         MOZ_ASSERT(data_.interpFrames_.sp() >= interpFrame()->base());
@@ -1310,17 +1310,17 @@ FrameIter::numFrameSlots() const
 Value
 FrameIter::frameSlotValue(size_t index) const
 {
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case JIT:
-        if (data_.jitFrames_.isIonScripted()) {
+        if (data_.jitFrames_.isIonJS()) {
             jit::SnapshotIterator si(ionInlineFrames_.snapshotIterator());
             index += ionInlineFrames_.script()->nfixed();
             return si.maybeReadAllocByIndex(index);
         }
 
         index += data_.jitFrames_.script()->nfixed();
         return *data_.jitFrames_.baselineFrame()->valueSlot(index);
       case INTERP:
@@ -1399,73 +1399,52 @@ js::CheckLocalUnaliased(MaybeCheckAliasi
     }
 }
 #endif
 
 jit::JitActivation::JitActivation(JSContext *cx, bool active)
   : Activation(cx, Jit),
     active_(active),
     rematerializedFrames_(nullptr),
-    ionRecovery_(cx),
-    bailoutData_(nullptr)
+    ionRecovery_(cx)
 {
     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),
-    bailoutData_(nullptr)
+    ionRecovery_(cx)
 {
     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_;
     }
 
+    clearRematerializedFrames();
     // All reocvered value are taken from activation during the bailout.
     MOZ_ASSERT(ionRecovery_.empty());
-
-    // The BailoutFrameInfo should have unregistered itself from the
-    // JitActivations.
-    MOZ_ASSERT(!bailoutData_);
-
-    clearRematerializedFrames();
     js_delete(rematerializedFrames_);
 }
 
-void
-jit::JitActivation::setBailoutData(jit::BailoutFrameInfo *bailoutData)
-{
-    MOZ_ASSERT(!bailoutData_);
-    bailoutData_ = bailoutData;
-}
-
-void
-jit::JitActivation::cleanBailoutData()
-{
-    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)
 {
     // Only allowed to deactivate/activate if activation is top.
     // (Not tested and will probably fail in other situations.)
@@ -1502,23 +1481,24 @@ 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 JitFrameIterator &iter, size_t inlineDepth)
+jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, const T &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());
+    MOZ_ASSERT(iter.isIonJS());
 
     if (!rematerializedFrames_) {
         rematerializedFrames_ = cx->new_<RematerializedFrameTable>(cx);
         if (!rematerializedFrames_ || !rematerializedFrames_->init()) {
             rematerializedFrames_ = nullptr;
             return nullptr;
         }
     }
@@ -1538,16 +1518,25 @@ 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,18 +1296,16 @@ 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
@@ -1324,23 +1322,16 @@ 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 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_;
     RegisterDump regs_;
@@ -1386,18 +1377,21 @@ 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.
-    RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, const JitFrameIterator &iter,
+    template <class T>
+    RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, const T &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,25 +1410,16 @@ class JitActivation : public Activation
     RInstructionResults *maybeIonFrameRecovery(IonJSFrameLayout *fp);
 
     // 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);
-
-    // Return the bailout information if it is registered.
-    const BailoutFrameInfo *bailoutData() const { return bailoutData_; }
-
-    // Register the bailout data when it is constructed.
-    void setBailoutData(BailoutFrameInfo *bailoutData);
-
-    // 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++();