Bug 829830 - Exactly root the fields in StackIter; r=nbp
authorTerrence Cole <terrence@mozilla.com>
Mon, 14 Jan 2013 18:02:24 -0800
changeset 119155 1739c6c51d1c782aac8c51215c44dcfbeb3e4192
parent 119154 27f62505f15ce4dc3f717bf362a61c0442d5ea44
child 119156 e3497f146c7cbd2cb4ccd40ad0d85f0b3cedbfb4
push id24195
push userMs2ger@gmail.com
push dateSat, 19 Jan 2013 16:10:11 +0000
treeherdermozilla-central@02e12a80aef9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs829830
milestone21.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 829830 - Exactly root the fields in StackIter; r=nbp
js/src/ion/Bailouts.cpp
js/src/ion/IonFrameIterator-inl.h
js/src/ion/IonFrameIterator.h
js/src/ion/IonFrames.cpp
js/src/jsfun.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/ion/Bailouts.cpp
+++ b/js/src/ion/Bailouts.cpp
@@ -41,33 +41,33 @@ SnapshotIterator::SnapshotIterator(const
   : SnapshotReader(iter.ionScript()->snapshots() + iter.snapshotOffset(),
                    iter.ionScript()->snapshots() + iter.ionScript()->snapshotsSize()),
     fp_(iter.jsFrame()),
     machine_(iter.machineState()),
     ionScript_(iter.ionScript())
 {
 }
 
-InlineFrameIterator::InlineFrameIterator(const IonBailoutIterator *iter)
+InlineFrameIterator::InlineFrameIterator(JSContext *cx, const IonBailoutIterator *iter)
   : frame_(iter),
     framesRead_(0),
-    callee_(NULL),
-    script_(NULL)
+    callee_(cx),
+    script_(cx)
 {
     if (iter) {
         start_ = SnapshotIterator(*iter);
         findNextFrame();
     }
 }
 
 void
 IonBailoutIterator::dump() const
 {
     if (type_ == IonFrame_OptimizedJS) {
-        InlineFrameIterator frames(this);
+        InlineFrameIterator frames(GetIonContext()->cx, this);
         for (;;) {
             frames.dump();
             if (!frames.more())
                 break;
             ++frames;
         }
     } else {
         IonFrameIterator::dump();
--- a/js/src/ion/IonFrameIterator-inl.h
+++ b/js/src/ion/IonFrameIterator-inl.h
@@ -44,34 +44,34 @@ SnapshotIterator::readFrameArgs(Op op, c
     if (iterEnd >= formalEnd) {
         for (; i < iterEnd; i++)
             op(argv[i]);
     }
 }
 
 template <class Op>
 inline void
-InlineFrameIterator::forEachCanonicalActualArg(Op op, unsigned start, unsigned count) const
+InlineFrameIterator::forEachCanonicalActualArg(JSContext *cx, Op op, unsigned start, unsigned count) const
 {
     unsigned nactual = numActualArgs();
     if (count == unsigned(-1))
         count = nactual - start;
 
     unsigned end = start + count;
     unsigned nformal = callee()->nargs;
 
     JS_ASSERT(start <= end && end <= nactual);
 
     if (more()) {
         // There is still a parent frame of this inlined frame.
         // Take arguments of the caller (parent inlined frame) it holds all actual
         // arguments, needed in case of overflow, and because the analyze phase
         // disable Ion inlining if the function redefine its arguments with JSOP_SETARG.
 
-        InlineFrameIterator it(this);
+        InlineFrameIterator it(cx, this);
         ++it;
         SnapshotIterator s(it.snapshotIterator());
 
         // Skip over all slots untill we get to the arguments slots
         // the +2 is for [this] and [scopechain]
         JS_ASSERT(s.slots() >= nactual + 2);
         unsigned skip = s.slots() - nactual - 2;
         for (unsigned j = 0; j < skip; j++)
--- a/js/src/ion/IonFrameIterator.h
+++ b/js/src/ion/IonFrameIterator.h
@@ -259,59 +259,65 @@ class SnapshotIterator : public Snapshot
 // Reads frame information in callstack order (that is, innermost frame to
 // outermost frame).
 class InlineFrameIterator
 {
     const IonFrameIterator *frame_;
     SnapshotIterator start_;
     SnapshotIterator si_;
     unsigned framesRead_;
-    HeapPtr<JSFunction> callee_;
-    HeapPtr<JSScript> script_;
+    RootedFunction callee_;
+    RootedScript script_;
     jsbytecode *pc_;
     uint32_t numActualArgs_;
 
   private:
     void findNextFrame();
 
   public:
-    InlineFrameIterator(const IonFrameIterator *iter);
-    InlineFrameIterator(const IonBailoutIterator *iter);
-    InlineFrameIterator(const InlineFrameIterator *iter);
+    InlineFrameIterator(JSContext *cx, const IonFrameIterator *iter);
+    InlineFrameIterator(JSContext *cx, const IonBailoutIterator *iter);
+    InlineFrameIterator(JSContext *cx, const InlineFrameIterator *iter);
 
     bool more() const {
         return frame_ && framesRead_ < start_.frameCount();
     }
     JSFunction *callee() const {
         JS_ASSERT(callee_);
         return callee_;
     }
     JSFunction *maybeCallee() const {
         return callee_;
     }
     unsigned numActualArgs() const;
 
     template <class Op>
-    inline void forEachCanonicalActualArg(Op op, unsigned start, unsigned count) const;
+    inline void forEachCanonicalActualArg(JSContext *cx, Op op, unsigned start, unsigned count) const;
 
     UnrootedScript script() const {
-        return script_.get();
+        return script_;
     }
     jsbytecode *pc() const {
         return pc_;
     }
     SnapshotIterator snapshotIterator() const {
         return si_;
     }
     bool isFunctionFrame() const;
     bool isConstructing() const;
     JSObject *scopeChain() const;
     JSObject *thisObject() const;
     InlineFrameIterator &operator++();
 
     void dump() const;
+
+    void resetOn(const IonFrameIterator *iter);
+
+  private:
+    InlineFrameIterator() MOZ_DELETE;
+    InlineFrameIterator(const InlineFrameIterator &iter) MOZ_DELETE;
 };
 
 } // namespace ion
 } // namespace js
 
 #endif // jsion_frames_iterator_h__
 
--- a/js/src/ion/IonFrames.cpp
+++ b/js/src/ion/IonFrames.cpp
@@ -311,17 +311,17 @@ ion::HandleException(ResumeFromException
     // an error in between ConvertFrames and ThunkToInterpreter.
     js_delete(cx->runtime->ionActivation->maybeTakeBailout());
 
     IonFrameIterator iter(cx->runtime->ionTop);
     while (!iter.isEntry()) {
         if (iter.isScripted()) {
             // Search each inlined frame for live iterator objects, and close
             // them.
-            InlineFrameIterator frames(&iter);
+            InlineFrameIterator frames(cx, &iter);
             for (;;) {
                 CloseLiveIterators(cx, frames);
 
                 // When profiling, each frame popped needs a notification that
                 // the function has exited, so invoke the probe that a function
                 // is exiting.
                 AutoAssertNoGC nogc;
                 RawScript script = frames.script();
@@ -688,17 +688,17 @@ ion::GetPcScript(JSContext *cx, MutableH
     }
 
     // Attempt to lookup address in cache.
     if (rt->ionPcScriptCache && rt->ionPcScriptCache->get(rt, hash, retAddr, scriptRes, pcRes))
         return;
 
     // Lookup failed: undertake expensive process to recover the innermost inlined frame.
     ++it; // Skip exit frame.
-    InlineFrameIterator ifi(&it);
+    InlineFrameIterator ifi(cx, &it);
 
     // Set the result.
     scriptRes.set(ifi.script());
     if (pcRes)
         *pcRes = ifi.pc();
 
     // Add entry to cache.
     if (rt->ionPcScriptCache)
@@ -870,33 +870,40 @@ IonFrameIterator::safepoint() const
 
 const OsiIndex *
 IonFrameIterator::osiIndex() const
 {
     SafepointReader reader(ionScript(), safepoint());
     return ionScript()->getOsiIndex(reader.osiReturnPointOffset());
 }
 
-InlineFrameIterator::InlineFrameIterator(const IonFrameIterator *iter)
-  : frame_(iter),
-    framesRead_(0),
-    callee_(NULL),
-    script_(NULL)
+InlineFrameIterator::InlineFrameIterator(JSContext *cx, const IonFrameIterator *iter)
+  : callee_(cx),
+    script_(cx)
 {
+    resetOn(iter);
+}
+
+void
+InlineFrameIterator::resetOn(const IonFrameIterator *iter)
+{
+    frame_ = iter;
+    framesRead_ = 0;
+
     if (iter) {
         start_ = SnapshotIterator(*iter);
         findNextFrame();
     }
 }
 
-InlineFrameIterator::InlineFrameIterator(const InlineFrameIterator *iter)
+InlineFrameIterator::InlineFrameIterator(JSContext *cx, const InlineFrameIterator *iter)
   : frame_(iter->frame_),
     framesRead_(0),
-    callee_(NULL),
-    script_(NULL)
+    callee_(cx),
+    script_(cx)
 {
     if (frame_) {
         start_ = SnapshotIterator(*frame_);
         // findNextFrame will iterate to the next frame and init. everything.
         // Therefore to settle on the same frame, we report one frame less readed.
         framesRead_ = iter->framesRead_ - 1;
         findNextFrame();
     }
@@ -975,17 +982,17 @@ MachineState::FromBailout(uintptr_t regs
     return machine;
 }
 
 bool
 InlineFrameIterator::isConstructing() const
 {
     // Skip the current frame and look at the caller's.
     if (more()) {
-        InlineFrameIterator parent(*this);
+        InlineFrameIterator parent(GetIonContext()->cx, this);
         ++parent;
 
         // Inlined Getters and Setters are never constructing.
         if (IsGetterPC(parent.pc()) || IsSetterPC(parent.pc()))
             return false;
 
         // In the case of a JS frame, look up the pc from the snapshot.
         JS_ASSERT(js_CodeSpec[*parent.pc()].format & JOF_INVOKE);
@@ -1003,17 +1010,17 @@ IonFrameIterator::isConstructing() const
 
     // Skip the current frame and look at the caller's.
     do {
         ++parent;
     } while (!parent.done() && !parent.isScripted());
 
     if (parent.isScripted()) {
         // In the case of a JS frame, look up the pc from the snapshot.
-        InlineFrameIterator inlinedParent(&parent);
+        InlineFrameIterator inlinedParent(GetIonContext()->cx, &parent);
 
         //Inlined Getters and Setters are never constructing.
         if (IsGetterPC(inlinedParent.pc()) || IsSetterPC(inlinedParent.pc()))
             return false;
 
         JS_ASSERT(js_CodeSpec[*inlinedParent.pc()].format & JOF_INVOKE);
 
         return (JSOp)*inlinedParent.pc() == JSOP_NEW;
@@ -1101,17 +1108,17 @@ IonFrameIterator::dump() const
 {
     switch (type_) {
       case IonFrame_Entry:
         fprintf(stderr, " Entry frame\n");
         fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
         break;
       case IonFrame_OptimizedJS:
       {
-        InlineFrameIterator frames(this);
+        InlineFrameIterator frames(GetIonContext()->cx, this);
         for (;;) {
             frames.dump();
             if (!frames.more())
                 break;
             ++frames;
         }
         break;
       }
@@ -1187,17 +1194,17 @@ InlineFrameIterator::dump() const
                 fprintf(stderr, "  scope chain: ");
             else if (i == 1)
                 fprintf(stderr, "  this: ");
             else if (i - 2 < callee()->nargs)
                 fprintf(stderr, "  formal (arg %d): ", i - 2);
             else {
                 if (i - 2 == callee()->nargs && numActualArgs() > callee()->nargs) {
                     DumpOp d(callee()->nargs);
-                    forEachCanonicalActualArg(d, d.i_, numActualArgs() - d.i_);
+                    forEachCanonicalActualArg(GetIonContext()->cx, d, d.i_, numActualArgs() - d.i_);
                 }
 
                 fprintf(stderr, "  slot %d: ", i - 2 - callee()->nargs);
             }
         } else
             fprintf(stderr, "  slot %u: ", i);
 #ifdef DEBUG
         js_DumpValue(si.maybeRead());
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -894,30 +894,30 @@ js_fun_apply(JSContext *cx, unsigned arg
         // supposed to be a fast path as opposed to StackIter which is doing
         // complex logic to settle on the next frame twice.
         if (fp->beginsIonActivation()) {
             ion::IonActivationIterator activations(cx);
             ion::IonFrameIterator frame(activations);
             JS_ASSERT(frame.isNative());
             // Stop on the next Ion JS Frame.
             ++frame;
-            ion::InlineFrameIterator iter(&frame);
+            ion::InlineFrameIterator iter(cx, &frame);
 
             unsigned length = iter.numActualArgs();
             JS_ASSERT(length <= StackSpace::ARGS_LENGTH_MAX);
 
             if (!cx->stack.pushInvokeArgs(cx, length, &args))
                 return false;
 
             /* Push fval, obj, and aobj's elements as args. */
             args.setCallee(fval);
             args.setThis(vp[2]);
 
             /* Steps 7-8. */
-            iter.forEachCanonicalActualArg(CopyTo(args.array()), 0, -1);
+            iter.forEachCanonicalActualArg(cx, CopyTo(args.array()), 0, -1);
         } else
 #endif
         {
             unsigned length = fp->numActualArgs();
             JS_ASSERT(length <= StackSpace::ARGS_LENGTH_MAX);
 
             if (!cx->stack.pushInvokeArgs(cx, length, &args))
                 return false;
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -59,17 +59,17 @@ ArgumentsObject::MaybeForwardToCallObjec
 struct CopyFrameArgs
 {
     AbstractFramePtr frame_;
 
     CopyFrameArgs(AbstractFramePtr frame)
       : frame_(frame)
     { }
 
-    void copyArgs(HeapValue *dst) const {
+    void copyArgs(JSContext *, HeapValue *dst) const {
         CopyStackFrameArguments(frame_, dst);
     }
 
     /*
      * If a call object exists and the arguments object aliases formals, the
      * call object is the canonical location for formals.
      */
     void maybeForwardToCallObject(JSObject *obj, ArgumentsData *data) {
@@ -80,24 +80,24 @@ struct CopyFrameArgs
 struct CopyStackIterArgs
 {
     StackIter &iter_;
 
     CopyStackIterArgs(StackIter &iter)
       : iter_(iter)
     { }
 
-    void copyArgs(HeapValue *dstBase) const {
+    void copyArgs(JSContext *cx, HeapValue *dstBase) const {
         if (!iter_.isIon()) {
             CopyStackFrameArguments(iter_.abstractFramePtr(), dstBase);
             return;
         }
 
         /* Copy actual arguments. */
-        iter_.ionForEachCanonicalActualArg(CopyToHeap(dstBase));
+        iter_.ionForEachCanonicalActualArg(cx, CopyToHeap(dstBase));
 
         /* Define formals which are not part of the actuals. */
         unsigned numActuals = iter_.numActualArgs();
         unsigned numFormals = iter_.callee()->nargs;
         if (numActuals < numFormals) {
             HeapValue *dst = dstBase + numActuals, *dstEnd = dstBase + numFormals;
             while (dst != dstEnd)
                 (dst++)->init(UndefinedValue());
@@ -150,17 +150,17 @@ ArgumentsObject::create(JSContext *cx, H
         return NULL;
 
     data->numArgs = numArgs;
     data->callee.init(ObjectValue(*callee.get()));
     data->script = script;
 
     /* Copy [0, numArgs) into data->slots. */
     HeapValue *dst = data->args, *dstEnd = data->args + numArgs;
-    copy.copyArgs(dst);
+    copy.copyArgs(cx, dst);
 
     data->deletedBits = reinterpret_cast<size_t *>(dstEnd);
     ClearAllBitArrayElements(data->deletedBits, numDeletedWords);
 
     RawObject obj = JSObject::create(cx, FINALIZE_KIND, shape, type, NULL);
     if (!obj)
         return NULL;
 
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -596,21 +596,21 @@ ContextStack::currentScript(jsbytecode *
 inline HandleObject
 ContextStack::currentScriptedScopeChain() const
 {
     return fp()->scopeChain();
 }
 
 template <class Op>
 inline void
-StackIter::ionForEachCanonicalActualArg(Op op)
+StackIter::ionForEachCanonicalActualArg(JSContext *cx, Op op)
 {
     JS_ASSERT(isIon());
 #ifdef JS_ION
-    ionInlineFrames_.forEachCanonicalActualArg(op, 0, -1);
+    ionInlineFrames_.forEachCanonicalActualArg(cx, op, 0, -1);
 #endif
 }
 
 inline void *
 AbstractFramePtr::maybeHookData() const
 {
     if (isStackFrame())
         return asStackFrame()->maybeHookData();
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1393,17 +1393,17 @@ StackIter::settleOnNewState()
                 // When invoked from JM, we don't re-use the entryfp, so we
                 // may have an empty Ion activation.
                 if (data_.ionFrames_.done()) {
                     data_.state_ = SCRIPTED;
                     return;
                 }
 
                 data_.state_ = ION;
-                ionInlineFrames_ = ion::InlineFrameIterator(&data_.ionFrames_);
+                ionInlineFrames_.resetOn(&data_.ionFrames_);
                 data_.pc_ = ionInlineFrames_.pc();
                 return;
             }
 #endif /* JS_ION */
 
             data_.state_ = SCRIPTED;
             return;
         }
@@ -1427,41 +1427,41 @@ StackIter::settleOnNewState()
         /* Pop the call and keep looking. */
         popCall();
         data_.poppedCallDuringSettle_ = true;
     }
 }
 
 StackIter::Data::Data(JSContext *cx, PerThreadData *perThread, SavedOption savedOption)
   : perThread_(perThread),
-    maybecx_(cx),
+    cx_(cx),
     savedOption_(savedOption),
     poppedCallDuringSettle_(false)
 #ifdef JS_ION
     , ionActivations_(cx),
     ionFrames_((uint8_t *)NULL)
 #endif
 {
 }
 
-StackIter::Data::Data(JSRuntime *rt, StackSegment *seg)
+StackIter::Data::Data(JSContext *cx, JSRuntime *rt, StackSegment *seg)
   : perThread_(&rt->mainThread),
-    maybecx_(NULL),
+    cx_(cx),
     savedOption_(STOP_AT_SAVED),
     poppedCallDuringSettle_(false)
 #ifdef JS_ION
     , ionActivations_(rt),
     ionFrames_((uint8_t *)NULL)
 #endif
 {
 }
 
 StackIter::Data::Data(const StackIter::Data &other)
   : perThread_(other.perThread_),
-    maybecx_(other.maybecx_),
+    cx_(other.cx_),
     savedOption_(other.savedOption_),
     state_(other.state_),
     fp_(other.fp_),
     calls_(other.calls_),
     seg_(other.seg_),
     pc_(other.pc_),
     args_(other.args_),
     poppedCallDuringSettle_(other.poppedCallDuringSettle_)
@@ -1470,17 +1470,17 @@ StackIter::Data::Data(const StackIter::D
     ionFrames_(other.ionFrames_)
 #endif
 {
 }
 
 StackIter::StackIter(JSContext *cx, SavedOption savedOption)
   : data_(cx, &cx->runtime->mainThread, savedOption)
 #ifdef JS_ION
-    , ionInlineFrames_((js::ion::IonFrameIterator*) NULL)
+    , ionInlineFrames_(cx, (js::ion::IonFrameIterator*) NULL)
 #endif
 {
 #ifdef JS_METHODJIT
     CompartmentVector &v = cx->runtime->compartments;
     for (size_t i = 0; i < v.length(); i++)
         mjit::ExpandInlineFrames(v[i]);
 #endif
 
@@ -1488,44 +1488,45 @@ StackIter::StackIter(JSContext *cx, Save
         startOnSegment(seg);
         settleOnNewState();
     } else {
         data_.state_ = DONE;
     }
 }
 
 StackIter::StackIter(JSRuntime *rt, StackSegment &seg)
-  : data_(rt, &seg)
+  : data_(seg.cx(), rt, &seg)
 #ifdef JS_ION
-    , ionInlineFrames_((js::ion::IonFrameIterator*) NULL)
+    , ionInlineFrames_(seg.cx(), (js::ion::IonFrameIterator*) NULL)
 #endif
 {
 #ifdef JS_METHODJIT
     CompartmentVector &v = rt->compartments;
     for (size_t i = 0; i < v.length(); i++)
         mjit::ExpandInlineFrames(v[i]);
 #endif
     startOnSegment(&seg);
     settleOnNewState();
 }
 
 StackIter::StackIter(const StackIter &other)
   : data_(other.data_)
 #ifdef JS_ION
-    , ionInlineFrames_(other.ionInlineFrames_)
+    , ionInlineFrames_(other.data_.seg_->cx(), &other.ionInlineFrames_)
 #endif
 {
 }
 
 StackIter::StackIter(const Data &data)
   : data_(data)
 #ifdef JS_ION
-    , ionInlineFrames_(data_.ionFrames_.isScripted() ? &data_.ionFrames_ : NULL)
+    , ionInlineFrames_(data.cx_, data_.ionFrames_.isScripted() ? &data_.ionFrames_ : NULL)
 #endif
 {
+    JS_ASSERT(data.cx_);
 }
 
 #ifdef JS_ION
 void
 StackIter::popIonFrame()
 {
     AutoAssertNoGC nogc;
     // Keep fp which describes all ion frames.
@@ -1534,17 +1535,17 @@ StackIter::popIonFrame()
         ++ionInlineFrames_;
         data_.pc_ = ionInlineFrames_.pc();
     } else {
         ++data_.ionFrames_;
         while (!data_.ionFrames_.done() && !data_.ionFrames_.isScripted())
             ++data_.ionFrames_;
 
         if (!data_.ionFrames_.done()) {
-            ionInlineFrames_ = ion::InlineFrameIterator(&data_.ionFrames_);
+            ionInlineFrames_.resetOn(&data_.ionFrames_);
             data_.pc_ = ionInlineFrames_.pc();
             return;
         }
 
         // The activation has no other frames. If entryfp is NULL, it was invoked
         // by a native written in C++, using FastInvoke, on top of another activation.
         ion::IonActivation *activation = data_.ionActivations_.activation();
         if (!activation->entryfp()) {
@@ -1609,17 +1610,17 @@ StackIter::copyData() const
 {
 #ifdef JS_ION
     /*
      * This doesn't work for optimized Ion frames since ionInlineFrames_ is
      * not copied.
      */
     JS_ASSERT(data_.ionFrames_.type() != ion::IonFrame_OptimizedJS);
 #endif
-    return data_.maybecx_->new_<Data>(data_);
+    return data_.cx_->new_<Data>(data_);
 }
 
 JSCompartment *
 StackIter::compartment() const
 {
     switch (data_.state_) {
       case DONE:
         break;
@@ -1766,17 +1767,17 @@ StackIter::abstractFramePtr() const
 
 void
 StackIter::updatePcQuadratic()
 {
     switch (data_.state_) {
       case DONE:
         break;
       case SCRIPTED:
-        data_.pc_ = interpFrame()->pcQuadratic(data_.maybecx_);
+        data_.pc_ = interpFrame()->pcQuadratic(data_.cx_);
         return;
       case ION:
         break;
       case NATIVE:
         break;
     }
     JS_NOT_REACHED("Unexpected state");
 }
@@ -1934,18 +1935,18 @@ StackIter::argsObj() const
     JS_NOT_REACHED("Unexpected state");
     return interpFrame()->argsObj();
 }
 
 bool
 StackIter::computeThis() const
 {
     if (isScript() && !isIon()) {
-        JS_ASSERT(data_.maybecx_);
-        return ComputeThis(data_.maybecx_, interpFrame());
+        JS_ASSERT(data_.cx_);
+        return ComputeThis(data_.cx_, interpFrame());
     }
     return true;
 }
 
 Value
 StackIter::thisv() const
 {
     switch (data_.state_) {
@@ -2009,19 +2010,19 @@ StackIter::numFrameSlots() const
         break;
       case ION:
 #ifdef JS_ION
         return ionInlineFrames_.snapshotIterator().slots() - ionInlineFrames_.script()->nfixed;
 #else
         break;
 #endif
       case SCRIPTED:
-        JS_ASSERT(data_.maybecx_);
-        JS_ASSERT(data_.maybecx_->regs().spForStackDepth(0) == interpFrame()->base());
-        return data_.maybecx_->regs().sp - interpFrame()->base();
+        JS_ASSERT(data_.cx_);
+        JS_ASSERT(data_.cx_->regs().spForStackDepth(0) == interpFrame()->base());
+        return data_.cx_->regs().sp - interpFrame()->base();
     }
     JS_NOT_REACHED("Unexpected state");
     return 0;
 }
 
 Value
 StackIter::frameSlotValue(size_t index) const
 {
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1957,17 +1957,17 @@ class StackIter
 
     /*
      * Unlike StackIter itself, StackIter::Data can be allocated on the heap,
      * so this structure should not contain any GC things.
      */
     struct Data
     {
         PerThreadData *perThread_;
-        JSContext    *maybecx_;
+        JSContext    *cx_;
         SavedOption  savedOption_;
 
         State        state_;
 
         StackFrame   *fp_;
         CallArgsList *calls_;
 
         StackSegment *seg_;
@@ -1977,17 +1977,17 @@ class StackIter
         bool          poppedCallDuringSettle_;
 
 #ifdef JS_ION
         ion::IonActivationIterator ionActivations_;
         ion::IonFrameIterator ionFrames_;
 #endif
 
         Data(JSContext *cx, PerThreadData *perThread, SavedOption savedOption);
-        Data(JSRuntime *rt, StackSegment *seg);
+        Data(JSContext *cx, JSRuntime *rt, StackSegment *seg);
         Data(const Data &other);
     };
 
     friend class ContextStack;
   private:
     Data data_;
 #ifdef JS_ION
     ion::InlineFrameIterator ionInlineFrames_;
@@ -2099,17 +2099,17 @@ class StackIter
 
     // These are only valid for the top frame.
     size_t      numFrameSlots() const;
     Value       frameSlotValue(size_t index) const;
 
     CallArgs nativeArgs() const { JS_ASSERT(isNativeCall()); return data_.args_; }
 
     template <class Op>
-    inline void ionForEachCanonicalActualArg(Op op);
+    inline void ionForEachCanonicalActualArg(JSContext *cx, Op op);
 };
 
 /* A filtering of the StackIter to only stop at scripts. */
 class ScriptFrameIter : public StackIter
 {
     void settle() {
         while (!done() && !isScript())
             StackIter::operator++();