Bug 547851 - remove JSStackFrame::regs, JSStackFrame::callerFrame.sp (r=dvander)
This commit is contained in:
@@ -386,10 +386,7 @@ js_PopInterpFrame(JSContext* cx, TracerState* state)
|
|||||||
cx->display[fp->script->staticLevel] = fp->displaySave;
|
cx->display[fp->script->staticLevel] = fp->displaySave;
|
||||||
|
|
||||||
/* Pop the frame and its memory. */
|
/* Pop the frame and its memory. */
|
||||||
JSStackFrame *down = fp->down;
|
cx->stack().popInlineFrame(cx, fp, fp->down);
|
||||||
cx->stack().popInlineFrame(cx, fp, down);
|
|
||||||
JS_ASSERT(cx->fp == down && cx->fp->regs == &fp->callerRegs);
|
|
||||||
down->regs = fp->regs;
|
|
||||||
|
|
||||||
/* Update the inline call count. */
|
/* Update the inline call count. */
|
||||||
*state->inlineCallCountp = *state->inlineCallCountp - 1;
|
*state->inlineCallCountp = *state->inlineCallCountp - 1;
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ StackSpace::getInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag,
|
|||||||
|
|
||||||
assertIsCurrent(cx);
|
assertIsCurrent(cx);
|
||||||
JS_ASSERT(currentCallStack->isActive());
|
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;
|
ptrdiff_t nvals = nmissing + VALUES_PER_CALL_STACK + VALUES_PER_STACK_FRAME + nfixed;
|
||||||
if (!ensureSpace(cx, start, nvals))
|
if (!ensureSpace(cx, start, nvals))
|
||||||
return false;
|
return false;
|
||||||
@@ -288,7 +288,7 @@ StackSpace::getInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag,
|
|||||||
|
|
||||||
JS_REQUIRES_STACK void
|
JS_REQUIRES_STACK void
|
||||||
StackSpace::pushInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag,
|
StackSpace::pushInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag,
|
||||||
InvokeFrameGuard &fg)
|
InvokeFrameGuard &fg, JSFrameRegs ®s)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!!ag.cs ^ !!fg.cs);
|
JS_ASSERT(!!ag.cs ^ !!fg.cs);
|
||||||
JS_ASSERT_IF(ag.cs, ag.cs == currentCallStack && !ag.cs->inContext());
|
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;
|
JSStackFrame *fp = fg.fp;
|
||||||
fp->down = cx->fp;
|
fp->down = cx->fp;
|
||||||
cx->pushCallStackAndFrame(currentCallStack, fp);
|
cx->pushCallStackAndFrame(currentCallStack, fp, regs);
|
||||||
currentCallStack->setInitialVarObj(NULL);
|
currentCallStack->setInitialVarObj(NULL);
|
||||||
fg.cx = cx;
|
fg.cx = cx;
|
||||||
}
|
}
|
||||||
@@ -361,13 +361,13 @@ StackSpace::getExecuteFrame(JSContext *cx, JSStackFrame *down,
|
|||||||
|
|
||||||
JS_REQUIRES_STACK void
|
JS_REQUIRES_STACK void
|
||||||
StackSpace::pushExecuteFrame(JSContext *cx, ExecuteFrameGuard &fg,
|
StackSpace::pushExecuteFrame(JSContext *cx, ExecuteFrameGuard &fg,
|
||||||
JSObject *initialVarObj)
|
JSFrameRegs ®s, JSObject *initialVarObj)
|
||||||
{
|
{
|
||||||
fg.fp->down = fg.down;
|
fg.fp->down = fg.down;
|
||||||
CallStack *cs = fg.cs;
|
CallStack *cs = fg.cs;
|
||||||
cs->setPreviousInThread(currentCallStack);
|
cs->setPreviousInThread(currentCallStack);
|
||||||
currentCallStack = cs;
|
currentCallStack = cs;
|
||||||
cx->pushCallStackAndFrame(cs, fg.fp);
|
cx->pushCallStackAndFrame(cs, fg.fp, regs);
|
||||||
cs->setInitialVarObj(initialVarObj);
|
cs->setInitialVarObj(initialVarObj);
|
||||||
fg.cx = cx;
|
fg.cx = cx;
|
||||||
}
|
}
|
||||||
@@ -391,13 +391,14 @@ StackSpace::getSynthesizedSlowNativeFrame(JSContext *cx, CallStack *&cs, JSStack
|
|||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK void
|
JS_REQUIRES_STACK void
|
||||||
StackSpace::pushSynthesizedSlowNativeFrame(JSContext *cx, CallStack *cs, JSStackFrame *fp)
|
StackSpace::pushSynthesizedSlowNativeFrame(JSContext *cx, CallStack *cs, JSStackFrame *fp,
|
||||||
|
JSFrameRegs ®s)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!fp->script && FUN_SLOW_NATIVE(fp->fun));
|
JS_ASSERT(!fp->script && FUN_SLOW_NATIVE(fp->fun));
|
||||||
fp->down = cx->fp;
|
fp->down = cx->fp;
|
||||||
cs->setPreviousInThread(currentCallStack);
|
cs->setPreviousInThread(currentCallStack);
|
||||||
currentCallStack = cs;
|
currentCallStack = cs;
|
||||||
cx->pushCallStackAndFrame(cs, fp);
|
cx->pushCallStackAndFrame(cs, fp, regs);
|
||||||
cs->setInitialVarObj(NULL);
|
cs->setInitialVarObj(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,6 +413,84 @@ StackSpace::popSynthesizedSlowNativeFrame(JSContext *cx)
|
|||||||
currentCallStack = currentCallStack->getPreviousInThread();
|
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
|
bool
|
||||||
JSThreadData::init()
|
JSThreadData::init()
|
||||||
{
|
{
|
||||||
@@ -1577,14 +1656,12 @@ ReportError(JSContext *cx, const char *message, JSErrorReport *reportp,
|
|||||||
static void
|
static void
|
||||||
PopulateReportBlame(JSContext *cx, JSErrorReport *report)
|
PopulateReportBlame(JSContext *cx, JSErrorReport *report)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Walk stack until we find a frame that is associated with some script
|
* Walk stack until we find a frame that is associated with some script
|
||||||
* rather than a native frame.
|
* rather than a native frame.
|
||||||
*/
|
*/
|
||||||
for (fp = js_GetTopStackFrame(cx); fp; fp = fp->down) {
|
for (JSStackFrame *fp = js_GetTopStackFrame(cx); fp; fp = fp->down) {
|
||||||
if (fp->regs) {
|
if (fp->pc(cx)) {
|
||||||
report->filename = fp->script->filename;
|
report->filename = fp->script->filename;
|
||||||
report->lineno = js_FramePCToLineNumber(cx, fp);
|
report->lineno = js_FramePCToLineNumber(cx, fp);
|
||||||
break;
|
break;
|
||||||
@@ -2163,13 +2240,10 @@ js_GetCurrentBytecodePC(JSContext* cx)
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
JS_ASSERT_NOT_ON_TRACE(cx); /* for static analysis */
|
JS_ASSERT_NOT_ON_TRACE(cx); /* for static analysis */
|
||||||
JSStackFrame* fp = cx->fp;
|
pc = cx->regs ? cx->regs->pc : NULL;
|
||||||
if (fp && fp->regs) {
|
if (!pc)
|
||||||
pc = fp->regs->pc;
|
|
||||||
imacpc = fp->imacpc;
|
|
||||||
} else {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
imacpc = cx->fp->imacpc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2194,18 +2268,27 @@ js_CurrentPCIsInImacro(JSContext *cx)
|
|||||||
JSContext::JSContext(JSRuntime *rt)
|
JSContext::JSContext(JSRuntime *rt)
|
||||||
: runtime(rt),
|
: runtime(rt),
|
||||||
fp(NULL),
|
fp(NULL),
|
||||||
|
regs(NULL),
|
||||||
regExpStatics(this),
|
regExpStatics(this),
|
||||||
busyArrays(this)
|
busyArrays(this)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void
|
void
|
||||||
JSContext::pushCallStackAndFrame(js::CallStack *newcs, JSStackFrame *newfp)
|
JSContext::pushCallStackAndFrame(js::CallStack *newcs, JSStackFrame *newfp,
|
||||||
|
JSFrameRegs &newregs)
|
||||||
{
|
{
|
||||||
if (hasActiveCallStack())
|
if (hasActiveCallStack()) {
|
||||||
currentCallStack->suspend(fp);
|
JS_ASSERT(fp->savedPC == JSStackFrame::sInvalidPC);
|
||||||
|
fp->savedPC = regs->pc;
|
||||||
|
currentCallStack->suspend(fp, regs);
|
||||||
|
}
|
||||||
newcs->setPreviousInContext(currentCallStack);
|
newcs->setPreviousInContext(currentCallStack);
|
||||||
currentCallStack = newcs;
|
currentCallStack = newcs;
|
||||||
|
#ifdef DEBUG
|
||||||
|
newfp->savedPC = JSStackFrame::sInvalidPC;
|
||||||
|
#endif
|
||||||
setCurrentFrame(newfp);
|
setCurrentFrame(newfp);
|
||||||
|
setCurrentRegs(&newregs);
|
||||||
newcs->joinContext(this, newfp);
|
newcs->joinContext(this, newfp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2214,18 +2297,25 @@ JSContext::popCallStackAndFrame()
|
|||||||
{
|
{
|
||||||
JS_ASSERT(currentCallStack->maybeContext() == this);
|
JS_ASSERT(currentCallStack->maybeContext() == this);
|
||||||
JS_ASSERT(currentCallStack->getInitialFrame() == fp);
|
JS_ASSERT(currentCallStack->getInitialFrame() == fp);
|
||||||
|
JS_ASSERT(fp->savedPC == JSStackFrame::sInvalidPC);
|
||||||
currentCallStack->leaveContext();
|
currentCallStack->leaveContext();
|
||||||
currentCallStack = currentCallStack->getPreviousInContext();
|
currentCallStack = currentCallStack->getPreviousInContext();
|
||||||
if (currentCallStack) {
|
if (currentCallStack) {
|
||||||
if (currentCallStack->isSaved()) {
|
if (currentCallStack->isSaved()) {
|
||||||
setCurrentFrame(NULL);
|
setCurrentFrame(NULL);
|
||||||
|
setCurrentRegs(NULL);
|
||||||
} else {
|
} else {
|
||||||
setCurrentFrame(currentCallStack->getSuspendedFrame());
|
setCurrentFrame(currentCallStack->getSuspendedFrame());
|
||||||
|
setCurrentRegs(currentCallStack->getSuspendedRegs());
|
||||||
currentCallStack->resume();
|
currentCallStack->resume();
|
||||||
|
#ifdef DEBUG
|
||||||
|
fp->savedPC = JSStackFrame::sInvalidPC;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(fp->down == NULL);
|
JS_ASSERT(fp->down == NULL);
|
||||||
setCurrentFrame(NULL);
|
setCurrentFrame(NULL);
|
||||||
|
setCurrentRegs(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2233,16 +2323,23 @@ void
|
|||||||
JSContext::saveActiveCallStack()
|
JSContext::saveActiveCallStack()
|
||||||
{
|
{
|
||||||
JS_ASSERT(hasActiveCallStack());
|
JS_ASSERT(hasActiveCallStack());
|
||||||
currentCallStack->save(fp);
|
currentCallStack->save(fp, regs);
|
||||||
|
JS_ASSERT(fp->savedPC == JSStackFrame::sInvalidPC);
|
||||||
|
fp->savedPC = regs->pc;
|
||||||
setCurrentFrame(NULL);
|
setCurrentFrame(NULL);
|
||||||
|
setCurrentRegs(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JSContext::restoreCallStack()
|
JSContext::restoreCallStack()
|
||||||
{
|
{
|
||||||
JS_ASSERT(!hasActiveCallStack());
|
js::CallStack *ccs = currentCallStack;
|
||||||
setCurrentFrame(currentCallStack->getSuspendedFrame());
|
setCurrentFrame(ccs->getSuspendedFrame());
|
||||||
currentCallStack->restore();
|
setCurrentRegs(ccs->getSuspendedRegs());
|
||||||
|
ccs->restore();
|
||||||
|
#ifdef DEBUG
|
||||||
|
fp->savedPC = JSStackFrame::sInvalidPC;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
JSGenerator *
|
JSGenerator *
|
||||||
@@ -2265,7 +2362,7 @@ JSContext::generatorFor(JSStackFrame *fp) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
CallStack *
|
CallStack *
|
||||||
JSContext::containingCallStack(JSStackFrame *target)
|
JSContext::containingCallStack(const JSStackFrame *target)
|
||||||
{
|
{
|
||||||
/* The context may have nothing running. */
|
/* The context may have nothing running. */
|
||||||
CallStack *cs = currentCallStack;
|
CallStack *cs = currentCallStack;
|
||||||
|
|||||||
118
js/src/jscntxt.h
118
js/src/jscntxt.h
@@ -200,6 +200,10 @@ struct TracerState
|
|||||||
uintN nativeVpLen;
|
uintN nativeVpLen;
|
||||||
jsval* nativeVp;
|
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,
|
TracerState(JSContext *cx, TraceMonitor *tm, TreeFragment *ti,
|
||||||
uintN &inlineCallCountp, VMSideExit** innermostNestedGuardp);
|
uintN &inlineCallCountp, VMSideExit** innermostNestedGuardp);
|
||||||
~TracerState();
|
~TracerState();
|
||||||
@@ -251,10 +255,11 @@ struct GlobalState {
|
|||||||
*
|
*
|
||||||
* A callstack in a context may additionally be "active" or "suspended". A
|
* A callstack in a context may additionally be "active" or "suspended". A
|
||||||
* suspended callstack |cs| has a "suspended frame" which serves as the current
|
* 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.
|
* frame of |cs|. Additionally, a suspended callstack has "suspended regs",
|
||||||
* Callstacks in a context execute LIFO and are maintained in a stack. The top
|
* which is a snapshot of |cx->regs| when |cs| was suspended. There is at most
|
||||||
* of this stack is the context's "current callstack". If a context |cx| has an
|
* one active callstack in a given context. Callstacks in a context execute
|
||||||
* active callstack |cs|, then:
|
* 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,
|
* 1. |cs| is |cx|'s current callstack,
|
||||||
* 2. |cx->fp != NULL|, and
|
* 2. |cx->fp != NULL|, and
|
||||||
* 3. |cs|'s current frame is |cx->fp|.
|
* 3. |cs|'s current frame is |cx->fp|.
|
||||||
@@ -284,6 +289,9 @@ class CallStack
|
|||||||
/* If this callstack is suspended, the top of the callstack. */
|
/* If this callstack is suspended, the top of the callstack. */
|
||||||
JSStackFrame *suspendedFrame;
|
JSStackFrame *suspendedFrame;
|
||||||
|
|
||||||
|
/* If this callstack is suspended, |cx->regs| when it was suspended. */
|
||||||
|
JSFrameRegs *suspendedRegs;
|
||||||
|
|
||||||
/* This callstack was suspended by JS_SaveFrameChain. */
|
/* This callstack was suspended by JS_SaveFrameChain. */
|
||||||
bool saved;
|
bool saved;
|
||||||
|
|
||||||
@@ -366,11 +374,12 @@ class CallStack
|
|||||||
|
|
||||||
/* Transitioning between isActive <--> isSuspended */
|
/* Transitioning between isActive <--> isSuspended */
|
||||||
|
|
||||||
void suspend(JSStackFrame *fp) {
|
void suspend(JSStackFrame *fp, JSFrameRegs *regs) {
|
||||||
JS_ASSERT(isActive());
|
JS_ASSERT(isActive());
|
||||||
JS_ASSERT(fp && contains(fp));
|
JS_ASSERT(fp && contains(fp));
|
||||||
suspendedFrame = fp;
|
suspendedFrame = fp;
|
||||||
JS_ASSERT(isSuspended());
|
JS_ASSERT(isSuspended());
|
||||||
|
suspendedRegs = regs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resume() {
|
void resume() {
|
||||||
@@ -381,9 +390,9 @@ class CallStack
|
|||||||
|
|
||||||
/* When isSuspended, transitioning isSaved <--> !isSaved */
|
/* When isSuspended, transitioning isSaved <--> !isSaved */
|
||||||
|
|
||||||
void save(JSStackFrame *fp) {
|
void save(JSStackFrame *fp, JSFrameRegs *regs) {
|
||||||
JS_ASSERT(!isSaved());
|
JS_ASSERT(!isSaved());
|
||||||
suspend(fp);
|
suspend(fp, regs);
|
||||||
saved = true;
|
saved = true;
|
||||||
JS_ASSERT(isSaved());
|
JS_ASSERT(isSaved());
|
||||||
}
|
}
|
||||||
@@ -423,6 +432,16 @@ class CallStack
|
|||||||
return suspendedFrame;
|
return suspendedFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSFrameRegs *getSuspendedRegs() const {
|
||||||
|
JS_ASSERT(isSuspended());
|
||||||
|
return suspendedRegs;
|
||||||
|
}
|
||||||
|
|
||||||
|
jsval *getSuspendedSP() const {
|
||||||
|
JS_ASSERT(isSuspended());
|
||||||
|
return suspendedRegs->sp;
|
||||||
|
}
|
||||||
|
|
||||||
/* JSContext / js::StackSpace bookkeeping. */
|
/* JSContext / js::StackSpace bookkeeping. */
|
||||||
|
|
||||||
void setPreviousInContext(CallStack *cs) {
|
void setPreviousInContext(CallStack *cs) {
|
||||||
@@ -682,7 +701,7 @@ class StackSpace
|
|||||||
|
|
||||||
JS_REQUIRES_STACK
|
JS_REQUIRES_STACK
|
||||||
void pushInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag,
|
void pushInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag,
|
||||||
InvokeFrameGuard &fg);
|
InvokeFrameGuard &fg, JSFrameRegs ®s);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For the simpler case when arguments are allocated at the same time as
|
* For the simpler case when arguments are allocated at the same time as
|
||||||
@@ -695,7 +714,7 @@ class StackSpace
|
|||||||
ExecuteFrameGuard &fg) const;
|
ExecuteFrameGuard &fg) const;
|
||||||
JS_REQUIRES_STACK
|
JS_REQUIRES_STACK
|
||||||
void pushExecuteFrame(JSContext *cx, ExecuteFrameGuard &fg,
|
void pushExecuteFrame(JSContext *cx, ExecuteFrameGuard &fg,
|
||||||
JSObject *initialVarObj);
|
JSFrameRegs ®s, JSObject *initialVarObj);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since RAII cannot be used for inline frames, callers must manually
|
* Since RAII cannot be used for inline frames, callers must manually
|
||||||
@@ -706,7 +725,8 @@ class StackSpace
|
|||||||
uintN nmissing, uintN nfixed) const;
|
uintN nmissing, uintN nfixed) const;
|
||||||
|
|
||||||
JS_REQUIRES_STACK
|
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
|
JS_REQUIRES_STACK
|
||||||
inline void popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down);
|
inline void popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down);
|
||||||
@@ -719,7 +739,8 @@ class StackSpace
|
|||||||
void getSynthesizedSlowNativeFrame(JSContext *cx, CallStack *&cs, JSStackFrame *&fp);
|
void getSynthesizedSlowNativeFrame(JSContext *cx, CallStack *&cs, JSStackFrame *&fp);
|
||||||
|
|
||||||
JS_REQUIRES_STACK
|
JS_REQUIRES_STACK
|
||||||
void pushSynthesizedSlowNativeFrame(JSContext *cx, CallStack *cs, JSStackFrame *fp);
|
void pushSynthesizedSlowNativeFrame(JSContext *cx, CallStack *cs, JSStackFrame *fp,
|
||||||
|
JSFrameRegs ®s);
|
||||||
|
|
||||||
JS_REQUIRES_STACK
|
JS_REQUIRES_STACK
|
||||||
void popSynthesizedSlowNativeFrame(JSContext *cx);
|
void popSynthesizedSlowNativeFrame(JSContext *cx);
|
||||||
@@ -731,6 +752,34 @@ class StackSpace
|
|||||||
|
|
||||||
JS_STATIC_ASSERT(StackSpace::CAPACITY_VALS % StackSpace::COMMIT_VALS == 0);
|
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. */
|
/* Holds the number of recording attemps for an address. */
|
||||||
typedef HashMap<jsbytecode*,
|
typedef HashMap<jsbytecode*,
|
||||||
size_t,
|
size_t,
|
||||||
@@ -1637,14 +1686,26 @@ struct JSContext
|
|||||||
JS_REQUIRES_STACK
|
JS_REQUIRES_STACK
|
||||||
JSStackFrame *fp;
|
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:
|
private:
|
||||||
friend class js::StackSpace;
|
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) {
|
void setCurrentFrame(JSStackFrame *fp) {
|
||||||
this->fp = fp;
|
this->fp = fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setCurrentRegs(JSFrameRegs *regs) {
|
||||||
|
this->regs = regs;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* Temporary arena pool used while compiling and decompiling. */
|
/* Temporary arena pool used while compiling and decompiling. */
|
||||||
JSArenaPool tempPool;
|
JSArenaPool tempPool;
|
||||||
@@ -1721,7 +1782,8 @@ struct JSContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Add the given callstack to the list as the new active callstack. */
|
/* 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 ®s);
|
||||||
|
|
||||||
/* Remove the active callstack and make the next callstack active. */
|
/* Remove the active callstack and make the next callstack active. */
|
||||||
void popCallStackAndFrame();
|
void popCallStackAndFrame();
|
||||||
@@ -1736,7 +1798,7 @@ struct JSContext
|
|||||||
* Perform a linear search of all frames in all callstacks in the given context
|
* 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.
|
* 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
|
#ifdef JS_THREADSAFE
|
||||||
JSThread *thread;
|
JSThread *thread;
|
||||||
@@ -1820,9 +1882,7 @@ struct JSContext
|
|||||||
JSGenerator *generatorFor(JSStackFrame *fp) const;
|
JSGenerator *generatorFor(JSStackFrame *fp) const;
|
||||||
|
|
||||||
/* Early OOM-check. */
|
/* Early OOM-check. */
|
||||||
bool ensureGeneratorStackSpace() {
|
inline bool ensureGeneratorStackSpace();
|
||||||
return genStack.reserve(genStack.length() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool enterGenerator(JSGenerator *gen) {
|
bool enterGenerator(JSGenerator *gen) {
|
||||||
return genStack.append(gen);
|
return genStack.append(gen);
|
||||||
@@ -1968,6 +2028,15 @@ struct JSContext
|
|||||||
return JS_THREAD_DATA(this)->stackSpace;
|
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:
|
private:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1993,6 +2062,13 @@ JSStackFrame::varobj(JSContext *cx) const
|
|||||||
return fun ? callobj : cx->activeCallStack()->getInitialVarObj();
|
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
|
* InvokeArgsGuard is used outside the JS engine (where jscntxtinlines.h is
|
||||||
* not included). To avoid visibility issues, force members inline.
|
* 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)
|
# define JS_THREAD_ID(cx) ((cx)->thread ? (cx)->thread->id : 0)
|
||||||
#endif
|
#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 **
|
static inline JSAtom **
|
||||||
FrameAtomBase(JSContext *cx, JSStackFrame *fp)
|
FrameAtomBase(JSContext *cx, JSStackFrame *fp)
|
||||||
@@ -2435,8 +2515,6 @@ class JSAutoResolveFlags
|
|||||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __cpluscplus */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Slightly more readable macros for testing per-context option settings (also
|
* Slightly more readable macros for testing per-context option settings (also
|
||||||
* to hide bitset implementation detail).
|
* to hide bitset implementation detail).
|
||||||
|
|||||||
@@ -46,6 +46,15 @@
|
|||||||
|
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
JSContext::ensureGeneratorStackSpace()
|
||||||
|
{
|
||||||
|
bool ok = genStack.reserve(genStack.length() + 1);
|
||||||
|
if (!ok)
|
||||||
|
js_ReportOutOfMemory(this);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
|
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
|
||||||
@@ -61,12 +70,12 @@ StackSpace::firstUnused() const
|
|||||||
CallStack *ccs = currentCallStack;
|
CallStack *ccs = currentCallStack;
|
||||||
if (!ccs)
|
if (!ccs)
|
||||||
return base;
|
return base;
|
||||||
if (!ccs->inContext())
|
if (JSContext *cx = ccs->maybeContext()) {
|
||||||
return ccs->getInitialArgEnd();
|
if (!ccs->isSuspended())
|
||||||
JSStackFrame *fp = ccs->getCurrentFrame();
|
return cx->regs->sp;
|
||||||
if (JSFrameRegs *regs = fp->regs)
|
return ccs->getSuspendedRegs()->sp;
|
||||||
return regs->sp;
|
}
|
||||||
return fp->slots();
|
return ccs->getInitialArgEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inline so we don't need the friend API. */
|
/* Inline so we don't need the friend API. */
|
||||||
@@ -124,7 +133,7 @@ StackSpace::getInlineFrame(JSContext *cx, jsval *sp,
|
|||||||
{
|
{
|
||||||
assertIsCurrent(cx);
|
assertIsCurrent(cx);
|
||||||
JS_ASSERT(cx->hasActiveCallStack());
|
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;
|
ptrdiff_t nvals = nmissing + VALUES_PER_STACK_FRAME + nfixed;
|
||||||
if (!ensureSpace(cx, sp, nvals))
|
if (!ensureSpace(cx, sp, nvals))
|
||||||
@@ -135,13 +144,18 @@ StackSpace::getInlineFrame(JSContext *cx, jsval *sp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
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);
|
assertIsCurrent(cx);
|
||||||
JS_ASSERT(cx->hasActiveCallStack());
|
JS_ASSERT(cx->hasActiveCallStack());
|
||||||
JS_ASSERT(cx->fp == fp);
|
JS_ASSERT(cx->fp == fp && cx->regs->pc == pc);
|
||||||
|
|
||||||
|
fp->savedPC = pc;
|
||||||
newfp->down = fp;
|
newfp->down = fp;
|
||||||
|
#ifdef DEBUG
|
||||||
|
newfp->savedPC = JSStackFrame::sInvalidPC;
|
||||||
|
#endif
|
||||||
cx->setCurrentFrame(newfp);
|
cx->setCurrentFrame(newfp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +165,14 @@ StackSpace::popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down)
|
|||||||
assertIsCurrent(cx);
|
assertIsCurrent(cx);
|
||||||
JS_ASSERT(cx->hasActiveCallStack());
|
JS_ASSERT(cx->hasActiveCallStack());
|
||||||
JS_ASSERT(cx->fp == up && up->down == down);
|
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);
|
cx->setCurrentFrame(down);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -684,19 +684,16 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|||||||
PodZero(fp->slots(), nfixed);
|
PodZero(fp->slots(), nfixed);
|
||||||
PodZero(fp);
|
PodZero(fp);
|
||||||
fp->script = script;
|
fp->script = script;
|
||||||
fp->regs = NULL;
|
|
||||||
fp->fun = fun;
|
fp->fun = fun;
|
||||||
fp->argv = vp + 2;
|
fp->argv = vp + 2;
|
||||||
fp->scopeChain = closure->getParent();
|
fp->scopeChain = closure->getParent();
|
||||||
if (script) {
|
|
||||||
JS_ASSERT(script->length >= JSOP_STOP_LENGTH);
|
/* Initialize regs. */
|
||||||
regs.pc = script->code + script->length - JSOP_STOP_LENGTH;
|
regs.pc = script ? script->code : NULL;
|
||||||
regs.sp = fp->slots() + script->nfixed;
|
regs.sp = fp->slots() + nfixed;
|
||||||
fp->regs = ®s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Officially push |fp|. |frame|'s destructor pops. */
|
/* 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. */
|
/* Now that fp has been pushed, get the call object. */
|
||||||
if (script && fun && fun->isHeavyweight() &&
|
if (script && fun && fun->isHeavyweight() &&
|
||||||
@@ -1070,7 +1067,7 @@ JS_GetFrameScript(JSContext *cx, JSStackFrame *fp)
|
|||||||
JS_PUBLIC_API(jsbytecode *)
|
JS_PUBLIC_API(jsbytecode *)
|
||||||
JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
|
JS_GetFramePC(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return fp->regs ? fp->regs->pc : NULL;
|
return fp->pc(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSStackFrame *)
|
JS_PUBLIC_API(JSStackFrame *)
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ jsdtrace_fun_linenumber(JSContext *cx, const JSFunction *fun)
|
|||||||
static int
|
static int
|
||||||
jsdtrace_frame_linenumber(JSContext *cx, JSStackFrame *fp)
|
jsdtrace_frame_linenumber(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
if (fp && fp->regs)
|
if (fp)
|
||||||
return (int) js_FramePCToLineNumber(cx, fp);
|
return (int) js_FramePCToLineNumber(cx, fp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
|||||||
elem->filename = NULL;
|
elem->filename = NULL;
|
||||||
if (fp->script) {
|
if (fp->script) {
|
||||||
elem->filename = fp->script->filename;
|
elem->filename = fp->script->filename;
|
||||||
if (fp->regs)
|
if (fp->pc(cx))
|
||||||
elem->ulineno = js_FramePCToLineNumber(cx, fp);
|
elem->ulineno = js_FramePCToLineNumber(cx, fp);
|
||||||
}
|
}
|
||||||
++elem;
|
++elem;
|
||||||
@@ -753,7 +753,7 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||||||
} else {
|
} else {
|
||||||
if (!fp)
|
if (!fp)
|
||||||
fp = js_GetScriptedCaller(cx, NULL);
|
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) ||
|
return (obj->getClass() != &js_ErrorClass) ||
|
||||||
|
|||||||
@@ -2621,14 +2621,8 @@ js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags)
|
|||||||
void
|
void
|
||||||
js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
|
js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp;
|
|
||||||
uintN error;
|
uintN error;
|
||||||
const char *name, *source;
|
const char *name = NULL, *source = NULL;
|
||||||
|
|
||||||
for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down)
|
|
||||||
continue;
|
|
||||||
name = source = NULL;
|
|
||||||
|
|
||||||
AutoValueRooter tvr(cx);
|
AutoValueRooter tvr(cx);
|
||||||
if (flags & JSV2F_ITERATOR) {
|
if (flags & JSV2F_ITERATOR) {
|
||||||
error = JSMSG_BAD_ITERATOR;
|
error = JSMSG_BAD_ITERATOR;
|
||||||
@@ -2650,15 +2644,18 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
|
|||||||
error = JSMSG_NOT_FUNCTION;
|
error = JSMSG_NOT_FUNCTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
js_ReportValueError3(cx, error,
|
LeaveTrace(cx);
|
||||||
(fp && fp->regs &&
|
FrameRegsIter i(cx);
|
||||||
StackBase(fp) <= vp && vp < fp->regs->sp)
|
while (!i.done() && !i.pc())
|
||||||
? vp - fp->regs->sp
|
++i;
|
||||||
: (flags & JSV2F_SEARCH_STACK)
|
|
||||||
? JSDVG_SEARCH_STACK
|
ptrdiff_t spindex =
|
||||||
: JSDVG_IGNORE_STACK,
|
!i.done() && StackBase(i.fp()) <= vp && vp < i.sp()
|
||||||
*vp, NULL,
|
? vp - i.sp()
|
||||||
name, source);
|
: flags & JSV2F_SEARCH_STACK ? JSDVG_SEARCH_STACK
|
||||||
|
: JSDVG_IGNORE_STACK;
|
||||||
|
|
||||||
|
js_ReportValueError3(cx, error, spindex, *vp, NULL, name, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -95,6 +95,10 @@ using namespace js;
|
|||||||
/* jsinvoke_cpp___ indicates inclusion from jsinvoke.cpp. */
|
/* jsinvoke_cpp___ indicates inclusion from jsinvoke.cpp. */
|
||||||
#if !JS_LONE_INTERPRET ^ defined jsinvoke_cpp___
|
#if !JS_LONE_INTERPRET ^ defined jsinvoke_cpp___
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
jsbytecode *const JSStackFrame::sInvalidPC = (jsbytecode *)0xbeef;
|
||||||
|
#endif
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
|
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
|
* Get a pointer to new frame/slots. This memory is not "claimed", so the
|
||||||
* code before pushInvokeFrame must not reenter the interpreter.
|
* code before pushInvokeFrame must not reenter the interpreter.
|
||||||
*/
|
*/
|
||||||
|
JSFrameRegs regs;
|
||||||
InvokeFrameGuard frame;
|
InvokeFrameGuard frame;
|
||||||
if (!cx->stack().getInvokeFrame(cx, args, nmissing, nfixed, frame))
|
if (!cx->stack().getInvokeFrame(cx, args, nmissing, nfixed, frame))
|
||||||
return false;
|
return false;
|
||||||
@@ -583,13 +588,21 @@ js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags)
|
|||||||
fp->annotation = NULL;
|
fp->annotation = NULL;
|
||||||
fp->scopeChain = NULL;
|
fp->scopeChain = NULL;
|
||||||
fp->blockChain = NULL;
|
fp->blockChain = NULL;
|
||||||
fp->regs = NULL;
|
|
||||||
fp->imacpc = NULL;
|
fp->imacpc = NULL;
|
||||||
fp->flags = flags;
|
fp->flags = flags;
|
||||||
fp->displaySave = NULL;
|
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. */
|
/* 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. */
|
/* Now that the frame has been pushed, fix up the scope chain. */
|
||||||
if (native) {
|
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
|
* N.B. when fp->argv is removed (bug 539144), argv will have to be copied
|
||||||
* in before execution and copied out after.
|
* in before execution and copied out after.
|
||||||
*/
|
*/
|
||||||
|
JSFrameRegs regs;
|
||||||
ExecuteFrameGuard frame;
|
ExecuteFrameGuard frame;
|
||||||
if (!cx->stack().getExecuteFrame(cx, down, 0, script->nslots, frame))
|
if (!cx->stack().getExecuteFrame(cx, down, 0, script->nslots, frame))
|
||||||
return false;
|
return false;
|
||||||
@@ -797,11 +811,14 @@ js_Execute(JSContext *cx, JSObject *const chain, JSScript *script,
|
|||||||
fp->script = script;
|
fp->script = script;
|
||||||
fp->imacpc = NULL;
|
fp->imacpc = NULL;
|
||||||
fp->rval = JSVAL_VOID;
|
fp->rval = JSVAL_VOID;
|
||||||
fp->regs = NULL;
|
|
||||||
fp->blockChain = NULL;
|
fp->blockChain = NULL;
|
||||||
|
|
||||||
|
/* Initialize regs. */
|
||||||
|
regs.pc = script->code;
|
||||||
|
regs.sp = StackBase(fp);
|
||||||
|
|
||||||
/* Officially push |fp|. |frame|'s destructor pops. */
|
/* 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. */
|
/* Now that the frame has been pushed, we can call the thisObject hook. */
|
||||||
if (!down) {
|
if (!down) {
|
||||||
@@ -1114,7 +1131,7 @@ js_EnterWith(JSContext *cx, jsint stackIndex)
|
|||||||
JSObject *obj, *parent, *withobj;
|
JSObject *obj, *parent, *withobj;
|
||||||
|
|
||||||
fp = cx->fp;
|
fp = cx->fp;
|
||||||
sp = fp->regs->sp;
|
sp = cx->regs->sp;
|
||||||
JS_ASSERT(stackIndex < 0);
|
JS_ASSERT(stackIndex < 0);
|
||||||
JS_ASSERT(StackBase(fp) <= sp + stackIndex);
|
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
|
* Unwind block and scope chains to match the given depth. The function sets
|
||||||
* fp->sp on return to stackDepth.
|
* fp->sp on return to stackDepth.
|
||||||
*/
|
*/
|
||||||
JS_REQUIRES_STACK JSBool
|
JS_STATIC_INTERPRET JS_REQUIRES_STACK JSBool
|
||||||
js_UnwindScope(JSContext *cx, JSStackFrame *fp, jsint stackDepth,
|
js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind)
|
||||||
JSBool normalUnwind)
|
|
||||||
{
|
{
|
||||||
JSObject *obj;
|
JSObject *obj;
|
||||||
JSClass *clasp;
|
JSClass *clasp;
|
||||||
|
|
||||||
JS_ASSERT(stackDepth >= 0);
|
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()) {
|
for (obj = fp->blockChain; obj; obj = obj->getParent()) {
|
||||||
JS_ASSERT(obj->getClass() == &js_BlockClass);
|
JS_ASSERT(obj->getClass() == &js_BlockClass);
|
||||||
if (OBJ_BLOCK_DEPTH(cx, obj) < stackDepth)
|
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;
|
return normalUnwind;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1274,7 +1291,7 @@ js_TraceOpcode(JSContext *cx)
|
|||||||
tracefp = (FILE *) cx->tracefp;
|
tracefp = (FILE *) cx->tracefp;
|
||||||
JS_ASSERT(tracefp);
|
JS_ASSERT(tracefp);
|
||||||
fp = cx->fp;
|
fp = cx->fp;
|
||||||
regs = fp->regs;
|
regs = cx->regs;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Operations in prologues don't produce interesting values, and
|
* Operations in prologues don't produce interesting values, and
|
||||||
@@ -2008,7 +2025,7 @@ js_Interpret(JSContext *cx)
|
|||||||
uintN inlineCallCount;
|
uintN inlineCallCount;
|
||||||
JSAtom **atoms;
|
JSAtom **atoms;
|
||||||
JSVersion currentVersion, originalVersion;
|
JSVersion currentVersion, originalVersion;
|
||||||
JSFrameRegs regs;
|
JSFrameRegs regs, *prevContextRegs;
|
||||||
JSObject *obj, *obj2, *parent;
|
JSObject *obj, *obj2, *parent;
|
||||||
JSBool ok, cond;
|
JSBool ok, cond;
|
||||||
jsint len;
|
jsint len;
|
||||||
@@ -2214,7 +2231,7 @@ js_Interpret(JSContext *cx)
|
|||||||
script = fp->script; \
|
script = fp->script; \
|
||||||
atoms = FrameAtomBase(cx, fp); \
|
atoms = FrameAtomBase(cx, fp); \
|
||||||
currentVersion = (JSVersion) script->version; \
|
currentVersion = (JSVersion) script->version; \
|
||||||
JS_ASSERT(fp->regs == ®s); \
|
JS_ASSERT(cx->regs == ®s); \
|
||||||
JS_END_MACRO
|
JS_END_MACRO
|
||||||
|
|
||||||
#define MONITOR_BRANCH(reason) \
|
#define MONITOR_BRANCH(reason) \
|
||||||
@@ -2312,21 +2329,18 @@ js_Interpret(JSContext *cx)
|
|||||||
*/
|
*/
|
||||||
CHECK_INTERRUPT_HANDLER();
|
CHECK_INTERRUPT_HANDLER();
|
||||||
|
|
||||||
#if !JS_HAS_GENERATORS
|
/*
|
||||||
JS_ASSERT(!fp->regs);
|
* Access to |cx->regs| is very common, so we copy in and repoint to a
|
||||||
#else
|
* local variable, and copy out on exit.
|
||||||
/* Initialize the pc and sp registers unless we're resuming a generator. */
|
*/
|
||||||
if (JS_LIKELY(!fp->regs)) {
|
JS_ASSERT(cx->regs);
|
||||||
#endif
|
prevContextRegs = cx->regs;
|
||||||
ASSERT_NOT_THROWING(cx);
|
regs = *cx->regs;
|
||||||
regs.pc = script->code;
|
cx->setCurrentRegs(®s);
|
||||||
regs.sp = StackBase(fp);
|
|
||||||
fp->regs = ®s;
|
|
||||||
#if JS_HAS_GENERATORS
|
#if JS_HAS_GENERATORS
|
||||||
} else {
|
if (JS_UNLIKELY(fp->isGenerator())) {
|
||||||
JS_ASSERT(fp->regs == &cx->generatorFor(fp)->savedRegs);
|
JS_ASSERT(prevContextRegs == &cx->generatorFor(fp)->savedRegs);
|
||||||
regs = *fp->regs;
|
|
||||||
fp->regs = ®s;
|
|
||||||
JS_ASSERT((size_t) (regs.pc - script->code) <= script->length);
|
JS_ASSERT((size_t) (regs.pc - script->code) <= script->length);
|
||||||
JS_ASSERT((size_t) (regs.sp - StackBase(fp)) <= StackDepth(script));
|
JS_ASSERT((size_t) (regs.sp - StackBase(fp)) <= StackDepth(script));
|
||||||
|
|
||||||
@@ -2344,13 +2358,10 @@ js_Interpret(JSContext *cx)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* JS_HAS_GENERATORS */
|
#endif
|
||||||
|
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
/*
|
/* We cannot reenter the interpreter while recording. */
|
||||||
* We cannot reenter the interpreter while recording; wait to abort until
|
|
||||||
* after cx->fp->regs is set.
|
|
||||||
*/
|
|
||||||
if (TRACE_RECORDER(cx))
|
if (TRACE_RECORDER(cx))
|
||||||
AbortRecording(cx, "attempt to reenter interpreter while recording");
|
AbortRecording(cx, "attempt to reenter interpreter while recording");
|
||||||
#endif
|
#endif
|
||||||
@@ -2415,6 +2426,7 @@ js_Interpret(JSContext *cx)
|
|||||||
#endif /* !JS_THREADED_INTERP */
|
#endif /* !JS_THREADED_INTERP */
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
JS_ASSERT(cx->regs == ®s);
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
if (fp->imacpc && cx->throwing) {
|
if (fp->imacpc && cx->throwing) {
|
||||||
// Handle other exceptions as if they came from the imacro-calling pc.
|
// 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;
|
regs.pc = (script)->main + tn->start + tn->length;
|
||||||
|
|
||||||
ok = js_UnwindScope(cx, fp, tn->stackDepth, JS_TRUE);
|
ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE);
|
||||||
JS_ASSERT(fp->regs->sp == StackBase(fp) + tn->stackDepth);
|
JS_ASSERT(regs.sp == StackBase(fp) + tn->stackDepth);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
/*
|
/*
|
||||||
* Restart the handler search with updated pc and stack depth
|
* Restart the handler search with updated pc and stack depth
|
||||||
@@ -2578,13 +2590,13 @@ js_Interpret(JSContext *cx)
|
|||||||
|
|
||||||
forced_return:
|
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.
|
* returns true.
|
||||||
*
|
*
|
||||||
* When a trap handler returns JSTRAP_RETURN, we jump here with ok set to
|
* When a trap handler returns JSTRAP_RETURN, we jump here with ok set to
|
||||||
* true bypassing any finally blocks.
|
* 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));
|
JS_ASSERT(regs.sp == StackBase(fp));
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@@ -2607,21 +2619,17 @@ js_Interpret(JSContext *cx)
|
|||||||
* frame pc.
|
* frame pc.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(inlineCallCount == 0);
|
JS_ASSERT(inlineCallCount == 0);
|
||||||
JS_ASSERT(fp->regs == ®s);
|
JS_ASSERT(cx->regs == ®s);
|
||||||
|
*prevContextRegs = regs;
|
||||||
|
cx->setCurrentRegs(prevContextRegs);
|
||||||
|
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
if (TRACE_RECORDER(cx))
|
if (TRACE_RECORDER(cx))
|
||||||
AbortRecording(cx, "recording out of js_Interpret");
|
AbortRecording(cx, "recording out of js_Interpret");
|
||||||
#endif
|
#endif
|
||||||
#if JS_HAS_GENERATORS
|
|
||||||
if (JS_UNLIKELY(fp->isGenerator())) {
|
JS_ASSERT_IF(!fp->isGenerator(), !fp->blockChain);
|
||||||
cx->generatorFor(fp)->savedRegs = regs;
|
JS_ASSERT_IF(!fp->isGenerator(), !js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
|
||||||
} else
|
|
||||||
#endif /* JS_HAS_GENERATORS */
|
|
||||||
{
|
|
||||||
JS_ASSERT(!fp->blockChain);
|
|
||||||
JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
|
|
||||||
}
|
|
||||||
fp->regs = NULL;
|
|
||||||
|
|
||||||
/* Undo the remaining effects committed on entry to js_Interpret. */
|
/* Undo the remaining effects committed on entry to js_Interpret. */
|
||||||
if (script->staticLevel < JS_DISPLAY_SIZE)
|
if (script->staticLevel < JS_DISPLAY_SIZE)
|
||||||
|
|||||||
@@ -80,13 +80,10 @@ enum JSFrameFlags {
|
|||||||
* function.
|
* function.
|
||||||
*
|
*
|
||||||
* NB: This struct is manually initialized in jsinterp.c and jsiter.c. If you
|
* 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
|
* add new members, update both files.
|
||||||
* sharp* and xml* members should be moved onto the stack as local variables
|
|
||||||
* with well-known slots, if possible.
|
|
||||||
*/
|
*/
|
||||||
struct JSStackFrame
|
struct JSStackFrame
|
||||||
{
|
{
|
||||||
JSFrameRegs *regs;
|
|
||||||
jsbytecode *imacpc; /* null or interpreter macro call pc */
|
jsbytecode *imacpc; /* null or interpreter macro call pc */
|
||||||
JSObject *callobj; /* lazily created Call object */
|
JSObject *callobj; /* lazily created Call object */
|
||||||
jsval argsobj; /* lazily created arguments object, must be
|
jsval argsobj; /* lazily created arguments object, must be
|
||||||
@@ -102,6 +99,10 @@ struct JSStackFrame
|
|||||||
/* Maintained by StackSpace operations */
|
/* Maintained by StackSpace operations */
|
||||||
JSStackFrame *down; /* previous frame, part of
|
JSStackFrame *down; /* previous frame, part of
|
||||||
stack layout invariant */
|
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
|
* We can't determine in advance which local variables can live on
|
||||||
@@ -150,12 +151,9 @@ struct JSStackFrame
|
|||||||
script->staticLevel */
|
script->staticLevel */
|
||||||
|
|
||||||
/* Members only needed for inline calls. */
|
/* Members only needed for inline calls. */
|
||||||
JSFrameRegs callerRegs; /* caller's regs for inline call */
|
|
||||||
void *hookData; /* debugger call hook data */
|
void *hookData; /* debugger call hook data */
|
||||||
JSVersion callerVersion; /* dynamic version of calling script */
|
JSVersion callerVersion; /* dynamic version of calling script */
|
||||||
|
|
||||||
inline void assertValidStackDepth(uintN depth);
|
|
||||||
|
|
||||||
void putActivationObjects(JSContext *cx) {
|
void putActivationObjects(JSContext *cx) {
|
||||||
/*
|
/*
|
||||||
* The order of calls here is important as js_PutCallObject needs to
|
* 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 {
|
jsval *argEnd() const {
|
||||||
return (jsval *)this;
|
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 *
|
static JS_INLINE jsval *
|
||||||
StackBase(JSStackFrame *fp)
|
StackBase(JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return fp->slots() + fp->script->nfixed;
|
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
|
static JS_INLINE uintN
|
||||||
GlobalVarCount(JSStackFrame *fp)
|
GlobalVarCount(JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
@@ -433,8 +414,7 @@ js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth);
|
|||||||
* fp->sp on return to stackDepth.
|
* fp->sp on return to stackDepth.
|
||||||
*/
|
*/
|
||||||
extern JS_REQUIRES_STACK JSBool
|
extern JS_REQUIRES_STACK JSBool
|
||||||
js_UnwindScope(JSContext *cx, JSStackFrame *fp, jsint stackDepth,
|
js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind);
|
||||||
JSBool normalUnwind);
|
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_OnUnknownMethod(JSContext *cx, jsval *vp);
|
js_OnUnknownMethod(JSContext *cx, jsval *vp);
|
||||||
|
|||||||
@@ -74,6 +74,7 @@
|
|||||||
#include "jsxml.h"
|
#include "jsxml.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "jscntxtinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsstrinlines.h"
|
#include "jsstrinlines.h"
|
||||||
|
|
||||||
@@ -794,14 +795,13 @@ js_NewGenerator(JSContext *cx)
|
|||||||
/* Initialize JSGenerator. */
|
/* Initialize JSGenerator. */
|
||||||
gen->obj = obj;
|
gen->obj = obj;
|
||||||
gen->state = JSGEN_NEWBORN;
|
gen->state = JSGEN_NEWBORN;
|
||||||
gen->savedRegs.pc = fp->regs->pc;
|
gen->savedRegs.pc = cx->regs->pc;
|
||||||
JS_ASSERT(fp->regs->sp == fp->slots() + fp->script->nfixed);
|
JS_ASSERT(cx->regs->sp == fp->slots() + fp->script->nfixed);
|
||||||
gen->savedRegs.sp = slots + fp->script->nfixed;
|
gen->savedRegs.sp = slots + fp->script->nfixed;
|
||||||
gen->vplen = vplen;
|
gen->vplen = vplen;
|
||||||
gen->liveFrame = newfp;
|
gen->liveFrame = newfp;
|
||||||
|
|
||||||
/* Copy generator's stack frame copy in from |cx->fp|. */
|
/* Copy generator's stack frame copy in from |cx->fp|. */
|
||||||
newfp->regs = &gen->savedRegs;
|
|
||||||
newfp->imacpc = NULL;
|
newfp->imacpc = NULL;
|
||||||
newfp->callobj = fp->callobj;
|
newfp->callobj = fp->callobj;
|
||||||
if (fp->callobj) { /* Steal call object. */
|
if (fp->callobj) { /* Steal call object. */
|
||||||
@@ -922,7 +922,6 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
|||||||
memcpy(vp, genVp, usedBefore * sizeof(jsval));
|
memcpy(vp, genVp, usedBefore * sizeof(jsval));
|
||||||
fp->flags &= ~JSFRAME_FLOATING_GENERATOR;
|
fp->flags &= ~JSFRAME_FLOATING_GENERATOR;
|
||||||
fp->argv = vp + 2;
|
fp->argv = vp + 2;
|
||||||
fp->regs = &gen->savedRegs;
|
|
||||||
gen->savedRegs.sp = fp->slots() + (gen->savedRegs.sp - genfp->slots());
|
gen->savedRegs.sp = fp->slots() + (gen->savedRegs.sp - genfp->slots());
|
||||||
JS_ASSERT(uintN(gen->savedRegs.sp - fp->slots()) <= fp->script->nslots);
|
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. */
|
(void)cx->enterGenerator(gen); /* OOM check above. */
|
||||||
|
|
||||||
/* Officially push |fp|. |frame|'s destructor pops. */
|
/* 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);
|
ok = js_Interpret(cx);
|
||||||
|
|
||||||
|
|||||||
@@ -1023,9 +1023,10 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
|
|||||||
return principals->codebase;
|
return principals->codebase;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (caller->regs && js_GetOpcode(cx, caller->script, caller->regs->pc) == JSOP_EVAL) {
|
jsbytecode *pc = caller->pc(cx);
|
||||||
JS_ASSERT(js_GetOpcode(cx, caller->script, caller->regs->pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
|
if (pc && js_GetOpcode(cx, caller->script, pc) == JSOP_EVAL) {
|
||||||
*linenop = GET_UINT16(caller->regs->pc + JSOP_EVAL_LENGTH);
|
JS_ASSERT(js_GetOpcode(cx, caller->script, pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
|
||||||
|
*linenop = GET_UINT16(pc + JSOP_EVAL_LENGTH);
|
||||||
} else {
|
} else {
|
||||||
*linenop = js_FramePCToLineNumber(cx, caller);
|
*linenop = js_FramePCToLineNumber(cx, caller);
|
||||||
}
|
}
|
||||||
@@ -1069,7 +1070,8 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp)
|
|||||||
return JS_FALSE;
|
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
|
* 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);
|
JS_ASSERT_NOT_ON_TRACE(cx);
|
||||||
|
|
||||||
JSStackFrame *fp;
|
|
||||||
jsbytecode *pc;
|
jsbytecode *pc;
|
||||||
const JSCodeSpec *cs;
|
const JSCodeSpec *cs;
|
||||||
uint32 format;
|
uint32 format;
|
||||||
uintN flags = 0;
|
uintN flags = 0;
|
||||||
|
|
||||||
fp = js_GetTopStackFrame(cx);
|
JSStackFrame *const fp = js_GetTopStackFrame(cx);
|
||||||
if (!fp || !fp->regs)
|
if (!fp || !(pc = cx->regs->pc))
|
||||||
return defaultFlags;
|
return defaultFlags;
|
||||||
pc = fp->regs->pc;
|
|
||||||
cs = &js_CodeSpec[js_GetOpcode(cx, fp->script, pc)];
|
cs = &js_CodeSpec[js_GetOpcode(cx, fp->script, pc)];
|
||||||
format = cs->format;
|
format = cs->format;
|
||||||
if (JOF_MODE(format) != JOF_NAME)
|
if (JOF_MODE(format) != JOF_NAME)
|
||||||
@@ -3010,15 +3010,11 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
|
|||||||
JS_REQUIRES_STACK JSBool
|
JS_REQUIRES_STACK JSBool
|
||||||
js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp;
|
|
||||||
JSObject *obj;
|
|
||||||
uintN depth, count;
|
|
||||||
|
|
||||||
/* Blocks have one fixed slot available for the first local.*/
|
/* Blocks have one fixed slot available for the first local.*/
|
||||||
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2);
|
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2);
|
||||||
|
|
||||||
fp = cx->fp;
|
JSStackFrame *const fp = cx->fp;
|
||||||
obj = fp->scopeChain;
|
JSObject *obj = fp->scopeChain;
|
||||||
JS_ASSERT(obj->getClass() == &js_BlockClass);
|
JS_ASSERT(obj->getClass() == &js_BlockClass);
|
||||||
JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp));
|
JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp));
|
||||||
JS_ASSERT(OBJ_IS_CLONED_BLOCK(obj));
|
JS_ASSERT(OBJ_IS_CLONED_BLOCK(obj));
|
||||||
@@ -3035,10 +3031,10 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
|||||||
JS_ASSERT(obj->numSlots() == JS_INITIAL_NSLOTS);
|
JS_ASSERT(obj->numSlots() == JS_INITIAL_NSLOTS);
|
||||||
|
|
||||||
/* The block and its locals must be on the current stack for GC safety. */
|
/* The block and its locals must be on the current stack for GC safety. */
|
||||||
depth = OBJ_BLOCK_DEPTH(cx, obj);
|
uintN depth = OBJ_BLOCK_DEPTH(cx, obj);
|
||||||
count = OBJ_BLOCK_COUNT(cx, obj);
|
uintN count = OBJ_BLOCK_COUNT(cx, obj);
|
||||||
JS_ASSERT(depth <= (size_t) (fp->regs->sp - StackBase(fp)));
|
JS_ASSERT(depth <= (size_t) (cx->regs->sp - StackBase(fp)));
|
||||||
JS_ASSERT(count <= (size_t) (fp->regs->sp - StackBase(fp) - depth));
|
JS_ASSERT(count <= (size_t) (cx->regs->sp - StackBase(fp) - depth));
|
||||||
|
|
||||||
/* See comments in CheckDestructuring from jsparse.cpp. */
|
/* See comments in CheckDestructuring from jsparse.cpp. */
|
||||||
JS_ASSERT(count >= 1);
|
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_FRIEND_API(bool)
|
||||||
js_CheckUndeclaredVarAssignment(JSContext *cx, jsval propname)
|
js_CheckUndeclaredVarAssignment(JSContext *cx, jsval propname)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp = js_GetTopStackFrame(cx);
|
JSStackFrame *const fp = js_GetTopStackFrame(cx);
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -6418,32 +6414,42 @@ MaybeDumpValue(const char *name, jsval v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JS_FRIEND_API(void)
|
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);
|
fprintf(stderr, "JSStackFrame at %p\n", (void *) fp);
|
||||||
if (fp->argv)
|
if (fp->argv) {
|
||||||
|
fprintf(stderr, "callee: ");
|
||||||
dumpValue(fp->argv[-2]);
|
dumpValue(fp->argv[-2]);
|
||||||
else
|
} else {
|
||||||
fprintf(stderr, "global frame, no callee");
|
fprintf(stderr, "global frame, no callee");
|
||||||
|
}
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
|
|
||||||
if (fp->script)
|
if (fp->script)
|
||||||
fprintf(stderr, "file %s line %u\n", fp->script->filename, (unsigned) fp->script->lineno);
|
fprintf(stderr, "file %s line %u\n", fp->script->filename, (unsigned) fp->script->lineno);
|
||||||
|
|
||||||
if (fp->regs) {
|
if (jsbytecode *pc = i.pc()) {
|
||||||
if (!fp->regs->pc) {
|
|
||||||
fprintf(stderr, "*** regs && !regs->pc, skipping frame\n\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!fp->script) {
|
if (!fp->script) {
|
||||||
fprintf(stderr, "*** regs && !script, skipping frame\n\n");
|
fprintf(stderr, "*** pc && !script, skipping frame\n\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
jsbytecode *pc = fp->regs->pc;
|
|
||||||
sp = fp->regs->sp;
|
|
||||||
if (fp->imacpc) {
|
if (fp->imacpc) {
|
||||||
fprintf(stderr, " pc in imacro at %p\n called from ", pc);
|
fprintf(stderr, " pc in imacro at %p\n called from ", pc);
|
||||||
pc = fp->imacpc;
|
pc = fp->imacpc;
|
||||||
@@ -6453,19 +6459,15 @@ js_DumpStackFrame(JSStackFrame *fp)
|
|||||||
fprintf(stderr, "pc = %p\n", pc);
|
fprintf(stderr, "pc = %p\n", pc);
|
||||||
fprintf(stderr, " current op: %s\n", js_CodeName[*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, " slots: %p\n", (void *) fp->slots());
|
||||||
fprintf(stderr, " sp: %p = slots + %u\n", (void *) sp, (unsigned) (sp - fp->slots()));
|
fprintf(stderr, " sp: %p = slots + %u\n", (void *) sp, (unsigned) (sp - fp->slots()));
|
||||||
if (sp - fp->slots() < 10000) { // sanity
|
if (sp - fp->slots() < 10000) { // sanity
|
||||||
for (jsval *p = fp->slots(); p < sp; p++) {
|
for (jsval *p = fp->slots(); p < sp; p++) {
|
||||||
fprintf(stderr, " %p: ", (void *) p);
|
fprintf(stderr, " %p: ", (void *) p);
|
||||||
dumpValue(*p);
|
dumpValue(*p);
|
||||||
fputc('\n', stderr);
|
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);
|
fprintf(stderr, " argv: %p (argc: %u)\n", (void *) fp->argv, (unsigned) fp->argc);
|
||||||
MaybeDumpObject("callobj", fp->callobj);
|
MaybeDumpObject("callobj", fp->callobj);
|
||||||
|
|||||||
@@ -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_DumpValue(jsval val);
|
||||||
JS_FRIEND_API(void) js_DumpId(jsid id);
|
JS_FRIEND_API(void) js_DumpId(jsid id);
|
||||||
JS_FRIEND_API(void) js_DumpObject(JSObject *obj);
|
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
|
#endif
|
||||||
|
|
||||||
extern uintN
|
extern uintN
|
||||||
|
|||||||
@@ -1993,7 +1993,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||||||
*/
|
*/
|
||||||
fp = js_GetScriptedCaller(cx, NULL);
|
fp = js_GetScriptedCaller(cx, NULL);
|
||||||
format = cs->format;
|
format = cs->format;
|
||||||
if (((fp && fp->regs && pc == fp->regs->pc) ||
|
if (((fp && pc == fp->pc(cx)) ||
|
||||||
(pc == startpc && nuses != 0)) &&
|
(pc == startpc && nuses != 0)) &&
|
||||||
format & (JOF_SET|JOF_DEL|JOF_INCDEC|JOF_FOR|JOF_VARPROP)) {
|
format & (JOF_SET|JOF_DEL|JOF_INCDEC|JOF_FOR|JOF_VARPROP)) {
|
||||||
mode = JOF_MODE(format);
|
mode = JOF_MODE(format);
|
||||||
@@ -5102,26 +5102,25 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
|
|||||||
JSStackFrame *fp;
|
JSStackFrame *fp;
|
||||||
jsbytecode *pc;
|
jsbytecode *pc;
|
||||||
JSScript *script;
|
JSScript *script;
|
||||||
JSFrameRegs *regs;
|
|
||||||
intN pcdepth;
|
|
||||||
jsval *sp, *stackBase;
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
JS_ASSERT(spindex < 0 ||
|
JS_ASSERT(spindex < 0 ||
|
||||||
spindex == JSDVG_IGNORE_STACK ||
|
spindex == JSDVG_IGNORE_STACK ||
|
||||||
spindex == JSDVG_SEARCH_STACK);
|
spindex == JSDVG_SEARCH_STACK);
|
||||||
|
|
||||||
fp = js_GetScriptedCaller(cx, NULL);
|
LeaveTrace(cx);
|
||||||
if (!fp || !fp->regs || !fp->regs->sp)
|
|
||||||
|
/* Get scripted caller */
|
||||||
|
FrameRegsIter i(cx);
|
||||||
|
while (!i.done() && !i.fp()->script)
|
||||||
|
++i;
|
||||||
|
|
||||||
|
if (i.done() || !i.pc())
|
||||||
goto do_fallback;
|
goto do_fallback;
|
||||||
|
|
||||||
|
fp = i.fp();
|
||||||
script = fp->script;
|
script = fp->script;
|
||||||
regs = fp->regs;
|
pc = fp->imacpc ? fp->imacpc : i.pc();
|
||||||
pc = fp->imacpc ? fp->imacpc : regs->pc;
|
JS_ASSERT(pc >= script->main && pc < script->code + script->length);
|
||||||
if (pc < script->main || script->code + script->length <= pc) {
|
|
||||||
JS_NOT_REACHED("bug");
|
|
||||||
goto do_fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spindex != JSDVG_IGNORE_STACK) {
|
if (spindex != JSDVG_IGNORE_STACK) {
|
||||||
jsbytecode **pcstack;
|
jsbytecode **pcstack;
|
||||||
@@ -5134,7 +5133,7 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
|
|||||||
cx->malloc(StackDepth(script) * sizeof *pcstack);
|
cx->malloc(StackDepth(script) * sizeof *pcstack);
|
||||||
if (!pcstack)
|
if (!pcstack)
|
||||||
return NULL;
|
return NULL;
|
||||||
pcdepth = ReconstructPCStack(cx, script, pc, pcstack);
|
intN pcdepth = ReconstructPCStack(cx, script, pc, pcstack);
|
||||||
if (pcdepth < 0)
|
if (pcdepth < 0)
|
||||||
goto release_pcstack;
|
goto release_pcstack;
|
||||||
|
|
||||||
@@ -5150,8 +5149,8 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
|
|||||||
* calculated value matching v under assumption that it is
|
* calculated value matching v under assumption that it is
|
||||||
* it that caused exception, see bug 328664.
|
* it that caused exception, see bug 328664.
|
||||||
*/
|
*/
|
||||||
stackBase = StackBase(fp);
|
jsval *stackBase = StackBase(fp);
|
||||||
sp = regs->sp;
|
jsval *sp = i.sp();
|
||||||
do {
|
do {
|
||||||
if (sp == stackBase) {
|
if (sp == stackBase) {
|
||||||
pcdepth = -1;
|
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;
|
jsbytecode* imacpc = fp->imacpc;
|
||||||
if (imacpc) {
|
if (imacpc) {
|
||||||
regs->pc = imacpc;
|
if (fp == cx->fp)
|
||||||
|
cx->regs->pc = imacpc;
|
||||||
|
else
|
||||||
|
fp->savedPC = imacpc;
|
||||||
fp->imacpc = NULL;
|
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
|
* FIXME: bug 489843. Stack reconstruction may have returned a pc
|
||||||
* value *inside* an imacro; this would confuse the decompiler.
|
* value *inside* an imacro; this would confuse the decompiler.
|
||||||
*/
|
*/
|
||||||
|
char *name;
|
||||||
if (imacpc && size_t(pc - script->code) >= script->length)
|
if (imacpc && size_t(pc - script->code) >= script->length)
|
||||||
name = FAILED_EXPRESSION_DECOMPILER;
|
name = FAILED_EXPRESSION_DECOMPILER;
|
||||||
else
|
else
|
||||||
name = DecompileExpression(cx, script, fp->fun, pc);
|
name = DecompileExpression(cx, script, fp->fun, pc);
|
||||||
|
|
||||||
if (imacpc) {
|
if (imacpc) {
|
||||||
regs->pc = savepc;
|
if (fp == cx->fp)
|
||||||
|
cx->regs->pc = imacpc;
|
||||||
|
else
|
||||||
|
fp->savedPC = savepc;
|
||||||
fp->imacpc = imacpc;
|
fp->imacpc = imacpc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name != FAILED_EXPRESSION_DECOMPILER)
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
if (name != FAILED_EXPRESSION_DECOMPILER)
|
|
||||||
return name;
|
|
||||||
|
|
||||||
do_fallback:
|
do_fallback:
|
||||||
if (!fallback) {
|
if (!fallback) {
|
||||||
|
|||||||
@@ -224,7 +224,6 @@ BEGIN_CASE(JSOP_STOP)
|
|||||||
{
|
{
|
||||||
JS_ASSERT(!fp->blockChain);
|
JS_ASSERT(!fp->blockChain);
|
||||||
JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
|
JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0));
|
||||||
JS_ASSERT(fp->down->regs == &fp->callerRegs);
|
|
||||||
|
|
||||||
if (JS_LIKELY(script->staticLevel < JS_DISPLAY_SIZE))
|
if (JS_LIKELY(script->staticLevel < JS_DISPLAY_SIZE))
|
||||||
cx->display[script->staticLevel] = fp->displaySave;
|
cx->display[script->staticLevel] = fp->displaySave;
|
||||||
@@ -277,15 +276,12 @@ BEGIN_CASE(JSOP_STOP)
|
|||||||
JSStackFrame *down = fp->down;
|
JSStackFrame *down = fp->down;
|
||||||
bool recursive = fp->script == down->script;
|
bool recursive = fp->script == down->script;
|
||||||
|
|
||||||
/* Restore caller's registers. */
|
/* Pop the frame. */
|
||||||
regs = fp->callerRegs;
|
|
||||||
regs.sp -= 1 + (size_t) fp->argc;
|
|
||||||
regs.sp[-1] = fp->rval;
|
|
||||||
down->regs = ®s;
|
|
||||||
|
|
||||||
/* Pop |fp| from the context. */
|
|
||||||
cx->stack().popInlineFrame(cx, fp, down);
|
cx->stack().popInlineFrame(cx, fp, down);
|
||||||
|
|
||||||
|
/* Propagate return value before fp is lost. */
|
||||||
|
regs.sp[-1] = fp->rval;
|
||||||
|
|
||||||
/* Sync interpreter registers. */
|
/* Sync interpreter registers. */
|
||||||
fp = cx->fp;
|
fp = cx->fp;
|
||||||
script = fp->script;
|
script = fp->script;
|
||||||
@@ -2071,7 +2067,6 @@ BEGIN_CASE(JSOP_APPLY)
|
|||||||
}
|
}
|
||||||
JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags));
|
JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags));
|
||||||
newfp->thisv = vp[1];
|
newfp->thisv = vp[1];
|
||||||
newfp->regs = NULL;
|
|
||||||
newfp->imacpc = NULL;
|
newfp->imacpc = NULL;
|
||||||
|
|
||||||
/* Push void to initialize local variables. */
|
/* Push void to initialize local variables. */
|
||||||
@@ -2091,16 +2086,15 @@ BEGIN_CASE(JSOP_APPLY)
|
|||||||
js_SetVersion(cx, currentVersion);
|
js_SetVersion(cx, currentVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push the frame and set interpreter registers. */
|
/* Push the frame. */
|
||||||
newfp->callerRegs = regs;
|
stack.pushInlineFrame(cx, fp, regs.pc, newfp);
|
||||||
fp->regs = &newfp->callerRegs;
|
|
||||||
regs.sp = newsp;
|
/* Initializer regs after pushInlineFrame snapshots pc. */
|
||||||
regs.pc = newscript->code;
|
regs.pc = newscript->code;
|
||||||
newfp->regs = ®s;
|
regs.sp = newsp;
|
||||||
stack.pushInlineFrame(cx, fp, newfp);
|
|
||||||
JS_ASSERT(newfp == cx->fp);
|
|
||||||
|
|
||||||
/* Import into locals. */
|
/* Import into locals. */
|
||||||
|
JS_ASSERT(newfp == cx->fp);
|
||||||
fp = newfp;
|
fp = newfp;
|
||||||
script = newscript;
|
script = newscript;
|
||||||
atoms = script->atomMap.vector;
|
atoms = script->atomMap.vector;
|
||||||
@@ -2132,8 +2126,8 @@ BEGIN_CASE(JSOP_APPLY)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else if (fp->script == fp->down->script &&
|
} else if (fp->script == fp->down->script &&
|
||||||
*fp->down->regs->pc == JSOP_CALL &&
|
*fp->down->savedPC == JSOP_CALL &&
|
||||||
*fp->regs->pc == JSOP_TRACE) {
|
*regs.pc == JSOP_TRACE) {
|
||||||
MONITOR_BRANCH(Record_EnterFrame);
|
MONITOR_BRANCH(Record_EnterFrame);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -3195,7 +3189,7 @@ END_CASE(JSOP_HOLE)
|
|||||||
|
|
||||||
BEGIN_CASE(JSOP_NEWARRAY)
|
BEGIN_CASE(JSOP_NEWARRAY)
|
||||||
len = GET_UINT16(regs.pc);
|
len = GET_UINT16(regs.pc);
|
||||||
cx->fp->assertValidStackDepth(len);
|
cx->assertValidStackDepth(len);
|
||||||
obj = js_NewArrayObject(cx, len, regs.sp - len, JS_TRUE);
|
obj = js_NewArrayObject(cx, len, regs.sp - len, JS_TRUE);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
goto error;
|
goto error;
|
||||||
|
|||||||
@@ -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
|
* Optimize the cached vword based on our parameters and the current pc's
|
||||||
* opcode format flags.
|
* opcode format flags.
|
||||||
*/
|
*/
|
||||||
pc = cx->fp->regs->pc;
|
pc = cx->regs->pc;
|
||||||
op = js_GetOpcode(cx, cx->fp->script, pc);
|
op = js_GetOpcode(cx, cx->fp->script, pc);
|
||||||
cs = &js_CodeSpec[op];
|
cs = &js_CodeSpec[op];
|
||||||
kshape = 0;
|
kshape = 0;
|
||||||
|
|||||||
@@ -163,8 +163,8 @@ TraceRecorder::downSnapshot(FrameInfo* downFrame)
|
|||||||
exitTypeMap[i] = typeMap[i];
|
exitTypeMap[i] = typeMap[i];
|
||||||
|
|
||||||
/* Add the return type. */
|
/* Add the return type. */
|
||||||
JS_ASSERT_IF(*cx->fp->regs->pc != JSOP_RETURN, *cx->fp->regs->pc == JSOP_STOP);
|
JS_ASSERT_IF(*cx->regs->pc != JSOP_RETURN, *cx->regs->pc == JSOP_STOP);
|
||||||
if (*cx->fp->regs->pc == JSOP_RETURN)
|
if (*cx->regs->pc == JSOP_RETURN)
|
||||||
exitTypeMap[downPostSlots] = determineSlotType(&stackval(-1));
|
exitTypeMap[downPostSlots] = determineSlotType(&stackval(-1));
|
||||||
else
|
else
|
||||||
exitTypeMap[downPostSlots] = TT_VOID;
|
exitTypeMap[downPostSlots] = TT_VOID;
|
||||||
@@ -198,12 +198,21 @@ TraceRecorder::downSnapshot(FrameInfo* downFrame)
|
|||||||
return exit;
|
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
|
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||||
TraceRecorder::upRecursion()
|
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,
|
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);
|
JS_ASSERT(callDepth == 0);
|
||||||
|
|
||||||
@@ -215,10 +224,10 @@ TraceRecorder::upRecursion()
|
|||||||
if (anchor && (anchor->exitType == RECURSIVE_EMPTY_RP_EXIT ||
|
if (anchor && (anchor->exitType == RECURSIVE_EMPTY_RP_EXIT ||
|
||||||
anchor->exitType == RECURSIVE_SLURP_MISMATCH_EXIT ||
|
anchor->exitType == RECURSIVE_SLURP_MISMATCH_EXIT ||
|
||||||
anchor->exitType == RECURSIVE_SLURP_FAIL_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;
|
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
|
* Need to compute this from the down frame, since the stack could have
|
||||||
* moved on this one.
|
* 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);
|
JS_ASSERT(cx->fp->argc == cx->fp->down->argc);
|
||||||
fi->set_argc(uint16(cx->fp->argc), false);
|
fi->set_argc(uint16(cx->fp->argc), false);
|
||||||
fi->callerHeight = downPostSlots;
|
fi->callerHeight = downPostSlots;
|
||||||
@@ -308,7 +317,7 @@ TraceRecorder::upRecursion()
|
|||||||
exit = downSnapshot(fi);
|
exit = downSnapshot(fi);
|
||||||
|
|
||||||
LIns* rval_ins;
|
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);
|
JS_ASSERT(!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT);
|
||||||
rval_ins = get(&stackval(-1));
|
rval_ins = get(&stackval(-1));
|
||||||
JS_ASSERT(rval_ins);
|
JS_ASSERT(rval_ins);
|
||||||
@@ -318,7 +327,7 @@ TraceRecorder::upRecursion()
|
|||||||
|
|
||||||
TraceType returnType = exit->stackTypeMap()[downPostSlots];
|
TraceType returnType = exit->stackTypeMap()[downPostSlots];
|
||||||
if (returnType == TT_INT32) {
|
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(determineSlotType(&stackval(-1)) == TT_INT32);
|
||||||
JS_ASSERT(isPromoteInt(rval_ins));
|
JS_ASSERT(isPromoteInt(rval_ins));
|
||||||
rval_ins = demote(lir, rval_ins);
|
rval_ins = demote(lir, rval_ins);
|
||||||
@@ -327,7 +336,7 @@ TraceRecorder::upRecursion()
|
|||||||
UpRecursiveSlotMap slotMap(*this, downPostSlots, rval_ins);
|
UpRecursiveSlotMap slotMap(*this, downPostSlots, rval_ins);
|
||||||
for (unsigned i = 0; i < downPostSlots; i++)
|
for (unsigned i = 0; i < downPostSlots; i++)
|
||||||
slotMap.addSlot(exit->stackType(i));
|
slotMap.addSlot(exit->stackType(i));
|
||||||
if (*cx->fp->regs->pc == JSOP_RETURN)
|
if (*cx->regs->pc == JSOP_RETURN)
|
||||||
slotMap.addSlot(&stackval(-1));
|
slotMap.addSlot(&stackval(-1));
|
||||||
else
|
else
|
||||||
slotMap.addSlot(TT_VOID);
|
slotMap.addSlot(TT_VOID);
|
||||||
@@ -386,7 +395,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
|
|||||||
unsigned frameDepth;
|
unsigned frameDepth;
|
||||||
unsigned downPostSlots;
|
unsigned downPostSlots;
|
||||||
|
|
||||||
JSStackFrame* fp = cx->fp;
|
FrameRegsIter i(cx);
|
||||||
LIns* fp_ins =
|
LIns* fp_ins =
|
||||||
addName(lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp), ACC_OTHER), "fp");
|
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) {
|
if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) {
|
||||||
fp_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, down), ACC_OTHER),
|
fp_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, down), ACC_OTHER),
|
||||||
"downFp");
|
"downFp");
|
||||||
fp = fp->down;
|
++i;
|
||||||
|
|
||||||
argv_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, argv), ACC_OTHER),
|
argv_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, argv), ACC_OTHER),
|
||||||
"argv");
|
"argv");
|
||||||
@@ -427,14 +436,12 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
|
|||||||
RECURSIVE_LOOP_EXIT);
|
RECURSIVE_LOOP_EXIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fp->down->regs->pc should be == pc. */
|
/* fp->down->savedPC should be == pc. */
|
||||||
guard(true,
|
guard(true,
|
||||||
lir->ins2(LIR_eqp,
|
lir->ins2(LIR_eqp,
|
||||||
lir->insLoad(LIR_ldp,
|
addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, savedPC),
|
||||||
addName(lir->insLoad(LIR_ldp, fp_ins,
|
ACC_OTHER),
|
||||||
offsetof(JSStackFrame, regs), ACC_OTHER),
|
"savedPC"),
|
||||||
"regs"),
|
|
||||||
offsetof(JSFrameRegs, pc), ACC_OTHER),
|
|
||||||
INS_CONSTPTR(return_pc)),
|
INS_CONSTPTR(return_pc)),
|
||||||
RECURSIVE_SLURP_MISMATCH_EXIT);
|
RECURSIVE_SLURP_MISMATCH_EXIT);
|
||||||
|
|
||||||
@@ -489,13 +496,13 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
|
|||||||
* thrown away.
|
* thrown away.
|
||||||
*/
|
*/
|
||||||
TraceType* typeMap = exit->stackTypeMap();
|
TraceType* typeMap = exit->stackTypeMap();
|
||||||
jsbytecode* oldpc = cx->fp->regs->pc;
|
jsbytecode* oldpc = cx->regs->pc;
|
||||||
cx->fp->regs->pc = exit->pc;
|
cx->regs->pc = exit->pc;
|
||||||
captureStackTypes(frameDepth, typeMap);
|
captureStackTypes(frameDepth, typeMap);
|
||||||
cx->fp->regs->pc = oldpc;
|
cx->regs->pc = oldpc;
|
||||||
if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) {
|
if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) {
|
||||||
JS_ASSERT_IF(*cx->fp->regs->pc != JSOP_RETURN, *cx->fp->regs->pc == JSOP_STOP);
|
JS_ASSERT_IF(*cx->regs->pc != JSOP_RETURN, *cx->regs->pc == JSOP_STOP);
|
||||||
if (*cx->fp->regs->pc == JSOP_RETURN)
|
if (*cx->regs->pc == JSOP_RETURN)
|
||||||
typeMap[downPostSlots] = determineSlotType(&stackval(-1));
|
typeMap[downPostSlots] = determineSlotType(&stackval(-1));
|
||||||
else
|
else
|
||||||
typeMap[downPostSlots] = TT_VOID;
|
typeMap[downPostSlots] = TT_VOID;
|
||||||
@@ -522,10 +529,10 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
|
|||||||
|
|
||||||
if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) {
|
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.
|
* 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);
|
JS_ASSERT(op == JSOP_RETURN || op == JSOP_STOP);
|
||||||
|
|
||||||
if (op == JSOP_RETURN) {
|
if (op == JSOP_RETURN) {
|
||||||
@@ -575,6 +582,8 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
|
|||||||
info.slurpFailSlot = (anchor && anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT) ?
|
info.slurpFailSlot = (anchor && anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT) ?
|
||||||
anchor->slurpFailSlot : 0;
|
anchor->slurpFailSlot : 0;
|
||||||
|
|
||||||
|
JSStackFrame *const fp = i.fp();
|
||||||
|
|
||||||
/* callee */
|
/* callee */
|
||||||
slurpSlot(lir->insLoad(LIR_ldp, argv_ins, -2 * ptrdiff_t(sizeof(jsval)), ACC_OTHER),
|
slurpSlot(lir->insLoad(LIR_ldp, argv_ins, -2 * ptrdiff_t(sizeof(jsval)), ACC_OTHER),
|
||||||
&fp->argv[-2],
|
&fp->argv[-2],
|
||||||
@@ -612,7 +621,8 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
|
|||||||
slots_ins,
|
slots_ins,
|
||||||
INS_CONSTWORD(nfixed * sizeof(jsval))),
|
INS_CONSTWORD(nfixed * sizeof(jsval))),
|
||||||
"stackBase");
|
"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)
|
if (anchor && anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT)
|
||||||
limit--;
|
limit--;
|
||||||
else
|
else
|
||||||
@@ -634,7 +644,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
|
|||||||
RecursiveSlotMap slotMap(*this, downPostSlots, rval_ins);
|
RecursiveSlotMap slotMap(*this, downPostSlots, rval_ins);
|
||||||
for (unsigned i = 0; i < downPostSlots; i++)
|
for (unsigned i = 0; i < downPostSlots; i++)
|
||||||
slotMap.addSlot(typeMap[i]);
|
slotMap.addSlot(typeMap[i]);
|
||||||
if (*cx->fp->regs->pc == JSOP_RETURN)
|
if (*cx->regs->pc == JSOP_RETURN)
|
||||||
slotMap.addSlot(&stackval(-1), typeMap[downPostSlots]);
|
slotMap.addSlot(&stackval(-1), typeMap[downPostSlots]);
|
||||||
else
|
else
|
||||||
slotMap.addSlot(TT_VOID);
|
slotMap.addSlot(TT_VOID);
|
||||||
|
|||||||
@@ -4783,7 +4783,7 @@ MatchRegExp(REGlobalData *gData, REMatchState *x)
|
|||||||
"entering REGEXP trace at %s:%u@%u, code: %p\n",
|
"entering REGEXP trace at %s:%u@%u, code: %p\n",
|
||||||
caller ? caller->script->filename : "<unknown>",
|
caller ? caller->script->filename : "<unknown>",
|
||||||
caller ? js_FramePCToLineNumber(gData->cx, caller) : 0,
|
caller ? js_FramePCToLineNumber(gData->cx, caller) : 0,
|
||||||
caller ? FramePCOffset(caller) : 0,
|
caller ? FramePCOffset(gData->cx, caller) : 0,
|
||||||
JS_FUNC_TO_DATA_PTR(void *, native));
|
JS_FUNC_TO_DATA_PTR(void *, native));
|
||||||
})
|
})
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1312,7 +1312,7 @@ js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc)
|
|||||||
uintN
|
uintN
|
||||||
js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp)
|
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
|
uintN
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1754,7 +1754,6 @@ ParseXMLSource(JSContext *cx, JSString *src)
|
|||||||
JSXML *xml;
|
JSXML *xml;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
uintN lineno;
|
uintN lineno;
|
||||||
JSStackFrame *fp;
|
|
||||||
JSOp op;
|
JSOp op;
|
||||||
JSParseNode *pn;
|
JSParseNode *pn;
|
||||||
JSXMLArray nsarray;
|
JSXMLArray nsarray;
|
||||||
@@ -1797,13 +1796,16 @@ ParseXMLSource(JSContext *cx, JSString *src)
|
|||||||
&dstlen);
|
&dstlen);
|
||||||
chars [offset + dstlen] = 0;
|
chars [offset + dstlen] = 0;
|
||||||
|
|
||||||
|
LeaveTrace(cx);
|
||||||
xml = NULL;
|
xml = NULL;
|
||||||
for (fp = js_GetTopStackFrame(cx); fp && !fp->regs; fp = fp->down)
|
FrameRegsIter i(cx);
|
||||||
JS_ASSERT(!fp->script);
|
for (; !i.done() && !i.pc(); ++i)
|
||||||
|
JS_ASSERT(!i.fp()->script);
|
||||||
filename = NULL;
|
filename = NULL;
|
||||||
lineno = 1;
|
lineno = 1;
|
||||||
if (fp) {
|
if (!i.done()) {
|
||||||
op = (JSOp) *fp->regs->pc;
|
JSStackFrame *fp = i.fp();
|
||||||
|
op = (JSOp) *i.pc();
|
||||||
if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) {
|
if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) {
|
||||||
filename = fp->script->filename;
|
filename = fp->script->filename;
|
||||||
lineno = js_FramePCToLineNumber(cx, fp);
|
lineno = js_FramePCToLineNumber(cx, fp);
|
||||||
@@ -7717,7 +7719,8 @@ js_StepXMLListFilter(JSContext *cx, JSBool initialized)
|
|||||||
JSXML *xml, *list;
|
JSXML *xml, *list;
|
||||||
JSXMLFilter *filter;
|
JSXMLFilter *filter;
|
||||||
|
|
||||||
sp = js_GetTopStackFrame(cx)->regs->sp;
|
LeaveTrace(cx);
|
||||||
|
sp = cx->regs->sp;
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
/*
|
/*
|
||||||
* We haven't iterated yet, so initialize the filter based on the
|
* We haven't iterated yet, so initialize the filter based on the
|
||||||
|
|||||||
@@ -3023,7 +3023,7 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||||||
ok = JS_EvaluateUCScript(scx, sobj, src, srclen,
|
ok = JS_EvaluateUCScript(scx, sobj, src, srclen,
|
||||||
fp->script->filename,
|
fp->script->filename,
|
||||||
JS_PCToLineNumber(cx, fp->script,
|
JS_PCToLineNumber(cx, fp->script,
|
||||||
fp->regs->pc),
|
fp->pc(cx)),
|
||||||
rval);
|
rval);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3061,13 +3061,13 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
|
|||||||
|
|
||||||
JS_ASSERT(cx->fp);
|
JS_ASSERT(cx->fp);
|
||||||
|
|
||||||
JSStackFrame *fp = cx->fp;
|
FrameRegsIter fi(cx);
|
||||||
for (uint32 i = 0; i < upCount; ++i) {
|
for (uint32 i = 0; i < upCount; ++i, ++fi) {
|
||||||
if (!fp->down)
|
if (!fi.fp()->down)
|
||||||
break;
|
break;
|
||||||
fp = fp->down;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSStackFrame *const fp = fi.fp();
|
||||||
if (!fp->script) {
|
if (!fp->script) {
|
||||||
JS_ReportError(cx, "cannot eval in non-script frame");
|
JS_ReportError(cx, "cannot eval in non-script frame");
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
@@ -3080,7 +3080,7 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
|
|||||||
JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, str->chars(), str->length(),
|
JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, str->chars(), str->length(),
|
||||||
fp->script->filename,
|
fp->script->filename,
|
||||||
JS_PCToLineNumber(cx, fp->script,
|
JS_PCToLineNumber(cx, fp->script,
|
||||||
fp->regs->pc),
|
fi.pc()),
|
||||||
vp);
|
vp);
|
||||||
|
|
||||||
if (saveCurrent)
|
if (saveCurrent)
|
||||||
|
|||||||
Reference in New Issue
Block a user