Bug 547851 - remove JSStackFrame::regs, JSStackFrame::callerFrame.sp (r=dvander)

This commit is contained in:
Luke Wagner
2010-03-03 18:10:13 -08:00
parent 4e60a6c93d
commit f6842fecdf
22 changed files with 671 additions and 483 deletions

View File

@@ -386,10 +386,7 @@ js_PopInterpFrame(JSContext* cx, TracerState* state)
cx->display[fp->script->staticLevel] = fp->displaySave;
/* Pop the frame and its memory. */
JSStackFrame *down = fp->down;
cx->stack().popInlineFrame(cx, fp, down);
JS_ASSERT(cx->fp == down && cx->fp->regs == &fp->callerRegs);
down->regs = fp->regs;
cx->stack().popInlineFrame(cx, fp, fp->down);
/* Update the inline call count. */
*state->inlineCallCountp = *state->inlineCallCountp - 1;

View File

@@ -277,7 +277,7 @@ StackSpace::getInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag,
assertIsCurrent(cx);
JS_ASSERT(currentCallStack->isActive());
jsval *start = cx->fp->regs->sp;
jsval *start = cx->regs->sp;
ptrdiff_t nvals = nmissing + VALUES_PER_CALL_STACK + VALUES_PER_STACK_FRAME + nfixed;
if (!ensureSpace(cx, start, nvals))
return false;
@@ -288,7 +288,7 @@ StackSpace::getInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag,
JS_REQUIRES_STACK void
StackSpace::pushInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag,
InvokeFrameGuard &fg)
InvokeFrameGuard &fg, JSFrameRegs &regs)
{
JS_ASSERT(!!ag.cs ^ !!fg.cs);
JS_ASSERT_IF(ag.cs, ag.cs == currentCallStack && !ag.cs->inContext());
@@ -298,7 +298,7 @@ StackSpace::pushInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag,
}
JSStackFrame *fp = fg.fp;
fp->down = cx->fp;
cx->pushCallStackAndFrame(currentCallStack, fp);
cx->pushCallStackAndFrame(currentCallStack, fp, regs);
currentCallStack->setInitialVarObj(NULL);
fg.cx = cx;
}
@@ -361,13 +361,13 @@ StackSpace::getExecuteFrame(JSContext *cx, JSStackFrame *down,
JS_REQUIRES_STACK void
StackSpace::pushExecuteFrame(JSContext *cx, ExecuteFrameGuard &fg,
JSObject *initialVarObj)
JSFrameRegs &regs, JSObject *initialVarObj)
{
fg.fp->down = fg.down;
CallStack *cs = fg.cs;
cs->setPreviousInThread(currentCallStack);
currentCallStack = cs;
cx->pushCallStackAndFrame(cs, fg.fp);
cx->pushCallStackAndFrame(cs, fg.fp, regs);
cs->setInitialVarObj(initialVarObj);
fg.cx = cx;
}
@@ -391,13 +391,14 @@ StackSpace::getSynthesizedSlowNativeFrame(JSContext *cx, CallStack *&cs, JSStack
}
JS_REQUIRES_STACK void
StackSpace::pushSynthesizedSlowNativeFrame(JSContext *cx, CallStack *cs, JSStackFrame *fp)
StackSpace::pushSynthesizedSlowNativeFrame(JSContext *cx, CallStack *cs, JSStackFrame *fp,
JSFrameRegs &regs)
{
JS_ASSERT(!fp->script && FUN_SLOW_NATIVE(fp->fun));
fp->down = cx->fp;
cs->setPreviousInThread(currentCallStack);
currentCallStack = cs;
cx->pushCallStackAndFrame(cs, fp);
cx->pushCallStackAndFrame(cs, fp, regs);
cs->setInitialVarObj(NULL);
}
@@ -412,6 +413,84 @@ StackSpace::popSynthesizedSlowNativeFrame(JSContext *cx)
currentCallStack = currentCallStack->getPreviousInThread();
}
/*
* When a pair of down-linked stack frames are in the same callstack, the
* up-frame's address is the top of the down-frame's stack, modulo missing
* arguments.
*/
static inline jsval *
InlineDownFrameSP(JSStackFrame *up)
{
JS_ASSERT(up->fun && up->script);
jsval *sp = up->argv + up->argc;
#ifdef DEBUG
uint16 nargs = up->fun->nargs;
uintN argc = up->argc;
uintN missing = argc < nargs ? nargs - argc : 0;
JS_ASSERT(sp == (jsval *)up - missing);
#endif
return sp;
}
JS_REQUIRES_STACK
FrameRegsIter::FrameRegsIter(JSContext *cx)
{
curcs = cx->getCurrentCallStack();
if (!curcs) {
curfp = NULL;
return;
}
if (curcs->isSuspended()) {
curfp = curcs->getSuspendedFrame();
cursp = curcs->getSuspendedRegs()->sp;
curpc = curcs->getSuspendedRegs()->pc;
}
JS_ASSERT(cx->fp);
curfp = cx->fp;
cursp = cx->regs->sp;
curpc = cx->regs->pc;
return;
}
FrameRegsIter &
FrameRegsIter::operator++()
{
JSStackFrame *up = curfp;
JSStackFrame *down = curfp = curfp->down;
if (!down)
return *this;
curpc = down->savedPC;
/* For a contiguous down and up, compute sp from up. */
if (up != curcs->getInitialFrame()) {
cursp = InlineDownFrameSP(up);
return *this;
}
/*
* If the up-frame is in csup and the down-frame is in csdown, it is not
* necessarily the case that |csup->getPreviousInContext == csdown| or that
* |csdown->getSuspendedFrame == down| (because of indirect eval and
* JS_EvaluateInStackFrame). To compute down's sp, we need to do a linear
* scan, keeping track of what is immediately after down in memory.
*/
curcs = curcs->getPreviousInContext();
cursp = curcs->getSuspendedSP();
JSStackFrame *f = curcs->getSuspendedFrame();
while (f != down) {
if (f == curcs->getInitialFrame()) {
curcs = curcs->getPreviousInContext();
cursp = curcs->getSuspendedSP();
f = curcs->getSuspendedFrame();
} else {
cursp = InlineDownFrameSP(f);
f = f->down;
}
}
return *this;
}
bool
JSThreadData::init()
{
@@ -1577,14 +1656,12 @@ ReportError(JSContext *cx, const char *message, JSErrorReport *reportp,
static void
PopulateReportBlame(JSContext *cx, JSErrorReport *report)
{
JSStackFrame *fp;
/*
* Walk stack until we find a frame that is associated with some script
* rather than a native frame.
*/
for (fp = js_GetTopStackFrame(cx); fp; fp = fp->down) {
if (fp->regs) {
for (JSStackFrame *fp = js_GetTopStackFrame(cx); fp; fp = fp->down) {
if (fp->pc(cx)) {
report->filename = fp->script->filename;
report->lineno = js_FramePCToLineNumber(cx, fp);
break;
@@ -2163,13 +2240,10 @@ js_GetCurrentBytecodePC(JSContext* cx)
#endif
{
JS_ASSERT_NOT_ON_TRACE(cx); /* for static analysis */
JSStackFrame* fp = cx->fp;
if (fp && fp->regs) {
pc = fp->regs->pc;
imacpc = fp->imacpc;
} else {
pc = cx->regs ? cx->regs->pc : NULL;
if (!pc)
return NULL;
}
imacpc = cx->fp->imacpc;
}
/*
@@ -2194,18 +2268,27 @@ js_CurrentPCIsInImacro(JSContext *cx)
JSContext::JSContext(JSRuntime *rt)
: runtime(rt),
fp(NULL),
regs(NULL),
regExpStatics(this),
busyArrays(this)
{}
void
JSContext::pushCallStackAndFrame(js::CallStack *newcs, JSStackFrame *newfp)
JSContext::pushCallStackAndFrame(js::CallStack *newcs, JSStackFrame *newfp,
JSFrameRegs &newregs)
{
if (hasActiveCallStack())
currentCallStack->suspend(fp);
if (hasActiveCallStack()) {
JS_ASSERT(fp->savedPC == JSStackFrame::sInvalidPC);
fp->savedPC = regs->pc;
currentCallStack->suspend(fp, regs);
}
newcs->setPreviousInContext(currentCallStack);
currentCallStack = newcs;
#ifdef DEBUG
newfp->savedPC = JSStackFrame::sInvalidPC;
#endif
setCurrentFrame(newfp);
setCurrentRegs(&newregs);
newcs->joinContext(this, newfp);
}
@@ -2214,18 +2297,25 @@ JSContext::popCallStackAndFrame()
{
JS_ASSERT(currentCallStack->maybeContext() == this);
JS_ASSERT(currentCallStack->getInitialFrame() == fp);
JS_ASSERT(fp->savedPC == JSStackFrame::sInvalidPC);
currentCallStack->leaveContext();
currentCallStack = currentCallStack->getPreviousInContext();
if (currentCallStack) {
if (currentCallStack->isSaved()) {
setCurrentFrame(NULL);
setCurrentRegs(NULL);
} else {
setCurrentFrame(currentCallStack->getSuspendedFrame());
setCurrentRegs(currentCallStack->getSuspendedRegs());
currentCallStack->resume();
#ifdef DEBUG
fp->savedPC = JSStackFrame::sInvalidPC;
#endif
}
} else {
JS_ASSERT(fp->down == NULL);
setCurrentFrame(NULL);
setCurrentRegs(NULL);
}
}
@@ -2233,16 +2323,23 @@ void
JSContext::saveActiveCallStack()
{
JS_ASSERT(hasActiveCallStack());
currentCallStack->save(fp);
currentCallStack->save(fp, regs);
JS_ASSERT(fp->savedPC == JSStackFrame::sInvalidPC);
fp->savedPC = regs->pc;
setCurrentFrame(NULL);
setCurrentRegs(NULL);
}
void
JSContext::restoreCallStack()
{
JS_ASSERT(!hasActiveCallStack());
setCurrentFrame(currentCallStack->getSuspendedFrame());
currentCallStack->restore();
js::CallStack *ccs = currentCallStack;
setCurrentFrame(ccs->getSuspendedFrame());
setCurrentRegs(ccs->getSuspendedRegs());
ccs->restore();
#ifdef DEBUG
fp->savedPC = JSStackFrame::sInvalidPC;
#endif
}
JSGenerator *
@@ -2265,7 +2362,7 @@ JSContext::generatorFor(JSStackFrame *fp) const
}
CallStack *
JSContext::containingCallStack(JSStackFrame *target)
JSContext::containingCallStack(const JSStackFrame *target)
{
/* The context may have nothing running. */
CallStack *cs = currentCallStack;

View File

@@ -200,6 +200,10 @@ struct TracerState
uintN nativeVpLen;
jsval* nativeVp;
// The regs pointed to by cx->regs while a deep-bailed slow native
// completes execution.
JSFrameRegs bailedSlowNativeRegs;
TracerState(JSContext *cx, TraceMonitor *tm, TreeFragment *ti,
uintN &inlineCallCountp, VMSideExit** innermostNestedGuardp);
~TracerState();
@@ -251,10 +255,11 @@ struct GlobalState {
*
* A callstack in a context may additionally be "active" or "suspended". A
* suspended callstack |cs| has a "suspended frame" which serves as the current
* frame of |cs|. There is at most one active callstack in a given context.
* Callstacks in a context execute LIFO and are maintained in a stack. The top
* of this stack is the context's "current callstack". If a context |cx| has an
* active callstack |cs|, then:
* frame of |cs|. Additionally, a suspended callstack has "suspended regs",
* which is a snapshot of |cx->regs| when |cs| was suspended. There is at most
* one active callstack in a given context. Callstacks in a context execute
* LIFO and are maintained in a stack. The top of this stack is the context's
* "current callstack". If a context |cx| has an active callstack |cs|, then:
* 1. |cs| is |cx|'s current callstack,
* 2. |cx->fp != NULL|, and
* 3. |cs|'s current frame is |cx->fp|.
@@ -284,6 +289,9 @@ class CallStack
/* If this callstack is suspended, the top of the callstack. */
JSStackFrame *suspendedFrame;
/* If this callstack is suspended, |cx->regs| when it was suspended. */
JSFrameRegs *suspendedRegs;
/* This callstack was suspended by JS_SaveFrameChain. */
bool saved;
@@ -366,11 +374,12 @@ class CallStack
/* Transitioning between isActive <--> isSuspended */
void suspend(JSStackFrame *fp) {
void suspend(JSStackFrame *fp, JSFrameRegs *regs) {
JS_ASSERT(isActive());
JS_ASSERT(fp && contains(fp));
suspendedFrame = fp;
JS_ASSERT(isSuspended());
suspendedRegs = regs;
}
void resume() {
@@ -381,9 +390,9 @@ class CallStack
/* When isSuspended, transitioning isSaved <--> !isSaved */
void save(JSStackFrame *fp) {
void save(JSStackFrame *fp, JSFrameRegs *regs) {
JS_ASSERT(!isSaved());
suspend(fp);
suspend(fp, regs);
saved = true;
JS_ASSERT(isSaved());
}
@@ -423,6 +432,16 @@ class CallStack
return suspendedFrame;
}
JSFrameRegs *getSuspendedRegs() const {
JS_ASSERT(isSuspended());
return suspendedRegs;
}
jsval *getSuspendedSP() const {
JS_ASSERT(isSuspended());
return suspendedRegs->sp;
}
/* JSContext / js::StackSpace bookkeeping. */
void setPreviousInContext(CallStack *cs) {
@@ -682,7 +701,7 @@ class StackSpace
JS_REQUIRES_STACK
void pushInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag,
InvokeFrameGuard &fg);
InvokeFrameGuard &fg, JSFrameRegs &regs);
/*
* For the simpler case when arguments are allocated at the same time as
@@ -695,7 +714,7 @@ class StackSpace
ExecuteFrameGuard &fg) const;
JS_REQUIRES_STACK
void pushExecuteFrame(JSContext *cx, ExecuteFrameGuard &fg,
JSObject *initialVarObj);
JSFrameRegs &regs, JSObject *initialVarObj);
/*
* Since RAII cannot be used for inline frames, callers must manually
@@ -706,7 +725,8 @@ class StackSpace
uintN nmissing, uintN nfixed) const;
JS_REQUIRES_STACK
inline void pushInlineFrame(JSContext *cx, JSStackFrame *fp, JSStackFrame *newfp);
inline void pushInlineFrame(JSContext *cx, JSStackFrame *fp, jsbytecode *pc,
JSStackFrame *newfp);
JS_REQUIRES_STACK
inline void popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down);
@@ -719,7 +739,8 @@ class StackSpace
void getSynthesizedSlowNativeFrame(JSContext *cx, CallStack *&cs, JSStackFrame *&fp);
JS_REQUIRES_STACK
void pushSynthesizedSlowNativeFrame(JSContext *cx, CallStack *cs, JSStackFrame *fp);
void pushSynthesizedSlowNativeFrame(JSContext *cx, CallStack *cs, JSStackFrame *fp,
JSFrameRegs &regs);
JS_REQUIRES_STACK
void popSynthesizedSlowNativeFrame(JSContext *cx);
@@ -731,6 +752,34 @@ class StackSpace
JS_STATIC_ASSERT(StackSpace::CAPACITY_VALS % StackSpace::COMMIT_VALS == 0);
/*
* While |cx->fp|'s pc/sp are available in |cx->regs|, to compute the saved
* value of pc/sp for any other frame, it is necessary to know about that
* frame's up-frame. This iterator maintains this information when walking down
* a chain of stack frames starting at |cx->fp|.
*
* Usage:
* for (FrameRegsIter i(cx); !i.done(); ++i)
* ... i.fp() ... i.sp() ... i.pc()
*/
class FrameRegsIter
{
CallStack *curcs;
JSStackFrame *curfp;
jsval *cursp;
jsbytecode *curpc;
public:
JS_REQUIRES_STACK FrameRegsIter(JSContext *cx);
bool done() const { return curfp == NULL; }
FrameRegsIter &operator++();
JSStackFrame *fp() const { return curfp; }
jsval *sp() const { return cursp; }
jsbytecode *pc() const { return curpc; }
};
/* Holds the number of recording attemps for an address. */
typedef HashMap<jsbytecode*,
size_t,
@@ -1637,14 +1686,26 @@ struct JSContext
JS_REQUIRES_STACK
JSStackFrame *fp;
/*
* Currently executing frame's regs, set by stack operations.
* |fp != NULL| iff |regs != NULL| (although regs->pc can be NULL)
*/
JS_REQUIRES_STACK
JSFrameRegs *regs;
private:
friend class js::StackSpace;
friend JSBool js_Interpret(JSContext *);
/* 'fp' must only be changed by calling this function. */
/* 'fp' and 'regs' must only be changed by calling these functions. */
void setCurrentFrame(JSStackFrame *fp) {
this->fp = fp;
}
void setCurrentRegs(JSFrameRegs *regs) {
this->regs = regs;
}
public:
/* Temporary arena pool used while compiling and decompiling. */
JSArenaPool tempPool;
@@ -1721,7 +1782,8 @@ struct JSContext
}
/* Add the given callstack to the list as the new active callstack. */
void pushCallStackAndFrame(js::CallStack *newcs, JSStackFrame *newfp);
void pushCallStackAndFrame(js::CallStack *newcs, JSStackFrame *newfp,
JSFrameRegs &regs);
/* Remove the active callstack and make the next callstack active. */
void popCallStackAndFrame();
@@ -1736,7 +1798,7 @@ struct JSContext
* Perform a linear search of all frames in all callstacks in the given context
* for the given frame, returning the callstack, if found, and null otherwise.
*/
js::CallStack *containingCallStack(JSStackFrame *target);
js::CallStack *containingCallStack(const JSStackFrame *target);
#ifdef JS_THREADSAFE
JSThread *thread;
@@ -1820,9 +1882,7 @@ struct JSContext
JSGenerator *generatorFor(JSStackFrame *fp) const;
/* Early OOM-check. */
bool ensureGeneratorStackSpace() {
return genStack.reserve(genStack.length() + 1);
}
inline bool ensureGeneratorStackSpace();
bool enterGenerator(JSGenerator *gen) {
return genStack.append(gen);
@@ -1968,6 +2028,15 @@ struct JSContext
return JS_THREAD_DATA(this)->stackSpace;
}
#ifdef DEBUG
void assertValidStackDepth(uintN depth) {
JS_ASSERT(0 <= regs->sp - StackBase(fp));
JS_ASSERT(depth <= uintptr_t(regs->sp - StackBase(fp)));
}
#else
void assertValidStackDepth(uintN /*depth*/) {}
#endif
private:
/*
@@ -1993,6 +2062,13 @@ JSStackFrame::varobj(JSContext *cx) const
return fun ? callobj : cx->activeCallStack()->getInitialVarObj();
}
JS_ALWAYS_INLINE jsbytecode *
JSStackFrame::pc(JSContext *cx) const
{
JS_ASSERT(cx->containingCallStack(this) != NULL);
return cx->fp == this ? cx->regs->pc : savedPC;
}
/*
* InvokeArgsGuard is used outside the JS engine (where jscntxtinlines.h is
* not included). To avoid visibility issues, force members inline.
@@ -2031,7 +2107,11 @@ InvokeArgsGuard::~InvokeArgsGuard()
# define JS_THREAD_ID(cx) ((cx)->thread ? (cx)->thread->id : 0)
#endif
#ifdef __cplusplus
static inline uintN
FramePCOffset(JSContext *cx, JSStackFrame* fp)
{
return uintN((fp->imacpc ? fp->imacpc : fp->pc(cx)) - fp->script->code);
}
static inline JSAtom **
FrameAtomBase(JSContext *cx, JSStackFrame *fp)
@@ -2435,8 +2515,6 @@ class JSAutoResolveFlags
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
#endif /* __cpluscplus */
/*
* Slightly more readable macros for testing per-context option settings (also
* to hide bitset implementation detail).

View File

@@ -46,6 +46,15 @@
#include "jsobjinlines.h"
inline bool
JSContext::ensureGeneratorStackSpace()
{
bool ok = genStack.reserve(genStack.length() + 1);
if (!ok)
js_ReportOutOfMemory(this);
return ok;
}
namespace js {
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
@@ -61,12 +70,12 @@ StackSpace::firstUnused() const
CallStack *ccs = currentCallStack;
if (!ccs)
return base;
if (!ccs->inContext())
if (JSContext *cx = ccs->maybeContext()) {
if (!ccs->isSuspended())
return cx->regs->sp;
return ccs->getSuspendedRegs()->sp;
}
return ccs->getInitialArgEnd();
JSStackFrame *fp = ccs->getCurrentFrame();
if (JSFrameRegs *regs = fp->regs)
return regs->sp;
return fp->slots();
}
/* Inline so we don't need the friend API. */
@@ -124,7 +133,7 @@ StackSpace::getInlineFrame(JSContext *cx, jsval *sp,
{
assertIsCurrent(cx);
JS_ASSERT(cx->hasActiveCallStack());
JS_ASSERT(cx->fp->regs->sp == sp);
JS_ASSERT(cx->regs->sp == sp);
ptrdiff_t nvals = nmissing + VALUES_PER_STACK_FRAME + nfixed;
if (!ensureSpace(cx, sp, nvals))
@@ -135,13 +144,18 @@ StackSpace::getInlineFrame(JSContext *cx, jsval *sp,
}
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
StackSpace::pushInlineFrame(JSContext *cx, JSStackFrame *fp, JSStackFrame *newfp)
StackSpace::pushInlineFrame(JSContext *cx, JSStackFrame *fp, jsbytecode *pc,
JSStackFrame *newfp)
{
assertIsCurrent(cx);
JS_ASSERT(cx->hasActiveCallStack());
JS_ASSERT(cx->fp == fp);
JS_ASSERT(cx->fp == fp && cx->regs->pc == pc);
fp->savedPC = pc;
newfp->down = fp;
#ifdef DEBUG
newfp->savedPC = JSStackFrame::sInvalidPC;
#endif
cx->setCurrentFrame(newfp);
}
@@ -151,7 +165,14 @@ StackSpace::popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down)
assertIsCurrent(cx);
JS_ASSERT(cx->hasActiveCallStack());
JS_ASSERT(cx->fp == up && up->down == down);
JS_ASSERT(up->savedPC == JSStackFrame::sInvalidPC);
JSFrameRegs *regs = cx->regs;
regs->pc = down->savedPC;
regs->sp = up->argv - 1;
#ifdef DEBUG
down->savedPC = JSStackFrame::sInvalidPC;
#endif
cx->setCurrentFrame(down);
}

View File

@@ -684,19 +684,16 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
PodZero(fp->slots(), nfixed);
PodZero(fp);
fp->script = script;
fp->regs = NULL;
fp->fun = fun;
fp->argv = vp + 2;
fp->scopeChain = closure->getParent();
if (script) {
JS_ASSERT(script->length >= JSOP_STOP_LENGTH);
regs.pc = script->code + script->length - JSOP_STOP_LENGTH;
regs.sp = fp->slots() + script->nfixed;
fp->regs = &regs;
}
/* Initialize regs. */
regs.pc = script ? script->code : NULL;
regs.sp = fp->slots() + nfixed;
/* Officially push |fp|. |frame|'s destructor pops. */
cx->stack().pushExecuteFrame(cx, frame, NULL);
cx->stack().pushExecuteFrame(cx, frame, regs, NULL);
/* Now that fp has been pushed, get the call object. */
if (script && fun && fun->isHeavyweight() &&
@@ -1070,7 +1067,7 @@ JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
JS_PUBLIC_API(jsbytecode *)
JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
{
return fp->regs ? fp->regs->pc : NULL;
return fp->pc(cx);
}
JS_PUBLIC_API(JSStackFrame *)

View File

@@ -79,7 +79,7 @@ jsdtrace_fun_linenumber(JSContext *cx, const JSFunction *fun)
static int
jsdtrace_frame_linenumber(JSContext *cx, JSStackFrame *fp)
{
if (fp && fp->regs)
if (fp)
return (int) js_FramePCToLineNumber(cx, fp);
return 0;

View File

@@ -338,7 +338,7 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
elem->filename = NULL;
if (fp->script) {
elem->filename = fp->script->filename;
if (fp->regs)
if (fp->pc(cx))
elem->ulineno = js_FramePCToLineNumber(cx, fp);
}
++elem;
@@ -753,7 +753,7 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
} else {
if (!fp)
fp = js_GetScriptedCaller(cx, NULL);
lineno = (fp && fp->regs) ? js_FramePCToLineNumber(cx, fp) : 0;
lineno = (fp && fp->pc(cx)) ? js_FramePCToLineNumber(cx, fp) : 0;
}
return (obj->getClass() != &js_ErrorClass) ||

View File

@@ -2621,14 +2621,8 @@ js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags)
void
js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
{
JSStackFrame *fp;
uintN error;
const char *name, *source;
for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down)
continue;
name = source = NULL;
const char *name = NULL, *source = NULL;
AutoValueRooter tvr(cx);
if (flags & JSV2F_ITERATOR) {
error = JSMSG_BAD_ITERATOR;
@@ -2650,15 +2644,18 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
error = JSMSG_NOT_FUNCTION;
}
js_ReportValueError3(cx, error,
(fp && fp->regs &&
StackBase(fp) <= vp && vp < fp->regs->sp)
? vp - fp->regs->sp
: (flags & JSV2F_SEARCH_STACK)
? JSDVG_SEARCH_STACK
: JSDVG_IGNORE_STACK,
*vp, NULL,
name, source);
LeaveTrace(cx);
FrameRegsIter i(cx);
while (!i.done() && !i.pc())
++i;
ptrdiff_t spindex =
!i.done() && StackBase(i.fp()) <= vp && vp < i.sp()
? vp - i.sp()
: flags & JSV2F_SEARCH_STACK ? JSDVG_SEARCH_STACK
: JSDVG_IGNORE_STACK;
js_ReportValueError3(cx, error, spindex, *vp, NULL, name, source);
}
/*

View File

@@ -95,6 +95,10 @@ using namespace js;
/* jsinvoke_cpp___ indicates inclusion from jsinvoke.cpp. */
#if !JS_LONE_INTERPRET ^ defined jsinvoke_cpp___
#ifdef DEBUG
jsbytecode *const JSStackFrame::sInvalidPC = (jsbytecode *)0xbeef;
#endif
JSObject *
js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
{
@@ -559,6 +563,7 @@ js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags)
* Get a pointer to new frame/slots. This memory is not "claimed", so the
* code before pushInvokeFrame must not reenter the interpreter.
*/
JSFrameRegs regs;
InvokeFrameGuard frame;
if (!cx->stack().getInvokeFrame(cx, args, nmissing, nfixed, frame))
return false;
@@ -583,13 +588,21 @@ js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags)
fp->annotation = NULL;
fp->scopeChain = NULL;
fp->blockChain = NULL;
fp->regs = NULL;
fp->imacpc = NULL;
fp->flags = flags;
fp->displaySave = NULL;
/* Initialize regs. */
if (script) {
regs.pc = script->code;
regs.sp = fp->slots() + script->nfixed;
} else {
regs.pc = NULL;
regs.sp = fp->slots();
}
/* Officially push |fp|. |frame|'s destructor pops. */
cx->stack().pushInvokeFrame(cx, args, frame);
cx->stack().pushInvokeFrame(cx, args, frame, regs);
/* Now that the frame has been pushed, fix up the scope chain. */
if (native) {
@@ -722,6 +735,7 @@ js_Execute(JSContext *cx, JSObject *const chain, JSScript *script,
* N.B. when fp->argv is removed (bug 539144), argv will have to be copied
* in before execution and copied out after.
*/
JSFrameRegs regs;
ExecuteFrameGuard frame;
if (!cx->stack().getExecuteFrame(cx, down, 0, script->nslots, frame))
return false;
@@ -797,11 +811,14 @@ js_Execute(JSContext *cx, JSObject *const chain, JSScript *script,
fp->script = script;
fp->imacpc = NULL;
fp->rval = JSVAL_VOID;
fp->regs = NULL;
fp->blockChain = NULL;
/* Initialize regs. */
regs.pc = script->code;
regs.sp = StackBase(fp);
/* Officially push |fp|. |frame|'s destructor pops. */
cx->stack().pushExecuteFrame(cx, frame, initialVarObj);
cx->stack().pushExecuteFrame(cx, frame, regs, initialVarObj);
/* Now that the frame has been pushed, we can call the thisObject hook. */
if (!down) {
@@ -1114,7 +1131,7 @@ js_EnterWith(JSContext *cx, jsint stackIndex)
JSObject *obj, *parent, *withobj;
fp = cx->fp;
sp = fp->regs->sp;
sp = cx->regs->sp;
JS_ASSERT(stackIndex < 0);
JS_ASSERT(StackBase(fp) <= sp + stackIndex);
@@ -1175,16 +1192,16 @@ js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth)
* Unwind block and scope chains to match the given depth. The function sets
* fp->sp on return to stackDepth.
*/
JS_REQUIRES_STACK JSBool
js_UnwindScope(JSContext *cx, JSStackFrame *fp, jsint stackDepth,
JSBool normalUnwind)
JS_STATIC_INTERPRET JS_REQUIRES_STACK JSBool
js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind)
{
JSObject *obj;
JSClass *clasp;
JS_ASSERT(stackDepth >= 0);
JS_ASSERT(StackBase(fp) + stackDepth <= fp->regs->sp);
JS_ASSERT(StackBase(cx->fp) + stackDepth <= cx->regs->sp);
JSStackFrame *fp = cx->fp;
for (obj = fp->blockChain; obj; obj = obj->getParent()) {
JS_ASSERT(obj->getClass() == &js_BlockClass);
if (OBJ_BLOCK_DEPTH(cx, obj) < stackDepth)
@@ -1205,7 +1222,7 @@ js_UnwindScope(JSContext *cx, JSStackFrame *fp, jsint stackDepth,
}
}
fp->regs->sp = StackBase(fp) + stackDepth;
cx->regs->sp = StackBase(fp) + stackDepth;
return normalUnwind;
}
@@ -1274,7 +1291,7 @@ js_TraceOpcode(JSContext *cx)
tracefp = (FILE *) cx->tracefp;
JS_ASSERT(tracefp);
fp = cx->fp;
regs = fp->regs;
regs = cx->regs;
/*
* Operations in prologues don't produce interesting values, and
@@ -2008,7 +2025,7 @@ js_Interpret(JSContext *cx)
uintN inlineCallCount;
JSAtom **atoms;
JSVersion currentVersion, originalVersion;
JSFrameRegs regs;
JSFrameRegs regs, *prevContextRegs;
JSObject *obj, *obj2, *parent;
JSBool ok, cond;
jsint len;
@@ -2214,7 +2231,7 @@ js_Interpret(JSContext *cx)
script = fp->script; \
atoms = FrameAtomBase(cx, fp); \
currentVersion = (JSVersion) script->version; \
JS_ASSERT(fp->regs == &regs); \
JS_ASSERT(cx->regs == &regs); \
JS_END_MACRO
#define MONITOR_BRANCH(reason) \
@@ -2312,21 +2329,18 @@ js_Interpret(JSContext *cx)
*/
CHECK_INTERRUPT_HANDLER();
#if !JS_HAS_GENERATORS
JS_ASSERT(!fp->regs);
#else
/* Initialize the pc and sp registers unless we're resuming a generator. */
if (JS_LIKELY(!fp->regs)) {
#endif
ASSERT_NOT_THROWING(cx);
regs.pc = script->code;
regs.sp = StackBase(fp);
fp->regs = &regs;
/*
* Access to |cx->regs| is very common, so we copy in and repoint to a
* local variable, and copy out on exit.
*/
JS_ASSERT(cx->regs);
prevContextRegs = cx->regs;
regs = *cx->regs;
cx->setCurrentRegs(&regs);
#if JS_HAS_GENERATORS
} else {
JS_ASSERT(fp->regs == &cx->generatorFor(fp)->savedRegs);
regs = *fp->regs;
fp->regs = &regs;
if (JS_UNLIKELY(fp->isGenerator())) {
JS_ASSERT(prevContextRegs == &cx->generatorFor(fp)->savedRegs);
JS_ASSERT((size_t) (regs.pc - script->code) <= script->length);
JS_ASSERT((size_t) (regs.sp - StackBase(fp)) <= StackDepth(script));
@@ -2344,13 +2358,10 @@ js_Interpret(JSContext *cx)
goto error;
}
}
#endif /* JS_HAS_GENERATORS */
#endif
#ifdef JS_TRACER
/*
* We cannot reenter the interpreter while recording; wait to abort until
* after cx->fp->regs is set.
*/
/* We cannot reenter the interpreter while recording. */
if (TRACE_RECORDER(cx))
AbortRecording(cx, "attempt to reenter interpreter while recording");
#endif
@@ -2415,6 +2426,7 @@ js_Interpret(JSContext *cx)
#endif /* !JS_THREADED_INTERP */
error:
JS_ASSERT(cx->regs == &regs);
#ifdef JS_TRACER
if (fp->imacpc && cx->throwing) {
// Handle other exceptions as if they came from the imacro-calling pc.
@@ -2507,8 +2519,8 @@ js_Interpret(JSContext *cx)
*/
regs.pc = (script)->main + tn->start + tn->length;
ok = js_UnwindScope(cx, fp, tn->stackDepth, JS_TRUE);
JS_ASSERT(fp->regs->sp == StackBase(fp) + tn->stackDepth);
ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE);
JS_ASSERT(regs.sp == StackBase(fp) + tn->stackDepth);
if (!ok) {
/*
* Restart the handler search with updated pc and stack depth
@@ -2578,13 +2590,13 @@ js_Interpret(JSContext *cx)
forced_return:
/*
* Unwind the scope making sure that ok stays false even when UnwindScope
* Unwind the scope making sure that ok stays false even when js_UnwindScope
* returns true.
*
* When a trap handler returns JSTRAP_RETURN, we jump here with ok set to
* true bypassing any finally blocks.
*/
ok &= js_UnwindScope(cx, fp, 0, ok || cx->throwing);
ok &= js_UnwindScope(cx, 0, ok || cx->throwing);
JS_ASSERT(regs.sp == StackBase(fp));
#ifdef DEBUG
@@ -2607,21 +2619,17 @@ js_Interpret(JSContext *cx)
* frame pc.
*/
JS_ASSERT(inlineCallCount == 0);
JS_ASSERT(fp->regs == &regs);
JS_ASSERT(cx->regs == &regs);
*prevContextRegs = regs;
cx->setCurrentRegs(prevContextRegs);
#ifdef JS_TRACER
if (TRACE_RECORDER(cx))
AbortRecording(cx, "recording out of js_Interpret");
#endif
#if JS_HAS_GENERATORS
if (JS_UNLIKELY(fp->isGenerator())) {
cx->generatorFor(fp)->savedRegs = regs;
} else
#endif /* JS_HAS_GENERATORS */
{
JS_ASSERT(!fp->blockChain);
JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
}
fp->regs = NULL;
JS_ASSERT_IF(!fp->isGenerator(), !fp->blockChain);
JS_ASSERT_IF(!fp->isGenerator(), !js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
/* Undo the remaining effects committed on entry to js_Interpret. */
if (script->staticLevel < JS_DISPLAY_SIZE)

View File

@@ -80,13 +80,10 @@ enum JSFrameFlags {
* function.
*
* NB: This struct is manually initialized in jsinterp.c and jsiter.c. If you
* add new members, update both files. But first, try to remove members. The
* sharp* and xml* members should be moved onto the stack as local variables
* with well-known slots, if possible.
* add new members, update both files.
*/
struct JSStackFrame
{
JSFrameRegs *regs;
jsbytecode *imacpc; /* null or interpreter macro call pc */
JSObject *callobj; /* lazily created Call object */
jsval argsobj; /* lazily created arguments object, must be
@@ -102,6 +99,10 @@ struct JSStackFrame
/* Maintained by StackSpace operations */
JSStackFrame *down; /* previous frame, part of
stack layout invariant */
jsbytecode *savedPC; /* only valid if cx->fp != this */
#ifdef DEBUG
static jsbytecode *const sInvalidPC;
#endif
/*
* We can't determine in advance which local variables can live on
@@ -150,12 +151,9 @@ struct JSStackFrame
script->staticLevel */
/* Members only needed for inline calls. */
JSFrameRegs callerRegs; /* caller's regs for inline call */
void *hookData; /* debugger call hook data */
JSVersion callerVersion; /* dynamic version of calling script */
inline void assertValidStackDepth(uintN depth);
void putActivationObjects(JSContext *cx) {
/*
* The order of calls here is important as js_PutCallObject needs to
@@ -169,6 +167,9 @@ struct JSStackFrame
}
}
/* Get the frame's current bytecode, assuming |this| is in |cx|. */
jsbytecode *pc(JSContext *cx) const;
jsval *argEnd() const {
return (jsval *)this;
}
@@ -220,32 +221,12 @@ JS_STATIC_ASSERT(sizeof(JSStackFrame) % sizeof(jsval) == 0);
}
#ifdef __cplusplus
static JS_INLINE uintN
FramePCOffset(JSStackFrame* fp)
{
return uintN((fp->imacpc ? fp->imacpc : fp->regs->pc) - fp->script->code);
}
#endif
static JS_INLINE jsval *
StackBase(JSStackFrame *fp)
{
return fp->slots() + fp->script->nfixed;
}
#ifdef DEBUG
void
JSStackFrame::assertValidStackDepth(uintN depth)
{
JS_ASSERT(0 <= regs->sp - StackBase(this));
JS_ASSERT(depth <= uintptr_t(regs->sp - StackBase(this)));
}
#else
void
JSStackFrame::assertValidStackDepth(uintN /*depth*/){}
#endif
static JS_INLINE uintN
GlobalVarCount(JSStackFrame *fp)
{
@@ -433,8 +414,7 @@ js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth);
* fp->sp on return to stackDepth.
*/
extern JS_REQUIRES_STACK JSBool
js_UnwindScope(JSContext *cx, JSStackFrame *fp, jsint stackDepth,
JSBool normalUnwind);
js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind);
extern JSBool
js_OnUnknownMethod(JSContext *cx, jsval *vp);

View File

@@ -74,6 +74,7 @@
#include "jsxml.h"
#endif
#include "jscntxtinlines.h"
#include "jsobjinlines.h"
#include "jsstrinlines.h"
@@ -794,14 +795,13 @@ js_NewGenerator(JSContext *cx)
/* Initialize JSGenerator. */
gen->obj = obj;
gen->state = JSGEN_NEWBORN;
gen->savedRegs.pc = fp->regs->pc;
JS_ASSERT(fp->regs->sp == fp->slots() + fp->script->nfixed);
gen->savedRegs.pc = cx->regs->pc;
JS_ASSERT(cx->regs->sp == fp->slots() + fp->script->nfixed);
gen->savedRegs.sp = slots + fp->script->nfixed;
gen->vplen = vplen;
gen->liveFrame = newfp;
/* Copy generator's stack frame copy in from |cx->fp|. */
newfp->regs = &gen->savedRegs;
newfp->imacpc = NULL;
newfp->callobj = fp->callobj;
if (fp->callobj) { /* Steal call object. */
@@ -922,7 +922,6 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
memcpy(vp, genVp, usedBefore * sizeof(jsval));
fp->flags &= ~JSFRAME_FLOATING_GENERATOR;
fp->argv = vp + 2;
fp->regs = &gen->savedRegs;
gen->savedRegs.sp = fp->slots() + (gen->savedRegs.sp - genfp->slots());
JS_ASSERT(uintN(gen->savedRegs.sp - fp->slots()) <= fp->script->nslots);
@@ -945,7 +944,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
(void)cx->enterGenerator(gen); /* OOM check above. */
/* Officially push |fp|. |frame|'s destructor pops. */
cx->stack().pushExecuteFrame(cx, frame, NULL);
cx->stack().pushExecuteFrame(cx, frame, gen->savedRegs, NULL);
ok = js_Interpret(cx);

View File

@@ -1023,9 +1023,10 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
return principals->codebase;
}
if (caller->regs && js_GetOpcode(cx, caller->script, caller->regs->pc) == JSOP_EVAL) {
JS_ASSERT(js_GetOpcode(cx, caller->script, caller->regs->pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
*linenop = GET_UINT16(caller->regs->pc + JSOP_EVAL_LENGTH);
jsbytecode *pc = caller->pc(cx);
if (pc && js_GetOpcode(cx, caller->script, pc) == JSOP_EVAL) {
JS_ASSERT(js_GetOpcode(cx, caller->script, pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
*linenop = GET_UINT16(pc + JSOP_EVAL_LENGTH);
} else {
*linenop = js_FramePCToLineNumber(cx, caller);
}
@@ -1069,7 +1070,8 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp)
return JS_FALSE;
}
bool indirectCall = (caller->regs && *caller->regs->pc != JSOP_EVAL);
jsbytecode *callerPC = caller->pc(cx);
bool indirectCall = (callerPC && *callerPC != JSOP_EVAL);
/*
* This call to js_GetWrappedObject is safe because of the security checks
@@ -2795,16 +2797,14 @@ js_InferFlags(JSContext *cx, uintN defaultFlags)
JS_ASSERT_NOT_ON_TRACE(cx);
JSStackFrame *fp;
jsbytecode *pc;
const JSCodeSpec *cs;
uint32 format;
uintN flags = 0;
fp = js_GetTopStackFrame(cx);
if (!fp || !fp->regs)
JSStackFrame *const fp = js_GetTopStackFrame(cx);
if (!fp || !(pc = cx->regs->pc))
return defaultFlags;
pc = fp->regs->pc;
cs = &js_CodeSpec[js_GetOpcode(cx, fp->script, pc)];
format = cs->format;
if (JOF_MODE(format) != JOF_NAME)
@@ -3010,15 +3010,11 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
JS_REQUIRES_STACK JSBool
js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
{
JSStackFrame *fp;
JSObject *obj;
uintN depth, count;
/* Blocks have one fixed slot available for the first local.*/
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2);
fp = cx->fp;
obj = fp->scopeChain;
JSStackFrame *const fp = cx->fp;
JSObject *obj = fp->scopeChain;
JS_ASSERT(obj->getClass() == &js_BlockClass);
JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp));
JS_ASSERT(OBJ_IS_CLONED_BLOCK(obj));
@@ -3035,10 +3031,10 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
JS_ASSERT(obj->numSlots() == JS_INITIAL_NSLOTS);
/* The block and its locals must be on the current stack for GC safety. */
depth = OBJ_BLOCK_DEPTH(cx, obj);
count = OBJ_BLOCK_COUNT(cx, obj);
JS_ASSERT(depth <= (size_t) (fp->regs->sp - StackBase(fp)));
JS_ASSERT(count <= (size_t) (fp->regs->sp - StackBase(fp) - depth));
uintN depth = OBJ_BLOCK_DEPTH(cx, obj);
uintN count = OBJ_BLOCK_COUNT(cx, obj);
JS_ASSERT(depth <= (size_t) (cx->regs->sp - StackBase(fp)));
JS_ASSERT(count <= (size_t) (cx->regs->sp - StackBase(fp) - depth));
/* See comments in CheckDestructuring from jsparse.cpp. */
JS_ASSERT(count >= 1);
@@ -4776,7 +4772,7 @@ js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, jsval *vp)
JS_FRIEND_API(bool)
js_CheckUndeclaredVarAssignment(JSContext *cx, jsval propname)
{
JSStackFrame *fp = js_GetTopStackFrame(cx);
JSStackFrame *const fp = js_GetTopStackFrame(cx);
if (!fp)
return true;
@@ -6418,32 +6414,42 @@ MaybeDumpValue(const char *name, jsval v)
}
JS_FRIEND_API(void)
js_DumpStackFrame(JSStackFrame *fp)
js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
{
jsval *sp = NULL;
/* This should only called during live debugging. */
VOUCH_DOES_NOT_REQUIRE_STACK();
if (!start)
start = cx->fp;
FrameRegsIter i(cx);
while (!i.done() && i.fp() != start)
++i;
if (i.done()) {
fprintf(stderr, "fp = %p not found in cx = %p\n", (void *)start, (void *)cx);
return;
}
for (; !i.done(); ++i) {
JSStackFrame *const fp = i.fp();
for (; fp; fp = fp->down) {
fprintf(stderr, "JSStackFrame at %p\n", (void *) fp);
if (fp->argv)
if (fp->argv) {
fprintf(stderr, "callee: ");
dumpValue(fp->argv[-2]);
else
} else {
fprintf(stderr, "global frame, no callee");
}
fputc('\n', stderr);
if (fp->script)
fprintf(stderr, "file %s line %u\n", fp->script->filename, (unsigned) fp->script->lineno);
if (fp->regs) {
if (!fp->regs->pc) {
fprintf(stderr, "*** regs && !regs->pc, skipping frame\n\n");
continue;
}
if (jsbytecode *pc = i.pc()) {
if (!fp->script) {
fprintf(stderr, "*** regs && !script, skipping frame\n\n");
fprintf(stderr, "*** pc && !script, skipping frame\n\n");
continue;
}
jsbytecode *pc = fp->regs->pc;
sp = fp->regs->sp;
if (fp->imacpc) {
fprintf(stderr, " pc in imacro at %p\n called from ", pc);
pc = fp->imacpc;
@@ -6453,7 +6459,7 @@ js_DumpStackFrame(JSStackFrame *fp)
fprintf(stderr, "pc = %p\n", pc);
fprintf(stderr, " current op: %s\n", js_CodeName[*pc]);
}
if (sp && fp->slots()) {
jsval *sp = i.sp();
fprintf(stderr, " slots: %p\n", (void *) fp->slots());
fprintf(stderr, " sp: %p = slots + %u\n", (void *) sp, (unsigned) (sp - fp->slots()));
if (sp - fp->slots() < 10000) { // sanity
@@ -6463,10 +6469,6 @@ js_DumpStackFrame(JSStackFrame *fp)
fputc('\n', stderr);
}
}
} else {
fprintf(stderr, " sp: %p\n", (void *) sp);
fprintf(stderr, " slots: %p\n", (void *) fp->slots());
}
fprintf(stderr, " argv: %p (argc: %u)\n", (void *) fp->argv, (unsigned) fp->argc);
MaybeDumpObject("callobj", fp->callobj);
MaybeDumpObject("argsobj", JSVAL_TO_OBJECT(fp->argsobj));

View File

@@ -1294,7 +1294,7 @@ JS_FRIEND_API(void) js_DumpAtom(JSAtom *atom);
JS_FRIEND_API(void) js_DumpValue(jsval val);
JS_FRIEND_API(void) js_DumpId(jsid id);
JS_FRIEND_API(void) js_DumpObject(JSObject *obj);
JS_FRIEND_API(void) js_DumpStackFrame(JSStackFrame *fp);
JS_FRIEND_API(void) js_DumpStackFrameChain(JSContext *cx, JSStackFrame *start = NULL);
#endif
extern uintN

View File

@@ -1993,7 +1993,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
*/
fp = js_GetScriptedCaller(cx, NULL);
format = cs->format;
if (((fp && fp->regs && pc == fp->regs->pc) ||
if (((fp && pc == fp->pc(cx)) ||
(pc == startpc && nuses != 0)) &&
format & (JOF_SET|JOF_DEL|JOF_INCDEC|JOF_FOR|JOF_VARPROP)) {
mode = JOF_MODE(format);
@@ -5102,26 +5102,25 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
JSStackFrame *fp;
jsbytecode *pc;
JSScript *script;
JSFrameRegs *regs;
intN pcdepth;
jsval *sp, *stackBase;
char *name;
JS_ASSERT(spindex < 0 ||
spindex == JSDVG_IGNORE_STACK ||
spindex == JSDVG_SEARCH_STACK);
fp = js_GetScriptedCaller(cx, NULL);
if (!fp || !fp->regs || !fp->regs->sp)
LeaveTrace(cx);
/* Get scripted caller */
FrameRegsIter i(cx);
while (!i.done() && !i.fp()->script)
++i;
if (i.done() || !i.pc())
goto do_fallback;
fp = i.fp();
script = fp->script;
regs = fp->regs;
pc = fp->imacpc ? fp->imacpc : regs->pc;
if (pc < script->main || script->code + script->length <= pc) {
JS_NOT_REACHED("bug");
goto do_fallback;
}
pc = fp->imacpc ? fp->imacpc : i.pc();
JS_ASSERT(pc >= script->main && pc < script->code + script->length);
if (spindex != JSDVG_IGNORE_STACK) {
jsbytecode **pcstack;
@@ -5134,7 +5133,7 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
cx->malloc(StackDepth(script) * sizeof *pcstack);
if (!pcstack)
return NULL;
pcdepth = ReconstructPCStack(cx, script, pc, pcstack);
intN pcdepth = ReconstructPCStack(cx, script, pc, pcstack);
if (pcdepth < 0)
goto release_pcstack;
@@ -5150,8 +5149,8 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
* calculated value matching v under assumption that it is
* it that caused exception, see bug 328664.
*/
stackBase = StackBase(fp);
sp = regs->sp;
jsval *stackBase = StackBase(fp);
jsval *sp = i.sp();
do {
if (sp == stackBase) {
pcdepth = -1;
@@ -5178,10 +5177,13 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
}
{
jsbytecode* savepc = regs->pc;
jsbytecode* savepc = i.pc();
jsbytecode* imacpc = fp->imacpc;
if (imacpc) {
regs->pc = imacpc;
if (fp == cx->fp)
cx->regs->pc = imacpc;
else
fp->savedPC = imacpc;
fp->imacpc = NULL;
}
@@ -5189,18 +5191,23 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
* FIXME: bug 489843. Stack reconstruction may have returned a pc
* value *inside* an imacro; this would confuse the decompiler.
*/
char *name;
if (imacpc && size_t(pc - script->code) >= script->length)
name = FAILED_EXPRESSION_DECOMPILER;
else
name = DecompileExpression(cx, script, fp->fun, pc);
if (imacpc) {
regs->pc = savepc;
if (fp == cx->fp)
cx->regs->pc = imacpc;
else
fp->savedPC = savepc;
fp->imacpc = imacpc;
}
}
if (name != FAILED_EXPRESSION_DECOMPILER)
return name;
}
do_fallback:
if (!fallback) {

View File

@@ -224,7 +224,6 @@ BEGIN_CASE(JSOP_STOP)
{
JS_ASSERT(!fp->blockChain);
JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
JS_ASSERT(fp->down->regs == &fp->callerRegs);
if (JS_LIKELY(script->staticLevel < JS_DISPLAY_SIZE))
cx->display[script->staticLevel] = fp->displaySave;
@@ -277,15 +276,12 @@ BEGIN_CASE(JSOP_STOP)
JSStackFrame *down = fp->down;
bool recursive = fp->script == down->script;
/* Restore caller's registers. */
regs = fp->callerRegs;
regs.sp -= 1 + (size_t) fp->argc;
regs.sp[-1] = fp->rval;
down->regs = &regs;
/* Pop |fp| from the context. */
/* Pop the frame. */
cx->stack().popInlineFrame(cx, fp, down);
/* Propagate return value before fp is lost. */
regs.sp[-1] = fp->rval;
/* Sync interpreter registers. */
fp = cx->fp;
script = fp->script;
@@ -2071,7 +2067,6 @@ BEGIN_CASE(JSOP_APPLY)
}
JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags));
newfp->thisv = vp[1];
newfp->regs = NULL;
newfp->imacpc = NULL;
/* Push void to initialize local variables. */
@@ -2091,16 +2086,15 @@ BEGIN_CASE(JSOP_APPLY)
js_SetVersion(cx, currentVersion);
}
/* Push the frame and set interpreter registers. */
newfp->callerRegs = regs;
fp->regs = &newfp->callerRegs;
regs.sp = newsp;
/* Push the frame. */
stack.pushInlineFrame(cx, fp, regs.pc, newfp);
/* Initializer regs after pushInlineFrame snapshots pc. */
regs.pc = newscript->code;
newfp->regs = &regs;
stack.pushInlineFrame(cx, fp, newfp);
JS_ASSERT(newfp == cx->fp);
regs.sp = newsp;
/* Import into locals. */
JS_ASSERT(newfp == cx->fp);
fp = newfp;
script = newscript;
atoms = script->atomMap.vector;
@@ -2132,8 +2126,8 @@ BEGIN_CASE(JSOP_APPLY)
goto error;
}
} else if (fp->script == fp->down->script &&
*fp->down->regs->pc == JSOP_CALL &&
*fp->regs->pc == JSOP_TRACE) {
*fp->down->savedPC == JSOP_CALL &&
*regs.pc == JSOP_TRACE) {
MONITOR_BRANCH(Record_EnterFrame);
}
#endif
@@ -3195,7 +3189,7 @@ END_CASE(JSOP_HOLE)
BEGIN_CASE(JSOP_NEWARRAY)
len = GET_UINT16(regs.pc);
cx->fp->assertValidStackDepth(len);
cx->assertValidStackDepth(len);
obj = js_NewArrayObject(cx, len, regs.sp - len, JS_TRUE);
if (!obj)
goto error;

View File

@@ -127,7 +127,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI
* Optimize the cached vword based on our parameters and the current pc's
* opcode format flags.
*/
pc = cx->fp->regs->pc;
pc = cx->regs->pc;
op = js_GetOpcode(cx, cx->fp->script, pc);
cs = &js_CodeSpec[op];
kshape = 0;

View File

@@ -163,8 +163,8 @@ TraceRecorder::downSnapshot(FrameInfo* downFrame)
exitTypeMap[i] = typeMap[i];
/* Add the return type. */
JS_ASSERT_IF(*cx->fp->regs->pc != JSOP_RETURN, *cx->fp->regs->pc == JSOP_STOP);
if (*cx->fp->regs->pc == JSOP_RETURN)
JS_ASSERT_IF(*cx->regs->pc != JSOP_RETURN, *cx->regs->pc == JSOP_STOP);
if (*cx->regs->pc == JSOP_RETURN)
exitTypeMap[downPostSlots] = determineSlotType(&stackval(-1));
else
exitTypeMap[downPostSlots] = TT_VOID;
@@ -198,12 +198,21 @@ TraceRecorder::downSnapshot(FrameInfo* downFrame)
return exit;
}
static JS_REQUIRES_STACK jsval *
DownFrameSP(JSContext *cx)
{
FrameRegsIter i(cx);
++i;
JS_ASSERT(i.fp() == cx->fp->down);
return i.sp();
}
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::upRecursion()
{
JS_ASSERT((JSOp)*cx->fp->down->regs->pc == JSOP_CALL);
JS_ASSERT((JSOp)*cx->fp->down->savedPC == JSOP_CALL);
JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, cx->fp->down->script,
cx->fp->down->regs->pc)].length == JSOP_CALL_LENGTH);
cx->fp->down->savedPC)].length == JSOP_CALL_LENGTH);
JS_ASSERT(callDepth == 0);
@@ -215,10 +224,10 @@ TraceRecorder::upRecursion()
if (anchor && (anchor->exitType == RECURSIVE_EMPTY_RP_EXIT ||
anchor->exitType == RECURSIVE_SLURP_MISMATCH_EXIT ||
anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT)) {
return slurpDownFrames(cx->fp->down->regs->pc);
return slurpDownFrames(cx->fp->down->savedPC);
}
jsbytecode* return_pc = cx->fp->down->regs->pc;
jsbytecode* return_pc = cx->fp->down->savedPC;
jsbytecode* recursive_pc = return_pc + JSOP_CALL_LENGTH;
/*
@@ -245,7 +254,7 @@ TraceRecorder::upRecursion()
* Need to compute this from the down frame, since the stack could have
* moved on this one.
*/
fi->spdist = cx->fp->down->regs->sp - cx->fp->down->slots();
fi->spdist = DownFrameSP(cx) - cx->fp->down->slots();
JS_ASSERT(cx->fp->argc == cx->fp->down->argc);
fi->set_argc(uint16(cx->fp->argc), false);
fi->callerHeight = downPostSlots;
@@ -308,7 +317,7 @@ TraceRecorder::upRecursion()
exit = downSnapshot(fi);
LIns* rval_ins;
if (*cx->fp->regs->pc == JSOP_RETURN) {
if (*cx->regs->pc == JSOP_RETURN) {
JS_ASSERT(!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT);
rval_ins = get(&stackval(-1));
JS_ASSERT(rval_ins);
@@ -318,7 +327,7 @@ TraceRecorder::upRecursion()
TraceType returnType = exit->stackTypeMap()[downPostSlots];
if (returnType == TT_INT32) {
JS_ASSERT(*cx->fp->regs->pc == JSOP_RETURN);
JS_ASSERT(*cx->regs->pc == JSOP_RETURN);
JS_ASSERT(determineSlotType(&stackval(-1)) == TT_INT32);
JS_ASSERT(isPromoteInt(rval_ins));
rval_ins = demote(lir, rval_ins);
@@ -327,7 +336,7 @@ TraceRecorder::upRecursion()
UpRecursiveSlotMap slotMap(*this, downPostSlots, rval_ins);
for (unsigned i = 0; i < downPostSlots; i++)
slotMap.addSlot(exit->stackType(i));
if (*cx->fp->regs->pc == JSOP_RETURN)
if (*cx->regs->pc == JSOP_RETURN)
slotMap.addSlot(&stackval(-1));
else
slotMap.addSlot(TT_VOID);
@@ -386,7 +395,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
unsigned frameDepth;
unsigned downPostSlots;
JSStackFrame* fp = cx->fp;
FrameRegsIter i(cx);
LIns* fp_ins =
addName(lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp), ACC_OTHER), "fp");
@@ -399,7 +408,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) {
fp_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, down), ACC_OTHER),
"downFp");
fp = fp->down;
++i;
argv_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, argv), ACC_OTHER),
"argv");
@@ -427,14 +436,12 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
RECURSIVE_LOOP_EXIT);
}
/* fp->down->regs->pc should be == pc. */
/* fp->down->savedPC should be == pc. */
guard(true,
lir->ins2(LIR_eqp,
lir->insLoad(LIR_ldp,
addName(lir->insLoad(LIR_ldp, fp_ins,
offsetof(JSStackFrame, regs), ACC_OTHER),
"regs"),
offsetof(JSFrameRegs, pc), ACC_OTHER),
addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, savedPC),
ACC_OTHER),
"savedPC"),
INS_CONSTPTR(return_pc)),
RECURSIVE_SLURP_MISMATCH_EXIT);
@@ -489,13 +496,13 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
* thrown away.
*/
TraceType* typeMap = exit->stackTypeMap();
jsbytecode* oldpc = cx->fp->regs->pc;
cx->fp->regs->pc = exit->pc;
jsbytecode* oldpc = cx->regs->pc;
cx->regs->pc = exit->pc;
captureStackTypes(frameDepth, typeMap);
cx->fp->regs->pc = oldpc;
cx->regs->pc = oldpc;
if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) {
JS_ASSERT_IF(*cx->fp->regs->pc != JSOP_RETURN, *cx->fp->regs->pc == JSOP_STOP);
if (*cx->fp->regs->pc == JSOP_RETURN)
JS_ASSERT_IF(*cx->regs->pc != JSOP_RETURN, *cx->regs->pc == JSOP_STOP);
if (*cx->regs->pc == JSOP_RETURN)
typeMap[downPostSlots] = determineSlotType(&stackval(-1));
else
typeMap[downPostSlots] = TT_VOID;
@@ -522,10 +529,10 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) {
/*
* It is safe to read cx->fp->regs->pc here because the frame hasn't
* It is safe to read cx->regs->pc here because the frame hasn't
* been popped yet. We're guaranteed to have a return or stop.
*/
JSOp op = JSOp(*cx->fp->regs->pc);
JSOp op = JSOp(*cx->regs->pc);
JS_ASSERT(op == JSOP_RETURN || op == JSOP_STOP);
if (op == JSOP_RETURN) {
@@ -575,6 +582,8 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
info.slurpFailSlot = (anchor && anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT) ?
anchor->slurpFailSlot : 0;
JSStackFrame *const fp = i.fp();
/* callee */
slurpSlot(lir->insLoad(LIR_ldp, argv_ins, -2 * ptrdiff_t(sizeof(jsval)), ACC_OTHER),
&fp->argv[-2],
@@ -612,7 +621,8 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
slots_ins,
INS_CONSTWORD(nfixed * sizeof(jsval))),
"stackBase");
size_t limit = size_t(fp->regs->sp - StackBase(fp));
size_t limit = size_t(i.sp() - StackBase(fp));
if (anchor && anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT)
limit--;
else
@@ -634,7 +644,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
RecursiveSlotMap slotMap(*this, downPostSlots, rval_ins);
for (unsigned i = 0; i < downPostSlots; i++)
slotMap.addSlot(typeMap[i]);
if (*cx->fp->regs->pc == JSOP_RETURN)
if (*cx->regs->pc == JSOP_RETURN)
slotMap.addSlot(&stackval(-1), typeMap[downPostSlots]);
else
slotMap.addSlot(TT_VOID);

View File

@@ -4783,7 +4783,7 @@ MatchRegExp(REGlobalData *gData, REMatchState *x)
"entering REGEXP trace at %s:%u@%u, code: %p\n",
caller ? caller->script->filename : "<unknown>",
caller ? js_FramePCToLineNumber(gData->cx, caller) : 0,
caller ? FramePCOffset(caller) : 0,
caller ? FramePCOffset(gData->cx, caller) : 0,
JS_FUNC_TO_DATA_PTR(void *, native));
})
#endif

View File

@@ -1312,7 +1312,7 @@ js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc)
uintN
js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp)
{
return js_PCToLineNumber(cx, fp->script, fp->imacpc ? fp->imacpc : fp->regs->pc);
return js_PCToLineNumber(cx, fp->script, fp->imacpc ? fp->imacpc : fp->pc(cx));
}
uintN

File diff suppressed because it is too large Load Diff

View File

@@ -1754,7 +1754,6 @@ ParseXMLSource(JSContext *cx, JSString *src)
JSXML *xml;
const char *filename;
uintN lineno;
JSStackFrame *fp;
JSOp op;
JSParseNode *pn;
JSXMLArray nsarray;
@@ -1797,13 +1796,16 @@ ParseXMLSource(JSContext *cx, JSString *src)
&dstlen);
chars [offset + dstlen] = 0;
LeaveTrace(cx);
xml = NULL;
for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down)
JS_ASSERT(!fp->script);
FrameRegsIter i(cx);
for (; !i.done() && !i.pc(); ++i)
JS_ASSERT(!i.fp()->script);
filename = NULL;
lineno = 1;
if (fp) {
op = (JSOp) *fp->regs->pc;
if (!i.done()) {
JSStackFrame *fp = i.fp();
op = (JSOp) *i.pc();
if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) {
filename = fp->script->filename;
lineno = js_FramePCToLineNumber(cx, fp);
@@ -7717,7 +7719,8 @@ js_StepXMLListFilter(JSContext *cx, JSBool initialized)
JSXML *xml, *list;
JSXMLFilter *filter;
sp = js_GetTopStackFrame(cx)->regs->sp;
LeaveTrace(cx);
sp = cx->regs->sp;
if (!initialized) {
/*
* We haven't iterated yet, so initialize the filter based on the

View File

@@ -3023,7 +3023,7 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
ok = JS_EvaluateUCScript(scx, sobj, src, srclen,
fp->script->filename,
JS_PCToLineNumber(cx, fp->script,
fp->regs->pc),
fp->pc(cx)),
rval);
}
@@ -3061,13 +3061,13 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
JS_ASSERT(cx->fp);
JSStackFrame *fp = cx->fp;
for (uint32 i = 0; i < upCount; ++i) {
if (!fp->down)
FrameRegsIter fi(cx);
for (uint32 i = 0; i < upCount; ++i, ++fi) {
if (!fi.fp()->down)
break;
fp = fp->down;
}
JSStackFrame *const fp = fi.fp();
if (!fp->script) {
JS_ReportError(cx, "cannot eval in non-script frame");
return JS_FALSE;
@@ -3080,7 +3080,7 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, str->chars(), str->length(),
fp->script->filename,
JS_PCToLineNumber(cx, fp->script,
fp->regs->pc),
fi.pc()),
vp);
if (saveCurrent)