Bug 797977 - Rename StackIter::fp() to StackIter::interpFrame(). r=luke

This commit is contained in:
Nicolas B. Pierron 2012-10-10 20:41:01 -07:00
parent 58c21513e0
commit be98caba91
19 changed files with 226 additions and 104 deletions

View File

@ -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

View File

@ -609,8 +609,7 @@ ion::ThunkToInterpreter(Value *vp)
StackFrame *fp = NULL;
Rooted<JSScript*> 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

View File

@ -302,6 +302,7 @@ class InlineFrameIterator
}
bool isFunctionFrame() const;
bool isConstructing() const;
JSObject *scopeChain() const;
JSObject *thisObject() const;
InlineFrameIterator operator++();

View File

@ -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
{

View File

@ -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();
}

View File

@ -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 {
/************************************************************************/

View File

@ -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___ */

View File

@ -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;
}

View File

@ -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());
}

View File

@ -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()) {
/*

View File

@ -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;

View File

@ -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());
if (!i.isIon())
MaybeDumpObject("blockChain", i.interpFrame()->maybeBlockChain());
MaybeDumpValue("this", i.thisv());
if (!i.isIon()) {
fprintf(stderr, " rval: ");
dumpValue(fp->returnValue());
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);

View File

@ -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) {
/*

View File

@ -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(),

View File

@ -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);
}
};

View File

@ -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;
}

View File

@ -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;

View File

@ -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,7 +1630,7 @@ StackIter::callee() const
break;
case SCRIPTED:
JS_ASSERT(isFunctionFrame());
return &fp()->callee();
return &interpFrame()->callee();
case ION:
#ifdef JS_ION
if (ionFrames_.isScripted())
@ -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();

View File

@ -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();