Bug 883171 - Remove JSContext::fp() and JSContext::regs(). r=luke
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 19 Jun 2013 11:33:13 +0200
changeset 135611 36fb664f91012fd4e13cc6999702253927e71256
parent 135571 bef2efa890878d444fa554e7d1f9c394d36de576
child 135612 5fae2a068802d23bd80a92417b6643c24f0ce8ae
push id24847
push userkwierso@gmail.com
push dateWed, 19 Jun 2013 23:38:15 +0000
treeherdermozilla-central@8ea92aeab783 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs883171
milestone24.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 883171 - Remove JSContext::fp() and JSContext::regs(). r=luke
js/src/frontend/Parser.cpp
js/src/ion/BaselineBailouts.cpp
js/src/ion/BaselineIC.cpp
js/src/ion/BaselineJIT.cpp
js/src/ion/Ion.cpp
js/src/jsapi.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscntxtinlines.h
js/src/jsdbgapi.cpp
js/src/jsfriendapi.cpp
js/src/jsfun.cpp
js/src/jsiter.cpp
js/src/jsiter.h
js/src/jsopcode.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/shell/js.cpp
js/src/vm/Interpreter-inl.h
js/src/vm/Interpreter.cpp
js/src/vm/ScopeObject.cpp
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6498,20 +6498,19 @@ template <>
 ParseNode *
 Parser<FullParseHandler>::newRegExp(const jschar *buf, size_t length, RegExpFlag flags)
 {
     ParseNode *pn = NullaryNode::create(PNK_REGEXP, &handler);
     if (!pn)
         return NULL;
 
     const StableCharPtr chars(buf, length);
-    RegExpStatics *res = context->regExpStatics();
 
     Rooted<RegExpObject*> reobj(context);
-    if (context->hasfp())
+    if (RegExpStatics *res = context->regExpStatics())
         reobj = RegExpObject::create(context, res, chars.get(), length, flags, &tokenStream);
     else
         reobj = RegExpObject::createNoStatics(context, chars.get(), length, flags, &tokenStream);
 
     if (!reobj)
         return NULL;
 
     pn->pn_objbox = newObjectBox(reobj);
@@ -6523,20 +6522,19 @@ Parser<FullParseHandler>::newRegExp(cons
 }
 
 template <>
 SyntaxParseHandler::Node
 Parser<SyntaxParseHandler>::newRegExp(const jschar *buf, size_t length, RegExpFlag flags)
 {
     // Create the regexp even when doing a syntax parse, to check the regexp's syntax.
     const StableCharPtr chars(buf, length);
-    RegExpStatics *res = context->regExpStatics();
 
     RegExpObject *reobj;
-    if (context->hasfp())
+    if (RegExpStatics *res = context->regExpStatics())
         reobj = RegExpObject::create(context, res, chars.get(), length, flags, &tokenStream);
     else
         reobj = RegExpObject::createNoStatics(context, chars.get(), length, flags, &tokenStream);
 
     return reobj ? SyntaxParseHandler::NodeGeneric : SyntaxParseHandler::NodeFailure;
 }
 
 template <typename ParseHandler>
--- a/js/src/ion/BaselineBailouts.cpp
+++ b/js/src/ion/BaselineBailouts.cpp
@@ -1210,17 +1210,17 @@ ion::FinishBailoutToBaseline(BaselineBai
     if (topFrame->scopeChain() && !EnsureHasScopeObjects(cx, topFrame))
         return false;
 
     // Create arguments objects for bailed out frames, to maintain the invariant
     // that script->needsArgsObj() implies frame->hasArgsObj().
     RootedScript innerScript(cx, NULL);
     RootedScript outerScript(cx, NULL);
 
-    JS_ASSERT(cx->mainThread().currentlyRunningInJit());
+    JS_ASSERT(cx->currentlyRunningInJit());
     IonFrameIterator iter(cx->mainThread().ionTop);
 
     uint32_t frameno = 0;
     while (frameno < numFrames) {
         JS_ASSERT(!iter.isOptimizedJS());
 
         if (iter.isBaselineJS()) {
             BaselineFrame *frame = iter.baselineFrame();
--- a/js/src/ion/BaselineIC.cpp
+++ b/js/src/ion/BaselineIC.cpp
@@ -671,17 +671,17 @@ ICStubCompiler::emitPostWriteBarrierSlot
 #endif // JSGC_GENERATIONAL
 
 //
 // UseCount_Fallback
 //
 static bool
 IsTopFrameConstructing(JSContext *cx)
 {
-    JS_ASSERT(cx->mainThread().currentlyRunningInJit());
+    JS_ASSERT(cx->currentlyRunningInJit());
     JitActivationIterator activations(cx->runtime());
     IonFrameIterator iter(activations);
     JS_ASSERT(iter.type() == IonFrame_Exit);
 
     ++iter;
     JS_ASSERT(iter.type() == IonFrame_BaselineStub);
 
     ++iter;
--- a/js/src/ion/BaselineJIT.cpp
+++ b/js/src/ion/BaselineJIT.cpp
@@ -122,28 +122,27 @@ EnterBaseline(JSContext *cx, StackFrame 
         fp->setRunningInJit();
 
         // Pass the scope chain for global and eval frames.
         JSObject *scopeChain = NULL;
         if (!fp->isNonEvalFunctionFrame())
             scopeChain = fp->scopeChain();
 
         // For OSR, pass the number of locals + stack values.
-        uint32_t numStackValues = osr ? fp->script()->nfixed + cx->regs().stackDepth() : 0;
+        uint32_t numStackValues = osr ? fp->script()->nfixed + cx->stack.regs().stackDepth() : 0;
         JS_ASSERT_IF(osr, !IsJSDEnabled(cx));
 
         AutoFlushInhibitor afi(cx->compartment()->ionCompartment());
         // Single transition point from Interpreter to Baseline.
         enter(jitcode, maxArgc, maxArgv, osr ? fp : NULL, calleeToken, scopeChain, numStackValues,
               result.address());
 
         fp->clearRunningInJit();
     }
 
-    JS_ASSERT(fp == cx->fp());
     JS_ASSERT(!cx->runtime()->hasIonReturnOverride());
 
     // The trampoline wrote the return value but did not set the HAS_RVAL flag.
     fp->setReturnValue(result);
 
     // Ion callers wrap primitive constructor return.
     if (!result.isMagic() && fp->isConstructing() && fp->returnValue().isPrimitive())
         fp->setReturnValue(ObjectValue(fp->constructorThis()));
@@ -242,17 +241,17 @@ ion::CanEnterBaselineJIT(JSContext *cx, 
 
     if (script->hasBaselineScript())
         return Method_Compiled;
 
     // Check script use count. However, always eagerly compile scripts if JSD
     // is enabled, so that we don't have to OSR and don't have to update the
     // frame pointer stored in JSD's frames list.
     if (IsJSDEnabled(cx)) {
-        if (JSOp(*cx->regs().pc) == JSOP_LOOPENTRY) // No OSR.
+        if (JSOp(*cx->stack.regs().pc) == JSOP_LOOPENTRY) // No OSR.
             return Method_Skipped;
     } else if (script->incUseCount() <= js_IonOptions.baselineUsesBeforeCompile) {
         return Method_Skipped;
     }
 
     if (script->isCallsiteClone) {
         // Ensure the original function is compiled too, so that bailouts from
         // Ion code have a BaselineScript to resume into.
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -1851,17 +1851,16 @@ EnterIon(JSContext *cx, StackFrame *fp, 
 
         // Single transition point from Interpreter to Ion.
         enter(jitcode, maxArgc, maxArgv, fp, calleeToken, /* scopeChain = */ NULL, 0,
               result.address());
 
         fp->clearRunningInJit();
     }
 
-    JS_ASSERT(fp == cx->fp());
     JS_ASSERT(!cx->runtime()->hasIonReturnOverride());
 
     // The trampoline wrote the return value but did not set the HAS_RVAL flag.
     fp->setReturnValue(result);
 
     // Ion callers wrap primitive constructor return.
     if (!result.isMagic() && fp->isConstructing() && fp->returnValue().isPrimitive())
         fp->setReturnValue(ObjectValue(fp->constructorThis()));
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5960,17 +5960,17 @@ JS_PUBLIC_API(void)
 JS_TriggerOperationCallback(JSRuntime *rt)
 {
     rt->triggerOperationCallback();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IsRunning(JSContext *cx)
 {
-    return cx->hasfp();
+    return cx->currentlyRunning();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SaveFrameChain(JSContext *cx)
 {
     AssertHeapIsIdleOrIterating(cx);
     CHECK_REQUEST(cx);
     return cx->saveFrameChain();
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1294,16 +1294,30 @@ JSContext::restoreFrameChain()
 
     if (Activation *act = mainThread().activation())
         act->restoreFrameChain();
 
     if (isExceptionPending())
         wrapPendingException();
 }
 
+bool
+JSContext::currentlyRunning() const
+{
+    for (ActivationIterator iter(runtime()); !iter.done(); ++iter) {
+        if (iter.activation()->cx() == this) {
+            if (iter.activation()->hasSavedFrameChain())
+                return false;
+            return true;
+        }
+    }
+
+    return false;
+}
+
 void
 JSRuntime::setGCMaxMallocBytes(size_t value)
 {
     /*
      * For compatibility treat any value that exceeds PTRDIFF_T_MAX to
      * mean that value.
      */
     gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -516,22 +516,16 @@ class PerThreadData : public js::PerThre
     }
     js::AsmJSActivation *asmJSActivationStackFromOwnerThread() const {
         return asmJSActivationStack_;
     }
 
     js::Activation *activation() const {
         return activation_;
     }
-    bool currentlyRunningInInterpreter() const {
-        return activation_->isInterpreter();
-    }
-    bool currentlyRunningInJit() const {
-        return activation_->isJit();
-    }
 
     /*
      * When this flag is non-zero, any attempt to GC will be skipped. It is used
      * to suppress GC when reporting an OOM (see js_ReportOutOfMemory) and in
      * debugging facilities that cannot tolerate a GC and would rather OOM
      * immediately, such as utilities exposed to GDB. Setting this flag is
      * extremely dangerous and should only be used when in an OOM situation or
      * in non-exposed debugging facilities.
@@ -1522,17 +1516,17 @@ struct JSContext : js::ContextFriendFiel
     JSRuntime *runtime() const { return runtime_; }
     JSCompartment *compartment() const { return compartment_; }
 
     inline JS::Zone *zone() const {
         JS_ASSERT_IF(!compartment(), !zone_);
         JS_ASSERT_IF(compartment(), js::GetCompartmentZone(compartment()) == zone_);
         return zone_;
     }
-    js::PerThreadData &mainThread() { return runtime()->mainThread; }
+    js::PerThreadData &mainThread() const { return runtime()->mainThread; }
 
   private:
     /* See JSContext::findVersion. */
     JSVersion           defaultVersion;      /* script compilation version */
     JSVersion           versionOverride;     /* supercedes defaultVersion when valid */
     bool                hasVersionOverride;
 
     /* Exception state -- the exception member is a GC root by definition. */
@@ -1612,23 +1606,16 @@ struct JSContext : js::ContextFriendFiel
     js::ContextStack    stack;
 
     /*
      * Current global. This is only safe to use within the scope of the
      * AutoCompartment from which it's called.
      */
     inline js::Handle<js::GlobalObject*> global() const;
 
-    /* ContextStack convenience functions */
-    inline bool hasfp() const               { return stack.hasfp(); }
-    inline js::StackFrame* fp() const       { return stack.fp(); }
-    inline js::StackFrame* maybefp() const  { return stack.maybefp(); }
-    inline js::FrameRegs& regs() const      { return stack.regs(); }
-    inline js::FrameRegs* maybeRegs() const { return stack.maybeRegs(); }
-
     /* Wrap cx->exception for the current compartment. */
     void wrapPendingException();
 
     /* State for object and array toSource conversion. */
     js::ObjectSet       cycleDetectorSet;
 
     /* Per-context optional error reporter. */
     JSErrorReporter     errorReporter;
@@ -1728,16 +1715,32 @@ struct JSContext : js::ContextFriendFiel
     js::Value           iterValue;
 
     bool jitIsBroken;
 
     inline bool typeInferenceEnabled() const;
 
     void updateJITEnabled();
 
+    /* Whether this context has JS frames on the stack. */
+    bool currentlyRunning() const;
+
+    bool currentlyRunningInInterpreter() const {
+        return mainThread().activation()->isInterpreter();
+    }
+    bool currentlyRunningInJit() const {
+        return mainThread().activation()->isJit();
+    }
+    js::StackFrame *interpreterFrame() const {
+        return mainThread().activation()->asInterpreter()->current();
+    }
+    js::FrameRegs &interpreterRegs() const {
+        return mainThread().activation()->asInterpreter()->regs();
+    }
+
 #ifdef MOZ_TRACE_JSCALLS
     /* Function entry/exit debugging callback. */
     JSFunctionCallback    functionCallback;
 
     void doFunctionCallback(const JSFunction *fun,
                             const JSScript *scr,
                             int entering) const
     {
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -121,21 +121,21 @@ NewObjectCache::newObjectFromHit(JSConte
     }
 
     return NULL;
 }
 
 struct PreserveRegsGuard
 {
     PreserveRegsGuard(JSContext *cx, FrameRegs &regs)
-      : prevContextRegs(cx->maybeRegs()), cx(cx), regs_(regs) {
+      : prevContextRegs(cx->stack.maybeRegs()), cx(cx), regs_(regs) {
         cx->stack.repointRegs(&regs_);
     }
     ~PreserveRegsGuard() {
-        JS_ASSERT(cx->maybeRegs() == &regs_);
+        JS_ASSERT(cx->stack.maybeRegs() == &regs_);
         *prevContextRegs = regs_;
         cx->stack.repointRegs(prevContextRegs);
     }
 
     FrameRegs *prevContextRegs;
 
   private:
     JSContext *cx;
@@ -453,17 +453,17 @@ CallSetter(JSContext *cx, HandleObject o
     return CallJSPropertyOpSetter(cx, op, obj, nid, strict, vp);
 }
 
 }  /* namespace js */
 
 inline bool
 JSContext::canSetDefaultVersion() const
 {
-    return !stack.hasfp() && !hasVersionOverride;
+    return !currentlyRunning() && !hasVersionOverride;
 }
 
 inline void
 JSContext::overrideVersion(JSVersion newVersion)
 {
     JS_ASSERT(!canSetDefaultVersion());
     versionOverride = newVersion;
     hasVersionOverride = true;
@@ -513,17 +513,17 @@ JSContext::setDefaultCompartmentObject(J
 
     if (!hasEnteredCompartment()) {
         /*
          * If JSAPI callers want to JS_SetGlobalObject while code is running,
          * they must have entered a compartment (otherwise there will be no
          * final leaveCompartment call to set the context's compartment back to
          * defaultCompartmentObject->compartment()).
          */
-        JS_ASSERT(!hasfp());
+        JS_ASSERT(!currentlyRunning());
         setCompartment(obj ? obj->compartment() : NULL);
         if (throwing)
             wrapPendingException();
     }
 }
 
 inline void
 JSContext::setDefaultCompartmentObjectIfUnset(JSObject *obj)
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -71,17 +71,17 @@ IsTopFrameConstructing(JSContext *cx, Ab
     ScriptFrameIter iter(cx);
     JS_ASSERT(iter.abstractFramePtr() == frame);
     return iter.isConstructing();
 }
 
 JSTrapStatus
 js::ScriptDebugPrologue(JSContext *cx, AbstractFramePtr frame)
 {
-    JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->fp());
+    JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->interpreterFrame());
 
     if (!frame.script()->selfHosted) {
         if (frame.isFramePushedByExecute()) {
             if (JSInterpreterHook hook = cx->runtime()->debugHooks.executeHook)
                 frame.setHookData(hook(cx, Jsvalify(frame), IsTopFrameConstructing(cx, frame),
                                        true, 0, cx->runtime()->debugHooks.executeHookData));
         } else {
             if (JSInterpreterHook hook = cx->runtime()->debugHooks.callHook)
@@ -108,17 +108,18 @@ js::ScriptDebugPrologue(JSContext *cx, A
         JS_NOT_REACHED("bad Debugger::onEnterFrame JSTrapStatus value");
     }
     return status;
 }
 
 bool
 js::ScriptDebugEpilogue(JSContext *cx, AbstractFramePtr frame, bool okArg)
 {
-    JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->fp());
+    JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->interpreterFrame());
+
     JSBool ok = okArg;
 
     // We don't add hook data for self-hosted scripts, so we don't need to check for them, here.
     if (void *hookData = frame.maybeHookData()) {
         if (frame.isFramePushedByExecute()) {
             if (JSInterpreterHook hook = cx->runtime()->debugHooks.executeHook)
                 hook(cx, Jsvalify(frame), IsTopFrameConstructing(cx, frame), false, &ok, hookData);
         } else {
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -399,24 +399,24 @@ JS_FRIEND_API(bool)
 js::IsOriginalScriptFunction(JSFunction *fun)
 {
     return fun->nonLazyScript()->function() == fun;
 }
 
 JS_FRIEND_API(JSScript *)
 js::GetOutermostEnclosingFunctionOfScriptedCaller(JSContext *cx)
 {
-    if (!cx->hasfp())
+    ScriptFrameIter iter(cx);
+    if (iter.done())
         return NULL;
 
-    StackFrame *fp = cx->fp();
-    if (!fp->isFunctionFrame())
+    if (!iter.isFunctionFrame())
         return NULL;
 
-    RootedFunction scriptedCaller(cx, fp->fun());
+    RootedFunction scriptedCaller(cx, iter.callee());
     RootedScript outermost(cx, scriptedCaller->nonLazyScript());
     for (StaticScopeIter i(cx, scriptedCaller); !i.done(); i++) {
         if (i.type() == StaticScopeIter::FUNCTION)
             outermost = i.funScript();
     }
     return outermost;
 }
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -879,17 +879,17 @@ js_fun_apply(JSContext *cx, unsigned arg
          * function and read actuals out of the frame.
          */
         /* Steps 4-6. */
 
 #ifdef JS_ION
         // We do not want to use ScriptFrameIter to abstract here because this
         // is supposed to be a fast path as opposed to ScriptFrameIter which is
         // doing complex logic to settle on the next frame twice.
-        if (cx->mainThread().currentlyRunningInJit()) {
+        if (cx->currentlyRunningInJit()) {
             ion::JitActivationIterator activations(cx->runtime());
             ion::IonFrameIterator frame(activations);
             if (frame.isNative()) {
                 // Stop on the next Ion JS Frame.
                 ++frame;
                 if (frame.isOptimizedJS()) {
                     ion::InlineFrameIterator iter(cx, &frame);
 
@@ -924,17 +924,17 @@ js_fun_apply(JSContext *cx, unsigned arg
                 JS_ASSERT(frame.isBaselineJS());
 
                 if (!PushBaselineFunApplyArguments(cx, frame, args, vp))
                     return false;
             }
         } else
 #endif
         {
-            StackFrame *fp = cx->fp();
+            StackFrame *fp = cx->interpreterFrame();
             unsigned length = fp->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);
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -1411,19 +1411,18 @@ Class js::GeneratorClass = {
  * Called from the JSOP_GENERATOR case in the interpreter, with fp referring
  * to the frame by which the generator function was activated.  Create a new
  * JSGenerator object, which contains its own StackFrame that we populate
  * from *fp.  We know that upon return, the JSOP_GENERATOR opcode will return
  * from the activation in fp, so we can steal away fp->callobj and fp->argsobj
  * if they are non-null.
  */
 JSObject *
-js_NewGenerator(JSContext *cx)
+js_NewGenerator(JSContext *cx, const FrameRegs &stackRegs)
 {
-    FrameRegs &stackRegs = cx->regs();
     JS_ASSERT(stackRegs.stackDepth() == 0);
     StackFrame *stackfp = stackRegs.fp();
 
     Rooted<GlobalObject*> global(cx, &stackfp->global());
     RootedObject obj(cx);
     {
         JSObject *proto = global->getOrCreateGeneratorPrototype(cx);
         if (!proto)
@@ -1544,17 +1543,17 @@ SendToGenerator(JSContext *cx, JSGenerat
 
         /*
          * Don't change the state until after the frame is successfully pushed
          * or else we might fail to scan some generator values.
          */
         gen->state = futureState;
 
         StackFrame *fp = gfg.fp();
-        gen->regs = cx->regs();
+        gen->regs = cx->stack.regs();
 
         cx->enterGenerator(gen);   /* OOM check above. */
         ok = RunScript(cx, fp);
         cx->leaveGenerator(gen);
     }
 
     if (gen->fp->isYielding()) {
         /*
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -341,17 +341,17 @@ struct JSGenerator
     JSGeneratorState    state;
     js::FrameRegs       regs;
     JSGenerator         *prevGenerator;
     js::StackFrame      *fp;
     js::HeapValue       stackSnapshot[1];
 };
 
 extern JSObject *
-js_NewGenerator(JSContext *cx);
+js_NewGenerator(JSContext *cx, const js::FrameRegs &regs);
 
 namespace js {
 
 bool
 GeneratorHasMarkableFrame(JSGenerator *gen);
 
 } /* namespace js */
 #endif
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -406,18 +406,19 @@ js_Disassemble(JSContext *cx, HandleScri
 
 JS_FRIEND_API(JSBool)
 js_DumpPC(JSContext *cx)
 {
     js::gc::AutoSuppressGC suppressGC(cx);
     Sprinter sprinter(cx);
     if (!sprinter.init())
         return JS_FALSE;
-    RootedScript script(cx, cx->fp()->script());
-    JSBool ok = js_DisassembleAtPC(cx, script, true, cx->regs().pc, false, &sprinter);
+    ScriptFrameIter iter(cx);
+    RootedScript script(cx, iter.script());
+    JSBool ok = js_DisassembleAtPC(cx, script, true, iter.pc(), false, &sprinter);
     fprintf(stdout, "%s", sprinter.string());
     return ok;
 }
 
 JS_FRIEND_API(JSBool)
 js_DumpScript(JSContext *cx, JSScript *scriptArg)
 {
     js::gc::AutoSuppressGC suppressGC(cx);
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -2233,22 +2233,16 @@ js_GetScriptLineExtent(JSScript *script)
     }
 
     if (maxLineNo > lineno)
         lineno = maxLineNo;
 
     return 1 + lineno - script->lineno;
 }
 
-unsigned
-js::CurrentLine(JSContext *cx)
-{
-    return PCToLineNumber(cx->fp()->script(), cx->regs().pc);
-}
-
 void
 js::CurrentScriptFileLineOriginSlow(JSContext *cx, const char **file, unsigned *linenop,
                                     JSPrincipals **origin)
 {
     NonBuiltinScriptFrameIter iter(cx);
 
     if (iter.done()) {
         *file = NULL;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -1448,19 +1448,16 @@ namespace js {
 
 extern unsigned
 PCToLineNumber(JSScript *script, jsbytecode *pc, unsigned *columnp = NULL);
 
 extern unsigned
 PCToLineNumber(unsigned startLine, jssrcnote *notes, jsbytecode *code, jsbytecode *pc,
                unsigned *columnp = NULL);
 
-extern unsigned
-CurrentLine(JSContext *cx);
-
 /*
  * This function returns the file and line number of the script currently
  * executing on cx. If there is no current script executing on cx (e.g., a
  * native called directly through JSAPI (e.g., by setTimeout)), NULL and 0 are
  * returned as the file and line. Additionally, this function avoids the full
  * linear scan to compute line number when the caller guarnatees that the
  * script compilation occurs at a JSOP_EVAL.
  */
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2594,18 +2594,16 @@ EvalInFrame(JSContext *cx, unsigned argc
 
     uint32_t upCount = JSVAL_TO_INT(argv[0]);
     RootedString str(cx, JSVAL_TO_STRING(argv[1]));
 
     bool saveCurrent = (argc >= 3 && JSVAL_IS_BOOLEAN(argv[2]))
                         ? !!(JSVAL_TO_BOOLEAN(argv[2]))
                         : false;
 
-    JS_ASSERT(cx->hasfp());
-
     /* This is a copy of CheckDebugMode. */
     if (!JS_GetDebugMode(cx)) {
         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
                                      NULL, JSMSG_NEED_DEBUG_MODE);
         return false;
     }
 
     /* Debug-mode currently disables Ion compilation. */
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -120,41 +120,32 @@ IsOptimizedArguments(AbstractFramePtr fr
     return vp->isMagic(JS_OPTIMIZED_ARGUMENTS);
 }
 
 /*
  * One optimized consumer of MagicValue(JS_OPTIMIZED_ARGUMENTS) is f.apply.
  * However, this speculation must be guarded before calling 'apply' in case it
  * is not the builtin Function.prototype.apply.
  */
-static bool
+static inline bool
 GuardFunApplyArgumentsOptimization(JSContext *cx, AbstractFramePtr frame, HandleValue callee,
                                    Value *args, uint32_t argc)
 {
     if (argc == 2 && IsOptimizedArguments(frame, &args[1])) {
         if (!IsNativeFunction(callee, js_fun_apply)) {
             RootedScript script(cx, frame.script());
             if (!JSScript::argumentsOptimizationFailed(cx, script))
                 return false;
             args[1] = ObjectValue(frame.argsObj());
         }
     }
 
     return true;
 }
 
-static inline bool
-GuardFunApplyArgumentsOptimization(JSContext *cx)
-{
-    FrameRegs &regs = cx->regs();
-    CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
-    return GuardFunApplyArgumentsOptimization(cx, cx->fp(), args.calleev(), args.array(),
-                                              args.length());
-}
-
 /*
  * Return an object on which we should look for the properties of |value|.
  * This helps us implement the custom [[Get]] method that ES5's GetValue
  * algorithm uses for primitive values, without actually constructing the
  * temporary object that the specification does.
  *
  * For objects, return the object itself. For string, boolean, and number
  * primitive values, return the appropriate constructor's prototype. For
@@ -592,17 +583,17 @@ ToIdOperation(JSContext *cx, HandleScrip
 }
 
 static JS_ALWAYS_INLINE bool
 GetObjectElementOperation(JSContext *cx, JSOp op, JSObject *objArg, bool wasObject,
                           HandleValue rref, MutableHandleValue res)
 {
     do {
         // Don't call GetPcScript (needed for analysis) from inside Ion since it's expensive.
-        bool analyze = cx->mainThread().currentlyRunningInInterpreter();
+        bool analyze = cx->currentlyRunningInInterpreter();
 
         uint32_t index;
         if (IsDefinitelyIndex(rref, &index)) {
             if (analyze && !objArg->isNative() && !objArg->isTypedArray()) {
                 JSScript *script = NULL;
                 jsbytecode *pc = NULL;
                 types::TypeScript::GetPcScript(cx, &script, &pc);
 
@@ -725,22 +716,16 @@ GetElementOperation(JSContext *cx, JSOp 
             str = cx->runtime()->staticStrings.getUnitStringForElement(cx, str, index);
             if (!str)
                 return false;
             res.setString(str);
             return true;
         }
     }
 
-    bool done = false;
-    if (!GetElemOptimizedArguments(cx, cx->fp(), lref, rref, res, &done))
-        return false;
-    if (done)
-        return true;
-
     bool isObject = lref.isObject();
     JSObject *obj = ToObjectFromStack(cx, lref);
     if (!obj)
         return false;
     return GetObjectElementOperation(cx, op, obj, isObject, rref, res);
 }
 
 static JS_ALWAYS_INLINE bool
@@ -753,17 +738,17 @@ SetObjectElementOperation(JSContext *cx,
     if (obj->isNative() && JSID_IS_INT(id)) {
         uint32_t length = obj->getDenseInitializedLength();
         int32_t i = JSID_TO_INT(id);
         if ((uint32_t)i >= length) {
             // In an Ion activation, GetPcScript won't work.  For non-baseline activations,
             // that's ok, because optimized ion doesn't generate analysis info.  However,
             // baseline must generate this information, so it passes the script and pc in
             // as arguments.
-            if (script || cx->mainThread().currentlyRunningInInterpreter()) {
+            if (script || cx->currentlyRunningInInterpreter()) {
                 JS_ASSERT(!!script == !!pc);
                 if (!script)
                     types::TypeScript::GetPcScript(cx, script.address(), &pc);
 
                 if (script->hasAnalysis())
                     script->analysis()->getCode(pc).arrayWriteHole = true;
             }
         }
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -78,30 +78,29 @@ CallThisObjectHook(JSContext *cx, Handle
  * influences performance. The JS_NEVER_INLINE is a temporary workaround until
  * we can remove the conservative scanner. See bug 849526 for more info.
  */
 #if defined(__clang__) && defined(JS_CPU_X86)
 static JS_NEVER_INLINE bool
 #else
 static bool
 #endif
-ToBooleanOp(JSContext *cx)
+ToBooleanOp(const FrameRegs &regs)
 {
-    return ToBoolean(cx->regs().sp[-1]);
+    return ToBoolean(regs.sp[-1]);
 }
 
 template <bool Eq>
 #if defined(__clang__) && defined(JS_CPU_X86)
 static JS_NEVER_INLINE bool
 #else
 static bool
 #endif
-LooseEqualityOp(JSContext *cx)
+LooseEqualityOp(JSContext *cx, FrameRegs &regs)
 {
-    FrameRegs &regs = cx->regs();
     Value rval = regs.sp[-1];
     Value lval = regs.sp[-2];
     bool cond;
     if (!LooselyEqual(cx, lval, rval, &cond))
         return false;
     cond = (cond == Eq);
     regs.sp--;
     regs.sp[-1].setBoolean(cond);
@@ -249,24 +248,24 @@ NoSuchMethod(JSContext *cx, unsigned arg
     JSBool ok = Invoke(cx, args);
     vp[0] = args.rval();
     return ok;
 }
 
 #endif /* JS_HAS_NO_SUCH_METHOD */
 
 inline bool
-GetPropertyOperation(JSContext *cx, HandleScript script, jsbytecode *pc, MutableHandleValue lval,
-                     MutableHandleValue vp)
+GetPropertyOperation(JSContext *cx, StackFrame *fp, HandleScript script, jsbytecode *pc,
+                     MutableHandleValue lval, MutableHandleValue vp)
 {
     JSOp op = JSOp(*pc);
 
     if (op == JSOP_LENGTH) {
-        if (IsOptimizedArguments(cx->fp(), lval.address())) {
-            vp.setInt32(cx->fp()->numActualArgs());
+        if (IsOptimizedArguments(fp, lval.address())) {
+            vp.setInt32(fp->numActualArgs());
             return true;
         }
 
         if (GetLengthProperty(lval, vp))
             return true;
     }
 
     JSObject *obj = ToObjectFromStack(cx, lval);
@@ -348,20 +347,20 @@ js::ValueToCallable(JSContext *cx, const
 }
 
 static JS_NEVER_INLINE bool
 Interpret(JSContext *cx, StackFrame *entryFrame);
 
 bool
 js::RunScript(JSContext *cx, StackFrame *fp)
 {
-    JS_ASSERT(fp == cx->fp());
+    JS_ASSERT(fp == cx->stack.fp());
     RootedScript script(cx, fp->script());
 
-    JS_ASSERT_IF(!fp->isGeneratorFrame(), cx->regs().pc == script->code);
+    JS_ASSERT_IF(!fp->isGeneratorFrame(), cx->stack.regs().pc == script->code);
     JS_ASSERT_IF(fp->isEvalFrame(), script->isActiveEval);
 
     JS_CHECK_RECURSION(cx, return false);
 
     // Check to see if useNewType flag should be set for this frame.
     if (fp->isFunctionFrame() && fp->isConstructing() && !fp->isGeneratorFrame() &&
         cx->typeInferenceEnabled())
     {
@@ -374,20 +373,20 @@ js::RunScript(JSContext *cx, StackFrame 
         }
     }
 
 #ifdef DEBUG
     struct CheckStackBalance {
         JSContext *cx;
         StackFrame *fp;
         CheckStackBalance(JSContext *cx)
-          : cx(cx), fp(cx->fp())
+          : cx(cx), fp(cx->stack.fp())
         {}
         ~CheckStackBalance() {
-            JS_ASSERT(fp == cx->fp());
+            JS_ASSERT(fp == cx->stack.fp());
         }
     } check(cx);
 #endif
 
     SPSEntryMarker marker(cx->runtime());
 
 #ifdef JS_ION
     if (ion::IsEnabled(cx)) {
@@ -803,48 +802,42 @@ js::TypeOfValue(JSContext *cx, const Val
     return JSTYPE_BOOLEAN;
 }
 
 /*
  * Enter the new with scope using an object at sp[-1] and associate the depth
  * of the with block with sp + stackIndex.
  */
 static bool
-EnterWith(JSContext *cx, int stackIndex)
+EnterWith(JSContext *cx, AbstractFramePtr frame, HandleValue val, uint32_t stackDepth)
 {
-    StackFrame *fp = cx->fp();
-    Value *sp = cx->regs().sp;
-    JS_ASSERT(stackIndex < 0);
-    JS_ASSERT(int(cx->regs().stackDepth()) + stackIndex >= 0);
-
     RootedObject obj(cx);
-    if (sp[-1].isObject()) {
-        obj = &sp[-1].toObject();
+    if (val.isObject()) {
+        obj = &val.toObject();
     } else {
-        obj = js_ValueToNonNullObject(cx, sp[-1]);
+        obj = js_ValueToNonNullObject(cx, val);
         if (!obj)
             return false;
-        sp[-1].setObject(*obj);
     }
 
-    WithObject *withobj = WithObject::create(cx, obj, fp->scopeChain(),
-                                             cx->regs().stackDepth() + stackIndex);
+    RootedObject scopeChain(cx, frame.scopeChain());
+    WithObject *withobj = WithObject::create(cx, obj, scopeChain, stackDepth);
     if (!withobj)
         return false;
 
-    fp->pushOnScopeChain(*withobj);
+    frame.pushOnScopeChain(*withobj);
     return true;
 }
 
 /* Unwind block and scope chains to match the given depth. */
 void
 js::UnwindScope(JSContext *cx, AbstractFramePtr frame, uint32_t stackDepth)
 {
-    JS_ASSERT_IF(frame.isStackFrame(), cx->fp() == frame.asStackFrame());
-    JS_ASSERT_IF(frame.isStackFrame(), stackDepth <= cx->regs().stackDepth());
+    JS_ASSERT_IF(frame.isStackFrame(), cx->stack.fp() == frame.asStackFrame());
+    JS_ASSERT_IF(frame.isStackFrame(), stackDepth <= cx->stack.regs().stackDepth());
 
     for (ScopeIter si(frame, cx); !si.done(); ++si) {
         switch (si.type()) {
           case ScopeIter::Block:
             if (si.staticBlock().stackDepth() < stackDepth)
                 return;
             frame.popBlock(cx);
             break;
@@ -1104,17 +1097,17 @@ Interpret(JSContext *cx, StackFrame *ent
 #define SET_SCRIPT(s)                                                         \
     JS_BEGIN_MACRO                                                            \
         script = (s);                                                         \
         if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts) \
             interrupts.enable();                                              \
     JS_END_MACRO
 
     /* Repoint cx->regs to a local variable for faster access. */
-    FrameRegs regs = cx->regs();
+    FrameRegs regs = cx->stack.regs();
     PreserveRegsGuard interpGuard(cx, regs);
 
     /*
      * Help Debugger find frames running scripts that it has put in
      * single-step mode.
      */
     InterpreterFrames interpreterFrame(cx, &regs, interrupts);
 
@@ -1405,29 +1398,34 @@ BEGIN_CASE(JSOP_POPN)
 END_CASE(JSOP_POPN)
 
 BEGIN_CASE(JSOP_SETRVAL)
 BEGIN_CASE(JSOP_POPV)
     POP_RETURN_VALUE();
 END_CASE(JSOP_POPV)
 
 BEGIN_CASE(JSOP_ENTERWITH)
-    if (!EnterWith(cx, -1))
+{
+    RootedValue &val = rootValue0;
+    val = regs.sp[-1];
+
+    if (!EnterWith(cx, regs.fp(), val, regs.stackDepth() - 1))
         goto error;
 
     /*
      * We must ensure that different "with" blocks have different stack depth
      * associated with them. This allows the try handler search to properly
      * recover the scope chain. Thus we must keep the stack at least at the
      * current level.
      *
      * We set sp[-1] to the current "with" object to help asserting the
      * enter/leave balance in [leavewith].
      */
     regs.sp[-1].setObject(*regs.fp()->scopeChain());
+}
 END_CASE(JSOP_ENTERWITH)
 
 BEGIN_CASE(JSOP_LEAVEWITH)
     JS_ASSERT(regs.sp[-1].toObject() == *regs.fp()->scopeChain());
     regs.fp()->popWith(cx);
     regs.sp--;
 END_CASE(JSOP_LEAVEWITH)
 
@@ -1492,49 +1490,49 @@ BEGIN_CASE(JSOP_GOTO)
 {
     len = GET_JUMP_OFFSET(regs.pc);
     BRANCH(len);
 }
 END_CASE(JSOP_GOTO)
 
 BEGIN_CASE(JSOP_IFEQ)
 {
-    bool cond = ToBooleanOp(cx);
+    bool cond = ToBooleanOp(regs);
     regs.sp--;
     if (cond == false) {
         len = GET_JUMP_OFFSET(regs.pc);
         BRANCH(len);
     }
 }
 END_CASE(JSOP_IFEQ)
 
 BEGIN_CASE(JSOP_IFNE)
 {
-    bool cond = ToBooleanOp(cx);
+    bool cond = ToBooleanOp(regs);
     regs.sp--;
     if (cond != false) {
         len = GET_JUMP_OFFSET(regs.pc);
         BRANCH(len);
     }
 }
 END_CASE(JSOP_IFNE)
 
 BEGIN_CASE(JSOP_OR)
 {
-    bool cond = ToBooleanOp(cx);
+    bool cond = ToBooleanOp(regs);
     if (cond == true) {
         len = GET_JUMP_OFFSET(regs.pc);
         DO_NEXT_OP(len);
     }
 }
 END_CASE(JSOP_OR)
 
 BEGIN_CASE(JSOP_AND)
 {
-    bool cond = ToBooleanOp(cx);
+    bool cond = ToBooleanOp(regs);
     if (cond == false) {
         len = GET_JUMP_OFFSET(regs.pc);
         DO_NEXT_OP(len);
     }
 }
 END_CASE(JSOP_AND)
 
 #define FETCH_ELEMENT_ID(n, id)                                               \
@@ -1750,22 +1748,22 @@ END_CASE(JSOP_BITXOR)
 
 BEGIN_CASE(JSOP_BITAND)
     BITWISE_OP(&);
 END_CASE(JSOP_BITAND)
 
 #undef BITWISE_OP
 
 BEGIN_CASE(JSOP_EQ)
-    if (!LooseEqualityOp<true>(cx))
+    if (!LooseEqualityOp<true>(cx, regs))
         goto error;
 END_CASE(JSOP_EQ)
 
 BEGIN_CASE(JSOP_NE)
-    if (!LooseEqualityOp<false>(cx))
+    if (!LooseEqualityOp<false>(cx, regs))
         goto error;
 END_CASE(JSOP_NE)
 
 #define STRICT_EQUALITY_OP(OP, COND)                                          \
     JS_BEGIN_MACRO                                                            \
         const Value &rref = regs.sp[-1];                                      \
         const Value &lref = regs.sp[-2];                                      \
         bool equal;                                                           \
@@ -1940,17 +1938,17 @@ BEGIN_CASE(JSOP_MOD)
     if (!ModOperation(cx, script, regs.pc, lval, rval, &regs.sp[-2]))
         goto error;
     regs.sp--;
 }
 END_CASE(JSOP_MOD)
 
 BEGIN_CASE(JSOP_NOT)
 {
-    bool cond = ToBooleanOp(cx);
+    bool cond = ToBooleanOp(regs);
     regs.sp--;
     PUSH_BOOLEAN(!cond);
 }
 END_CASE(JSOP_NOT)
 
 BEGIN_CASE(JSOP_BITNOT)
 {
     int32_t i;
@@ -2080,18 +2078,19 @@ BEGIN_CASE(JSOP_THIS)
     PUSH_COPY(regs.fp()->thisValue());
 END_CASE(JSOP_THIS)
 
 BEGIN_CASE(JSOP_GETPROP)
 BEGIN_CASE(JSOP_GETXPROP)
 BEGIN_CASE(JSOP_LENGTH)
 BEGIN_CASE(JSOP_CALLPROP)
 {
+
     MutableHandleValue lval = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
-    if (!GetPropertyOperation(cx, script, regs.pc, lval, lval))
+    if (!GetPropertyOperation(cx, regs.fp(), script, regs.pc, lval, lval))
         goto error;
 
     TypeScript::Monitor(cx, script, regs.pc, lval);
     assertSameCompartmentDebugOnly(cx, lval);
 }
 END_CASE(JSOP_GETPROP)
 
 BEGIN_CASE(JSOP_SETINTRINSIC)
@@ -2135,20 +2134,27 @@ BEGIN_CASE(JSOP_SETPROP)
 }
 END_CASE(JSOP_SETPROP)
 
 BEGIN_CASE(JSOP_GETELEM)
 BEGIN_CASE(JSOP_CALLELEM)
 {
     MutableHandleValue lval = MutableHandleValue::fromMarkedLocation(&regs.sp[-2]);
     HandleValue rval = HandleValue::fromMarkedLocation(&regs.sp[-1]);
-
     MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-2]);
-    if (!GetElementOperation(cx, op, lval, rval, res))
+
+    bool done = false;
+    if (!GetElemOptimizedArguments(cx, regs.fp(), lval, rval, res, &done))
         goto error;
+
+    if (!done) {
+        if (!GetElementOperation(cx, op, lval, rval, res))
+            goto error;
+    }
+
     TypeScript::Monitor(cx, script, regs.pc, res);
     regs.sp--;
 }
 END_CASE(JSOP_GETELEM)
 
 BEGIN_CASE(JSOP_SETELEM)
 {
     RootedObject &obj = rootObject0;
@@ -2190,19 +2196,23 @@ BEGIN_CASE(JSOP_EVAL)
             goto error;
     }
     regs.sp = args.spAfterCall();
     TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
 }
 END_CASE(JSOP_EVAL)
 
 BEGIN_CASE(JSOP_FUNAPPLY)
-    if (!GuardFunApplyArgumentsOptimization(cx))
+{
+    CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
+    if (!GuardFunApplyArgumentsOptimization(cx, regs.fp(), args.calleev(), args.array(),
+                                            args.length()))
         goto error;
     /* FALL THROUGH */
+}
 
 BEGIN_CASE(JSOP_NEW)
 BEGIN_CASE(JSOP_CALL)
 BEGIN_CASE(JSOP_FUNCALL)
 {
     if (regs.fp()->hasPushedSPSFrame())
         cx->runtime()->spsProfiler.updatePC(script, regs.pc);
     JS_ASSERT(regs.stackDepth() >= 2 + GET_ARGC(regs.pc));
@@ -2988,17 +2998,17 @@ BEGIN_CASE(JSOP_LEAVEBLOCKEXPR)
 END_CASE(JSOP_LEAVEBLOCK)
 
 #if JS_HAS_GENERATORS
 BEGIN_CASE(JSOP_GENERATOR)
 {
     JS_ASSERT(!cx->isExceptionPending());
     regs.fp()->initGeneratorFrame();
     regs.pc += JSOP_GENERATOR_LENGTH;
-    JSObject *obj = js_NewGenerator(cx);
+    JSObject *obj = js_NewGenerator(cx, regs);
     if (!obj)
         goto error;
     regs.fp()->setReturnValue(ObjectValue(*obj));
     regs.fp()->setYielding();
     interpReturnOK = true;
     if (entryFrame != regs.fp())
         goto inline_return;
     goto exit;
@@ -3041,17 +3051,17 @@ END_CASE(JSOP_ARRAYPUSH)
                                  JSMSG_BAD_BYTECODE, numBuf);
             goto error;
           }
 
         } /* switch (op) */
     } /* for (;;) */
 
   error:
-    JS_ASSERT(&cx->regs() == &regs);
+    JS_ASSERT(&cx->stack.regs() == &regs);
     JS_ASSERT(uint32_t(regs.pc - script->code) < script->length);
 
     if (cx->isExceptionPending()) {
         /* Call debugger throw hooks. */
         if (cx->compartment()->debugMode()) {
             JSTrapStatus status = DebugExceptionUnwind(cx, regs.fp(), regs.pc);
             switch (status) {
               case JSTRAP_ERROR:
@@ -3068,17 +3078,17 @@ END_CASE(JSOP_ARRAYPUSH)
               default:
                 JS_NOT_REACHED("Invalid trap status");
             }
         }
 
         for (TryNoteIter tni(cx, regs); !tni.done(); ++tni) {
             JSTryNote *tn = *tni;
 
-            UnwindScope(cx, cx->fp(), tn->stackDepth);
+            UnwindScope(cx, regs.fp(), tn->stackDepth);
 
             /*
              * Set pc to the first bytecode after the the try note to point
              * to the beginning of catch or finally or to [enditer] closing
              * the for-in loop.
              */
             regs.pc = (script)->main() + tn->start + tn->length;
             regs.sp = regs.spForStackDepth(tn->stackDepth);
@@ -3143,17 +3153,17 @@ END_CASE(JSOP_ARRAYPUSH)
         }
 #endif
     } else {
         UnwindForUncatchableException(cx, regs);
         interpReturnOK = false;
     }
 
   forced_return:
-    UnwindScope(cx, cx->fp(), 0);
+    UnwindScope(cx, regs.fp(), 0);
     regs.setToEndOfScript();
 
     if (entryFrame != regs.fp())
         goto inline_return;
 
   exit:
     if (cx->compartment()->debugMode())
         interpReturnOK = ScriptDebugEpilogue(cx, regs.fp(), interpReturnOK);
@@ -3243,21 +3253,25 @@ js::Lambda(JSContext *cx, HandleFunction
 {
     RootedObject clone(cx, CloneFunctionObjectIfNotSingleton(cx, fun, parent, TenuredObject));
     if (!clone)
         return NULL;
 
     if (fun->isArrow()) {
         // Note that this will assert if called from Ion code. Ion can't yet
         // emit code for a bound arrow function (bug 851913).
-        AbstractFramePtr frame = cx->fp();
+        AbstractFramePtr frame;
+        if (cx->currentlyRunningInInterpreter()) {
+            frame = cx->interpreterFrame();
+        } else {
 #ifdef JS_ION
-        if (cx->mainThread().currentlyRunningInJit())
+            JS_ASSERT(cx->currentlyRunningInJit());
             frame = ion::GetTopBaselineFrame(cx);
 #endif
+        }
 
         if (!ComputeThis(cx, frame))
             return NULL;
 
         RootedValue thisval(cx, frame.thisValue());
         clone = js_fun_bind(cx, clone, thisval, NULL, 0);
         if (!clone)
             return NULL;
@@ -3283,18 +3297,17 @@ js::DefFunOperation(JSContext *cx, Handl
      */
     RootedFunction fun(cx, funArg);
     if (fun->isNative() || fun->environment() != scopeChain) {
         fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain, TenuredObject);
         if (!fun)
             return false;
     } else {
         JS_ASSERT(script->compileAndGo);
-        JS_ASSERT_IF(cx->mainThread().currentlyRunningInInterpreter(),
-                     cx->fp()->isGlobalFrame() || cx->fp()->isEvalInFunction());
+        JS_ASSERT(!script->function());
     }
 
     /*
      * We define the function as a property of the variable object and not the
      * current scope chain even for the case of function expression statements
      * and functions defined by eval inside let or with blocks.
      */
     RootedObject parent(cx, scopeChain);
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -282,18 +282,18 @@ CallObject::createForFunction(JSContext 
 
     return callobj;
 }
 
 CallObject *
 CallObject::createForStrictEval(JSContext *cx, AbstractFramePtr frame)
 {
     JS_ASSERT(frame.isStrictEvalFrame());
-    JS_ASSERT_IF(frame.isStackFrame(), cx->fp() == frame.asStackFrame());
-    JS_ASSERT_IF(frame.isStackFrame(), cx->regs().pc == frame.script()->code);
+    JS_ASSERT_IF(frame.isStackFrame(), cx->interpreterFrame() == frame.asStackFrame());
+    JS_ASSERT_IF(frame.isStackFrame(), cx->interpreterRegs().pc == frame.script()->code);
 
     RootedFunction callee(cx);
     RootedScript script(cx, frame.script());
     RootedObject scopeChain(cx, frame.scopeChain());
     return create(cx, script, scopeChain, callee);
 }
 
 Class CallObject::class_ = {
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -69,17 +69,17 @@ StackFrame::compartment() const
     JS_ASSERT(scopeChain()->compartment() == script()->compartment());
     return scopeChain()->compartment();
 }
 
 inline void
 StackFrame::initPrev(JSContext *cx)
 {
     JS_ASSERT(flags_ & HAS_PREVPC);
-    if (FrameRegs *regs = cx->maybeRegs()) {
+    if (FrameRegs *regs = cx->stack.maybeRegs()) {
         prev_ = regs->fp();
         prevpc_ = regs->pc;
         JS_ASSERT(uint32_t(prevpc_ - prev_->script()->code) < prev_->script()->length);
     } else {
         prev_ = NULL;
 #ifdef DEBUG
         prevpc_ = (jsbytecode *)0xbadc;
 #endif
@@ -448,16 +448,30 @@ AbstractFramePtr::scopeChain() const
         return asStackFrame()->scopeChain();
 #ifdef JS_ION
     return asBaselineFrame()->scopeChain();
 #else
     JS_NOT_REACHED("Invalid frame");
 #endif
 }
 
+inline void
+AbstractFramePtr::pushOnScopeChain(ScopeObject &scope)
+{
+    if (isStackFrame()) {
+        asStackFrame()->pushOnScopeChain(scope);
+        return;
+    }
+#ifdef JS_ION
+    asBaselineFrame()->pushOnScopeChain(scope);
+#else
+    JS_NOT_REACHED("Invalid frame");
+#endif
+}
+
 inline CallObject &
 AbstractFramePtr::callObj() const
 {
     if (isStackFrame())
         return asStackFrame()->callObj();
 #ifdef JS_ION
     return asBaselineFrame()->callObj();
 #else
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -283,17 +283,17 @@ StackFrame::initFunctionScopeObjects(JSC
 }
 
 bool
 StackFrame::prologue(JSContext *cx)
 {
     RootedScript script(cx, this->script());
 
     JS_ASSERT(!isGeneratorFrame());
-    JS_ASSERT(cx->regs().pc == script->code);
+    JS_ASSERT(cx->interpreterRegs().pc == script->code);
 
     if (isEvalFrame()) {
         if (script->strict) {
             CallObject *callobj = CallObject::createForStrictEval(cx, this);
             if (!callobj)
                 return false;
             pushOnScopeChain(*callobj);
             flags_ |= HAS_CALL_OBJ;
@@ -800,17 +800,17 @@ ContextStack::onTop() const
  * Additionally, to minimize calls to ensureSpace, ensureOnTop ensures that
  * there is space for nvars slots on top of the stack.
  */
 Value *
 ContextStack::ensureOnTop(JSContext *cx, MaybeReportError report, unsigned nvars,
                           MaybeExtend extend, bool *pushedSeg)
 {
     Value *firstUnused = space().firstUnused();
-    FrameRegs *regs = cx->maybeRegs();
+    FrameRegs *regs = cx->stack.maybeRegs();
 
     if (onTop() && extend) {
         if (!space().ensureSpace(cx, report, firstUnused, nvars))
             return NULL;
         return firstUnused;
     }
 
     if (!space().ensureSpace(cx, report, firstUnused, VALUES_PER_STACK_SEGMENT + nvars))
@@ -1767,18 +1767,18 @@ ScriptFrameIter::numFrameSlots() const
         ion::BaselineFrame *frame = data_.ionFrames_.baselineFrame();
         return frame->numValueSlots() - data_.ionFrames_.script()->nfixed;
 #else
         break;
 #endif
       }
       case SCRIPTED:
         JS_ASSERT(data_.cx_);
-        JS_ASSERT(data_.cx_->regs().spForStackDepth(0) == interpFrame()->base());
-        return data_.cx_->regs().sp - interpFrame()->base();
+        JS_ASSERT(data_.cx_->stack.regs().spForStackDepth(0) == interpFrame()->base());
+        return data_.cx_->stack.regs().sp - interpFrame()->base();
     }
     JS_NOT_REACHED("Unexpected state");
     return 0;
 }
 
 Value
 ScriptFrameIter::frameSlotValue(size_t index) const
 {
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -178,16 +178,18 @@ class AbstractFramePtr
 
     operator bool() const { return !!ptr_; }
 
     inline JSGenerator *maybeSuspendedGenerator(JSRuntime *rt) const;
 
     inline JSObject *scopeChain() const;
     inline CallObject &callObj() const;
     inline bool initFunctionScopeObjects(JSContext *cx);
+    inline void pushOnScopeChain(ScopeObject &scope);
+
     inline JSCompartment *compartment() const;
 
     inline StaticBlockObject *maybeBlockChain() const;
     inline bool hasCallObj() const;
     inline bool isGeneratorFrame() const;
     inline bool isYielding() const;
     inline bool isFunctionFrame() const;
     inline bool isGlobalFrame() const;
@@ -1600,16 +1602,19 @@ class InterpreterActivation : public Act
 
         current_ = frame->prev();
         JS_ASSERT(current_);
     }
     StackFrame *current() const {
         JS_ASSERT(current_);
         return current_;
     }
+    FrameRegs &regs() const {
+        return regs_;
+    }
 };
 
 // Iterates over a runtime's activation list.
 class ActivationIterator
 {
     uint8_t *jitTop_;
 
   protected: