Bug 849388 - Allow js::ion::InlineFrameIterator to be used in NoGC contexts. r=nbp,dvander
authorKannan Vijayan <kvijayan@mozilla.com>
Wed, 20 Mar 2013 14:11:08 -0400
changeset 125661 2b9b303c91616b932be370fdf438fbc7e53f3fdd
parent 125660 7134a31534be9cbe7644c5e602ac4dd43f24733c
child 125662 164abd8f727da361f3e07e4ae494faac5a88c5f6
push id25039
push userkvijayan@mozilla.com
push dateWed, 20 Mar 2013 18:11:31 +0000
treeherdermozilla-inbound@2b9b303c9161 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp, dvander
bugs849388
milestone22.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 849388 - Allow js::ion::InlineFrameIterator to be used in NoGC contexts. r=nbp,dvander
js/src/ion/Bailouts.cpp
js/src/ion/CodeGenerator.cpp
js/src/ion/ExecutionModeInlines.h
js/src/ion/IonFrameIterator-inl.h
js/src/ion/IonFrameIterator.h
js/src/ion/IonFrames.cpp
--- a/js/src/ion/Bailouts.cpp
+++ b/js/src/ion/Bailouts.cpp
@@ -41,28 +41,16 @@ 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(JSContext *cx, const IonBailoutIterator *iter)
-  : frame_(iter),
-    framesRead_(0),
-    callee_(cx),
-    script_(cx)
-{
-    if (iter) {
-        start_ = SnapshotIterator(*iter);
-        findNextFrame();
-    }
-}
-
 void
 IonBailoutIterator::dump() const
 {
     if (type_ == IonFrame_OptimizedJS) {
         InlineFrameIterator frames(GetIonContext()->cx, this);
         for (;;) {
             frames.dump();
             if (!frames.more())
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -1335,34 +1335,34 @@ CodeGenerator::emitParCallToUncompiledSc
 
 bool
 CodeGenerator::visitCallKnown(LCallKnown *call)
 {
     JSContext *cx = GetIonContext()->cx;
     Register calleereg = ToRegister(call->getFunction());
     Register objreg    = ToRegister(call->getTempObject());
     uint32_t unusedStack = StackOffsetOfPassedArg(call->argslot());
-    RootedFunction target(cx, call->getSingleTarget());
+    RawFunction target = call->getSingleTarget();
     ExecutionMode executionMode = gen->info().executionMode();
     Label end, uncompiled;
 
     // Native single targets are handled by LCallNative.
     JS_ASSERT(!target->isNative());
     // Missing arguments must have been explicitly appended by the IonBuilder.
     JS_ASSERT(target->nargs <= call->numStackArgs());
 
     masm.checkStackAlignment();
 
     // Make sure the function has a JSScript
     if (target->isInterpretedLazy() && !target->getOrCreateScript(cx))
         return false;
 
     // If the function is known to be uncompilable, just emit the call to
     // Invoke in sequential mode, else mark as cannot compile.
-    RootedScript targetScript(cx, target->nonLazyScript());
+    RawScript targetScript = target->nonLazyScript();
     if (GetIonScript(targetScript, executionMode) == ION_DISABLED_SCRIPT) {
         if (executionMode == ParallelExecution)
             return false;
 
         if (!emitCallInvokeFunction(call, calleereg, call->numActualArgs(), unusedStack))
             return false;
 
         if (call->mir()->isConstructing()) {
@@ -1562,18 +1562,18 @@ CodeGenerator::visitApplyArgsGeneric(LAp
     // Copy the arguments of the current function.
     emitPushArguments(apply, copyreg);
 
     masm.checkStackAlignment();
 
     // If the function is known to be uncompilable, only emit the call to InvokeFunction.
     ExecutionMode executionMode = gen->info().executionMode();
     if (apply->hasSingleTarget()) {
-        RootedFunction target(cx, apply->getSingleTarget());
-        if (!CanIonCompile(cx, target, executionMode)) {
+        RawFunction target = apply->getSingleTarget();
+        if (!CanIonCompile(target, executionMode)) {
             if (!emitCallInvokeFunction(apply, copyreg))
                 return false;
             emitPopArguments(apply, copyreg);
             return true;
         }
     }
 
     Label end, invoke;
@@ -4486,17 +4486,17 @@ CodeGenerator::link()
     Linker linker(masm);
     IonCode *code = linker.newCode(cx, JSC::ION_CODE);
     if (!code)
         return false;
 
     // We encode safepoints after the OSI-point offsets have been determined.
     encodeSafepoints();
 
-    RootedScript script(cx, gen->info().script());
+    RawScript script = gen->info().script();
     ExecutionMode executionMode = gen->info().executionMode();
     JS_ASSERT(!HasIonScript(script, executionMode));
 
     uint32_t scriptFrameSize = frameClass_ == FrameSizeClass::None()
                            ? frameDepth_
                            : FrameSizeClass::FromDepth(frameDepth_).frameSize();
 
     // Check to make sure we didn't have a mid-build invalidation. If so, we
--- a/js/src/ion/ExecutionModeInlines.h
+++ b/js/src/ion/ExecutionModeInlines.h
@@ -35,32 +35,29 @@ static inline void SetIonScript(RawScrip
 {
     switch (cmode) {
       case SequentialExecution: script->ion = ionScript; return;
       case ParallelExecution: script->parallelIon = ionScript; return;
     }
     JS_NOT_REACHED("No such execution mode");
 }
 
-static inline bool CanIonCompile(HandleScript script, ExecutionMode cmode)
+static inline bool CanIonCompile(RawScript script, ExecutionMode cmode)
 {
     switch (cmode) {
       case SequentialExecution: return script->canIonCompile();
       case ParallelExecution: return script->canParallelIonCompile();
     }
     JS_NOT_REACHED("No such execution mode");
     return false;
 }
 
-static inline bool CanIonCompile(JSContext *cx, HandleFunction fun, ExecutionMode cmode)
+static inline bool CanIonCompile(RawFunction fun, ExecutionMode cmode)
 {
-    if (!fun->isInterpreted())
-        return false;
-    RootedScript script(cx, fun->nonLazyScript());
-    return CanIonCompile(script, cmode);
+    return fun->isInterpreted() && CanIonCompile(fun->nonLazyScript(), cmode);
 }
 
 static inline bool CompilingOffThread(RawScript script, ExecutionMode cmode)
 {
     switch (cmode) {
       case SequentialExecution: return script->isIonCompilingOffThread();
       case ParallelExecution: return script->isParallelIonCompilingOffThread();
     }
--- a/js/src/ion/IonFrameIterator-inl.h
+++ b/js/src/ion/IonFrameIterator-inl.h
@@ -4,16 +4,18 @@
  * 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/. */
 
 #ifndef jsion_frame_iterator_inl_h__
 #define jsion_frame_iterator_inl_h__
 
 #include "ion/IonFrameIterator.h"
+#include "ion/Bailouts.h"
+#include "ion/Ion.h"
 
 namespace js {
 namespace ion {
 
 template <class Op>
 inline void
 SnapshotIterator::readFrameArgs(Op &op, const Value *argv, Value *scopeChain, Value *thisv,
                                 unsigned start, unsigned formalEnd, unsigned iterEnd)
@@ -42,19 +44,50 @@ SnapshotIterator::readFrameArgs(Op &op, 
         op(v);
     }
     if (iterEnd >= formalEnd) {
         for (; i < iterEnd; i++)
             op(argv[i]);
     }
 }
 
+template <AllowGC allowGC>
+inline
+InlineFrameIteratorMaybeGC<allowGC>::InlineFrameIteratorMaybeGC(
+                                JSContext *cx, const IonFrameIterator *iter)
+  : callee_(cx),
+    script_(cx)
+{
+    resetOn(iter);
+}
+
+template <AllowGC allowGC>
+inline
+InlineFrameIteratorMaybeGC<allowGC>::InlineFrameIteratorMaybeGC(
+        JSContext *cx,
+        const InlineFrameIteratorMaybeGC<allowGC> *iter)
+  : frame_(iter ? iter->frame_ : NULL),
+    framesRead_(0),
+    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();
+    }
+}
+
+template <AllowGC allowGC>
 template <class Op>
 inline void
-InlineFrameIterator::forEachCanonicalActualArg(JSContext *cx, Op op, unsigned start, unsigned count) const
+InlineFrameIteratorMaybeGC<allowGC>::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;
 
@@ -69,17 +102,17 @@ InlineFrameIterator::forEachCanonicalAct
 
         // Get the non overflown arguments
         unsigned formal_end = (end < nformal) ? end : nformal;
         SnapshotIterator s(si_);
         s.readFrameArgs(op, NULL, NULL, NULL, start, nformal, formal_end);
 
         // The overflown arguments are not available in current frame.
         // They are the last pushed arguments in the parent frame of this inlined frame.
-        InlineFrameIterator it(cx, this);
+        InlineFrameIteratorMaybeGC it(cx, this);
         SnapshotIterator parent_s((++it).snapshotIterator());
 
         // Skip over all slots untill we get to the last slots (= arguments slots of callee)
         // the +2 is for [this] and [scopechain]
         JS_ASSERT(parent_s.slots() >= nactual + 2);
         unsigned skip = parent_s.slots() - nactual - 2;
         for (unsigned j = 0; j < skip; j++)
             parent_s.skip();
@@ -87,13 +120,84 @@ InlineFrameIterator::forEachCanonicalAct
         // Get the overflown arguments
         parent_s.readFrameArgs(op, NULL, NULL, NULL, nformal, nactual, end);
     } else {
         SnapshotIterator s(si_);
         Value *argv = frame_->actualArgs();
         s.readFrameArgs(op, argv, NULL, NULL, start, nformal, end);
     }
 }
+ 
+template <AllowGC allowGC>
+inline JSObject *
+InlineFrameIteratorMaybeGC<allowGC>::scopeChain() const
+{
+    SnapshotIterator s(si_);
+
+    // scopeChain
+    Value v = s.read();
+    if (v.isObject()) {
+        JS_ASSERT_IF(script()->hasAnalysis(), script()->analysis()->usesScopeChain());
+        return &v.toObject();
+    }
+
+    return callee()->environment();
+}
+
+template <AllowGC allowGC>
+inline JSObject *
+InlineFrameIteratorMaybeGC<allowGC>::thisObject() const
+{
+    // JS_ASSERT(isConstructing(...));
+    SnapshotIterator s(si_);
+
+    // scopeChain
+    s.skip();
+
+    // In strict modes, |this| may not be an object and thus may not be
+    // readable which can either segv in read or trigger the assertion.
+    Value v = s.read();
+    JS_ASSERT(v.isObject());
+    return &v.toObject();
+}
+
+template <AllowGC allowGC>
+inline unsigned
+InlineFrameIteratorMaybeGC<allowGC>::numActualArgs() const
+{
+    // The number of actual arguments of inline frames is recovered by the
+    // iteration process. It is recovered from the bytecode because this
+    // property still hold since the for inlined frames. This property does not
+    // hold for the parent frame because it can have optimize a call to
+    // js_fun_call or js_fun_apply.
+    if (more())
+        return numActualArgs_;
+
+    return frame_->numActualArgs();
+}
+
+template <AllowGC allowGC>
+inline
+InlineFrameIteratorMaybeGC<allowGC>::InlineFrameIteratorMaybeGC(
+                                                JSContext *cx, const IonBailoutIterator *iter)
+  : frame_(iter),
+    framesRead_(0),
+    callee_(cx),
+    script_(cx)
+{
+    if (iter) {
+        start_ = SnapshotIterator(*iter);
+        findNextFrame();
+    }
+}
+
+template <AllowGC allowGC>
+inline InlineFrameIteratorMaybeGC<allowGC> &
+InlineFrameIteratorMaybeGC<allowGC>::operator++()
+{
+    findNextFrame();
+    return *this;
+}
 
 } // namespace ion
 } // namespace js
 
 #endif // jsion_frame_iterator_inl_h__
--- a/js/src/ion/IonFrameIterator.h
+++ b/js/src/ion/IonFrameIterator.h
@@ -254,71 +254,74 @@ class SnapshotIterator : public Snapshot
             skip();
 
         return s;
     }
 };
 
 // Reads frame information in callstack order (that is, innermost frame to
 // outermost frame).
-class InlineFrameIterator
+template <AllowGC allowGC=CanGC>
+class InlineFrameIteratorMaybeGC
 {
     const IonFrameIterator *frame_;
     SnapshotIterator start_;
     SnapshotIterator si_;
     unsigned framesRead_;
-    RootedFunction callee_;
-    RootedScript script_;
+    typename MaybeRooted<JSFunction*, allowGC>::RootType callee_;
+    typename MaybeRooted<JSScript*, allowGC>::RootType script_;
     jsbytecode *pc_;
     uint32_t numActualArgs_;
 
   private:
     void findNextFrame();
 
   public:
-    InlineFrameIterator(JSContext *cx, const IonFrameIterator *iter);
-    InlineFrameIterator(JSContext *cx, const IonBailoutIterator *iter);
-    InlineFrameIterator(JSContext *cx, const InlineFrameIterator *iter);
+    inline InlineFrameIteratorMaybeGC(JSContext *cx, const IonFrameIterator *iter);
+    inline InlineFrameIteratorMaybeGC(JSContext *cx, const IonBailoutIterator *iter);
+    inline InlineFrameIteratorMaybeGC(JSContext *cx, const InlineFrameIteratorMaybeGC *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;
+    inline unsigned numActualArgs() const;
 
     template <class Op>
     inline void forEachCanonicalActualArg(JSContext *cx, Op op, unsigned start, unsigned count) const;
 
     RawScript script() const {
         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++();
+    inline JSObject *scopeChain() const;
+    inline JSObject *thisObject() const;
+    inline InlineFrameIteratorMaybeGC &operator++();
 
     void dump() const;
 
     void resetOn(const IonFrameIterator *iter);
 
   private:
-    InlineFrameIterator() MOZ_DELETE;
-    InlineFrameIterator(const InlineFrameIterator &iter) MOZ_DELETE;
+    InlineFrameIteratorMaybeGC() MOZ_DELETE;
+    InlineFrameIteratorMaybeGC(const InlineFrameIteratorMaybeGC &iter) MOZ_DELETE;
 };
+typedef InlineFrameIteratorMaybeGC<CanGC> InlineFrameIterator;
+typedef InlineFrameIteratorMaybeGC<NoGC> InlineFrameIteratorNoGC;
 
 } // namespace ion
 } // namespace js
 
 #endif // jsion_frames_iterator_h__
 
--- a/js/src/ion/IonFrames.cpp
+++ b/js/src/ion/IonFrames.cpp
@@ -18,18 +18,18 @@
 #include "IonMacroAssembler.h"
 #include "PcScriptCache.h"
 #include "PcScriptCache-inl.h"
 #include "gc/Marking.h"
 #include "SnapshotReader.h"
 #include "Safepoints.h"
 #include "VMFunctions.h"
 
-using namespace js;
-using namespace js::ion;
+namespace js {
+namespace ion {
 
 IonFrameIterator::IonFrameIterator(const IonActivationIterator &activations)
     : current_(activations.top()),
       type_(IonFrame_Exit),
       returnAddressToFp_(NULL),
       frameSize_(0),
       cachedSafepointIndex_(NULL),
       activation_(activations.activation())
@@ -128,17 +128,17 @@ IonFrameIterator::isDOMExit() const
     if (type_ != IonFrame_Exit)
         return false;
     return exitFrame()->isDomExit();
 }
 
 bool
 IonFrameIterator::isFunctionFrame() const
 {
-    return js::ion::CalleeTokenIsFunction(calleeToken());
+    return CalleeTokenIsFunction(calleeToken());
 }
 
 bool
 IonFrameIterator::isEntryJSFrame() const
 {
     if (prevType() == IonFrame_OptimizedJS || prevType() == IonFrame_Unwound_OptimizedJS)
         return false;
 
@@ -291,17 +291,17 @@ CloseLiveIterators(JSContext *cx, const 
         JS_ASSERT(tn->stackDepth > 0);
 
         uint32_t localSlot = tn->stackDepth;
         CloseLiveIterator(cx, frame, localSlot);
     }
 }
 
 void
-ion::HandleException(ResumeFromException *rfe)
+HandleException(ResumeFromException *rfe)
 {
     JSContext *cx = GetIonContext()->cx;
 
     IonSpew(IonSpew_Invalidate, "handling exception");
 
     // Immediately remove any bailout frame guard that might be left over from
     // an error in between ConvertFrames and ThunkToInterpreter.
     js_delete(cx->mainThread().ionActivation->maybeTakeBailout());
@@ -339,17 +339,17 @@ ion::HandleException(ResumeFromException
     // otherwise clear the return override.
     if (cx->runtime->hasIonReturnOverride())
         cx->runtime->takeIonReturnOverride();
 
     rfe->stackPointer = iter.fp();
 }
 
 void
-ion::EnsureExitFrame(IonCommonFrameLayout *frame)
+EnsureExitFrame(IonCommonFrameLayout *frame)
 {
     if (frame->prevType() == IonFrame_Entry) {
         // The previous frame type is the entry frame, so there's no actual
         // need for an exit frame.
         return;
     }
 
     if (frame->prevType() == IonFrame_Rectifier) {
@@ -664,31 +664,31 @@ MarkIonActivation(JSTracer *trc, const I
           default:
             JS_NOT_REACHED("unexpected frame type");
             break;
         }
     }
 }
 
 void
-ion::MarkIonActivations(JSRuntime *rt, JSTracer *trc)
+MarkIonActivations(JSRuntime *rt, JSTracer *trc)
 {
     for (IonActivationIterator activations(rt); activations.more(); ++activations)
         MarkIonActivation(trc, activations);
 }
 
 void
-ion::AutoTempAllocatorRooter::trace(JSTracer *trc)
+AutoTempAllocatorRooter::trace(JSTracer *trc)
 {
     for (CompilerRootNode *root = temp->rootList(); root != NULL; root = root->next)
         gc::MarkGCThingRoot(trc, root->address(), "ion-compiler-root");
 }
 
 void
-ion::GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
+GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
 {
     JS_ASSERT(cx->fp()->beginsIonActivation());
     IonSpew(IonSpew_Snapshots, "Recover PC & Script from the last frame.");
 
     JSRuntime *rt = cx->runtime;
 
     // Recover the return address.
     IonFrameIterator it(rt->mainThread.ionTop);
@@ -886,52 +886,34 @@ IonFrameIterator::safepoint() const
 
 const OsiIndex *
 IonFrameIterator::osiIndex() const
 {
     SafepointReader reader(ionScript(), safepoint());
     return ionScript()->getOsiIndex(reader.osiReturnPointOffset());
 }
 
-InlineFrameIterator::InlineFrameIterator(JSContext *cx, const IonFrameIterator *iter)
-  : callee_(cx),
-    script_(cx)
-{
-    resetOn(iter);
-}
-
+template <AllowGC allowGC>
 void
-InlineFrameIterator::resetOn(const IonFrameIterator *iter)
+InlineFrameIteratorMaybeGC<allowGC>::resetOn(const IonFrameIterator *iter)
 {
     frame_ = iter;
     framesRead_ = 0;
 
     if (iter) {
         start_ = SnapshotIterator(*iter);
         findNextFrame();
     }
 }
+template void InlineFrameIteratorMaybeGC<NoGC>::resetOn(const IonFrameIterator *iter);
+template void InlineFrameIteratorMaybeGC<CanGC>::resetOn(const IonFrameIterator *iter);
 
-InlineFrameIterator::InlineFrameIterator(JSContext *cx, const InlineFrameIterator *iter)
-  : frame_(iter ? iter->frame_ : NULL),
-    framesRead_(0),
-    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();
-    }
-}
-
+template <AllowGC allowGC>
 void
-InlineFrameIterator::findNextFrame()
+InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
 {
     JS_ASSERT(more());
 
     si_ = start_;
 
     // Read the initial frame.
     callee_ = frame_->maybeCallee();
     script_ = frame_->script();
@@ -967,64 +949,65 @@ InlineFrameIterator::findNextFrame()
 
         callee_ = funval.toObject().toFunction();
         script_ = callee_->nonLazyScript();
         pc_ = script_->code + si_.pcOffset();
     }
 
     framesRead_++;
 }
+template void InlineFrameIteratorMaybeGC<NoGC>::findNextFrame();
+template void InlineFrameIteratorMaybeGC<CanGC>::findNextFrame();
 
-InlineFrameIterator &
-InlineFrameIterator::operator++()
-{
-    findNextFrame();
-    return *this;
-}
-
+template <AllowGC allowGC>
 bool
-InlineFrameIterator::isFunctionFrame() const
+InlineFrameIteratorMaybeGC<allowGC>::isFunctionFrame() const
 {
     return !!callee_;
 }
+template bool InlineFrameIteratorMaybeGC<NoGC>::isFunctionFrame() const;
+template bool InlineFrameIteratorMaybeGC<CanGC>::isFunctionFrame() const;
 
 MachineState
 MachineState::FromBailout(uintptr_t regs[Registers::Total],
                           double fpregs[FloatRegisters::Total])
 {
     MachineState machine;
 
     for (unsigned i = 0; i < Registers::Total; i++)
         machine.setRegisterLocation(Register::FromCode(i), &regs[i]);
     for (unsigned i = 0; i < FloatRegisters::Total; i++)
         machine.setRegisterLocation(FloatRegister::FromCode(i), &fpregs[i]);
 
     return machine;
 }
 
+template <AllowGC allowGC>
 bool
-InlineFrameIterator::isConstructing() const
+InlineFrameIteratorMaybeGC<allowGC>::isConstructing() const
 {
     // Skip the current frame and look at the caller's.
     if (more()) {
-        InlineFrameIterator parent(GetIonContext()->cx, this);
+        InlineFrameIteratorMaybeGC<allowGC> 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);
 
         return (JSOp)*parent.pc() == JSOP_NEW;
     }
 
     return frame_->isConstructing();
 }
+template bool InlineFrameIteratorMaybeGC<NoGC>::isConstructing() const;
+template bool InlineFrameIteratorMaybeGC<CanGC>::isConstructing() const;
 
 bool
 IonFrameIterator::isConstructing() const
 {
     IonFrameIterator parent(*this);
 
     // Skip the current frame and look at the caller's.
     do {
@@ -1055,130 +1038,50 @@ IonFrameIterator::isConstructing() const
     // a C++ native using FastInvoke. In both of these cases we don't handle
     // constructor calls.
     if (activation_->entryfp()->callingIntoIon())
         return false;
     JS_ASSERT(activation_->entryfp()->runningInIon());
     return activation_->entryfp()->isConstructing();
 }
 
-JSObject *
-InlineFrameIterator::scopeChain() const
-{
-    SnapshotIterator s(si_);
-
-    // scopeChain
-    Value v = s.read();
-    if (v.isObject()) {
-        JS_ASSERT_IF(script()->hasAnalysis(), script()->analysis()->usesScopeChain());
-        return &v.toObject();
-    }
-
-    return callee()->environment();
-}
-
-JSObject *
-InlineFrameIterator::thisObject() const
-{
-    // JS_ASSERT(isConstructing(...));
-    SnapshotIterator s(si_);
-
-    // scopeChain
-    s.skip();
-
-    // In strict modes, |this| may not be an object and thus may not be
-    // readable which can either segv in read or trigger the assertion.
-    Value v = s.read();
-    JS_ASSERT(v.isObject());
-    return &v.toObject();
-}
-
-unsigned
-InlineFrameIterator::numActualArgs() const
-{
-    // The number of actual arguments of inline frames is recovered by the
-    // iteration process. It is recovered from the bytecode because this
-    // property still hold since the for inlined frames. This property does not
-    // hold for the parent frame because it can have optimize a call to
-    // js_fun_call or js_fun_apply.
-    if (more())
-        return numActualArgs_;
-
-    return frame_->numActualArgs();
-}
-
 unsigned
 IonFrameIterator::numActualArgs() const
 {
     if (isScripted())
         return jsFrame()->numActualArgs();
 
     JS_ASSERT(isNative());
     return exitFrame()->nativeExit()->argc();
 }
 
 void
 SnapshotIterator::warnUnreadableSlot()
 {
     fprintf(stderr, "Warning! Tried to access unreadable IonMonkey slot (possible f.arguments).\n");
 }
 
-void
-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(GetIonContext()->cx, this);
-        for (;;) {
-            frames.dump();
-            if (!frames.more())
-                break;
-            ++frames;
-        }
-        break;
-      }
-      case IonFrame_Rectifier:
-      case IonFrame_Unwound_Rectifier:
-        fprintf(stderr, " Rectifier frame\n");
-        fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
-        break;
-      case IonFrame_Unwound_OptimizedJS:
-        fprintf(stderr, "Warning! Unwound JS frames are not observable.\n");
-        break;
-      case IonFrame_Exit:
-        break;
-      case IonFrame_Osr:
-        fprintf(stderr, "Warning! OSR frame are not defined yet.\n");
-        break;
-    };
-    fputc('\n', stderr);
-}
-
 struct DumpOp {
     DumpOp(unsigned int i) : i_(i) {}
 
     unsigned int i_;
     void operator()(const Value& v) {
         fprintf(stderr, "  actual (arg %d): ", i_);
 #ifdef DEBUG
         js_DumpValue(v);
 #else
         fprintf(stderr, "?\n");
 #endif
         i_++;
     }
 };
 
+template <AllowGC allowGC>
 void
-InlineFrameIterator::dump() const
+InlineFrameIteratorMaybeGC<allowGC>::dump() const
 {
     if (more())
         fprintf(stderr, " JS frame (inlined)\n");
     else
         fprintf(stderr, " JS frame\n");
 
     bool isFunction = false;
     if (isFunctionFrame()) {
@@ -1227,8 +1130,49 @@ InlineFrameIterator::dump() const
         js_DumpValue(si.maybeRead());
 #else
         fprintf(stderr, "?\n");
 #endif
     }
 
     fputc('\n', stderr);
 }
+template void InlineFrameIteratorMaybeGC<NoGC>::dump() const;
+template void InlineFrameIteratorMaybeGC<CanGC>::dump() const;
+
+void
+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(GetIonContext()->cx, this);
+        for (;;) {
+            frames.dump();
+            if (!frames.more())
+                break;
+            ++frames;
+        }
+        break;
+      }
+      case IonFrame_Rectifier:
+      case IonFrame_Unwound_Rectifier:
+        fprintf(stderr, " Rectifier frame\n");
+        fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
+        break;
+      case IonFrame_Unwound_OptimizedJS:
+        fprintf(stderr, "Warning! Unwound JS frames are not observable.\n");
+        break;
+      case IonFrame_Exit:
+        break;
+      case IonFrame_Osr:
+        fprintf(stderr, "Warning! OSR frame are not defined yet.\n");
+        break;
+    };
+    fputc('\n', stderr);
+}
+
+} // namespace ion
+} // namespace js