Bug 1381930: Move JitFrameIterator methods to their own cpp file; r=nbp
authorBenjamin Bouvier <benj@benj.me>
Tue, 18 Jul 2017 20:10:48 +0200
changeset 418447 f15bf893f71fb75f4c8c4b3a17994c5531408368
parent 418446 33cf2dcc5aaf1819ee5099defab131afb51e76fd
child 418448 6d68d842f601c310626d2ccedab94b38da321b72
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs1381930
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1381930: Move JitFrameIterator methods to their own cpp file; r=nbp MozReview-Commit-ID: 6ShujTv5EIM
js/src/jit/BaselineBailouts.cpp
js/src/jit/JitFrameIterator-inl.h
js/src/jit/JitFrameIterator.cpp
js/src/jit/JitFrames-inl.h
js/src/jit/JitFrames.cpp
js/src/moz.build
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ScopeExit.h"
 #include "mozilla/SizePrintfMacros.h"
 
 #include "jsprf.h"
 #include "jsutil.h"
 #include "jit/arm/Simulator-arm.h"
+#include "jit/BaselineFrame.h"
 #include "jit/BaselineIC.h"
 #include "jit/BaselineJIT.h"
 #include "jit/CompileInfo.h"
 #include "jit/JitSpewer.h"
 #include "jit/mips32/Simulator-mips32.h"
 #include "jit/mips64/Simulator-mips64.h"
 #include "jit/Recover.h"
 #include "jit/RematerializedFrame.h"
--- a/js/src/jit/JitFrameIterator-inl.h
+++ b/js/src/jit/JitFrameIterator-inl.h
@@ -11,16 +11,44 @@
 
 #include "jit/Bailouts.h"
 #include "jit/BaselineFrame.h"
 #include "jit/JitFrames.h"
 
 namespace js {
 namespace jit {
 
+inline uint8_t*
+JitFrameIterator::returnAddress() const
+{
+    CommonFrameLayout* current = (CommonFrameLayout*) current_;
+    return current->returnAddress();
+}
+
+inline FrameType
+JitFrameIterator::prevType() const
+{
+    CommonFrameLayout* current = (CommonFrameLayout*) current_;
+    return current->prevType();
+}
+
+inline ExitFrameLayout*
+JitFrameIterator::exitFrame() const
+{
+    MOZ_ASSERT(isExitFrame());
+    return (ExitFrameLayout*) fp();
+}
+
+inline size_t
+JitFrameIterator::prevFrameLocalSize() const
+{
+    CommonFrameLayout* current = (CommonFrameLayout*) current_;
+    return current->prevFrameLocalSize();
+}
+
 inline JitFrameLayout*
 JitProfilingFrameIterator::framePtr()
 {
     MOZ_ASSERT(!done());
     return (JitFrameLayout*) fp_;
 }
 
 inline JSScript*
new file mode 100644
--- /dev/null
+++ b/js/src/jit/JitFrameIterator.cpp
@@ -0,0 +1,468 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jit/JitFrameIterator-inl.h"
+
+#include "mozilla/SizePrintfMacros.h"
+
+#include "jit/BaselineIC.h"
+#include "jit/JitcodeMap.h"
+#include "jit/JitFrames.h"
+
+using namespace js;
+using namespace js::jit;
+
+JitFrameIterator::JitFrameIterator()
+  : current_(nullptr),
+    type_(JitFrame_Exit),
+    returnAddressToFp_(nullptr),
+    frameSize_(0),
+    cachedSafepointIndex_(nullptr),
+    activation_(nullptr)
+{
+}
+
+JitFrameIterator::JitFrameIterator(const JitActivation* activation)
+  : current_(activation->exitFP()),
+    type_(JitFrame_Exit),
+    returnAddressToFp_(nullptr),
+    frameSize_(0),
+    cachedSafepointIndex_(nullptr),
+    activation_(activation)
+{
+    if (activation_->bailoutData()) {
+        current_ = activation_->bailoutData()->fp();
+        frameSize_ = activation_->bailoutData()->topFrameSize();
+        type_ = JitFrame_Bailout;
+    }
+}
+
+JitFrameIterator::JitFrameIterator(JSContext* cx)
+  : JitFrameIterator(cx->activation()->asJit())
+{
+}
+
+JitFrameIterator::JitFrameIterator(const ActivationIterator& activations)
+  : JitFrameIterator(activations->asJit())
+{
+}
+
+bool
+JitFrameIterator::checkInvalidation() const
+{
+    IonScript* dummy;
+    return checkInvalidation(&dummy);
+}
+
+bool
+JitFrameIterator::checkInvalidation(IonScript** ionScriptOut) const
+{
+    JSScript* script = this->script();
+    if (isBailoutJS()) {
+        *ionScriptOut = activation_->bailoutData()->ionScript();
+        return !script->hasIonScript() || script->ionScript() != *ionScriptOut;
+    }
+
+    uint8_t* returnAddr = returnAddressToFp();
+    // N.B. the current IonScript is not the same as the frame's
+    // IonScript if the frame has since been invalidated.
+    bool invalidated = !script->hasIonScript() ||
+                       !script->ionScript()->containsReturnAddress(returnAddr);
+    if (!invalidated)
+        return false;
+
+    int32_t invalidationDataOffset = ((int32_t*) returnAddr)[-1];
+    uint8_t* ionScriptDataOffset = returnAddr + invalidationDataOffset;
+    IonScript* ionScript = (IonScript*) Assembler::GetPointer(ionScriptDataOffset);
+    MOZ_ASSERT(ionScript->containsReturnAddress(returnAddr));
+    *ionScriptOut = ionScript;
+    return true;
+}
+
+CalleeToken
+JitFrameIterator::calleeToken() const
+{
+    return ((JitFrameLayout*) current_)->calleeToken();
+}
+
+JSFunction*
+JitFrameIterator::callee() const
+{
+    MOZ_ASSERT(isScripted());
+    MOZ_ASSERT(isFunctionFrame());
+    return CalleeTokenToFunction(calleeToken());
+}
+
+JSFunction*
+JitFrameIterator::maybeCallee() const
+{
+    if (isScripted() && (isFunctionFrame()))
+        return callee();
+    return nullptr;
+}
+
+bool
+JitFrameIterator::isBareExit() const
+{
+    if (type_ != JitFrame_Exit)
+        return false;
+    return exitFrame()->isBareExit();
+}
+
+bool
+JitFrameIterator::isFunctionFrame() const
+{
+    return CalleeTokenIsFunction(calleeToken());
+}
+
+JSScript*
+JitFrameIterator::script() const
+{
+    MOZ_ASSERT(isScripted());
+    if (isBaselineJS())
+        return baselineFrame()->script();
+    JSScript* script = ScriptFromCalleeToken(calleeToken());
+    MOZ_ASSERT(script);
+    return script;
+}
+
+void
+JitFrameIterator::baselineScriptAndPc(JSScript** scriptRes, jsbytecode** pcRes) const
+{
+    MOZ_ASSERT(isBaselineJS());
+    JSScript* script = this->script();
+    if (scriptRes)
+        *scriptRes = script;
+
+    MOZ_ASSERT(pcRes);
+
+    // Use the frame's override pc, if we have one. This should only happen
+    // when we're in FinishBailoutToBaseline, handling an exception or toggling
+    // debug mode.
+    if (jsbytecode* overridePc = baselineFrame()->maybeOverridePc()) {
+        *pcRes = overridePc;
+        return;
+    }
+
+    // Else, there must be an ICEntry for the current return address.
+    uint8_t* retAddr = returnAddressToFp();
+    ICEntry& icEntry = script->baselineScript()->icEntryFromReturnAddress(retAddr);
+    *pcRes = icEntry.pc(script);
+}
+
+Value*
+JitFrameIterator::actualArgs() const
+{
+    return jsFrame()->argv() + 1;
+}
+
+uint8_t*
+JitFrameIterator::prevFp() const
+{
+    return current_ + current()->prevFrameLocalSize() + current()->headerSize();
+}
+
+JitFrameIterator&
+JitFrameIterator::operator++()
+{
+    MOZ_ASSERT(type_ != JitFrame_Entry);
+
+    frameSize_ = prevFrameLocalSize();
+    cachedSafepointIndex_ = nullptr;
+
+    // If the next frame is the entry frame, just exit. Don't update current_,
+    // since the entry and first frames overlap.
+    if (current()->prevType() == JitFrame_Entry) {
+        type_ = JitFrame_Entry;
+        return *this;
+    }
+
+    type_ = current()->prevType();
+    returnAddressToFp_ = current()->returnAddress();
+    current_ = prevFp();
+
+    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 tracing 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);
+
+    char* floatSpill = reinterpret_cast<char*>(spillAlign);
+    FloatRegisterSet fregs = reader.allFloatSpills().set();
+    fregs = fregs.reduceSetForPush();
+    for (FloatRegisterBackwardIterator iter(fregs); iter.more(); ++iter) {
+        floatSpill -= (*iter).size();
+        for (uint32_t a = 0; a < (*iter).numAlignedAliased(); a++) {
+            // Only say that registers that actually start here start here.
+            // e.g. d0 should not start at s1, only at s0.
+            FloatRegister ftmp;
+            (*iter).alignedAliased(a, &ftmp);
+            machine.setRegisterLocation(ftmp, (double*)floatSpill);
+        }
+    }
+
+    return machine;
+}
+
+JitFrameLayout*
+JitFrameIterator::jsFrame() const
+{
+    MOZ_ASSERT(isScripted());
+    if (isBailoutJS())
+        return (JitFrameLayout*) activation_->bailoutData()->fp();
+
+    return (JitFrameLayout*) fp();
+}
+
+IonScript*
+JitFrameIterator::ionScript() const
+{
+    MOZ_ASSERT(isIonScripted());
+    if (isBailoutJS())
+        return activation_->bailoutData()->ionScript();
+
+    IonScript* ionScript = nullptr;
+    if (checkInvalidation(&ionScript))
+        return ionScript;
+    return ionScriptFromCalleeToken();
+}
+
+IonScript*
+JitFrameIterator::ionScriptFromCalleeToken() const
+{
+    MOZ_ASSERT(isIonJS());
+    MOZ_ASSERT(!checkInvalidation());
+    return script()->ionScript();
+}
+
+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());
+}
+
+bool
+JitFrameIterator::isConstructing() const
+{
+    return CalleeTokenIsConstructing(calleeToken());
+}
+
+unsigned
+JitFrameIterator::numActualArgs() const
+{
+    if (isScripted())
+        return jsFrame()->numActualArgs();
+
+    MOZ_ASSERT(isExitFrameLayout<NativeExitFrameLayout>());
+    return exitFrame()->as<NativeExitFrameLayout>()->argc();
+}
+
+void
+JitFrameIterator::dumpBaseline() const
+{
+    MOZ_ASSERT(isBaselineJS());
+
+    fprintf(stderr, " JS Baseline frame\n");
+    if (isFunctionFrame()) {
+        fprintf(stderr, "  callee fun: ");
+#ifdef DEBUG
+        DumpObject(callee());
+#else
+        fprintf(stderr, "?\n");
+#endif
+    } else {
+        fprintf(stderr, "  global frame, no callee\n");
+    }
+
+    fprintf(stderr, "  file %s line %" PRIuSIZE "\n",
+            script()->filename(), script()->lineno());
+
+    JSContext* cx = TlsContext.get();
+    RootedScript script(cx);
+    jsbytecode* pc;
+    baselineScriptAndPc(script.address(), &pc);
+
+    fprintf(stderr, "  script = %p, pc = %p (offset %u)\n", (void*)script, pc, uint32_t(script->pcToOffset(pc)));
+    fprintf(stderr, "  current op: %s\n", CodeName[*pc]);
+
+    fprintf(stderr, "  actual args: %d\n", numActualArgs());
+
+    BaselineFrame* frame = baselineFrame();
+
+    for (unsigned i = 0; i < frame->numValueSlots(); i++) {
+        fprintf(stderr, "  slot %u: ", i);
+#ifdef DEBUG
+        Value* v = frame->valueSlot(i);
+        DumpValue(*v);
+#else
+        fprintf(stderr, "?\n");
+#endif
+    }
+}
+
+void
+JitFrameIterator::dump() const
+{
+    switch (type_) {
+      case JitFrame_Entry:
+        fprintf(stderr, " Entry frame\n");
+        fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
+        break;
+      case JitFrame_BaselineJS:
+        dumpBaseline();
+        break;
+      case JitFrame_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(TlsContext.get(), this);
+        for (;;) {
+            frames.dump();
+            if (!frames.more())
+                break;
+            ++frames;
+        }
+        break;
+      }
+      case JitFrame_Rectifier:
+        fprintf(stderr, " Rectifier frame\n");
+        fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
+        break;
+      case JitFrame_IonICCall:
+        fprintf(stderr, " Ion IC call\n");
+        fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
+        break;
+      case JitFrame_Exit:
+        fprintf(stderr, " Exit frame\n");
+        break;
+    };
+    fputc('\n', stderr);
+}
+
+#ifdef DEBUG
+bool
+JitFrameIterator::verifyReturnAddressUsingNativeToBytecodeMap()
+{
+    MOZ_ASSERT(returnAddressToFp_ != nullptr);
+
+    // Only handle Ion frames for now.
+    if (type_ != JitFrame_IonJS && type_ != JitFrame_BaselineJS)
+        return true;
+
+    JSRuntime* rt = TlsContext.get()->runtime();
+
+    // Don't verify while off thread.
+    if (!CurrentThreadCanAccessRuntime(rt))
+        return true;
+
+    // Don't verify if sampling is being suppressed.
+    if (!TlsContext.get()->isProfilerSamplingEnabled())
+        return true;
+
+    if (JS::CurrentThreadIsHeapMinorCollecting())
+        return true;
+
+    JitRuntime* jitrt = rt->jitRuntime();
+
+    // Look up and print bytecode info for the native address.
+    const JitcodeGlobalEntry* entry = jitrt->getJitcodeGlobalTable()->lookup(returnAddressToFp_);
+    if (!entry)
+        return true;
+
+    JitSpew(JitSpew_Profiling, "Found nativeToBytecode entry for %p: %p - %p",
+            returnAddressToFp_, entry->nativeStartAddr(), entry->nativeEndAddr());
+
+    JitcodeGlobalEntry::BytecodeLocationVector location;
+    uint32_t depth = UINT32_MAX;
+    if (!entry->callStackAtAddr(rt, returnAddressToFp_, location, &depth))
+        return false;
+    MOZ_ASSERT(depth > 0 && depth != UINT32_MAX);
+    MOZ_ASSERT(location.length() == depth);
+
+    JitSpew(JitSpew_Profiling, "Found bytecode location of depth %d:", depth);
+    for (size_t i = 0; i < location.length(); i++) {
+        JitSpew(JitSpew_Profiling, "   %s:%" PRIuSIZE " - %" PRIuSIZE,
+                location[i].script->filename(), location[i].script->lineno(),
+                size_t(location[i].pc - location[i].script->code()));
+    }
+
+    if (type_ == JitFrame_IonJS) {
+        // Create an InlineFrameIterator here and verify the mapped info against the iterator info.
+        InlineFrameIterator inlineFrames(TlsContext.get(), this);
+        for (size_t idx = 0; idx < location.length(); idx++) {
+            MOZ_ASSERT(idx < location.length());
+            MOZ_ASSERT_IF(idx < location.length() - 1, inlineFrames.more());
+
+            JitSpew(JitSpew_Profiling,
+                    "Match %d: ION %s:%" PRIuSIZE "(%" PRIuSIZE ") vs N2B %s:%" PRIuSIZE "(%" PRIuSIZE ")",
+                    (int)idx,
+                    inlineFrames.script()->filename(),
+                    inlineFrames.script()->lineno(),
+                    size_t(inlineFrames.pc() - inlineFrames.script()->code()),
+                    location[idx].script->filename(),
+                    location[idx].script->lineno(),
+                    size_t(location[idx].pc - location[idx].script->code()));
+
+            MOZ_ASSERT(inlineFrames.script() == location[idx].script);
+
+            if (inlineFrames.more())
+                ++inlineFrames;
+        }
+    }
+
+    return true;
+}
+#endif // DEBUG
--- a/js/src/jit/JitFrames-inl.h
+++ b/js/src/jit/JitFrames-inl.h
@@ -4,17 +4,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_JitFrames_inl_h
 #define jit_JitFrames_inl_h
 
 #include "jit/JitFrames.h"
 
-#include "jit/JitFrameIterator.h"
 #include "jit/LIR.h"
 
 #include "jit/JitFrameIterator-inl.h"
 
 namespace js {
 namespace jit {
 
 inline void
@@ -22,44 +21,16 @@ SafepointIndex::resolve()
 {
     MOZ_ASSERT(!resolved);
     safepointOffset_ = safepoint_->offset();
 #ifdef DEBUG
     resolved = true;
 #endif
 }
 
-inline uint8_t*
-JitFrameIterator::returnAddress() const
-{
-    CommonFrameLayout* current = (CommonFrameLayout*) current_;
-    return current->returnAddress();
-}
-
-inline size_t
-JitFrameIterator::prevFrameLocalSize() const
-{
-    CommonFrameLayout* current = (CommonFrameLayout*) current_;
-    return current->prevFrameLocalSize();
-}
-
-inline FrameType
-JitFrameIterator::prevType() const
-{
-    CommonFrameLayout* current = (CommonFrameLayout*) current_;
-    return current->prevType();
-}
-
-inline ExitFrameLayout*
-JitFrameIterator::exitFrame() const
-{
-    MOZ_ASSERT(isExitFrame());
-    return (ExitFrameLayout*) fp();
-}
-
 inline BaselineFrame*
 GetTopBaselineFrame(JSContext* cx)
 {
     JitFrameIterator iter(cx);
     MOZ_ASSERT(iter.type() == JitFrame_Exit);
     ++iter;
     if (iter.isBaselineStub())
         ++iter;
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -91,235 +91,16 @@ ReadFrameInt32Slot(JitFrameLayout* fp, i
 }
 
 static inline bool
 ReadFrameBooleanSlot(JitFrameLayout* fp, int32_t slot)
 {
     return *(bool*) AddressOfFrameSlot(fp, slot);
 }
 
-JitFrameIterator::JitFrameIterator()
-  : current_(nullptr),
-    type_(JitFrame_Exit),
-    returnAddressToFp_(nullptr),
-    frameSize_(0),
-    cachedSafepointIndex_(nullptr),
-    activation_(nullptr)
-{
-}
-
-JitFrameIterator::JitFrameIterator(const JitActivation* activation)
-  : current_(activation->exitFP()),
-    type_(JitFrame_Exit),
-    returnAddressToFp_(nullptr),
-    frameSize_(0),
-    cachedSafepointIndex_(nullptr),
-    activation_(activation)
-{
-    if (activation_->bailoutData()) {
-        current_ = activation_->bailoutData()->fp();
-        frameSize_ = activation_->bailoutData()->topFrameSize();
-        type_ = JitFrame_Bailout;
-    }
-}
-
-JitFrameIterator::JitFrameIterator(JSContext* cx)
-  : JitFrameIterator(cx->activation()->asJit())
-{
-}
-
-JitFrameIterator::JitFrameIterator(const ActivationIterator& activations)
-  : JitFrameIterator(activations->asJit())
-{
-}
-
-bool
-JitFrameIterator::checkInvalidation() const
-{
-    IonScript* dummy;
-    return checkInvalidation(&dummy);
-}
-
-bool
-JitFrameIterator::checkInvalidation(IonScript** ionScriptOut) const
-{
-    JSScript* script = this->script();
-    if (isBailoutJS()) {
-        *ionScriptOut = activation_->bailoutData()->ionScript();
-        return !script->hasIonScript() || script->ionScript() != *ionScriptOut;
-    }
-
-    uint8_t* returnAddr = returnAddressToFp();
-    // N.B. the current IonScript is not the same as the frame's
-    // IonScript if the frame has since been invalidated.
-    bool invalidated = !script->hasIonScript() ||
-                       !script->ionScript()->containsReturnAddress(returnAddr);
-    if (!invalidated)
-        return false;
-
-    int32_t invalidationDataOffset = ((int32_t*) returnAddr)[-1];
-    uint8_t* ionScriptDataOffset = returnAddr + invalidationDataOffset;
-    IonScript* ionScript = (IonScript*) Assembler::GetPointer(ionScriptDataOffset);
-    MOZ_ASSERT(ionScript->containsReturnAddress(returnAddr));
-    *ionScriptOut = ionScript;
-    return true;
-}
-
-CalleeToken
-JitFrameIterator::calleeToken() const
-{
-    return ((JitFrameLayout*) current_)->calleeToken();
-}
-
-JSFunction*
-JitFrameIterator::callee() const
-{
-    MOZ_ASSERT(isScripted());
-    MOZ_ASSERT(isFunctionFrame());
-    return CalleeTokenToFunction(calleeToken());
-}
-
-JSFunction*
-JitFrameIterator::maybeCallee() const
-{
-    if (isScripted() && (isFunctionFrame()))
-        return callee();
-    return nullptr;
-}
-
-bool
-JitFrameIterator::isBareExit() const
-{
-    if (type_ != JitFrame_Exit)
-        return false;
-    return exitFrame()->isBareExit();
-}
-
-bool
-JitFrameIterator::isFunctionFrame() const
-{
-    return CalleeTokenIsFunction(calleeToken());
-}
-
-JSScript*
-JitFrameIterator::script() const
-{
-    MOZ_ASSERT(isScripted());
-    if (isBaselineJS())
-        return baselineFrame()->script();
-    JSScript* script = ScriptFromCalleeToken(calleeToken());
-    MOZ_ASSERT(script);
-    return script;
-}
-
-void
-JitFrameIterator::baselineScriptAndPc(JSScript** scriptRes, jsbytecode** pcRes) const
-{
-    MOZ_ASSERT(isBaselineJS());
-    JSScript* script = this->script();
-    if (scriptRes)
-        *scriptRes = script;
-
-    MOZ_ASSERT(pcRes);
-
-    // Use the frame's override pc, if we have one. This should only happen
-    // when we're in FinishBailoutToBaseline, handling an exception or toggling
-    // debug mode.
-    if (jsbytecode* overridePc = baselineFrame()->maybeOverridePc()) {
-        *pcRes = overridePc;
-        return;
-    }
-
-    // Else, there must be an ICEntry for the current return address.
-    uint8_t* retAddr = returnAddressToFp();
-    ICEntry& icEntry = script->baselineScript()->icEntryFromReturnAddress(retAddr);
-    *pcRes = icEntry.pc(script);
-}
-
-Value*
-JitFrameIterator::actualArgs() const
-{
-    return jsFrame()->argv() + 1;
-}
-
-uint8_t*
-JitFrameIterator::prevFp() const
-{
-    return current_ + current()->prevFrameLocalSize() + current()->headerSize();
-}
-
-JitFrameIterator&
-JitFrameIterator::operator++()
-{
-    MOZ_ASSERT(type_ != JitFrame_Entry);
-
-    frameSize_ = prevFrameLocalSize();
-    cachedSafepointIndex_ = nullptr;
-
-    // If the next frame is the entry frame, just exit. Don't update current_,
-    // since the entry and first frames overlap.
-    if (current()->prevType() == JitFrame_Entry) {
-        type_ = JitFrame_Entry;
-        return *this;
-    }
-
-    type_ = current()->prevType();
-    returnAddressToFp_ = current()->returnAddress();
-    current_ = prevFp();
-
-    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 tracing 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);
-
-    char* floatSpill = reinterpret_cast<char*>(spillAlign);
-    FloatRegisterSet fregs = reader.allFloatSpills().set();
-    fregs = fregs.reduceSetForPush();
-    for (FloatRegisterBackwardIterator iter(fregs); iter.more(); ++iter) {
-        floatSpill -= (*iter).size();
-        for (uint32_t a = 0; a < (*iter).numAlignedAliased(); a++) {
-            // Only say that registers that actually start here start here.
-            // e.g. d0 should not start at s1, only at s0.
-            FloatRegister ftmp;
-            (*iter).alignedAliased(a, &ftmp);
-            machine.setRegisterLocation(ftmp, (double*)floatSpill);
-        }
-    }
-
-    return machine;
-}
-
 static uint32_t
 NumArgAndLocalSlots(const InlineFrameIterator& frame)
 {
     JSScript* script = frame.script();
     return CountArgSlots(script, frame.maybeCalleeTemplate()) + script->nfixed();
 }
 
 static void
@@ -2243,73 +2024,16 @@ SnapshotIterator::maybeReadAllocByIndex(
     }
 
     while (moreAllocations())
         skip();
 
     return s;
 }
 
-JitFrameLayout*
-JitFrameIterator::jsFrame() const
-{
-    MOZ_ASSERT(isScripted());
-    if (isBailoutJS())
-        return (JitFrameLayout*) activation_->bailoutData()->fp();
-
-    return (JitFrameLayout*) fp();
-}
-
-IonScript*
-JitFrameIterator::ionScript() const
-{
-    MOZ_ASSERT(isIonScripted());
-    if (isBailoutJS())
-        return activation_->bailoutData()->ionScript();
-
-    IonScript* ionScript = nullptr;
-    if (checkInvalidation(&ionScript))
-        return ionScript;
-    return ionScriptFromCalleeToken();
-}
-
-IonScript*
-JitFrameIterator::ionScriptFromCalleeToken() const
-{
-    MOZ_ASSERT(isIonJS());
-    MOZ_ASSERT(!checkInvalidation());
-    return script()->ionScript();
-}
-
-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(JSContext* cx, const JitFrameIterator* iter)
   : calleeTemplate_(cx),
     calleeRVA_(),
     script_(cx)
 {
     resetOn(iter);
 }
 
@@ -2562,32 +2286,16 @@ InlineFrameIterator::isConstructing() co
         MOZ_ASSERT(IsCallPC(parent.pc()) && !IsSpreadCallPC(parent.pc()));
 
         return IsConstructorCallPC(parent.pc());
     }
 
     return frame_->isConstructing();
 }
 
-bool
-JitFrameIterator::isConstructing() const
-{
-    return CalleeTokenIsConstructing(calleeToken());
-}
-
-unsigned
-JitFrameIterator::numActualArgs() const
-{
-    if (isScripted())
-        return jsFrame()->numActualArgs();
-
-    MOZ_ASSERT(isExitFrameLayout<NativeExitFrameLayout>());
-    return exitFrame()->as<NativeExitFrameLayout>()->argc();
-}
-
 void
 SnapshotIterator::warnUnreadableAllocation()
 {
     fprintf(stderr, "Warning! Tried to access unreadable value allocation (possible f.arguments).\n");
 }
 
 struct DumpOp {
     explicit DumpOp(unsigned int i) : i_(i) {}
@@ -2600,59 +2308,16 @@ struct DumpOp {
 #else
         fprintf(stderr, "?\n");
 #endif
         i_++;
     }
 };
 
 void
-JitFrameIterator::dumpBaseline() const
-{
-    MOZ_ASSERT(isBaselineJS());
-
-    fprintf(stderr, " JS Baseline frame\n");
-    if (isFunctionFrame()) {
-        fprintf(stderr, "  callee fun: ");
-#ifdef DEBUG
-        DumpObject(callee());
-#else
-        fprintf(stderr, "?\n");
-#endif
-    } else {
-        fprintf(stderr, "  global frame, no callee\n");
-    }
-
-    fprintf(stderr, "  file %s line %" PRIuSIZE "\n",
-            script()->filename(), script()->lineno());
-
-    JSContext* cx = TlsContext.get();
-    RootedScript script(cx);
-    jsbytecode* pc;
-    baselineScriptAndPc(script.address(), &pc);
-
-    fprintf(stderr, "  script = %p, pc = %p (offset %u)\n", (void*)script, pc, uint32_t(script->pcToOffset(pc)));
-    fprintf(stderr, "  current op: %s\n", CodeName[*pc]);
-
-    fprintf(stderr, "  actual args: %d\n", numActualArgs());
-
-    BaselineFrame* frame = baselineFrame();
-
-    for (unsigned i = 0; i < frame->numValueSlots(); i++) {
-        fprintf(stderr, "  slot %u: ", i);
-#ifdef DEBUG
-        Value* v = frame->valueSlot(i);
-        DumpValue(*v);
-#else
-        fprintf(stderr, "?\n");
-#endif
-    }
-}
-
-void
 InlineFrameIterator::dump() const
 {
     MaybeReadFallback fallback(UndefinedValue());
 
     if (more())
         fprintf(stderr, " JS frame (inlined)\n");
     else
         fprintf(stderr, " JS frame\n");
@@ -2705,133 +2370,16 @@ InlineFrameIterator::dump() const
 #else
         fprintf(stderr, "?\n");
 #endif
     }
 
     fputc('\n', stderr);
 }
 
-void
-JitFrameIterator::dump() const
-{
-    switch (type_) {
-      case JitFrame_Entry:
-        fprintf(stderr, " Entry frame\n");
-        fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
-        break;
-      case JitFrame_BaselineJS:
-        dumpBaseline();
-        break;
-      case JitFrame_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(TlsContext.get(), this);
-        for (;;) {
-            frames.dump();
-            if (!frames.more())
-                break;
-            ++frames;
-        }
-        break;
-      }
-      case JitFrame_Rectifier:
-        fprintf(stderr, " Rectifier frame\n");
-        fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
-        break;
-      case JitFrame_IonICCall:
-        fprintf(stderr, " Ion IC call\n");
-        fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
-        break;
-      case JitFrame_Exit:
-        fprintf(stderr, " Exit frame\n");
-        break;
-    };
-    fputc('\n', stderr);
-}
-
-#ifdef DEBUG
-bool
-JitFrameIterator::verifyReturnAddressUsingNativeToBytecodeMap()
-{
-    MOZ_ASSERT(returnAddressToFp_ != nullptr);
-
-    // Only handle Ion frames for now.
-    if (type_ != JitFrame_IonJS && type_ != JitFrame_BaselineJS)
-        return true;
-
-    JSRuntime* rt = TlsContext.get()->runtime();
-
-    // Don't verify while off thread.
-    if (!CurrentThreadCanAccessRuntime(rt))
-        return true;
-
-    // Don't verify if sampling is being suppressed.
-    if (!TlsContext.get()->isProfilerSamplingEnabled())
-        return true;
-
-    if (JS::CurrentThreadIsHeapMinorCollecting())
-        return true;
-
-    JitRuntime* jitrt = rt->jitRuntime();
-
-    // Look up and print bytecode info for the native address.
-    const JitcodeGlobalEntry* entry = jitrt->getJitcodeGlobalTable()->lookup(returnAddressToFp_);
-    if (!entry)
-        return true;
-
-    JitSpew(JitSpew_Profiling, "Found nativeToBytecode entry for %p: %p - %p",
-            returnAddressToFp_, entry->nativeStartAddr(), entry->nativeEndAddr());
-
-    JitcodeGlobalEntry::BytecodeLocationVector location;
-    uint32_t depth = UINT32_MAX;
-    if (!entry->callStackAtAddr(rt, returnAddressToFp_, location, &depth))
-        return false;
-    MOZ_ASSERT(depth > 0 && depth != UINT32_MAX);
-    MOZ_ASSERT(location.length() == depth);
-
-    JitSpew(JitSpew_Profiling, "Found bytecode location of depth %d:", depth);
-    for (size_t i = 0; i < location.length(); i++) {
-        JitSpew(JitSpew_Profiling, "   %s:%" PRIuSIZE " - %" PRIuSIZE,
-                location[i].script->filename(), location[i].script->lineno(),
-                size_t(location[i].pc - location[i].script->code()));
-    }
-
-    if (type_ == JitFrame_IonJS) {
-        // Create an InlineFrameIterator here and verify the mapped info against the iterator info.
-        InlineFrameIterator inlineFrames(TlsContext.get(), this);
-        for (size_t idx = 0; idx < location.length(); idx++) {
-            MOZ_ASSERT(idx < location.length());
-            MOZ_ASSERT_IF(idx < location.length() - 1, inlineFrames.more());
-
-            JitSpew(JitSpew_Profiling,
-                    "Match %d: ION %s:%" PRIuSIZE "(%" PRIuSIZE ") vs N2B %s:%" PRIuSIZE "(%" PRIuSIZE ")",
-                    (int)idx,
-                    inlineFrames.script()->filename(),
-                    inlineFrames.script()->lineno(),
-                    size_t(inlineFrames.pc() - inlineFrames.script()->code()),
-                    location[idx].script->filename(),
-                    location[idx].script->lineno(),
-                    size_t(location[idx].pc - location[idx].script->code()));
-
-            MOZ_ASSERT(inlineFrames.script() == location[idx].script);
-
-            if (inlineFrames.more())
-                ++inlineFrames;
-        }
-    }
-
-    return true;
-}
-#endif // DEBUG
-
 JitProfilingFrameIterator::JitProfilingFrameIterator(
         JSContext* cx, const JS::ProfilingFrameIterator::RegisterState& state)
 {
     // If no profilingActivation is live, initialize directly to
     // end-of-iteration state.
     if (!cx->profilingActivation()) {
         type_ = JitFrame_Entry;
         fp_ = nullptr;
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -229,16 +229,17 @@ UNIFIED_SOURCES += [
     'jit/IonAnalysis.cpp',
     'jit/IonBuilder.cpp',
     'jit/IonCacheIRCompiler.cpp',
     'jit/IonCaches.cpp',
     'jit/IonControlFlow.cpp',
     'jit/IonIC.cpp',
     'jit/IonOptimizationLevels.cpp',
     'jit/JitcodeMap.cpp',
+    'jit/JitFrameIterator.cpp',
     'jit/JitFrames.cpp',
     'jit/JitOptions.cpp',
     'jit/JitSpewer.cpp',
     'jit/JSONSpewer.cpp',
     'jit/LICM.cpp',
     'jit/Linker.cpp',
     'jit/LIR.cpp',
     'jit/LoopUnroller.cpp',