From 4ccf62b3ab7064083d1243719297e374ab5d59b7 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Wed, 10 Oct 2012 20:41:01 -0700 Subject: [PATCH] Bug 797977 - Rename StackIter::fp() to StackIter::interpFrame(). r=luke --- js/src/builtin/Eval.cpp | 1 + js/src/ion/Bailouts.cpp | 3 +- js/src/ion/IonFrameIterator.h | 1 + js/src/ion/IonFrames.cpp | 11 ++++ js/src/jsapi.cpp | 2 +- js/src/jscntxt.h | 6 -- js/src/jscntxtinlines.h | 12 ---- js/src/jscompartment.cpp | 15 ++++- js/src/jsdbgapi.cpp | 31 ++++++--- js/src/jsfun.cpp | 6 +- js/src/jsinterpinlines.h | 1 + js/src/jsobj.cpp | 48 +++++++------- js/src/jsscript.cpp | 15 ++++- js/src/shell/js.cpp | 8 ++- js/src/vm/ArgumentsObject.cpp | 6 +- js/src/vm/Debugger.cpp | 12 +++- js/src/vm/ScopeObject.cpp | 9 ++- js/src/vm/Stack.cpp | 115 +++++++++++++++++++++++++--------- js/src/vm/Stack.h | 28 +++++++-- 19 files changed, 226 insertions(+), 104 deletions(-) diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp index ec00d34720ae..8527565b2504 100644 --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -184,6 +184,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *c unsigned staticLevel; RootedValue thisv(cx); if (evalType == DIRECT_EVAL) { + JS_ASSERT(!caller->runningInIon()); staticLevel = caller->script()->staticLevel + 1; // Direct calls to eval are supposed to see the caller's |this|. If we diff --git a/js/src/ion/Bailouts.cpp b/js/src/ion/Bailouts.cpp index 2e198b76a773..9b2058fd0faa 100644 --- a/js/src/ion/Bailouts.cpp +++ b/js/src/ion/Bailouts.cpp @@ -609,8 +609,7 @@ ion::ThunkToInterpreter(Value *vp) StackFrame *fp = NULL; Rooted script(cx, NULL); do { - JS_ASSERT(!iter.isIon()); - fp = iter.fp(); + fp = iter.interpFrame(); script = iter.script(); if (script->needsArgsObj()) { // Currently IonMonkey does not compile if the script needs an diff --git a/js/src/ion/IonFrameIterator.h b/js/src/ion/IonFrameIterator.h index 685e23912af1..039199b42e3a 100644 --- a/js/src/ion/IonFrameIterator.h +++ b/js/src/ion/IonFrameIterator.h @@ -302,6 +302,7 @@ class InlineFrameIterator } bool isFunctionFrame() const; bool isConstructing() const; + JSObject *scopeChain() const; JSObject *thisObject() const; InlineFrameIterator operator++(); diff --git a/js/src/ion/IonFrames.cpp b/js/src/ion/IonFrames.cpp index 284f18111cca..6912742d35aa 100644 --- a/js/src/ion/IonFrames.cpp +++ b/js/src/ion/IonFrames.cpp @@ -1030,6 +1030,17 @@ IonFrameIterator::isConstructing() const return activation_->entryfp()->isConstructing(); } +JSObject * +InlineFrameIterator::scopeChain() const +{ + SnapshotIterator s(si_); + + // scopeChain + Value v = s.read(); + JS_ASSERT(v.isObject()); + return &v.toObject(); +} + JSObject * InlineFrameIterator::thisObject() const { diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index adf8a3fcf29a..6f21d34d6ad4 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -7317,6 +7317,6 @@ JS_GetScriptedGlobal(JSContext *cx) ScriptFrameIter i(cx); if (i.done()) return cx->global(); - return &i.fp()->global(); + return &i.scopeChain()->global(); } diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index a7246c3656b1..357873cdc37a 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -1972,12 +1972,6 @@ namespace mjit { } /* namespace js */ -/* How much expansion of inlined frames to do when inspecting the stack. */ -enum FrameExpandKind { - FRAME_EXPAND_NONE = 0, - FRAME_EXPAND_ALL = 1 -}; - namespace js { /************************************************************************/ diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index 211ff457f551..ad0800248118 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -585,16 +585,4 @@ JSContext::setDefaultCompartmentObjectIfUnset(JSObject *obj) setDefaultCompartmentObject(obj); } -/* Get the current frame, first lazily instantiating stack frames if needed. */ -static inline js::StackFrame * -js_GetTopStackFrame(JSContext *cx, FrameExpandKind expand) -{ -#ifdef JS_METHODJIT - if (expand) - js::mjit::ExpandInlineFrames(cx->compartment); -#endif - - return cx->maybefp(); -} - #endif /* jscntxtinlines_h___ */ diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 024cb6479c1c..536c690852ad 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -682,10 +682,21 @@ JSCompartment::onTooMuchMalloc() bool JSCompartment::hasScriptsOnStack() { - for (AllFramesIter i(rt->stackSpace); !i.done(); ++i) { - if (i.fp()->script()->compartment() == this) + for (AllFramesIter afi(rt->stackSpace); !afi.done(); ++afi) { +#ifdef JS_ION + // If this is an Ion frame, check the IonActivation instead + if (afi.isIon()) + continue; +#endif + if (afi.interpFrame()->script()->compartment() == this) return true; } +#ifdef JS_ION + for (ion::IonActivationIterator iai(rt); iai.more(); ++iai) { + if (iai.activation()->compartment() == this) + return true; + } +#endif return false; } diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index e66954e247bd..fcc3c8ac7948 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -477,7 +477,21 @@ JS_PUBLIC_API(JSStackFrame *) JS_BrokenFrameIterator(JSContext *cx, JSStackFrame **iteratorp) { StackFrame *fp = Valueify(*iteratorp); - *iteratorp = Jsvalify((fp == NULL) ? js_GetTopStackFrame(cx, FRAME_EXPAND_ALL) : fp->prev()); + if (!fp) { +#ifdef JS_METHODJIT + js::mjit::ExpandInlineFrames(cx->compartment); +#endif + fp = cx->maybefp(); + } else { + fp = fp->prev(); + } + + // settle on the next non-ion frame as it is not considered safe to inspect + // Ion's activation StackFrame. + while (fp && fp->runningInIon()) + fp = fp->prev(); + + *iteratorp = Jsvalify(fp); return *iteratorp; } @@ -1188,7 +1202,7 @@ JS::DescribeStack(JSContext *cx, unsigned maxFrames) FrameDescription desc; desc.script = i.script(); desc.lineno = PCToLineNumber(i.script(), i.pc()); - desc.fun = i.fp()->maybeFun(); + desc.fun = i.maybeCallee(); if (!frames.append(desc)) return NULL; if (frames.length() == maxFrames) @@ -1261,11 +1275,12 @@ FormatFrame(JSContext *cx, const ScriptFrameIter &iter, char *buf, int num, JSScript* script = iter.script(); jsbytecode* pc = iter.pc(); - JSAutoCompartment ac(cx, iter.fp()->scopeChain()); + RootedObject scopeChain(cx, iter.scopeChain()); + JSAutoCompartment ac(cx, scopeChain); const char *filename = script->filename; unsigned lineno = PCToLineNumber(script, pc); - JSFunction *fun = iter.fp()->maybeFun(); + JSFunction *fun = iter.maybeCallee(); JSString *funname = NULL; if (fun) funname = fun->atom(); @@ -1273,16 +1288,16 @@ FormatFrame(JSContext *cx, const ScriptFrameIter &iter, char *buf, int num, JSObject *callObj = NULL; AutoPropertyDescArray callProps(cx); - if (showArgs || showLocals) { - callObj = JS_GetFrameCallObject(cx, Jsvalify(iter.fp())); + if (!iter.isIon() && (showArgs || showLocals)) { + callObj = JS_GetFrameCallObject(cx, Jsvalify(iter.interpFrame())); if (callObj) callProps.fetch(callObj); } Value thisVal = UndefinedValue(); AutoPropertyDescArray thisProps(cx); - if (ComputeThis(cx, iter.fp())) { - thisVal = iter.fp()->thisValue(); + if (iter.computeThis()) { + thisVal = iter.thisv(); if (showThisProps && !thisVal.isPrimitive()) thisProps.fetch(&thisVal.toObject()); } diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 439b9ebf9a61..7d0817b5f7a5 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -138,9 +138,9 @@ fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, MutableHandleValu } #ifdef JS_METHODJIT - StackFrame *fp = iter.fp(); - if (iter.isScript() && iter.isIon()) - fp = NULL; + StackFrame *fp = NULL; + if (iter.isScript() && !iter.isIon()) + fp = iter.interpFrame(); if (JSID_IS_ATOM(id, cx->names().caller) && fp && fp->prev()) { /* diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h index 4999b6870386..abac258dcaf0 100644 --- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -80,6 +80,7 @@ ComputeImplicitThis(JSContext *cx, HandleObject obj, Value *vp) inline bool ComputeThis(JSContext *cx, StackFrame *fp) { + JS_ASSERT(!fp->runningInIon()); Value &thisv = fp->thisValue(); if (thisv.isObject()) return true; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 20e57b3d76ff..d150843f709f 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -4449,12 +4449,12 @@ js::GetMethod(JSContext *cx, HandleObject obj, HandleId id, unsigned getHow, Mut JS_FRIEND_API(bool) js::CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname) { - StackFrame *const fp = js_GetTopStackFrame(cx, FRAME_EXPAND_ALL); - if (!fp) + JSScript *script = cx->stack.currentScript(NULL, ContextStack::ALLOW_CROSS_COMPARTMENT); + if (!script) return true; /* If neither cx nor the code is strict, then no check is needed. */ - if (!fp->script()->strictModeCode && !cx->hasStrictOption()) + if (!script->strictModeCode && !cx->hasStrictOption()) return true; JSAutoByteString bytes(cx, propname); @@ -5468,7 +5468,7 @@ js_DumpStackFrame(JSContext *cx, StackFrame *start) return; } } else { - while (!i.done() && i.fp() != start) + while (!i.done() && !i.isIon() && i.interpFrame() != start) ++i; if (i.done()) { @@ -5479,44 +5479,49 @@ js_DumpStackFrame(JSContext *cx, StackFrame *start) } for (; !i.done(); ++i) { - StackFrame *const fp = i.fp(); + if (i.isIon()) + fprintf(stderr, "IonFrame\n"); + else + fprintf(stderr, "StackFrame at %p\n", (void *) i.interpFrame()); - fprintf(stderr, "StackFrame at %p\n", (void *) fp); - if (fp->isFunctionFrame()) { + if (i.isFunctionFrame()) { fprintf(stderr, "callee fun: "); - dumpValue(ObjectValue(fp->callee())); + dumpValue(i.calleev()); } else { fprintf(stderr, "global frame, no callee"); } fputc('\n', stderr); fprintf(stderr, "file %s line %u\n", - fp->script()->filename, (unsigned) fp->script()->lineno); + i.script()->filename, (unsigned) i.script()->lineno); if (jsbytecode *pc = i.pc()) { fprintf(stderr, " pc = %p\n", pc); fprintf(stderr, " current op: %s\n", js_CodeName[*pc]); } - MaybeDumpObject("blockChain", fp->maybeBlockChain()); - MaybeDumpValue("this", fp->thisValue()); - fprintf(stderr, " rval: "); - dumpValue(fp->returnValue()); - fputc('\n', stderr); + if (!i.isIon()) + MaybeDumpObject("blockChain", i.interpFrame()->maybeBlockChain()); + MaybeDumpValue("this", i.thisv()); + if (!i.isIon()) { + fprintf(stderr, " rval: "); + dumpValue(i.interpFrame()->returnValue()); + fputc('\n', stderr); + } fprintf(stderr, " flags:"); - if (fp->isConstructing()) + if (i.isConstructing()) fprintf(stderr, " constructing"); - if (fp->isDebuggerFrame()) + if (!i.isIon() && i.interpFrame()->isDebuggerFrame()) fprintf(stderr, " debugger"); - if (fp->isEvalFrame()) + if (i.isEvalFrame()) fprintf(stderr, " eval"); - if (fp->isYielding()) + if (!i.isIon() && i.interpFrame()->isYielding()) fprintf(stderr, " yielding"); - if (fp->isGeneratorFrame()) + if (!i.isIon() && i.interpFrame()->isGeneratorFrame()) fprintf(stderr, " generator"); fputc('\n', stderr); - fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) fp->scopeChain()); + fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) i.scopeChain()); fputc('\n', stderr); } @@ -5535,7 +5540,8 @@ js_DumpBacktrace(JSContext *cx) const char *filename = JS_GetScriptFilename(cx, i.script()); unsigned line = JS_PCToLineNumber(cx, i.script(), i.pc()); sprinter.printf("#%d %14p %s:%d (%p @ %d)\n", - depth, (i.isIon() ? 0 : i.fp()), filename, line, + depth, (i.isIon() ? 0 : i.interpFrame()), + filename, line, i.script(), i.pc() - i.script()->code); } else { sprinter.printf("#%d ???\n", depth); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 3c4f63ed4523..a923d7918fc1 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -2572,8 +2572,19 @@ JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script) * - type inference data for the script assuming script->needsArgsObj; and */ for (AllFramesIter i(cx->stack.space()); !i.done(); ++i) { - StackFrame *fp = i.fp(); - if (fp->isFunctionFrame() && !fp->runningInIon() && fp->script() == script) { + /* + * We cannot reliably create an arguments object for Ion activations of + * this script. To maintain the invariant that "script->needsArgsObj + * implies fp->hasArgsObj", the Ion bail mechanism will create an + * arguments object right after restoring the StackFrame and before + * entering the interpreter (in ion::ThunkToInterpreter). This delay is + * safe since the engine avoids any observation of a StackFrame when it + * beginsIonActivation (see StackIter::interpFrame comment). + */ + if (i.isIon()) + continue; + StackFrame *fp = i.interpFrame(); + if (fp->isFunctionFrame() && fp->script() == script) { ArgumentsObject *argsobj = ArgumentsObject::createExpected(cx, fp); if (!argsobj) { /* diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index df3da3e3ddd7..faf79e3141c6 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1382,7 +1382,8 @@ TrapHandler(JSContext *cx, JSScript *, jsbytecode *pc, jsval *rval, ScriptFrameIter iter(cx); JS_ASSERT(!iter.done()); - JSStackFrame *caller = Jsvalify(iter.fp()); + /* Debug-mode currently disables Ion compilation. */ + JSStackFrame *caller = Jsvalify(iter.interpFrame()); JSScript *script = iter.script(); size_t length; @@ -2504,9 +2505,10 @@ EvalInFrame(JSContext *cx, unsigned argc, jsval *vp) JS_ASSERT(cx->hasfp()); + /* Debug-mode currently disables Ion compilation. */ ScriptFrameIter fi(cx); for (uint32_t i = 0; i < upCount; ++i, ++fi) { - if (!fi.fp()->prev()) + if (!fi.interpFrame()->prev()) break; } @@ -2519,7 +2521,7 @@ EvalInFrame(JSContext *cx, unsigned argc, jsval *vp) if (!chars) return false; - StackFrame *fp = fi.fp(); + StackFrame *fp = fi.interpFrame(); bool ok = !!JS_EvaluateUCInStackFrame(cx, Jsvalify(fp), chars, length, fp->script()->filename, JS_PCToLineNumber(cx, fp->script(), diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index 770bf0bb34e9..d211868bcd86 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -25,7 +25,7 @@ using namespace js::gc; static void CopyStackFrameArguments(const StackFrame *fp, HeapValue *dst) { - JS_ASSERT(!fp->beginsIonActivation()); + JS_ASSERT(!fp->runningInIon()); unsigned numActuals = fp->numActualArgs(); unsigned numFormals = fp->callee().nargs; @@ -87,7 +87,7 @@ struct CopyStackIterArgs void copyArgs(HeapValue *dstBase) const { if (!iter_.isIon()) { - CopyStackFrameArguments(iter_.fp(), dstBase); + CopyStackFrameArguments(iter_.interpFrame(), dstBase); return; } @@ -110,7 +110,7 @@ struct CopyStackIterArgs */ void maybeForwardToCallObject(JSObject *obj, ArgumentsData *data) { if (!iter_.isIon()) - ArgumentsObject::MaybeForwardToCallObject(iter_.fp(), obj, data); + ArgumentsObject::MaybeForwardToCallObject(iter_.interpFrame(), obj, data); } }; diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 9e97512f813b..355e35c419e2 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -1762,8 +1762,14 @@ Debugger::getNewestFrame(JSContext *cx, unsigned argc, Value *vp) * Since there may be multiple contexts, use AllFramesIter instead. */ for (AllFramesIter i(cx->stack.space()); !i.done(); ++i) { - if (dbg->observesFrame(i.fp())) - return dbg->getScriptFrame(cx, i.fp(), vp); + /* + * Debug-mode currently disables Ion compilation in the compartment of + * the debuggee. + */ + if (i.isIon()) + continue; + if (dbg->observesFrame(i.interpFrame())) + return dbg->getScriptFrame(cx, i.interpFrame(), vp); } args.rval().setNull(); return true; @@ -2113,7 +2119,7 @@ class Debugger::ScriptQuery { */ JS_ASSERT(script->isForEval()); - GlobalObject *global = &fri.fp()->global(); + GlobalObject *global = &fri.interpFrame()->global(); if (!consider(script, global, vector)) return false; } diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 76622a61177a..a23df8c59646 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -1834,7 +1834,14 @@ DebugScopes::updateLiveScopes(JSContext *cx) * the flag for us, at exactly the time when execution resumes fp->prev(). */ for (AllFramesIter i(cx->runtime->stackSpace); !i.done(); ++i) { - StackFrame *fp = i.fp(); + /* + * Debug-mode currently disables Ion compilation in the compartment of + * the debuggee. + */ + if (i.isIon()) + continue; + + StackFrame *fp = i.interpFrame(); if (fp->scopeChain()->compartment() != cx->compartment) continue; diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 554d5efab4eb..0e6a51d4227d 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -15,6 +15,7 @@ #include "jsgcinlines.h" #include "jsobjinlines.h" +#include "jsinterpinlines.h" #include "jsopcode.h" @@ -823,7 +824,13 @@ bool StackSpace::containsSlow(StackFrame *fp) { for (AllFramesIter i(*this); !i.done(); ++i) { - if (i.fp() == fp) + /* + * Debug-mode currently disables Ion compilation in the compartment of + * the debuggee. + */ + if (i.isIon()) + continue; + if (i.interpFrame() == fp) return true; } return false; @@ -863,16 +870,6 @@ ContextStack::onTop() const return seg_ && seg_ == space().seg_; } -bool -ContextStack::containsSlow(const StackFrame *target) const -{ - for (StackSegment *s = seg_; s; s = s->prevInContext()) { - if (s->contains(target)) - return true; - } - return false; -} - /* * This helper function brings the ContextStack to the top of the thread stack * (so that it can be extended to push a frame and/or arguments) by potentially @@ -1055,8 +1052,13 @@ ContextStack::pushExecuteFrame(JSContext *cx, JSScript *script, const Value &thi /* Though the prev-frame is given, need to search for prev-call. */ StackSegment &seg = cx->stack.space().containingSegment(evalInFrame); StackIter iter(cx->runtime, seg); - while (!iter.isScript() || iter.fp() != evalInFrame) + /* Debug-mode currently disables Ion compilation. */ + JS_ASSERT(!evalInFrame->runningInIon()); + JS_ASSERT_IF(evalInFrame->compartment() == iter.compartment(), !iter.isIon()); + while (!iter.isScript() || iter.isIon() || iter.interpFrame() != evalInFrame) { ++iter; + JS_ASSERT_IF(evalInFrame->compartment() == iter.compartment(), !iter.isIon()); + } evalInFrameCalls = iter.calls_; extend = CANT_EXTEND; } else { @@ -1330,9 +1332,9 @@ StackIter::settleOnNewState() /* Avoid duplicating logic; seg_ contains fp_, so no iloop. */ StackIter tmp = *this; tmp.startOnSegment(seg_); - while (!tmp.isScript() || tmp.fp() != fp_) + while (!tmp.isScript() || tmp.fp_ != fp_) ++tmp; - JS_ASSERT(tmp.state_ == SCRIPTED && tmp.seg_ == seg_ && tmp.fp_ == fp_); + JS_ASSERT(tmp.isScript() && tmp.seg_ == seg_ && tmp.fp_ == fp_); *this = tmp; return; } @@ -1521,10 +1523,31 @@ StackIter::operator==(const StackIter &rhs) const return done() == rhs.done() && (done() || (isScript() == rhs.isScript() && - ((isScript() && fp() == rhs.fp()) || + ((isScript() && fp_ == rhs.fp_) || (!isScript() && nativeArgs().base() == rhs.nativeArgs().base())))); } +JSCompartment * +StackIter::compartment() const +{ + switch (state_) { + case DONE: + break; + case SCRIPTED: + return fp_->compartment(); + case ION: +#ifdef JS_ION + return ionActivations_.activation()->compartment(); +#else + break; +#endif + case NATIVE: + return calls_->callee().compartment(); + } + JS_NOT_REACHED("Unexpected state"); + return NULL; +} + bool StackIter::isFunctionFrame() const { @@ -1532,7 +1555,7 @@ StackIter::isFunctionFrame() const case DONE: break; case SCRIPTED: - return fp()->isFunctionFrame(); + return interpFrame()->isFunctionFrame(); case ION: #ifdef JS_ION return ionInlineFrames_.isFunctionFrame(); @@ -1553,7 +1576,7 @@ StackIter::isEvalFrame() const case DONE: break; case SCRIPTED: - return fp()->isEvalFrame(); + return interpFrame()->isEvalFrame(); case ION: case NATIVE: return false; @@ -1570,7 +1593,7 @@ StackIter::isNonEvalFunctionFrame() const case DONE: break; case SCRIPTED: - return fp()->isNonEvalFunctionFrame(); + return interpFrame()->isNonEvalFunctionFrame(); case ION: case NATIVE: return !isEvalFrame() && isFunctionFrame(); @@ -1584,19 +1607,18 @@ StackIter::isConstructing() const { switch (state_) { case DONE: - JS_NOT_REACHED("Unexpected state"); - return false; + break; case ION: #ifdef JS_ION return ionInlineFrames_.isConstructing(); #else - JS_NOT_REACHED("Unexpected state"); - return false; + break; #endif case SCRIPTED: case NATIVE: - return fp()->isConstructing(); + return fp_->isConstructing(); } + JS_NOT_REACHED("Unexpected state"); return false; } @@ -1608,9 +1630,9 @@ StackIter::callee() const break; case SCRIPTED: JS_ASSERT(isFunctionFrame()); - return &fp()->callee(); + return &interpFrame()->callee(); case ION: -#ifdef JS_ION +#ifdef JS_ION if (ionFrames_.isScripted()) return ionInlineFrames_.callee(); JS_ASSERT(ionFrames_.isNative()); @@ -1633,7 +1655,7 @@ StackIter::calleev() const break; case SCRIPTED: JS_ASSERT(isFunctionFrame()); - return fp()->calleev(); + return interpFrame()->calleev(); case ION: #ifdef JS_ION return ObjectValue(*callee()); @@ -1655,7 +1677,7 @@ StackIter::numActualArgs() const break; case SCRIPTED: JS_ASSERT(isFunctionFrame()); - return fp()->numActualArgs(); + return interpFrame()->numActualArgs(); case ION: #ifdef JS_ION return ionInlineFrames_.numActualArgs(); @@ -1669,6 +1691,37 @@ StackIter::numActualArgs() const return 0; } +JSObject * +StackIter::scopeChain() const +{ + switch (state_) { + case DONE: + break; + case ION: +#ifdef JS_ION + return ionInlineFrames_.scopeChain(); +#else + break; +#endif + case SCRIPTED: + return interpFrame()->scopeChain(); + case NATIVE: + break; + } + JS_NOT_REACHED("Unexpected state"); + return NULL; +} + +bool +StackIter::computeThis() const +{ + if (isScript() && !isIon()) { + JS_ASSERT(maybecx_); + return ComputeThis(maybecx_, interpFrame()); + } + return true; +} + Value StackIter::thisv() const { @@ -1683,7 +1736,7 @@ StackIter::thisv() const #endif case SCRIPTED: case NATIVE: - return fp()->thisValue(); + return fp_->thisValue(); } JS_NOT_REACHED("Unexpected state"); return NullValue(); @@ -1704,8 +1757,8 @@ StackIter::numFrameSlots() const #endif case SCRIPTED: JS_ASSERT(maybecx_); - JS_ASSERT(maybecx_->regs().spForStackDepth(0) == fp()->base()); - return maybecx_->regs().sp - fp()->base(); + JS_ASSERT(maybecx_->regs().spForStackDepth(0) == interpFrame()->base()); + return maybecx_->regs().sp - interpFrame()->base(); } JS_NOT_REACHED("Unexpected state"); return 0; @@ -1729,7 +1782,7 @@ StackIter::frameSlotValue(size_t index) const break; #endif case SCRIPTED: - return fp()->base()[index]; + return interpFrame()->base()[index]; } JS_NOT_REACHED("Unexpected state"); return NullValue(); diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index da9086774ad6..01ad14790934 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1443,6 +1443,7 @@ class StackSpace JS_FRIEND_API(size_t) sizeOfCommitted(); #ifdef DEBUG + /* Only used in assertion of debuggers API. */ bool containsSlow(StackFrame *fp); #endif }; @@ -1533,9 +1534,6 @@ class ContextStack /* The StackSpace currently hosting this ContextStack. */ StackSpace &space() const { return *space_; } - /* Return whether the given frame is in this context's stack. */ - bool containsSlow(const StackFrame *target) const; - /*** Stack manipulation ***/ /* @@ -1750,6 +1748,8 @@ class StackIter bool operator==(const StackIter &rhs) const; bool operator!=(const StackIter &rhs) const { return !(*this == rhs); } + JSCompartment *compartment() const; + bool isScript() const { JS_ASSERT(!done()); #ifdef JS_ION @@ -1776,15 +1776,30 @@ class StackIter bool isNonEvalFunctionFrame() const; bool isConstructing() const; - // :TODO: Add && !isIon() in JS_ASSERT of fp() and sp(). - StackFrame *fp() const { JS_ASSERT(isScript()); return fp_; } + /* + * When entering IonMonkey, the top interpreter frame (pushed by the caller) + * is kept on the stack as bookkeeping (with runningInIon() set). The + * contents of the frame are ignored by Ion code (and GC) and thus + * immediately become garbage and must not be touched directly. + */ + StackFrame *interpFrame() const { JS_ASSERT(isScript() && !isIon()); return fp_; } + jsbytecode *pc() const { JS_ASSERT(isScript()); return pc_; } JSScript *script() const { JS_ASSERT(isScript()); return script_; } JSFunction *callee() const; Value calleev() const; unsigned numActualArgs() const; + + JSObject *scopeChain() const; + + // Ensure that thisv is correct, see ComputeThis. + bool computeThis() const; Value thisv() const; + JSFunction *maybeCallee() const { + return isFunctionFrame() ? callee() : NULL; + } + // These are only valid for the top frame. size_t numFrameSlots() const; Value frameSlotValue(size_t index) const; @@ -1839,7 +1854,8 @@ class AllFramesIter bool done() const { return fp_ == NULL; } AllFramesIter& operator++(); - StackFrame *fp() const { return fp_; } + bool isIon() const { return fp_->runningInIon(); } + StackFrame *interpFrame() const { return fp_; } private: void settle();