Bug 539144 - Make formal args a jit-time const offset from fp; rm argv/argc/thisv/script/callobj (r=brendan,dvander)

This commit is contained in:
Luke Wagner 2010-08-09 22:43:33 -07:00
Родитель de7daf410d
Коммит dc78a5f3d3
64 изменённых файлов: 3619 добавлений и 3236 удалений

Просмотреть файл

@ -5432,7 +5432,7 @@ nsContentUtils::CanAccessNativeAnon()
// Some code is running, we can't make the assumption, as above, but we // Some code is running, we can't make the assumption, as above, but we
// can't use a native frame, so clear fp. // can't use a native frame, so clear fp.
fp = nsnull; fp = nsnull;
} else if (!fp->hasScript()) { } else if (!JS_IsScriptFrame(cx, fp)) {
fp = nsnull; fp = nsnull;
} }
@ -5447,8 +5447,8 @@ nsContentUtils::CanAccessNativeAnon()
// if they've been cloned into less privileged contexts. // if they've been cloned into less privileged contexts.
static const char prefix[] = "chrome://global/"; static const char prefix[] = "chrome://global/";
const char *filename; const char *filename;
if (fp && fp->hasScript() && if (fp && JS_IsScriptFrame(cx, fp) &&
(filename = fp->getScript()->filename) && (filename = JS_GetFrameScript(cx, fp)->filename) &&
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) { !strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
return PR_TRUE; return PR_TRUE;
} }

Просмотреть файл

@ -90,6 +90,7 @@
#include "jsatominlines.h" #include "jsatominlines.h"
#include "jscntxtinlines.h" #include "jscntxtinlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jsscopeinlines.h" #include "jsscopeinlines.h"
#include "jscntxtinlines.h" #include "jscntxtinlines.h"
@ -1795,7 +1796,7 @@ JS_GetGlobalForScopeChain(JSContext *cx)
VOUCH_DOES_NOT_REQUIRE_STACK(); VOUCH_DOES_NOT_REQUIRE_STACK();
if (cx->hasfp()) if (cx->hasfp())
return cx->fp()->getScopeChain()->getGlobal(); return cx->fp()->scopeChain().getGlobal();
JSObject *scope = cx->globalObject; JSObject *scope = cx->globalObject;
if (!scope) { if (!scope) {
@ -4760,7 +4761,7 @@ JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv)
// of object to create, create it, and clamp the return value to an object, // of object to create, create it, and clamp the return value to an object,
// among other details. js_InvokeConstructor does the hard work. // among other details. js_InvokeConstructor does the hard work.
InvokeArgsGuard args; InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, argc, args)) if (!cx->stack().pushInvokeArgs(cx, argc, &args))
return NULL; return NULL;
args.callee().setObject(*ctor); args.callee().setObject(*ctor);
@ -4836,7 +4837,7 @@ JS_IsRunning(JSContext *cx)
#endif #endif
JSStackFrame *fp = cx->maybefp(); JSStackFrame *fp = cx->maybefp();
while (fp && fp->isDummyFrame()) while (fp && fp->isDummyFrame())
fp = fp->down; fp = fp->prev();
return fp != NULL; return fp != NULL;
} }

Просмотреть файл

@ -1350,7 +1350,7 @@ array_toString(JSContext *cx, uintN argc, Value *vp)
LeaveTrace(cx); LeaveTrace(cx);
InvokeArgsGuard args; InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, 0, args)) if (!cx->stack().pushInvokeArgs(cx, 0, &args))
return false; return false;
args.callee() = join; args.callee() = join;
@ -1954,7 +1954,7 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp)
LeaveTrace(cx); LeaveTrace(cx);
CompareArgs ca(cx, fval); CompareArgs ca(cx, fval);
if (!cx->stack().pushInvokeArgs(cx, 2, ca.args)) if (!cx->stack().pushInvokeArgs(cx, 2, &ca.args))
return false; return false;
if (!js_MergeSort(vec, size_t(newlen), sizeof(Value), if (!js_MergeSort(vec, size_t(newlen), sizeof(Value),
@ -2743,7 +2743,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
argc = 3 + REDUCE_MODE(mode); argc = 3 + REDUCE_MODE(mode);
InvokeArgsGuard args; InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, argc, args)) if (!cx->stack().pushInvokeArgs(cx, argc, &args))
return JS_FALSE; return JS_FALSE;
MUST_FLOW_THROUGH("out"); MUST_FLOW_THROUGH("out");

Просмотреть файл

@ -598,13 +598,13 @@ JS_DECLARE_CALLINFO(js_NewNullClosure)
/* Defined in jsfun.cpp. */ /* Defined in jsfun.cpp. */
JS_DECLARE_CALLINFO(js_AllocFlatClosure) JS_DECLARE_CALLINFO(js_AllocFlatClosure)
JS_DECLARE_CALLINFO(js_PutArguments) JS_DECLARE_CALLINFO(js_PutArgumentsOnTrace)
JS_DECLARE_CALLINFO(js_PutCallObjectOnTrace) JS_DECLARE_CALLINFO(js_PutCallObjectOnTrace)
JS_DECLARE_CALLINFO(js_SetCallVar) JS_DECLARE_CALLINFO(js_SetCallVar)
JS_DECLARE_CALLINFO(js_SetCallArg) JS_DECLARE_CALLINFO(js_SetCallArg)
JS_DECLARE_CALLINFO(js_CloneFunctionObject) JS_DECLARE_CALLINFO(js_CloneFunctionObject)
JS_DECLARE_CALLINFO(js_CreateCallObjectOnTrace) JS_DECLARE_CALLINFO(js_CreateCallObjectOnTrace)
JS_DECLARE_CALLINFO(js_Arguments) JS_DECLARE_CALLINFO(js_NewArgumentsOnTrace)
/* Defined in jsnum.cpp. */ /* Defined in jsnum.cpp. */
JS_DECLARE_CALLINFO(js_NumberToString) JS_DECLARE_CALLINFO(js_NumberToString)

Просмотреть файл

@ -76,6 +76,8 @@
#include "jstracer.h" #include "jstracer.h"
#include "jscntxtinlines.h" #include "jscntxtinlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h"
#ifdef XP_WIN #ifdef XP_WIN
# include "jswin.h" # include "jswin.h"
@ -112,13 +114,13 @@ StackSegment::contains(const JSStackFrame *fp) const
if (isActive()) { if (isActive()) {
JS_ASSERT(cx->hasfp()); JS_ASSERT(cx->hasfp());
start = cx->fp(); start = cx->fp();
stop = cx->activeSegment()->initialFrame->down; stop = cx->activeSegment()->initialFrame->prev();
} else { } else {
JS_ASSERT(suspendedRegs && suspendedRegs->fp); JS_ASSERT(suspendedRegs && suspendedRegs->fp);
start = suspendedRegs->fp; start = suspendedRegs->fp;
stop = initialFrame->down; stop = initialFrame->prev();
} }
for (JSStackFrame *f = start; f != stop; f = f->down) { for (JSStackFrame *f = start; f != stop; f = f->prev()) {
if (f == fp) if (f == fp)
return true; return true;
} }
@ -199,7 +201,7 @@ StackSpace::bumpCommit(Value *from, ptrdiff_t nvals) const
} }
#endif #endif
JS_REQUIRES_STACK void void
StackSpace::mark(JSTracer *trc) StackSpace::mark(JSTracer *trc)
{ {
/* /*
@ -215,33 +217,33 @@ StackSpace::mark(JSTracer *trc)
for (StackSegment *seg = currentSegment; seg; seg = seg->getPreviousInMemory()) { for (StackSegment *seg = currentSegment; seg; seg = seg->getPreviousInMemory()) {
if (seg->inContext()) { if (seg->inContext()) {
/* This may be the only pointer to the initialVarObj. */ /* This may be the only pointer to the initialVarObj. */
if (JSObject *varobj = seg->getInitialVarObj()) if (seg->hasInitialVarObj())
JS_CALL_OBJECT_TRACER(trc, varobj, "varobj"); MarkObject(trc, seg->getInitialVarObj(), "varobj");
/* Mark slots/args trailing off of the last stack frame. */ /* Mark slots/args trailing off of the last stack frame. */
JSStackFrame *fp = seg->getCurrentFrame(); JSStackFrame *fp = seg->getCurrentFrame();
MarkStackRangeConservatively(trc, fp->slots(), end); MarkStackRangeConservatively(trc, fp->slots(), end);
/* Mark stack frames and slots/args between stack frames. */ /* Mark stack frames and slots/args between stack frames. */
JSStackFrame *initialFrame = seg->getInitialFrame(); JSStackFrame *initial = seg->getInitialFrame();
for (JSStackFrame *f = fp; f != initialFrame; f = f->down) { for (JSStackFrame *f = fp; f != initial; f = f->prev()) {
js_TraceStackFrame(trc, f); js_TraceStackFrame(trc, f);
MarkStackRangeConservatively(trc, f->down->slots(), f->argEnd()); MarkStackRangeConservatively(trc, f->prev()->slots(), (Value *)f);
} }
/* Mark initialFrame stack frame and leading args. */ /* Mark initial stack frame and leading args. */
js_TraceStackFrame(trc, initialFrame); js_TraceStackFrame(trc, initial);
MarkValueRange(trc, seg->getInitialArgBegin(), initialFrame->argEnd(), "stack"); MarkStackRangeConservatively(trc, seg->valueRangeBegin(), (Value *)initial);
} else { } else {
/* Mark slots/args trailing off segment. */ /* Mark slots/args trailing off segment. */
MarkValueRange(trc, seg->getInitialArgBegin(), end, "stack"); MarkValueRange(trc, seg->valueRangeBegin(), end, "stack");
} }
end = seg->previousSegmentEnd(); end = (Value *)seg;
} }
} }
JS_REQUIRES_STACK bool bool
StackSpace::pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard &ag) StackSpace::pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard *ag)
{ {
Value *start = firstUnused(); Value *start = firstUnused();
ptrdiff_t nvals = VALUES_PER_STACK_SEGMENT + 2 + argc; ptrdiff_t nvals = VALUES_PER_STACK_SEGMENT + 2 + argc;
@ -252,24 +254,24 @@ StackSpace::pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard &ag)
seg->setPreviousInMemory(currentSegment); seg->setPreviousInMemory(currentSegment);
currentSegment = seg; currentSegment = seg;
ag.cx = cx; ag->cx = cx;
ag.seg = seg; ag->seg = seg;
ag.argv_ = seg->getInitialArgBegin() + 2; ag->argv_ = seg->valueRangeBegin() + 2;
ag.argc_ = argc; ag->argc_ = argc;
/* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */ /* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */
#ifdef DEBUG #ifdef DEBUG
ag.prevInvokeSegment = invokeSegment; ag->prevInvokeSegment = invokeSegment;
invokeSegment = seg; invokeSegment = seg;
ag.prevInvokeFrame = invokeFrame; ag->prevInvokeFrame = invokeFrame;
invokeFrame = NULL; invokeFrame = NULL;
#endif #endif
ag.prevInvokeArgEnd = invokeArgEnd; ag->prevInvokeArgEnd = invokeArgEnd;
invokeArgEnd = ag.argv() + ag.argc(); invokeArgEnd = ag->argv() + ag->argc();
return true; return true;
} }
JS_REQUIRES_STACK void void
StackSpace::popSegmentForInvoke(const InvokeArgsGuard &ag) StackSpace::popSegmentForInvoke(const InvokeArgsGuard &ag)
{ {
JS_ASSERT(!currentSegment->inContext()); JS_ASSERT(!currentSegment->inContext());
@ -286,44 +288,41 @@ StackSpace::popSegmentForInvoke(const InvokeArgsGuard &ag)
invokeArgEnd = ag.prevInvokeArgEnd; invokeArgEnd = ag.prevInvokeArgEnd;
} }
/* bool
* Always push a segment when starting a new execute frame since segments StackSpace::getSegmentAndFrame(JSContext *cx, uintN vplen, uintN nfixed,
* provide initialVarObj, which may change. FrameGuard *fg) const
*/
JS_REQUIRES_STACK bool
StackSpace::getExecuteFrame(JSContext *cx, JSStackFrame *down,
uintN vplen, uintN nfixed,
FrameGuard &fg) const
{ {
Value *start = firstUnused(); Value *start = firstUnused();
ptrdiff_t nvals = VALUES_PER_STACK_SEGMENT + vplen + VALUES_PER_STACK_FRAME + nfixed; uintN nvals = VALUES_PER_STACK_SEGMENT + vplen + VALUES_PER_STACK_FRAME + nfixed;
if (!ensureSpace(cx, start, nvals)) if (!ensureSpace(cx, start, nvals))
return false; return false;
fg.seg = new(start) StackSegment; fg->seg_ = new(start) StackSegment;
fg.vp = start + VALUES_PER_STACK_SEGMENT; fg->vp_ = start + VALUES_PER_STACK_SEGMENT;
fg.fp = reinterpret_cast<JSStackFrame *>(fg.vp + vplen); fg->fp_ = reinterpret_cast<JSStackFrame *>(fg->vp() + vplen);
fg.down = down;
return true; return true;
} }
JS_REQUIRES_STACK void void
StackSpace::pushExecuteFrame(JSContext *cx, FrameGuard &fg, StackSpace::pushSegmentAndFrame(JSContext *cx, JSObject *initialVarObj,
JSFrameRegs &regs, JSObject *initialVarObj) JSFrameRegs *regs, FrameGuard *fg)
{ {
fg.fp->down = fg.down; /* Caller should have already initialized regs. */
StackSegment *seg = fg.seg; JS_ASSERT(regs->fp == fg->fp());
/* Push segment. */
StackSegment *seg = fg->segment();
seg->setPreviousInMemory(currentSegment); seg->setPreviousInMemory(currentSegment);
currentSegment = seg; currentSegment = seg;
regs.fp = fg.fp; /* Push frame. */
cx->pushSegmentAndFrame(seg, regs); cx->pushSegmentAndFrame(seg, *regs);
seg->setInitialVarObj(initialVarObj); seg->setInitialVarObj(initialVarObj);
fg.cx = cx; fg->cx_ = cx;
} }
JS_REQUIRES_STACK void void
StackSpace::popFrame(JSContext *cx) StackSpace::popSegmentAndFrame(JSContext *cx)
{ {
JS_ASSERT(isCurrentAndActive(cx)); JS_ASSERT(isCurrentAndActive(cx));
JS_ASSERT(cx->hasActiveSegment()); JS_ASSERT(cx->hasActiveSegment());
@ -331,34 +330,78 @@ StackSpace::popFrame(JSContext *cx)
currentSegment = currentSegment->getPreviousInMemory(); currentSegment = currentSegment->getPreviousInMemory();
} }
JS_REQUIRES_STACK
FrameGuard::~FrameGuard() FrameGuard::~FrameGuard()
{ {
if (!pushed()) if (!pushed())
return; return;
JS_ASSERT(cx->activeSegment() == seg); JS_ASSERT(cx_->activeSegment() == segment());
JS_ASSERT(cx->maybefp() == fp); JS_ASSERT(cx_->maybefp() == fp());
cx->stack().popFrame(cx); cx_->stack().popSegmentAndFrame(cx_);
} }
JS_REQUIRES_STACK bool bool
StackSpace::pushDummyFrame(JSContext *cx, FrameGuard &fg, JSFrameRegs &regs, JSObject *scopeChain) StackSpace::getExecuteFrame(JSContext *cx, JSScript *script, ExecuteFrameGuard *fg) const
{ {
if (!getExecuteFrame(cx, cx->maybefp(), 0, 0, fg)) return getSegmentAndFrame(cx, 2, script->nfixed, fg);
}
void
StackSpace::pushExecuteFrame(JSContext *cx, JSObject *initialVarObj, ExecuteFrameGuard *fg)
{
JSStackFrame *fp = fg->fp();
JSScript *script = fp->script();
fg->regs_.pc = script->code;
fg->regs_.fp = fp;
fg->regs_.sp = fp->base();
pushSegmentAndFrame(cx, initialVarObj, &fg->regs_, fg);
}
bool
StackSpace::pushDummyFrame(JSContext *cx, JSObject &scopeChain, DummyFrameGuard *fg)
{
if (!getSegmentAndFrame(cx, 0 /*vplen*/, 0 /*nfixed*/, fg))
return false; return false;
fg->fp()->initDummyFrame(cx, scopeChain);
JSStackFrame *fp = fg.getFrame(); fg->regs_.fp = fg->fp();
PodZero(fp); fg->regs_.pc = NULL;
fp->setScopeChain(scopeChain); fg->regs_.sp = fg->fp()->slots();
fp->flags = JSFRAME_DUMMY; pushSegmentAndFrame(cx, NULL /*varobj*/, &fg->regs_, fg);
regs.pc = NULL;
regs.sp = fp->slots();
pushExecuteFrame(cx, fg, regs, NULL);
return true; return true;
} }
bool
StackSpace::getGeneratorFrame(JSContext *cx, uintN vplen, uintN nfixed, GeneratorFrameGuard *fg)
{
return getSegmentAndFrame(cx, vplen, nfixed, fg);
}
void
StackSpace::pushGeneratorFrame(JSContext *cx, JSFrameRegs *regs, GeneratorFrameGuard *fg)
{
JS_ASSERT(regs->fp == fg->fp());
JS_ASSERT(regs->fp->prev() == cx->maybefp());
pushSegmentAndFrame(cx, NULL /*varobj*/, regs, fg);
}
bool
StackSpace::bumpCommitAndLimit(JSStackFrame *base, Value *sp, uintN nvals, Value **limit) const
{
JS_ASSERT(sp == firstUnused());
JS_ASSERT(sp + nvals >= *limit);
#ifdef XP_WIN
if (commitEnd <= *limit) {
Value *quotaEnd = (Value *)base + STACK_QUOTA;
if (sp + nvals < quotaEnd) {
if (!ensureSpace(NULL, sp, nvals))
return false;
*limit = Min(quotaEnd, commitEnd);
return true;
}
}
#endif
return false;
}
void void
FrameRegsIter::initSlow() FrameRegsIter::initSlow()
{ {
@ -377,35 +420,35 @@ FrameRegsIter::initSlow()
/* /*
* Using the invariant described in the js::StackSegment comment, we know that, * Using the invariant described in the js::StackSegment comment, we know that,
* when a pair of down-linked stack frames are in the same segment, the * when a pair of prev-linked stack frames are in the same segment, the
* up-frame's address is the top of the down-frame's stack, modulo missing * first frame's address is the top of the prev-frame's stack, modulo missing
* arguments. * arguments.
*/ */
void void
FrameRegsIter::incSlow(JSStackFrame *up, JSStackFrame *down) FrameRegsIter::incSlow(JSStackFrame *fp, JSStackFrame *prev)
{ {
JS_ASSERT(down); JS_ASSERT(prev);
JS_ASSERT(curpc == down->savedPC); JS_ASSERT(curpc == prev->savedpc_);
JS_ASSERT(up == curseg->getInitialFrame()); JS_ASSERT(fp == curseg->getInitialFrame());
/* /*
* If the up-frame is in csup and the down-frame is in csdown, it is not * If fp is in cs and the prev-frame is in csprev, it is not necessarily
* necessarily the case that |csup->getPreviousInContext == csdown| or that * the case that |cs->getPreviousInContext == csprev| or that
* |csdown->getSuspendedFrame == down| (because of indirect eval and * |csprev->getSuspendedFrame == prev| (because of indirect eval and
* JS_EvaluateInStackFrame). To compute down's sp, we need to do a linear * JS_EvaluateInStackFrame). To compute prev's sp, we need to do a linear
* scan, keeping track of what is immediately after down in memory. * scan, keeping track of what is immediately after prev in memory.
*/ */
curseg = curseg->getPreviousInContext(); curseg = curseg->getPreviousInContext();
cursp = curseg->getSuspendedRegs()->sp; cursp = curseg->getSuspendedRegs()->sp;
JSStackFrame *f = curseg->getSuspendedFrame(); JSStackFrame *f = curseg->getSuspendedFrame();
while (f != down) { while (f != prev) {
if (f == curseg->getInitialFrame()) { if (f == curseg->getInitialFrame()) {
curseg = curseg->getPreviousInContext(); curseg = curseg->getPreviousInContext();
cursp = curseg->getSuspendedRegs()->sp; cursp = curseg->getSuspendedRegs()->sp;
f = curseg->getSuspendedFrame(); f = curseg->getSuspendedFrame();
} else { } else {
cursp = contiguousDownFrameSP(f); cursp = f->formalArgsEnd();
f = f->down; f = f->prev();
} }
} }
} }
@ -424,7 +467,7 @@ AllFramesIter::operator++()
curcs = curcs->getPreviousInMemory(); curcs = curcs->getPreviousInMemory();
curfp = curcs ? curcs->getCurrentFrame() : NULL; curfp = curcs ? curcs->getCurrentFrame() : NULL;
} else { } else {
curfp = curfp->down; curfp = curfp->prev();
} }
return *this; return *this;
} }
@ -1346,9 +1389,9 @@ PopulateReportBlame(JSContext *cx, JSErrorReport *report)
* 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 (JSStackFrame *fp = js_GetTopStackFrame(cx); fp; fp = fp->down) { for (JSStackFrame *fp = js_GetTopStackFrame(cx); fp; fp = fp->prev()) {
if (fp->pc(cx)) { if (fp->pc(cx)) {
report->filename = fp->getScript()->filename; report->filename = fp->script()->filename;
report->lineno = js_FramePCToLineNumber(cx, fp); report->lineno = js_FramePCToLineNumber(cx, fp);
break; break;
} }
@ -1442,7 +1485,7 @@ checkReportFlags(JSContext *cx, uintN *flags)
* the nearest scripted frame is strict, see bug 536306. * the nearest scripted frame is strict, see bug 536306.
*/ */
JSStackFrame *fp = js_GetScriptedCaller(cx, NULL); JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
if (fp && fp->getScript()->strictModeCode) if (fp && fp->script()->strictModeCode)
*flags &= ~JSREPORT_WARNING; *flags &= ~JSREPORT_WARNING;
else if (JS_HAS_STRICT_OPTION(cx)) else if (JS_HAS_STRICT_OPTION(cx))
*flags |= JSREPORT_WARNING; *flags |= JSREPORT_WARNING;
@ -1917,8 +1960,8 @@ js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
if (!fp) if (!fp)
fp = js_GetTopStackFrame(cx); fp = js_GetTopStackFrame(cx);
while (fp && fp->isDummyFrame()) while (fp && fp->isDummyFrame())
fp = fp->down; fp = fp->prev();
JS_ASSERT_IF(fp, fp->hasScript()); JS_ASSERT_IF(fp, fp->isScriptFrame());
return fp; return fp;
} }
@ -1938,7 +1981,7 @@ js_GetCurrentBytecodePC(JSContext* cx)
pc = cx->regs ? cx->regs->pc : NULL; pc = cx->regs ? cx->regs->pc : NULL;
if (!pc) if (!pc)
return NULL; return NULL;
imacpc = cx->fp()->maybeIMacroPC(); imacpc = cx->fp()->maybeImacropc();
} }
/* /*
@ -1956,7 +1999,7 @@ js_CurrentPCIsInImacro(JSContext *cx)
VOUCH_DOES_NOT_REQUIRE_STACK(); VOUCH_DOES_NOT_REQUIRE_STACK();
if (JS_ON_TRACE(cx)) if (JS_ON_TRACE(cx))
return cx->bailExit->imacpc != NULL; return cx->bailExit->imacpc != NULL;
return cx->fp()->hasIMacroPC(); return cx->fp()->hasImacropc();
#else #else
return false; return false;
#endif #endif
@ -2009,15 +2052,16 @@ JSContext::JSContext(JSRuntime *rt)
void void
JSContext::pushSegmentAndFrame(js::StackSegment *newseg, JSFrameRegs &newregs) JSContext::pushSegmentAndFrame(js::StackSegment *newseg, JSFrameRegs &newregs)
{ {
JS_ASSERT(regs != &newregs);
if (hasActiveSegment()) { if (hasActiveSegment()) {
JS_ASSERT(regs->fp->savedPC == JSStackFrame::sInvalidPC); JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
regs->fp->savedPC = regs->pc; regs->fp->savedpc_ = regs->pc;
currentSegment->suspend(regs); currentSegment->suspend(regs);
} }
newseg->setPreviousInContext(currentSegment); newseg->setPreviousInContext(currentSegment);
currentSegment = newseg; currentSegment = newseg;
#ifdef DEBUG #ifdef DEBUG
newregs.fp->savedPC = JSStackFrame::sInvalidPC; newregs.fp->savedpc_ = JSStackFrame::sInvalidpc;
#endif #endif
setCurrentRegs(&newregs); setCurrentRegs(&newregs);
newseg->joinContext(this, newregs.fp); newseg->joinContext(this, newregs.fp);
@ -2028,7 +2072,7 @@ JSContext::popSegmentAndFrame()
{ {
JS_ASSERT(currentSegment->maybeContext() == this); JS_ASSERT(currentSegment->maybeContext() == this);
JS_ASSERT(currentSegment->getInitialFrame() == regs->fp); JS_ASSERT(currentSegment->getInitialFrame() == regs->fp);
JS_ASSERT(regs->fp->savedPC == JSStackFrame::sInvalidPC); JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
currentSegment->leaveContext(); currentSegment->leaveContext();
currentSegment = currentSegment->getPreviousInContext(); currentSegment = currentSegment->getPreviousInContext();
if (currentSegment) { if (currentSegment) {
@ -2038,11 +2082,11 @@ JSContext::popSegmentAndFrame()
setCurrentRegs(currentSegment->getSuspendedRegs()); setCurrentRegs(currentSegment->getSuspendedRegs());
currentSegment->resume(); currentSegment->resume();
#ifdef DEBUG #ifdef DEBUG
regs->fp->savedPC = JSStackFrame::sInvalidPC; regs->fp->savedpc_ = JSStackFrame::sInvalidpc;
#endif #endif
} }
} else { } else {
JS_ASSERT(regs->fp->down == NULL); JS_ASSERT(regs->fp->prev() == NULL);
setCurrentRegs(NULL); setCurrentRegs(NULL);
} }
} }
@ -2052,8 +2096,8 @@ JSContext::saveActiveSegment()
{ {
JS_ASSERT(hasActiveSegment()); JS_ASSERT(hasActiveSegment());
currentSegment->save(regs); currentSegment->save(regs);
JS_ASSERT(regs->fp->savedPC == JSStackFrame::sInvalidPC); JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
regs->fp->savedPC = regs->pc; regs->fp->savedpc_ = regs->pc;
setCurrentRegs(NULL); setCurrentRegs(NULL);
} }
@ -2064,23 +2108,23 @@ JSContext::restoreSegment()
setCurrentRegs(ccs->getSuspendedRegs()); setCurrentRegs(ccs->getSuspendedRegs());
ccs->restore(); ccs->restore();
#ifdef DEBUG #ifdef DEBUG
regs->fp->savedPC = JSStackFrame::sInvalidPC; regs->fp->savedpc_ = JSStackFrame::sInvalidpc;
#endif #endif
} }
JSGenerator * JSGenerator *
JSContext::generatorFor(JSStackFrame *fp) const JSContext::generatorFor(JSStackFrame *fp) const
{ {
JS_ASSERT(stack().contains(fp) && fp->isGenerator()); JS_ASSERT(stack().contains(fp) && fp->isGeneratorFrame());
JS_ASSERT(!fp->isFloatingGenerator()); JS_ASSERT(!fp->isFloatingGenerator());
JS_ASSERT(!genStack.empty()); JS_ASSERT(!genStack.empty());
if (JS_LIKELY(fp == genStack.back()->liveFrame)) if (JS_LIKELY(fp == genStack.back()->liveFrame()))
return genStack.back(); return genStack.back();
/* General case; should only be needed for debug APIs. */ /* General case; should only be needed for debug APIs. */
for (size_t i = 0; i < genStack.length(); ++i) { for (size_t i = 0; i < genStack.length(); ++i) {
if (genStack[i]->liveFrame == fp) if (genStack[i]->liveFrame() == fp)
return genStack[i]; return genStack[i];
} }
JS_NOT_REACHED("no matching generator"); JS_NOT_REACHED("no matching generator");
@ -2100,8 +2144,8 @@ JSContext::containingSegment(const JSStackFrame *target)
JS_ASSERT(regs->fp); JS_ASSERT(regs->fp);
JS_ASSERT(activeSegment() == seg); JS_ASSERT(activeSegment() == seg);
JSStackFrame *f = regs->fp; JSStackFrame *f = regs->fp;
JSStackFrame *stop = seg->getInitialFrame()->down; JSStackFrame *stop = seg->getInitialFrame()->prev();
for (; f != stop; f = f->down) { for (; f != stop; f = f->prev()) {
if (f == target) if (f == target)
return seg; return seg;
} }
@ -2111,8 +2155,8 @@ JSContext::containingSegment(const JSStackFrame *target)
/* A suspended segment's top frame is its suspended frame. */ /* A suspended segment's top frame is its suspended frame. */
for (; seg; seg = seg->getPreviousInContext()) { for (; seg; seg = seg->getPreviousInContext()) {
JSStackFrame *f = seg->getSuspendedFrame(); JSStackFrame *f = seg->getSuspendedFrame();
JSStackFrame *stop = seg->getInitialFrame()->down; JSStackFrame *stop = seg->getInitialFrame()->prev();
for (; f != stop; f = f->down) { for (; f != stop; f = f->prev()) {
if (f == target) if (f == target)
return seg; return seg;
} }

Просмотреть файл

@ -280,19 +280,18 @@ struct GlobalState {
}; };
/* /*
* A StackSegment (referred to as just a 'segment') contains a down-linked set * A StackSegment (referred to as just a 'segment') contains a prev-linked set
* of stack frames and the slots associated with each frame. A segment and its * of stack frames and the slots associated with each frame. A segment and its
* contained frames/slots also have a precise memory layout that is described * contained frames/slots also have a precise memory layout that is described
* in the js::StackSpace comment. A key layout invariant for segments is that * in the js::StackSpace comment. A key layout invariant for segments is that
* down-linked frames are adjacent in memory, separated only by the values that * prev-linked frames are adjacent in memory, separated only by the values that
* constitute the locals and expression stack of the down-frame and arguments * constitute the locals and expression stack of the prev-frame.
* of the up-frame.
* *
* The set of stack frames in a non-empty segment start at the segment's * The set of stack frames in a non-empty segment start at the segment's
* "current frame", which is the most recently pushed frame, and ends at the * "current frame", which is the most recently pushed frame, and ends at the
* segment's "initial frame". Note that, while all stack frames in a segment * segment's "initial frame". Note that, while all stack frames in a segment
* are down-linked, not all down-linked frames are in the same segment. Hence, * are prev-linked, not all prev-linked frames are in the same segment. Hence,
* for a segment |ss|, |ss->getInitialFrame()->down| may be non-null and in a * for a segment |ss|, |ss->getInitialFrame()->prev| may be non-null and in a
* different segment. This occurs when the VM reenters itself (via Invoke or * different segment. This occurs when the VM reenters itself (via Invoke or
* Execute). In full generality, a single context may contain a forest of trees * Execute). In full generality, a single context may contain a forest of trees
* of stack frames. With respect to this forest, a segment contains a linear * of stack frames. With respect to this forest, a segment contains a linear
@ -372,11 +371,7 @@ class StackSegment
/* Safe casts guaranteed by the contiguous-stack layout. */ /* Safe casts guaranteed by the contiguous-stack layout. */
Value *previousSegmentEnd() const { Value *valueRangeBegin() const {
return (Value *)this;
}
Value *getInitialArgBegin() const {
return (Value *)(this + 1); return (Value *)(this + 1);
} }
@ -515,9 +510,14 @@ class StackSegment
initialVarObj = obj; initialVarObj = obj;
} }
JSObject *getInitialVarObj() const { bool hasInitialVarObj() {
JS_ASSERT(inContext()); JS_ASSERT(inContext());
return initialVarObj; return initialVarObj != NULL;
}
JSObject &getInitialVarObj() const {
JS_ASSERT(inContext() && initialVarObj);
return *initialVarObj;
} }
#ifdef DEBUG #ifdef DEBUG
@ -559,33 +559,51 @@ struct InvokeArgsAlreadyOnTheStack : CallArgs
class InvokeFrameGuard class InvokeFrameGuard
{ {
friend class StackSpace; friend class StackSpace;
JSContext *cx; /* null implies nothing pushed */ JSContext *cx_; /* null implies nothing pushed */
JSFrameRegs regs; JSFrameRegs regs_;
JSFrameRegs *prevRegs; JSFrameRegs *prevRegs_;
public: public:
InvokeFrameGuard() : cx(NULL) {} InvokeFrameGuard() : cx_(NULL) {}
JS_REQUIRES_STACK ~InvokeFrameGuard(); JS_REQUIRES_STACK ~InvokeFrameGuard();
bool pushed() const { return cx != NULL; } bool pushed() const { return cx_ != NULL; }
JSFrameRegs &getRegs() { return regs; } JSStackFrame *fp() const { return regs_.fp; }
}; };
/* See StackSpace::pushExecuteFrame. */ /* Reusable base; not for direct use. */
class FrameGuard class FrameGuard
{ {
friend class StackSpace; friend class StackSpace;
JSContext *cx; /* null implies nothing pushed */ JSContext *cx_; /* null implies nothing pushed */
StackSegment *seg; StackSegment *seg_;
Value *vp; Value *vp_;
JSStackFrame *fp; JSStackFrame *fp_;
JSStackFrame *down;
public: public:
FrameGuard() : cx(NULL), vp(NULL), fp(NULL) {} FrameGuard() : cx_(NULL), vp_(NULL), fp_(NULL) {}
JS_REQUIRES_STACK ~FrameGuard(); JS_REQUIRES_STACK ~FrameGuard();
bool pushed() const { return cx != NULL; } bool pushed() const { return cx_ != NULL; }
Value *getvp() const { return vp; } StackSegment *segment() const { return seg_; }
JSStackFrame *getFrame() const { return fp; } Value *vp() const { return vp_; }
JSStackFrame *fp() const { return fp_; }
}; };
/* See StackSpace::pushExecuteFrame. */
class ExecuteFrameGuard : public FrameGuard
{
friend class StackSpace;
JSFrameRegs regs_;
};
/* See StackSpace::pushDummyFrame. */
class DummyFrameGuard : public FrameGuard
{
friend class StackSpace;
JSFrameRegs regs_;
};
/* See StackSpace::pushGeneratorFrame. */
class GeneratorFrameGuard : public FrameGuard
{};
/* /*
* Stack layout * Stack layout
* *
@ -610,7 +628,7 @@ class FrameGuard
* |segment| slots |frame| slots |frame| slots |frame| slots | * |segment| slots |frame| slots |frame| slots |frame| slots |
* | ^ | ^ | * | ^ | ^ |
* ? <----------' `----------' `----------' * ? <----------' `----------' `----------'
* down down down * prev prev prev
* *
* Moreover, the bytes in the following ranges form a contiguous array of * Moreover, the bytes in the following ranges form a contiguous array of
* Values that are marked during GC: * Values that are marked during GC:
@ -653,7 +671,7 @@ class FrameGuard
* preserves order (in terms of previousInContext and previousInMemory, * preserves order (in terms of previousInContext and previousInMemory,
* respectively). * respectively).
* 2. the mapping from stack frames to their containing segment preserves * 2. the mapping from stack frames to their containing segment preserves
* order (in terms of down and previousInContext, respectively). * order (in terms of prev and previousInContext, respectively).
*/ */
class StackSpace class StackSpace
{ {
@ -674,23 +692,42 @@ class StackSpace
#endif #endif
Value *invokeArgEnd; Value *invokeArgEnd;
JS_REQUIRES_STACK bool pushSegmentForInvoke(JSContext *cx, uintN argc,
InvokeArgsGuard &ag);
JS_REQUIRES_STACK bool pushInvokeFrameSlow(JSContext *cx, const InvokeArgsGuard &ag,
InvokeFrameGuard &fg);
JS_REQUIRES_STACK void popInvokeFrameSlow(const CallArgs &args);
JS_REQUIRES_STACK void popSegmentForInvoke(const InvokeArgsGuard &ag);
/* Although guards are friends, XGuard should only call popX(). */
friend class InvokeArgsGuard; friend class InvokeArgsGuard;
JS_REQUIRES_STACK inline void popInvokeArgs(const InvokeArgsGuard &args);
friend class InvokeFrameGuard; friend class InvokeFrameGuard;
JS_REQUIRES_STACK void popInvokeFrame(const InvokeFrameGuard &ag);
friend class FrameGuard; friend class FrameGuard;
JS_REQUIRES_STACK void popFrame(JSContext *cx);
/* Return a pointer to the first unused slot. */ bool pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard *ag);
JS_REQUIRES_STACK void popSegmentForInvoke(const InvokeArgsGuard &ag);
bool pushInvokeFrameSlow(JSContext *cx, const InvokeArgsGuard &ag,
InvokeFrameGuard *fg);
void popInvokeFrameSlow(const CallArgs &args);
bool getSegmentAndFrame(JSContext *cx, uintN vplen, uintN nfixed,
FrameGuard *fg) const;
void pushSegmentAndFrame(JSContext *cx, JSObject *initialVarObj,
JSFrameRegs *regs, FrameGuard *fg);
void popSegmentAndFrame(JSContext *cx);
struct EnsureSpaceCheck {
inline bool operator()(const StackSpace &, JSContext *, Value *, uintN);
};
struct LimitCheck {
JSStackFrame *base;
Value **limit;
LimitCheck(JSStackFrame *base, Value **limit) : base(base), limit(limit) {}
inline bool operator()(const StackSpace &, JSContext *, Value *, uintN);
};
template <class Check>
inline JSStackFrame *getCallFrame(JSContext *cx, Value *sp, uintN nactual,
JSFunction *fun, JSScript *script,
uint32 *pflags, Check check) const;
inline void popInvokeArgs(const InvokeArgsGuard &args);
inline void popInvokeFrame(const InvokeFrameGuard &ag);
inline Value *firstUnused() const; inline Value *firstUnused() const;
inline bool isCurrentAndActive(JSContext *cx) const; inline bool isCurrentAndActive(JSContext *cx) const;
@ -714,6 +751,19 @@ class StackSpace
static const size_t COMMIT_VALS = 16 * 1024; static const size_t COMMIT_VALS = 16 * 1024;
static const size_t COMMIT_BYTES = COMMIT_VALS * sizeof(Value); static const size_t COMMIT_BYTES = COMMIT_VALS * sizeof(Value);
/*
* SunSpider and v8bench have roughly an average of 9 slots per script.
* Our heuristic for a quick over-recursion check uses a generous slot
* count based on this estimate. We take this frame size and multiply it
* by the old recursion limit from the interpreter.
*
* Worst case, if an average size script (<=9 slots) over recurses, it'll
* effectively be the same as having increased the old inline call count
* to <= 5,000.
*/
static const size_t STACK_QUOTA = (VALUES_PER_STACK_FRAME + 18) *
JS_MAX_INLINE_CALL_COUNT;
/* Kept as a member of JSThreadData; cannot use constructor/destructor. */ /* Kept as a member of JSThreadData; cannot use constructor/destructor. */
bool init(); bool init();
void finish(); void finish();
@ -735,6 +785,9 @@ class StackSpace
*/ */
inline bool ensureEnoughSpaceToEnterTrace(); inline bool ensureEnoughSpaceToEnterTrace();
/* See stubs::HitStackQuota. */
inline bool bumpCommitEnd(Value *from, uintN nslots);
/* +1 for slow native's stack frame. */ /* +1 for slow native's stack frame. */
static const ptrdiff_t MAX_TRACE_SPACE_VALS = static const ptrdiff_t MAX_TRACE_SPACE_VALS =
MAX_NATIVE_STACK_SLOTS + MAX_CALL_STACK_ENTRIES * VALUES_PER_STACK_FRAME + MAX_NATIVE_STACK_SLOTS + MAX_CALL_STACK_ENTRIES * VALUES_PER_STACK_FRAME +
@ -744,14 +797,14 @@ class StackSpace
JS_REQUIRES_STACK void mark(JSTracer *trc); JS_REQUIRES_STACK void mark(JSTracer *trc);
/* /*
* For all four use cases below: * For all five use cases below:
* - The boolean-valued functions call js_ReportOutOfScriptQuota on OOM. * - The boolean-valued functions call js_ReportOutOfScriptQuota on OOM.
* - The "get*Frame" functions do not change any global state, they just * - The "get*Frame" functions do not change any global state, they just
* check OOM and return pointers to an uninitialized frame with the * check OOM and return pointers to an uninitialized frame with the
* requested missing arguments/slots. Only once the "push*Frame" * requested missing arguments/slots. Only once the "push*Frame"
* function has been called is global state updated. Thus, between * function has been called is global state updated. Thus, between
* "get*Frame" and "push*Frame", the frame and slots are unrooted. * "get*Frame" and "push*Frame", the frame and slots are unrooted.
* - The "push*Frame" functions will set fp->down; the caller needn't. * - The "push*Frame" functions will set fp->prev; the caller needn't.
* - Functions taking "*Guard" arguments will use the guard's destructor * - Functions taking "*Guard" arguments will use the guard's destructor
* to pop the allocation. The caller must ensure the guard has the * to pop the allocation. The caller must ensure the guard has the
* appropriate lifetime. * appropriate lifetime.
@ -765,66 +818,54 @@ class StackSpace
* Invoke calls. The InvokeArgumentsGuard passed to Invoke must come from * Invoke calls. The InvokeArgumentsGuard passed to Invoke must come from
* an immediately-enclosing (stack-wise) call to pushInvokeArgs. * an immediately-enclosing (stack-wise) call to pushInvokeArgs.
*/ */
JS_REQUIRES_STACK bool pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard *ag);
bool pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard &ag);
/* These functions are called inside Invoke, not Invoke clients. */ /* These functions are called inside Invoke, not Invoke clients. */
bool getInvokeFrame(JSContext *cx, const CallArgs &args, bool getInvokeFrame(JSContext *cx, const CallArgs &args, JSFunction *fun,
uintN nmissing, uintN nfixed, JSScript *script, uint32 *flags, InvokeFrameGuard *fg) const;
InvokeFrameGuard &fg) const;
JS_REQUIRES_STACK void pushInvokeFrame(JSContext *cx, const CallArgs &args, InvokeFrameGuard *fg);
void pushInvokeFrame(JSContext *cx, const CallArgs &args, InvokeFrameGuard &fg);
/* /* These functions are called inside Execute, not Execute clients. */
* For the simpler case when arguments are allocated at the same time as bool getExecuteFrame(JSContext *cx, JSScript *script, ExecuteFrameGuard *fg) const;
* the frame and it is not necessary to have rooted argument values before void pushExecuteFrame(JSContext *cx, JSObject *initialVarObj, ExecuteFrameGuard *fg);
* pushing the frame.
*/
JS_REQUIRES_STACK
bool getExecuteFrame(JSContext *cx, JSStackFrame *down,
uintN vplen, uintN nfixed,
FrameGuard &fg) const;
JS_REQUIRES_STACK
void pushExecuteFrame(JSContext *cx, FrameGuard &fg,
JSFrameRegs &regs, JSObject *initialVarObj);
/* /*
* Since RAII cannot be used for inline frames, callers must manually * Since RAII cannot be used for inline frames, callers must manually
* call pushInlineFrame/popInlineFrame. * call pushInlineFrame/popInlineFrame.
*/ */
JS_REQUIRES_STACK inline JSStackFrame *getInlineFrame(JSContext *cx, Value *sp, uintN nactual,
inline JSStackFrame *getInlineFrame(JSContext *cx, Value *sp, JSFunction *fun, JSScript *script,
uintN nmissing, uintN nfixed) const; uint32 *flags) const;
inline void pushInlineFrame(JSContext *cx, JSScript *script, JSStackFrame *fp,
JSFrameRegs *regs);
inline void popInlineFrame(JSContext *cx, JSStackFrame *prev, js::Value *newsp);
JS_REQUIRES_STACK /* These functions are called inside SendToGenerator. */
inline JSStackFrame *getInlineFrameUnchecked(JSContext *cx, Value *sp, bool getGeneratorFrame(JSContext *cx, uintN vplen, uintN nfixed,
uintN nmissing) const; GeneratorFrameGuard *fg);
void pushGeneratorFrame(JSContext *cx, JSFrameRegs *regs, GeneratorFrameGuard *fg);
JS_REQUIRES_STACK /* Pushes a JSStackFrame::isDummyFrame. */
inline void pushInlineFrame(JSContext *cx, JSStackFrame *fp, jsbytecode *pc, bool pushDummyFrame(JSContext *cx, JSObject &scopeChain, DummyFrameGuard *fg);
JSStackFrame *newfp);
JS_REQUIRES_STACK /* Check and bump the given stack limit. */
inline void popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down); inline JSStackFrame *getInlineFrameWithinLimit(JSContext *cx, Value *sp, uintN nactual,
JSFunction *fun, JSScript *script, uint32 *flags,
JSStackFrame *base, Value **limit) const;
/* /*
* For pushing a bookkeeping frame. * Compute a stack limit for entering method jit code which allows the
* method jit to check for end-of-stack and over-recursion with a single
* comparison. See STACK_QUOTA above.
*/ */
JS_REQUIRES_STACK inline Value *getStackLimit(JSContext *cx);
bool pushDummyFrame(JSContext *cx, FrameGuard &fg, JSFrameRegs &regs, JSObject *scopeChain);
/* /*
* Ensure space based on an over-recursion limit. * Try to bump the given 'limit' by bumping the commit limit. Return false
* if fully committed or if 'limit' exceeds 'base' + STACK_QUOTA.
*/ */
inline bool ensureSpace(JSContext *maybecx, Value *start, Value *from, bool bumpCommitAndLimit(JSStackFrame *base, Value *from, uintN nvals, Value **limit) const;
Value *& limit, uint32 nslots) const;
/*
* Create a stack limit for quickly detecting over-recursion and whether
* a commit bump is needed.
*/
inline Value *makeStackLimit(Value *start) const;
}; };
JS_STATIC_ASSERT(StackSpace::CAPACITY_VALS % StackSpace::COMMIT_VALS == 0); JS_STATIC_ASSERT(StackSpace::CAPACITY_VALS % StackSpace::COMMIT_VALS == 0);
@ -832,7 +873,7 @@ 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 * 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 * 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 * frame's next-frame. This iterator maintains this information when walking
* a chain of stack frames starting at |cx->fp|. * a chain of stack frames starting at |cx->fp|.
* *
* Usage: * Usage:
@ -847,8 +888,7 @@ class FrameRegsIter
jsbytecode *curpc; jsbytecode *curpc;
void initSlow(); void initSlow();
void incSlow(JSStackFrame *up, JSStackFrame *down); void incSlow(JSStackFrame *fp, JSStackFrame *prev);
static inline Value *contiguousDownFrameSP(JSStackFrame *up);
public: public:
JS_REQUIRES_STACK inline FrameRegsIter(JSContext *cx); JS_REQUIRES_STACK inline FrameRegsIter(JSContext *cx);
@ -2155,10 +2195,10 @@ struct JSContext
JSStackFrame *findFrameAtLevel(uintN targetLevel) { JSStackFrame *findFrameAtLevel(uintN targetLevel) {
JSStackFrame *fp = this->regs->fp; JSStackFrame *fp = this->regs->fp;
while (true) { while (true) {
JS_ASSERT(fp && fp->hasScript()); JS_ASSERT(fp && fp->isScriptFrame());
if (fp->getScript()->staticLevel == targetLevel) if (fp->script()->staticLevel == targetLevel)
break; break;
fp = fp->down; fp = fp->prev();
} }
return fp; return fp;
} }
@ -2373,27 +2413,6 @@ js_TraceRegExpStatics(JSTracer *trc, JSContext *acx)
acx->regExpStatics.mark(trc); acx->regExpStatics.mark(trc);
} }
JS_ALWAYS_INLINE JSObject *
JSStackFrame::varobj(js::StackSegment *seg) const
{
JS_ASSERT(seg->contains(this));
return hasFunction() ? maybeCallObj() : seg->getInitialVarObj();
}
JS_ALWAYS_INLINE JSObject *
JSStackFrame::varobj(JSContext *cx) const
{
JS_ASSERT(cx->activeSegment()->contains(this));
return hasFunction() ? maybeCallObj() : cx->activeSegment()->getInitialVarObj();
}
JS_ALWAYS_INLINE jsbytecode *
JSStackFrame::pc(JSContext *cx) const
{
JS_ASSERT(cx->regs && cx->containingSegment(this) != NULL);
return (cx->regs->fp == this) ? cx->regs->pc : savedPC;
}
#ifdef JS_THREADSAFE #ifdef JS_THREADSAFE
# define JS_THREAD_ID(cx) ((cx)->thread ? (cx)->thread->id : 0) # define JS_THREAD_ID(cx) ((cx)->thread ? (cx)->thread->id : 0)
#endif #endif
@ -2428,16 +2447,16 @@ class AutoCheckRequestDepth {
static inline uintN static inline uintN
FramePCOffset(JSContext *cx, JSStackFrame* fp) FramePCOffset(JSContext *cx, JSStackFrame* fp)
{ {
jsbytecode *pc = fp->hasIMacroPC() ? fp->getIMacroPC() : fp->pc(cx); jsbytecode *pc = fp->hasImacropc() ? fp->imacropc() : fp->pc(cx);
return uintN(pc - fp->getScript()->code); return uintN(pc - fp->script()->code);
} }
static inline JSAtom ** static inline JSAtom **
FrameAtomBase(JSContext *cx, JSStackFrame *fp) FrameAtomBase(JSContext *cx, JSStackFrame *fp)
{ {
return fp->hasIMacroPC() return fp->hasImacropc()
? COMMON_ATOMS_START(&cx->runtime->atomState) ? COMMON_ATOMS_START(&cx->runtime->atomState)
: fp->getScript()->atomMap.vector; : fp->script()->atomMap.vector;
} }
namespace js { namespace js {

Просмотреть файл

@ -108,63 +108,14 @@ StackSpace::isCurrentAndActive(JSContext *cx) const
currentSegment == cx->getCurrentSegment(); currentSegment == cx->getCurrentSegment();
} }
/*
* SunSpider and v8bench have roughly an average of 9 slots per script.
* Our heuristic for a quick over-recursion check uses a generous slot
* count based on this estimate. We take this frame size and multiply it
* by the old recursion limit from the interpreter.
*
* Worst case, if an average size script (<=9 slots) over recurses, it'll
* effectively be the same as having increased the old inline call count
* to <= 5,000.
*/
static const uint32 MAX_STACK_USAGE = (VALUES_PER_STACK_FRAME + 18) * JS_MAX_INLINE_CALL_COUNT;
JS_ALWAYS_INLINE Value *
StackSpace::makeStackLimit(Value *start) const
{
Value *limit = JS_MIN(start + MAX_STACK_USAGE, end);
#ifdef XP_WIN
limit = JS_MIN(limit, commitEnd);
#endif
return limit;
}
JS_ALWAYS_INLINE bool
StackSpace::ensureSpace(JSContext *maybecx, Value *start, Value *from,
Value *& limit, uint32 nslots) const
{
JS_ASSERT(from == firstUnused());
#ifdef XP_WIN
/*
* If commitEnd < limit, we're guaranteed that we reached the end of the
* commit depth, because stackLimit is MIN(commitEnd, limit). If we did
* reach this soft limit, check if we can bump the commit end without
* over-recursing.
*/
ptrdiff_t nvals = VALUES_PER_STACK_FRAME + nslots;
if (commitEnd <= limit && from + nvals < (start + MAX_STACK_USAGE)) {
if (!ensureSpace(maybecx, from, nvals))
return false;
/* Compute a new limit. */
limit = makeStackLimit(start);
return true;
}
#endif
js_ReportOverRecursed(maybecx);
return false;
}
JS_ALWAYS_INLINE bool JS_ALWAYS_INLINE bool
StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
{ {
JS_ASSERT(from == firstUnused()); JS_ASSERT(from == firstUnused());
#ifdef XP_WIN #ifdef XP_WIN
JS_ASSERT(from <= commitEnd); JS_ASSERT(from <= commitEnd);
if (commitEnd - from >= nvals) if (JS_LIKELY(commitEnd - from >= nvals))
return true; goto success;
if (end - from < nvals) { if (end - from < nvals) {
if (maybecx) if (maybecx)
js_ReportOutOfScriptQuota(maybecx); js_ReportOutOfScriptQuota(maybecx);
@ -175,15 +126,20 @@ StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
js_ReportOutOfScriptQuota(maybecx); js_ReportOutOfScriptQuota(maybecx);
return false; return false;
} }
return true; goto success;
#else #else
if (end - from < nvals) { if (JS_LIKELY(end - from < nvals)) {
if (maybecx) if (maybecx)
js_ReportOutOfScriptQuota(maybecx); js_ReportOutOfScriptQuota(maybecx);
return false; return false;
} }
return true; goto success;
#endif #endif
success:
#ifdef DEBUG
memset(from, 0xde, nvals * sizeof(js::Value));
#endif
return true;
} }
JS_ALWAYS_INLINE bool JS_ALWAYS_INLINE bool
@ -195,8 +151,29 @@ StackSpace::ensureEnoughSpaceToEnterTrace()
return end - firstUnused() > MAX_TRACE_SPACE_VALS; return end - firstUnused() > MAX_TRACE_SPACE_VALS;
} }
JS_ALWAYS_INLINE bool
StackSpace::EnsureSpaceCheck::operator()(const StackSpace &stack, JSContext *cx,
Value *from, uintN nvals)
{
return stack.ensureSpace(cx, from, nvals);
}
JS_ALWAYS_INLINE bool
StackSpace::LimitCheck::operator()(const StackSpace &stack, JSContext *cx,
Value *from, uintN nvals)
{
JS_ASSERT(from == stack.firstUnused());
JS_ASSERT(from < *limit);
if (*limit - from >= ptrdiff_t(nvals))
return true;
if (stack.bumpCommitAndLimit(base, from, nvals, limit))
return true;
js_ReportOverRecursed(cx);
return false;
}
JS_REQUIRES_STACK JS_ALWAYS_INLINE bool JS_REQUIRES_STACK JS_ALWAYS_INLINE bool
StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard &ag) StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard *ag)
{ {
if (JS_UNLIKELY(!isCurrentAndActive(cx))) if (JS_UNLIKELY(!isCurrentAndActive(cx)))
return pushSegmentForInvoke(cx, argc, ag); return pushSegmentForInvoke(cx, argc, ag);
@ -213,18 +190,18 @@ StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard &ag)
MakeValueRangeGCSafe(vp, vpend); MakeValueRangeGCSafe(vp, vpend);
/* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */ /* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */
ag.prevInvokeArgEnd = invokeArgEnd; ag->prevInvokeArgEnd = invokeArgEnd;
invokeArgEnd = vpend; invokeArgEnd = vpend;
#ifdef DEBUG #ifdef DEBUG
ag.prevInvokeSegment = invokeSegment; ag->prevInvokeSegment = invokeSegment;
invokeSegment = currentSegment; invokeSegment = currentSegment;
ag.prevInvokeFrame = invokeFrame; ag->prevInvokeFrame = invokeFrame;
invokeFrame = cx->maybefp(); invokeFrame = cx->maybefp();
#endif #endif
ag.cx = cx; ag->cx = cx;
ag.argv_ = vp + 2; ag->argv_ = vp + 2;
ag.argc_ = argc; ag->argc_ = argc;
return true; return true;
} }
@ -256,61 +233,99 @@ InvokeArgsGuard::~InvokeArgsGuard()
cx->stack().popInvokeArgs(*this); cx->stack().popInvokeArgs(*this);
} }
template <class Check>
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
StackSpace::getCallFrame(JSContext *cx, Value *firstUnused, uintN nactual,
JSFunction *fun, JSScript *script, uint32 *flags,
Check check) const
{
JS_ASSERT(fun->script() == script);
/* Include an extra sizeof(JSStackFrame) for the method-jit. */
uintN nvals = VALUES_PER_STACK_FRAME + script->nslots;
uintN nformal = fun->nargs;
/* Maintain layout invariant: &formalArgs[0] == ((Value *)fp) - nformal. */
if (nactual == nformal) {
if (JS_UNLIKELY(!check(*this, cx, firstUnused, nvals)))
return NULL;
return reinterpret_cast<JSStackFrame *>(firstUnused);
}
if (nactual < nformal) {
*flags |= JSFRAME_UNDERFLOW_ARGS;
uintN nmissing = nformal - nactual;
if (JS_UNLIKELY(!check(*this, cx, firstUnused, nmissing + nvals)))
return NULL;
SetValueRangeToUndefined(firstUnused, nmissing);
return reinterpret_cast<JSStackFrame *>(firstUnused + nmissing);
}
*flags |= JSFRAME_OVERFLOW_ARGS;
uintN ncopy = 2 + nformal;
if (JS_UNLIKELY(!check(*this, cx, firstUnused, ncopy + nvals)))
return NULL;
memcpy(firstUnused, firstUnused - (2 + nactual), ncopy * sizeof(Value));
return reinterpret_cast<JSStackFrame *>(firstUnused + ncopy);
}
JS_REQUIRES_STACK JS_ALWAYS_INLINE bool JS_REQUIRES_STACK JS_ALWAYS_INLINE bool
StackSpace::getInvokeFrame(JSContext *cx, const CallArgs &args, StackSpace::getInvokeFrame(JSContext *cx, const CallArgs &args,
uintN nmissing, uintN nfixed, JSFunction *fun, JSScript *script,
InvokeFrameGuard &fg) const uint32 *flags, InvokeFrameGuard *fg) const
{ {
JS_ASSERT(firstUnused() == args.argv() + args.argc()); JS_ASSERT(firstUnused() == args.argv() + args.argc());
Value *start = args.argv() + args.argc(); Value *firstUnused = args.argv() + args.argc();
ptrdiff_t nvals = nmissing + VALUES_PER_STACK_FRAME + nfixed; fg->regs_.fp = getCallFrame(cx, firstUnused, args.argc(), fun, script, flags,
if (!ensureSpace(cx, start, nvals)) EnsureSpaceCheck());
return false; fg->regs_.sp = fg->regs_.fp->slots() + script->nfixed;
fg.regs.fp = reinterpret_cast<JSStackFrame *>(start + nmissing); fg->regs_.pc = script->code;
return true;
return fg->regs_.fp != NULL;
} }
JS_REQUIRES_STACK JS_ALWAYS_INLINE void JS_REQUIRES_STACK JS_ALWAYS_INLINE void
StackSpace::pushInvokeFrame(JSContext *cx, const CallArgs &args, StackSpace::pushInvokeFrame(JSContext *cx, const CallArgs &args,
InvokeFrameGuard &fg) InvokeFrameGuard *fg)
{ {
JS_ASSERT(firstUnused() == args.argv() + args.argc()); JS_ASSERT(firstUnused() == args.argv() + args.argc());
JSStackFrame *fp = fg.regs.fp; JSStackFrame *fp = fg->regs_.fp;
JSStackFrame *down = cx->maybefp(); JSStackFrame *prev = cx->maybefp();
fp->down = down; fp->prev_ = prev;
if (JS_UNLIKELY(!currentSegment->inContext())) { if (JS_UNLIKELY(!currentSegment->inContext())) {
cx->pushSegmentAndFrame(currentSegment, fg.regs); cx->pushSegmentAndFrame(currentSegment, fg->regs_);
} else { } else {
#ifdef DEBUG #ifdef DEBUG
fp->savedPC = JSStackFrame::sInvalidPC; fp->savedpc_ = JSStackFrame::sInvalidpc;
JS_ASSERT(down->savedPC == JSStackFrame::sInvalidPC); JS_ASSERT(prev->savedpc_ == JSStackFrame::sInvalidpc);
#endif #endif
down->savedPC = cx->regs->pc; prev->savedpc_ = cx->regs->pc;
fg.prevRegs = cx->regs; fg->prevRegs_ = cx->regs;
cx->setCurrentRegs(&fg.regs); cx->setCurrentRegs(&fg->regs_);
} }
fg.cx = cx;
fg->cx_ = cx;
JS_ASSERT(isCurrentAndActive(cx)); JS_ASSERT(isCurrentAndActive(cx));
} }
JS_REQUIRES_STACK JS_ALWAYS_INLINE void JS_REQUIRES_STACK JS_ALWAYS_INLINE void
StackSpace::popInvokeFrame(const InvokeFrameGuard &fg) StackSpace::popInvokeFrame(const InvokeFrameGuard &fg)
{ {
JSContext *cx = fg.cx; JSContext *cx = fg.cx_;
JSStackFrame *fp = fg.regs.fp; JSStackFrame *fp = fg.regs_.fp;
JS_ASSERT(isCurrentAndActive(cx)); JS_ASSERT(isCurrentAndActive(cx));
if (JS_UNLIKELY(currentSegment->getInitialFrame() == fp)) { if (JS_UNLIKELY(currentSegment->getInitialFrame() == fp)) {
cx->popSegmentAndFrame(); cx->popSegmentAndFrame();
} else { } else {
JS_ASSERT(&fg.regs == cx->regs); JS_ASSERT(&fg.regs_ == cx->regs);
JS_ASSERT(fp->down == fg.prevRegs->fp); JS_ASSERT(fp->prev_ == fg.prevRegs_->fp);
cx->setCurrentRegs(fg.prevRegs); cx->setCurrentRegs(fg.prevRegs_);
#ifdef DEBUG #ifdef DEBUG
cx->fp()->savedPC = JSStackFrame::sInvalidPC; cx->fp()->savedpc_ = JSStackFrame::sInvalidpc;
#endif #endif
} }
} }
@ -320,60 +335,92 @@ InvokeFrameGuard::~InvokeFrameGuard()
{ {
if (JS_UNLIKELY(!pushed())) if (JS_UNLIKELY(!pushed()))
return; return;
cx->stack().popInvokeFrame(*this); cx_->stack().popInvokeFrame(*this);
} }
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame * JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
StackSpace::getInlineFrameUnchecked(JSContext *cx, Value *sp, StackSpace::getInlineFrame(JSContext *cx, Value *sp, uintN nactual,
uintN nmissing) const JSFunction *fun, JSScript *script, uint32 *flags) const
{ {
JS_ASSERT(isCurrentAndActive(cx)); JS_ASSERT(isCurrentAndActive(cx));
JS_ASSERT(cx->hasActiveSegment()); JS_ASSERT(cx->hasActiveSegment());
JS_ASSERT(cx->regs->sp == sp); JS_ASSERT(cx->regs->sp == sp);
JSStackFrame *fp = reinterpret_cast<JSStackFrame *>(sp + nmissing); return getCallFrame(cx, sp, nactual, fun, script, flags, EnsureSpaceCheck());
return fp;
} }
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame * JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
StackSpace::getInlineFrame(JSContext *cx, Value *sp, StackSpace::getInlineFrameWithinLimit(JSContext *cx, Value *sp, uintN nactual,
uintN nmissing, uintN nfixed) const JSFunction *fun, JSScript *script, uint32 *flags,
{ JSStackFrame *base, Value **limit) const
ptrdiff_t nvals = nmissing + VALUES_PER_STACK_FRAME + nfixed;
if (!ensureSpace(cx, sp, nvals))
return NULL;
return getInlineFrameUnchecked(cx, sp, nmissing);
}
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
StackSpace::pushInlineFrame(JSContext *cx, JSStackFrame *fp, jsbytecode *pc,
JSStackFrame *newfp)
{
JS_ASSERT(isCurrentAndActive(cx));
JS_ASSERT(cx->regs->fp == fp && cx->regs->pc == pc);
fp->savedPC = pc;
newfp->down = fp;
#ifdef DEBUG
newfp->savedPC = JSStackFrame::sInvalidPC;
#endif
}
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
StackSpace::popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down)
{ {
JS_ASSERT(isCurrentAndActive(cx)); JS_ASSERT(isCurrentAndActive(cx));
JS_ASSERT(cx->hasActiveSegment()); JS_ASSERT(cx->hasActiveSegment());
JS_ASSERT(cx->regs->fp == up && up->down == down); JS_ASSERT(cx->regs->sp == sp);
JS_ASSERT(up->savedPC == JSStackFrame::sInvalidPC);
JS_ASSERT(!up->hasIMacroPC()); return getCallFrame(cx, sp, nactual, fun, script, flags, LimitCheck(base, limit));
}
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
StackSpace::pushInlineFrame(JSContext *cx, JSScript *script, JSStackFrame *fp,
JSFrameRegs *regs)
{
JS_ASSERT(isCurrentAndActive(cx));
JS_ASSERT(cx->regs == regs && script == fp->script());
regs->fp->savedpc_ = regs->pc;
fp->prev_ = regs->fp;
#ifdef DEBUG
fp->savedpc_ = JSStackFrame::sInvalidpc;
#endif
regs->fp = fp;
regs->pc = script->code;
regs->sp = fp->slots() + script->nfixed;
}
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
StackSpace::popInlineFrame(JSContext *cx, JSStackFrame *prev, Value *newsp)
{
JS_ASSERT(isCurrentAndActive(cx));
JS_ASSERT(cx->hasActiveSegment());
JS_ASSERT(cx->regs->fp->prev_ == prev);
JS_ASSERT(cx->regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
JS_ASSERT(!cx->regs->fp->hasImacropc());
JS_ASSERT(prev->base() <= newsp && newsp <= cx->regs->fp->formalArgsEnd());
JSFrameRegs *regs = cx->regs; JSFrameRegs *regs = cx->regs;
regs->fp = down; regs->fp = prev;
regs->pc = down->savedPC; regs->pc = prev->savedpc_;
regs->sp = newsp;
#ifdef DEBUG #ifdef DEBUG
down->savedPC = JSStackFrame::sInvalidPC; prev->savedpc_ = JSStackFrame::sInvalidpc;
#endif
}
JS_ALWAYS_INLINE Value *
StackSpace::getStackLimit(JSContext *cx)
{
Value *sp = cx->regs->sp;
JS_ASSERT(sp == firstUnused());
Value *limit = sp + STACK_QUOTA;
/*
* Try to reserve the whole STACK_QUOTA. If that fails, though, just
* reserve the minimum required space: enough for the nslots + an
* additional stack frame.
*/
#ifdef XP_WIN
if (JS_LIKELY(limit <= commitEnd))
return limit;
if (ensureSpace(NULL /* don't report error */, sp, STACK_QUOTA))
return limit;
uintN minimum = cx->fp()->numSlots() + VALUES_PER_STACK_FRAME;
return ensureSpace(cx, sp, minimum) ? sp + minimum : NULL;
#else
if (JS_LIKELY(limit <= end))
return limit;
uintN minimum = cx->fp()->numSlots() + VALUES_PER_STACK_FRAME;
return ensureSpace(cx, sp, minimum) ? sp + minimum : NULL;
#endif #endif
} }
@ -392,42 +439,22 @@ FrameRegsIter::FrameRegsIter(JSContext *cx)
return; return;
} }
inline Value *
FrameRegsIter::contiguousDownFrameSP(JSStackFrame *up)
{
JS_ASSERT(up->argv);
Value *sp = up->argv + up->numActualArgs();
#ifdef DEBUG
JS_ASSERT(sp <= up->argEnd());
JS_ASSERT(sp >= (up->down->hasScript() ? up->down->base() : up->down->slots()));
if (up->hasFunction()) {
uint16 nargs = up->getFunction()->nargs;
uintN argc = up->numActualArgs();
uintN missing = argc < nargs ? nargs - argc : 0;
JS_ASSERT(sp == up->argEnd() - missing);
} else {
JS_ASSERT(sp == up->argEnd());
}
#endif
return sp;
}
inline FrameRegsIter & inline FrameRegsIter &
FrameRegsIter::operator++() FrameRegsIter::operator++()
{ {
JSStackFrame *up = curfp; JSStackFrame *fp = curfp;
JSStackFrame *down = curfp = curfp->down; JSStackFrame *prev = curfp = curfp->prev();
if (!down) if (!prev)
return *this; return *this;
curpc = down->savedPC; curpc = prev->savedpc_;
if (JS_UNLIKELY(up == curseg->getInitialFrame())) { if (JS_UNLIKELY(fp == curseg->getInitialFrame())) {
incSlow(up, down); incSlow(fp, prev);
return *this; return *this;
} }
cursp = contiguousDownFrameSP(up); cursp = fp->formalArgsEnd();
return *this; return *this;
} }

Просмотреть файл

@ -2056,7 +2056,7 @@ date_toJSON(JSContext *cx, uintN argc, Value *vp)
/* Step 6. */ /* Step 6. */
LeaveTrace(cx); LeaveTrace(cx);
InvokeArgsGuard args; InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, 0, args)) if (!cx->stack().pushInvokeArgs(cx, 0, &args))
return false; return false;
args.callee() = toISO; args.callee() = toISO;

Просмотреть файл

@ -64,6 +64,7 @@
#include "jsstr.h" #include "jsstr.h"
#include "jsatominlines.h" #include "jsatominlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jsscopeinlines.h" #include "jsscopeinlines.h"
@ -1077,7 +1078,7 @@ JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
JS_PUBLIC_API(JSStackFrame *) JS_PUBLIC_API(JSStackFrame *)
JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp) JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
{ {
*iteratorp = (*iteratorp == NULL) ? js_GetTopStackFrame(cx) : (*iteratorp)->down; *iteratorp = (*iteratorp == NULL) ? js_GetTopStackFrame(cx) : (*iteratorp)->prev();
return *iteratorp; return *iteratorp;
} }
@ -1104,16 +1105,16 @@ js_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
{ {
JSSecurityCallbacks *callbacks; JSSecurityCallbacks *callbacks;
if (fp->hasFunction()) { if (fp->isFunctionFrame()) {
callbacks = JS_GetSecurityCallbacks(cx); callbacks = JS_GetSecurityCallbacks(cx);
if (callbacks && callbacks->findObjectPrincipals) { if (callbacks && callbacks->findObjectPrincipals) {
if (FUN_OBJECT(fp->getFunction()) != fp->callee()) if (&fp->fun()->compiledFunObj() != &fp->callee())
return callbacks->findObjectPrincipals(cx, fp->callee()); return callbacks->findObjectPrincipals(cx, &fp->callee());
/* FALL THROUGH */ /* FALL THROUGH */
} }
} }
if (fp->hasScript()) if (fp->isScriptFrame())
return fp->getScript()->principals; return fp->script()->principals;
return NULL; return NULL;
} }
@ -1140,7 +1141,7 @@ js_EvalFramePrincipals(JSContext *cx, JSObject *callee, JSStackFrame *caller)
JS_PUBLIC_API(void *) JS_PUBLIC_API(void *)
JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp) JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
{ {
if (fp->hasAnnotation() && fp->hasScript()) { if (fp->annotation() && fp->isScriptFrame()) {
JSPrincipals *principals = js_StackFramePrincipals(cx, fp); JSPrincipals *principals = js_StackFramePrincipals(cx, fp);
if (principals && principals->globalPrivilegesEnabled(cx, principals)) { if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
@ -1148,7 +1149,7 @@ JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
* Give out an annotation only if privileges have not been revoked * Give out an annotation only if privileges have not been revoked
* or disabled globally. * or disabled globally.
*/ */
return fp->getAnnotation(); return fp->annotation();
} }
} }
@ -1182,7 +1183,7 @@ JS_IsScriptFrame(JSContext *cx, JSStackFrame *fp)
JS_PUBLIC_API(JSObject *) JS_PUBLIC_API(JSObject *)
JS_GetFrameObject(JSContext *cx, JSStackFrame *fp) JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
{ {
return fp->maybeScopeChain(); return &fp->scopeChain();
} }
JS_PUBLIC_API(JSObject *) JS_PUBLIC_API(JSObject *)
@ -1200,7 +1201,7 @@ JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
{ {
JS_ASSERT(cx->stack().contains(fp)); JS_ASSERT(cx->stack().contains(fp));
if (!fp->hasFunction()) if (!fp->isFunctionFrame())
return NULL; return NULL;
/* Force creation of argument object if not yet created */ /* Force creation of argument object if not yet created */
@ -1218,37 +1219,36 @@ JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
{ {
if (fp->isDummyFrame()) if (fp->isDummyFrame())
return NULL; return NULL;
else return fp->computeThisObject(cx);
return fp->getThisObject(cx);
} }
JS_PUBLIC_API(JSFunction *) JS_PUBLIC_API(JSFunction *)
JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp) JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
{ {
return fp->maybeFunction(); return fp->maybeFun();
} }
JS_PUBLIC_API(JSObject *) JS_PUBLIC_API(JSObject *)
JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp) JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
{ {
if (!fp->hasFunction()) if (!fp->isFunctionFrame())
return NULL; return NULL;
JS_ASSERT(fp->callee()->isFunction()); JS_ASSERT(fp->callee().isFunction());
JS_ASSERT(fp->callee()->getPrivate() == fp->getFunction()); JS_ASSERT(fp->callee().getPrivate() == fp->fun());
return fp->callee(); return &fp->callee();
} }
JS_PUBLIC_API(JSBool) JS_PUBLIC_API(JSBool)
JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp) JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
{ {
return (fp->flags & JSFRAME_CONSTRUCTING) != 0; return fp->isConstructing();
} }
JS_PUBLIC_API(JSObject *) JS_PUBLIC_API(JSObject *)
JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp) JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
{ {
return fp->callee(); return fp->maybeCallee();
} }
JS_PUBLIC_API(JSBool) JS_PUBLIC_API(JSBool)
@ -1265,13 +1265,13 @@ JS_GetValidFrameCalleeObject(JSContext *cx, JSStackFrame *fp, jsval *vp)
JS_PUBLIC_API(JSBool) JS_PUBLIC_API(JSBool)
JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp) JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
{ {
return (fp->flags & JSFRAME_DEBUGGER) != 0; return fp->isDebuggerFrame();
} }
JS_PUBLIC_API(jsval) JS_PUBLIC_API(jsval)
JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp) JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
{ {
return Jsvalify(fp->getReturnValue()); return Jsvalify(fp->returnValue());
} }
JS_PUBLIC_API(void) JS_PUBLIC_API(void)
@ -1354,7 +1354,7 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
if (!script) if (!script)
return false; return false;
bool ok = !!Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL, Valueify(rval)); bool ok = Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL, Valueify(rval));
js_DestroyScript(cx, script); js_DestroyScript(cx, script);
return ok; return ok;
@ -1534,13 +1534,14 @@ js_GetPropertyByIdWithFakeFrame(JSContext *cx, JSObject *obj, JSObject *scopeobj
{ {
JS_ASSERT(scopeobj->isGlobal()); JS_ASSERT(scopeobj->isGlobal());
JSFrameRegs regs; DummyFrameGuard frame;
FrameGuard frame; if (!cx->stack().pushDummyFrame(cx, *scopeobj, &frame))
if (!cx->stack().pushDummyFrame(cx, frame, regs, scopeobj))
return false; return false;
bool ok = JS_GetPropertyById(cx, obj, id, vp); bool ok = JS_GetPropertyById(cx, obj, id, vp);
frame.getFrame()->putActivationObjects(cx);
JS_ASSERT(!frame.fp()->hasCallObj());
JS_ASSERT(!frame.fp()->hasArgsObj());
return ok; return ok;
} }
@ -1550,13 +1551,14 @@ js_SetPropertyByIdWithFakeFrame(JSContext *cx, JSObject *obj, JSObject *scopeobj
{ {
JS_ASSERT(scopeobj->isGlobal()); JS_ASSERT(scopeobj->isGlobal());
JSFrameRegs regs; DummyFrameGuard frame;
FrameGuard frame; if (!cx->stack().pushDummyFrame(cx, *scopeobj, &frame))
if (!cx->stack().pushDummyFrame(cx, frame, regs, scopeobj))
return false; return false;
bool ok = JS_SetPropertyById(cx, obj, id, vp); bool ok = JS_SetPropertyById(cx, obj, id, vp);
frame.getFrame()->putActivationObjects(cx);
JS_ASSERT(!frame.fp()->hasCallObj());
JS_ASSERT(!frame.fp()->hasArgsObj());
return ok; return ok;
} }
@ -1566,13 +1568,14 @@ js_CallFunctionValueWithFakeFrame(JSContext *cx, JSObject *obj, JSObject *scopeo
{ {
JS_ASSERT(scopeobj->isGlobal()); JS_ASSERT(scopeobj->isGlobal());
JSFrameRegs regs; DummyFrameGuard frame;
FrameGuard frame; if (!cx->stack().pushDummyFrame(cx, *scopeobj, &frame))
if (!cx->stack().pushDummyFrame(cx, frame, regs, scopeobj))
return false; return false;
bool ok = JS_CallFunctionValue(cx, obj, funval, argc, argv, rval); bool ok = JS_CallFunctionValue(cx, obj, funval, argc, argv, rval);
frame.getFrame()->putActivationObjects(cx);
JS_ASSERT(!frame.fp()->hasCallObj());
JS_ASSERT(!frame.fp()->hasArgsObj());
return ok; return ok;
} }
@ -1747,9 +1750,9 @@ JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
if (!fp) if (!fp)
fp = js_GetTopStackFrame(cx); fp = js_GetTopStackFrame(cx);
while (fp) { while (fp) {
if (fp->hasScript()) if (fp->isScriptFrame())
return JS_GetScriptFilenameFlags(fp->getScript()); return JS_GetScriptFilenameFlags(fp->script());
fp = fp->down; fp = fp->prev();
} }
return 0; return 0;
} }
@ -2254,7 +2257,7 @@ inline char *
jstv_Filename(JSStackFrame *fp) jstv_Filename(JSStackFrame *fp)
{ {
while (fp && fp->script == NULL) while (fp && fp->script == NULL)
fp = fp->down; fp = fp->prev;
return (fp && fp->script && fp->script->filename) return (fp && fp->script && fp->script->filename)
? (char *)fp->script->filename ? (char *)fp->script->filename
: jstv_empty; : jstv_empty;
@ -2263,7 +2266,7 @@ inline uintN
jstv_Lineno(JSContext *cx, JSStackFrame *fp) jstv_Lineno(JSContext *cx, JSStackFrame *fp)
{ {
while (fp && fp->pc(cx) == NULL) while (fp && fp->pc(cx) == NULL)
fp = fp->down; fp = fp->prev;
return (fp && fp->pc(cx)) ? js_FramePCToLineNumber(cx, fp) : 0; return (fp && fp->pc(cx)) ? js_FramePCToLineNumber(cx, fp) : 0;
} }

Просмотреть файл

@ -1894,7 +1894,7 @@ static bool
MakeUpvarForEval(JSParseNode *pn, JSCodeGenerator *cg) MakeUpvarForEval(JSParseNode *pn, JSCodeGenerator *cg)
{ {
JSContext *cx = cg->parser->context; JSContext *cx = cg->parser->context;
JSFunction *fun = cg->parser->callerFrame->getFunction(); JSFunction *fun = cg->parser->callerFrame->fun();
uintN upvarLevel = fun->u.i.script->staticLevel; uintN upvarLevel = fun->u.i.script->staticLevel;
JSFunctionBox *funbox = cg->funbox; JSFunctionBox *funbox = cg->funbox;
@ -2077,8 +2077,8 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (cg->flags & TCF_IN_FOR_INIT) if (cg->flags & TCF_IN_FOR_INIT)
return JS_TRUE; return JS_TRUE;
JS_ASSERT(caller->hasScript()); JS_ASSERT(caller->isScriptFrame());
if (!caller->hasFunction()) if (!caller->isFunctionFrame())
return JS_TRUE; return JS_TRUE;
/* /*
@ -2107,7 +2107,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
* defeats the display optimization to static link searching used * defeats the display optimization to static link searching used
* by JSOP_{GET,CALL}UPVAR. * by JSOP_{GET,CALL}UPVAR.
*/ */
JSFunction *fun = cg->parser->callerFrame->getFunction(); JSFunction *fun = cg->parser->callerFrame->fun();
JS_ASSERT(cg->staticLevel >= fun->u.i.script->staticLevel); JS_ASSERT(cg->staticLevel >= fun->u.i.script->staticLevel);
unsigned skip = cg->staticLevel - fun->u.i.script->staticLevel; unsigned skip = cg->staticLevel - fun->u.i.script->staticLevel;
if (cg->skipSpansGenerator(skip)) if (cg->skipSpansGenerator(skip))
@ -2202,8 +2202,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
#ifdef DEBUG #ifdef DEBUG
JSStackFrame *caller = cg->parser->callerFrame; JSStackFrame *caller = cg->parser->callerFrame;
#endif #endif
JS_ASSERT(caller); JS_ASSERT(caller->isScriptFrame());
JS_ASSERT(caller->hasScript());
JSTreeContext *tc = cg; JSTreeContext *tc = cg;
while (tc->staticLevel != level) while (tc->staticLevel != level)
@ -2212,7 +2211,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JSCodeGenerator *evalcg = (JSCodeGenerator *) tc; JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
JS_ASSERT(evalcg->compileAndGo()); JS_ASSERT(evalcg->compileAndGo());
JS_ASSERT(caller->hasFunction() && cg->parser->callerVarObj == evalcg->scopeChain); JS_ASSERT(caller->isFunctionFrame() && cg->parser->callerVarObj == evalcg->scopeChain);
/* /*
* Don't generate upvars on the left side of a for loop. See * Don't generate upvars on the left side of a for loop. See

Просмотреть файл

@ -63,6 +63,7 @@
#include "jsstaticcheck.h" #include "jsstaticcheck.h"
#include "jscntxtinlines.h" #include "jscntxtinlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
using namespace js; using namespace js;
@ -257,6 +258,19 @@ GetStackTraceValueBuffer(JSExnPrivate *priv)
return (jsval *)(priv->stackElems + priv->stackDepth); return (jsval *)(priv->stackElems + priv->stackDepth);
} }
namespace {
struct CopyTo
{
Value *dst;
CopyTo(jsval *dst) : dst(Valueify(dst)) {}
void operator()(uintN, Value *src) {
*dst++ = *src;
}
};
}
static JSBool static JSBool
InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message, InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
JSString *filename, uintN lineno, JSErrorReport *report) JSString *filename, uintN lineno, JSErrorReport *report)
@ -292,11 +306,11 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom); callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom);
stackDepth = 0; stackDepth = 0;
valueCount = 0; valueCount = 0;
for (fp = js_GetTopStackFrame(cx); fp; fp = fp->down) { for (fp = js_GetTopStackFrame(cx); fp; fp = fp->prev()) {
if (fp->hasFunction() && fp->argv && !fp->isEvalFrame()) { if (fp->isFunctionFrame() && !fp->isEvalFrame()) {
Value v = NullValue(); Value v = NullValue();
if (checkAccess && if (checkAccess &&
!checkAccess(cx, fp->callee(), callerid, JSACC_READ, &v)) { !checkAccess(cx, &fp->callee(), callerid, JSACC_READ, &v)) {
break; break;
} }
valueCount += fp->numActualArgs(); valueCount += fp->numActualArgs();
@ -333,22 +347,22 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
values = GetStackTraceValueBuffer(priv); values = GetStackTraceValueBuffer(priv);
elem = priv->stackElems; elem = priv->stackElems;
for (fp = js_GetTopStackFrame(cx); fp != fpstop; fp = fp->down) { for (fp = js_GetTopStackFrame(cx); fp != fpstop; fp = fp->prev()) {
if (!fp->hasFunction() || fp->isEvalFrame()) { if (!fp->isFunctionFrame() || fp->isEvalFrame()) {
elem->funName = NULL; elem->funName = NULL;
elem->argc = 0; elem->argc = 0;
} else { } else {
elem->funName = fp->getFunction()->atom elem->funName = fp->fun()->atom
? ATOM_TO_STRING(fp->getFunction()->atom) ? ATOM_TO_STRING(fp->fun()->atom)
: cx->runtime->emptyString; : cx->runtime->emptyString;
elem->argc = fp->numActualArgs(); elem->argc = fp->numActualArgs();
memcpy(values, fp->argv, elem->argc * sizeof(jsval)); fp->forEachCanonicalActualArg(CopyTo(values));
values += elem->argc; values += elem->argc;
} }
elem->ulineno = 0; elem->ulineno = 0;
elem->filename = NULL; elem->filename = NULL;
if (fp->hasScript()) { if (fp->isScriptFrame()) {
elem->filename = fp->getScript()->filename; elem->filename = fp->script()->filename;
if (fp->pc(cx)) if (fp->pc(cx))
elem->ulineno = js_FramePCToLineNumber(cx, fp); elem->ulineno = js_FramePCToLineNumber(cx, fp);
} }
@ -746,7 +760,7 @@ Exception(JSContext *cx, uintN argc, Value *vp)
} else { } else {
fp = js_GetScriptedCaller(cx, NULL); fp = js_GetScriptedCaller(cx, NULL);
if (fp) { if (fp) {
filename = FilenameToString(cx, fp->getScript()->filename); filename = FilenameToString(cx, fp->script()->filename);
if (!filename) if (!filename)
return JS_FALSE; return JS_FALSE;
} else { } else {

Просмотреть файл

@ -88,6 +88,7 @@
#include "jsatominlines.h" #include "jsatominlines.h"
#include "jscntxtinlines.h" #include "jscntxtinlines.h"
#include "jsfuninlines.h" #include "jsfuninlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
using namespace js; using namespace js;
@ -103,10 +104,10 @@ js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp)
{ {
JSObject *argsobj; JSObject *argsobj;
if (fp->flags & JSFRAME_OVERRIDE_ARGS) { if (fp->hasOverriddenArgs()) {
JS_ASSERT(fp->hasCallObj()); JS_ASSERT(fp->hasCallObj());
jsid id = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom); jsid id = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
return fp->getCallObj()->getProperty(cx, id, vp); return fp->callObj().getProperty(cx, id, vp);
} }
argsobj = js_GetArgsObject(cx, fp); argsobj = js_GetArgsObject(cx, fp);
if (!argsobj) if (!argsobj)
@ -118,12 +119,14 @@ js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp)
JSBool JSBool
js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp) js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp)
{ {
if (fp->flags & JSFRAME_OVERRIDE_ARGS) { JS_ASSERT(fp->isFunctionFrame());
if (fp->hasOverriddenArgs()) {
JS_ASSERT(fp->hasCallObj()); JS_ASSERT(fp->hasCallObj());
jsid argumentsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom); jsid argumentsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
Value v; Value v;
if (!fp->getCallObj()->getProperty(cx, argumentsid, &v)) if (!fp->callObj().getProperty(cx, argumentsid, &v))
return false; return false;
JSObject *obj; JSObject *obj;
@ -146,7 +149,7 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp)
if (argsobj->getArgsElement(arg).isMagic(JS_ARGS_HOLE)) if (argsobj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
return argsobj->getProperty(cx, id, vp); return argsobj->getProperty(cx, id, vp);
} }
*vp = fp->argv[arg]; *vp = fp->canonicalActualArg(arg);
} else { } else {
/* /*
* Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share
@ -173,7 +176,7 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp)
} }
static JSObject * static JSObject *
NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee) NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
{ {
JSObject *proto; JSObject *proto;
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto)) if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
@ -190,7 +193,7 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
SetValueRangeToUndefined(data->slots, argc); SetValueRangeToUndefined(data->slots, argc);
/* Can't fail from here on, so initialize everything in argsobj. */ /* Can't fail from here on, so initialize everything in argsobj. */
argsobj->init(callee->getFunctionPrivate()->inStrictMode() argsobj->init(callee.getFunctionPrivate()->inStrictMode()
? &StrictArgumentsClass ? &StrictArgumentsClass
: &js_ArgumentsClass, : &js_ArgumentsClass,
proto, parent, NULL, cx); proto, parent, NULL, cx);
@ -199,21 +202,24 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
argsobj->setArgsLength(argc); argsobj->setArgsLength(argc);
argsobj->setArgsData(data); argsobj->setArgsData(data);
data->callee = ObjectValue(*callee); data->callee.setObject(callee);
return argsobj; return argsobj;
} }
static void namespace {
PutArguments(JSContext *cx, JSObject *argsobj, Value *args)
struct PutArg
{ {
JS_ASSERT(argsobj->isNormalArguments()); PutArg(Value *dst) : dst(dst) {}
uint32 argc = argsobj->getArgsInitialLength(); Value *dst;
ArgumentsData *data = argsobj->getArgsData(); void operator()(uintN, Value *src) {
for (uint32 i = 0; i != argc; ++i) { if (!dst->isMagic(JS_ARGS_HOLE))
if (!data->slots[i].isMagic(JS_ARGS_HOLE)) *dst = *src;
data->slots[i] = args[i]; ++dst;
} }
};
} }
JSObject * JSObject *
@ -223,21 +229,18 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
* We must be in a function activation; the function must be lightweight * We must be in a function activation; the function must be lightweight
* or else fp must have a variable object. * or else fp must have a variable object.
*/ */
JS_ASSERT(fp->hasFunction()); JS_ASSERT_IF(fp->fun()->isHeavyweight(), fp->hasCallObj());
JS_ASSERT_IF(fp->getFunction()->flags & JSFUN_HEAVYWEIGHT,
fp->varobj(cx->containingSegment(fp)));
/* Skip eval and debugger frames. */ while (fp->isEvalOrDebuggerFrame())
while (fp->flags & JSFRAME_SPECIAL) fp = fp->prev();
fp = fp->down;
/* Create an arguments object for fp only if it lacks one. */ /* Create an arguments object for fp only if it lacks one. */
if (fp->hasArgsObj()) if (fp->hasArgsObj())
return fp->getArgsObj(); return &fp->argsObj();
/* Compute the arguments object's parent slot from fp's scope chain. */ /* Compute the arguments object's parent slot from fp's scope chain. */
JSObject *global = fp->getScopeChain()->getGlobal(); JSObject *global = fp->scopeChain().getGlobal();
JSObject *argsobj = NewArguments(cx, global, fp->numActualArgs(), &fp->argv[-2].toObject()); JSObject *argsobj = NewArguments(cx, global, fp->numActualArgs(), fp->callee());
if (!argsobj) if (!argsobj)
return argsobj; return argsobj;
@ -251,26 +254,25 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
* retrieve up-to-date parameter values. * retrieve up-to-date parameter values.
*/ */
if (argsobj->isStrictArguments()) if (argsobj->isStrictArguments())
memcpy(argsobj->getArgsData()->slots, fp->argv, fp->numActualArgs() * sizeof(Value)); fp->forEachCanonicalActualArg(PutArg(argsobj->getArgsData()->slots));
else else
argsobj->setPrivate(fp); argsobj->setPrivate(fp);
fp->setArgsObj(argsobj); fp->setArgsObj(*argsobj);
return argsobj; return argsobj;
} }
void void
js_PutArgsObject(JSContext *cx, JSStackFrame *fp) js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
{ {
JSObject *argsobj = fp->getArgsObj(); JSObject &argsobj = fp->argsObj();
if (argsobj->isNormalArguments()) { if (argsobj.isNormalArguments()) {
JS_ASSERT(argsobj->getPrivate() == fp); JS_ASSERT(argsobj.getPrivate() == fp);
PutArguments(cx, argsobj, fp->argv); fp->forEachCanonicalActualArg(PutArg(argsobj.getArgsData()->slots));
argsobj->setPrivate(NULL); argsobj.setPrivate(NULL);
} else { } else {
JS_ASSERT(!argsobj->getPrivate()); JS_ASSERT(!argsobj.getPrivate());
} }
fp->setArgsObj(NULL);
} }
#ifdef JS_TRACER #ifdef JS_TRACER
@ -279,9 +281,9 @@ js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
* Traced versions of js_GetArgsObject and js_PutArgsObject. * Traced versions of js_GetArgsObject and js_PutArgsObject.
*/ */
JSObject * JS_FASTCALL JSObject * JS_FASTCALL
js_Arguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee) js_NewArgumentsOnTrace(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
{ {
JSObject *argsobj = NewArguments(cx, parent, argc, callee); JSObject *argsobj = NewArguments(cx, parent, argc, *callee);
if (!argsobj) if (!argsobj)
return NULL; return NULL;
@ -297,20 +299,32 @@ js_Arguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
return argsobj; return argsobj;
} }
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_Arguments, CONTEXT, OBJECT, UINT32, OBJECT, JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewArgumentsOnTrace, CONTEXT, OBJECT, UINT32, OBJECT,
0, nanojit::ACCSET_STORE_ANY) 0, nanojit::ACCSET_STORE_ANY)
/* FIXME change the return type to void. */ /* FIXME change the return type to void. */
JSBool JS_FASTCALL JSBool JS_FASTCALL
js_PutArguments(JSContext *cx, JSObject *argsobj, Value *args) js_PutArgumentsOnTrace(JSContext *cx, JSObject *argsobj, Value *args)
{ {
JS_ASSERT(argsobj->isNormalArguments()); JS_ASSERT(argsobj->isNormalArguments());
JS_ASSERT(argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE); JS_ASSERT(argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE);
PutArguments(cx, argsobj, args);
/*
* TraceRecorder::putActivationObjects builds a single, contiguous array of
* the arguments, regardless of whether #actuals > #formals so there is no
* need to worry about actual vs. formal arguments.
*/
Value *srcend = args + argsobj->getArgsInitialLength();
Value *dst = argsobj->getArgsData()->slots;
for (Value *src = args; src != srcend; ++src, ++dst) {
if (!dst->isMagic(JS_ARGS_HOLE))
*dst = *src;
}
argsobj->setPrivate(NULL); argsobj->setPrivate(NULL);
return true; return true;
} }
JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArguments, CONTEXT, OBJECT, VALUEPTR, 0, JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArgumentsOnTrace, CONTEXT, OBJECT, VALUEPTR, 0,
nanojit::ACCSET_STORE_ANY) nanojit::ACCSET_STORE_ANY)
#endif /* JS_TRACER */ #endif /* JS_TRACER */
@ -496,7 +510,8 @@ ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
if (arg < obj->getArgsInitialLength()) { if (arg < obj->getArgsInitialLength()) {
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
if (fp) { if (fp) {
*vp = fp->argv[arg]; JS_ASSERT(fp->numActualArgs() == obj->getArgsInitialLength());
*vp = fp->canonicalActualArg(arg);
} else { } else {
const Value &v = obj->getArgsElement(arg); const Value &v = obj->getArgsElement(arg);
if (!v.isMagic(JS_ARGS_HOLE)) if (!v.isMagic(JS_ARGS_HOLE))
@ -551,7 +566,7 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
if (arg < obj->getArgsInitialLength()) { if (arg < obj->getArgsInitialLength()) {
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
if (fp) { if (fp) {
fp->argv[arg] = *vp; fp->canonicalActualArg(arg) = *vp;
return true; return true;
} }
} }
@ -800,7 +815,7 @@ MaybeMarkGenerator(JSTracer *trc, JSObject *obj)
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
if (fp && fp->isFloatingGenerator()) { if (fp && fp->isFloatingGenerator()) {
JSObject *genobj = js_FloatingFrameToGenerator(fp)->obj; JSObject *genobj = js_FloatingFrameToGenerator(fp)->obj;
MarkObject(trc, genobj, "generator object"); MarkObject(trc, *genobj, "generator object");
} }
#endif #endif
} }
@ -816,7 +831,7 @@ args_trace(JSTracer *trc, JSObject *obj)
ArgumentsData *data = obj->getArgsData(); ArgumentsData *data = obj->getArgsData();
if (data->callee.isObject()) if (data->callee.isObject())
MarkObject(trc, &data->callee.toObject(), js_callee_str); MarkObject(trc, data->callee.toObject(), js_callee_str);
MarkValueRange(trc, obj->getArgsInitialLength(), data->slots, js_arguments_str); MarkValueRange(trc, obj->getArgsInitialLength(), data->slots, js_arguments_str);
MaybeMarkGenerator(trc, obj); MaybeMarkGenerator(trc, obj);
@ -887,10 +902,6 @@ Class StrictArgumentsClass = {
} }
const uint32 JSSLOT_CALLEE = JSSLOT_PRIVATE + 1;
const uint32 JSSLOT_CALL_ARGUMENTS = JSSLOT_PRIVATE + 2;
const uint32 CALL_CLASS_RESERVED_SLOTS = 2;
/* /*
* A Declarative Environment object stores its active JSStackFrame pointer in * A Declarative Environment object stores its active JSStackFrame pointer in
* its private slot, just as Call and Arguments objects do. * its private slot, just as Call and Arguments objects do.
@ -951,13 +962,13 @@ CalleeGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
} }
static JSObject * static JSObject *
NewCallObject(JSContext *cx, JSFunction *fun, JSObject *scopeChain) NewCallObject(JSContext *cx, JSFunction *fun, JSObject &scopeChain, JSObject &callee)
{ {
JSObject *callobj = js_NewGCObject(cx); JSObject *callobj = js_NewGCObject(cx);
if (!callobj) if (!callobj)
return NULL; return NULL;
callobj->init(&js_CallClass, NULL, scopeChain, NULL, cx); callobj->init(&js_CallClass, NULL, &scopeChain, NULL, cx);
callobj->setMap(fun->u.i.names); callobj->setMap(fun->u.i.names);
/* This must come after callobj->lastProp has been set. */ /* This must come after callobj->lastProp has been set. */
@ -973,6 +984,8 @@ NewCallObject(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
} }
} }
#endif #endif
callobj->setCallObjCallee(callee);
return callobj; return callobj;
} }
@ -983,7 +996,7 @@ NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
if (!envobj) if (!envobj)
return NULL; return NULL;
envobj->init(&js_DeclEnvClass, NULL, fp->maybeScopeChain(), fp, cx); envobj->init(&js_DeclEnvClass, NULL, &fp->scopeChain(), fp, cx);
envobj->setMap(cx->runtime->emptyDeclEnvShape); envobj->setMap(cx->runtime->emptyDeclEnvShape);
return envobj; return envobj;
} }
@ -992,17 +1005,17 @@ JSObject *
js_GetCallObject(JSContext *cx, JSStackFrame *fp) js_GetCallObject(JSContext *cx, JSStackFrame *fp)
{ {
/* Create a call object for fp only if it lacks one. */ /* Create a call object for fp only if it lacks one. */
JS_ASSERT(fp->hasFunction()); JS_ASSERT(fp->isFunctionFrame());
if (fp->hasCallObj()) if (fp->hasCallObj())
return fp->getCallObj(); return &fp->callObj();
#ifdef DEBUG #ifdef DEBUG
/* A call object should be a frame's outermost scope chain element. */ /* A call object should be a frame's outermost scope chain element. */
Class *clasp = fp->getScopeChain()->getClass(); Class *clasp = fp->scopeChain().getClass();
if (clasp == &js_WithClass || clasp == &js_BlockClass) if (clasp == &js_WithClass || clasp == &js_BlockClass)
JS_ASSERT(fp->getScopeChain()->getPrivate() != js_FloatingFrameIfGenerator(cx, fp)); JS_ASSERT(fp->scopeChain().getPrivate() != js_FloatingFrameIfGenerator(cx, fp));
else if (clasp == &js_CallClass) else if (clasp == &js_CallClass)
JS_ASSERT(fp->getScopeChain()->getPrivate() != fp); JS_ASSERT(fp->scopeChain().getPrivate() != fp);
#endif #endif
/* /*
@ -1012,17 +1025,16 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
* function's name. * function's name.
*/ */
JSAtom *lambdaName = JSAtom *lambdaName =
(fp->getFunction()->flags & JSFUN_LAMBDA) ? fp->getFunction()->atom : NULL; (fp->fun()->flags & JSFUN_LAMBDA) ? fp->fun()->atom : NULL;
if (lambdaName) { if (lambdaName) {
JSObject *envobj = NewDeclEnvObject(cx, fp); JSObject *envobj = NewDeclEnvObject(cx, fp);
if (!envobj) if (!envobj)
return NULL; return NULL;
/* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */ /* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */
fp->setScopeChain(envobj); fp->setScopeChainNoCallObj(*envobj);
JS_ASSERT(fp->argv); if (!js_DefineNativeProperty(cx, &fp->scopeChain(), ATOM_TO_JSID(lambdaName),
if (!js_DefineNativeProperty(cx, fp->getScopeChain(), ATOM_TO_JSID(lambdaName), ObjectValue(fp->callee()),
fp->calleeValue(),
CalleeGetter, NULL, CalleeGetter, NULL,
JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_PERMANENT | JSPROP_READONLY,
0, 0, NULL)) { 0, 0, NULL)) {
@ -1030,21 +1042,18 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
} }
} }
JSObject *callobj = NewCallObject(cx, fp->getFunction(), fp->getScopeChain()); JSObject *callobj = NewCallObject(cx, fp->fun(), fp->scopeChain(), fp->callee());
if (!callobj) if (!callobj)
return NULL; return NULL;
callobj->setPrivate(fp); callobj->setPrivate(fp);
JS_ASSERT(fp->argv); JS_ASSERT(fp->fun() == fp->callee().getFunctionPrivate());
JS_ASSERT(fp->getFunction() == GET_FUNCTION_PRIVATE(cx, fp->callee()));
callobj->setSlot(JSSLOT_CALLEE, fp->calleeValue());
fp->setCallObj(callobj);
/* /*
* Push callobj on the top of the scope chain, and make it the * Push callobj on the top of the scope chain, and make it the
* variables object. * variables object.
*/ */
fp->setScopeChain(callobj); fp->setScopeChainAndCallObj(*callobj);
return callobj; return callobj;
} }
@ -1052,38 +1061,22 @@ JSObject * JS_FASTCALL
js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain) js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain)
{ {
JS_ASSERT(!js_IsNamedLambda(fun)); JS_ASSERT(!js_IsNamedLambda(fun));
JSObject *callobj = NewCallObject(cx, fun, scopeChain); JS_ASSERT(scopeChain);
if (!callobj) return NewCallObject(cx, fun, *scopeChain, *callee);
return NULL;
callobj->setSlot(JSSLOT_CALLEE, ObjectValue(*callee));
return callobj;
} }
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTION, OBJECT, OBJECT, JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTION, OBJECT, OBJECT,
0, nanojit::ACCSET_STORE_ANY) 0, nanojit::ACCSET_STORE_ANY)
JSFunction *
js_GetCallObjectFunction(JSObject *obj)
{
JS_ASSERT(obj->isCall());
const Value &v = obj->getSlot(JSSLOT_CALLEE);
if (v.isUndefined()) {
/* Newborn or prototype object. */
return NULL;
}
JS_ASSERT(v.isObject());
return GET_FUNCTION_PRIVATE(cx, &v.toObject());
}
inline static void inline static void
CopyValuesToCallObject(JSObject *callobj, uintN nargs, Value *argv, uintN nvars, Value *slots) CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars, Value *slots)
{ {
/* Copy however many args fit into fslots. */ /* Copy however many args fit into fslots. */
uintN first = JSSLOT_PRIVATE + CALL_CLASS_RESERVED_SLOTS + 1; uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
JS_ASSERT(first <= JS_INITIAL_NSLOTS); JS_ASSERT(first <= JS_INITIAL_NSLOTS);
Value *vp = &callobj->fslots[first]; Value *vp = &callobj.fslots[first];
uintN len = JS_MIN(nargs, JS_INITIAL_NSLOTS - first); uintN len = Min(nargs, uintN(JS_INITIAL_NSLOTS) - first);
memcpy(vp, argv, len * sizeof(Value)); memcpy(vp, argv, len * sizeof(Value));
vp += len; vp += len;
@ -1091,7 +1084,7 @@ CopyValuesToCallObject(JSObject *callobj, uintN nargs, Value *argv, uintN nvars,
nargs -= len; nargs -= len;
if (nargs != 0) { if (nargs != 0) {
/* Copy any remaining args into dslots. */ /* Copy any remaining args into dslots. */
vp = callobj->dslots; vp = callobj.dslots;
memcpy(vp, argv + len, nargs * sizeof(Value)); memcpy(vp, argv + len, nargs * sizeof(Value));
vp += nargs; vp += nargs;
} else { } else {
@ -1101,7 +1094,7 @@ CopyValuesToCallObject(JSObject *callobj, uintN nargs, Value *argv, uintN nvars,
memcpy(vp, slots, len * sizeof(Value)); memcpy(vp, slots, len * sizeof(Value));
slots += len; slots += len;
nvars -= len; nvars -= len;
vp = callobj->dslots; vp = callobj.dslots;
} }
/* Copy any remaining vars into dslots. */ /* Copy any remaining vars into dslots. */
@ -1111,17 +1104,17 @@ CopyValuesToCallObject(JSObject *callobj, uintN nargs, Value *argv, uintN nvars,
void void
js_PutCallObject(JSContext *cx, JSStackFrame *fp) js_PutCallObject(JSContext *cx, JSStackFrame *fp)
{ {
JSObject *callobj = fp->getCallObj(); JSObject &callobj = fp->callObj();
/* Get the arguments object to snapshot fp's actual argument values. */ /* Get the arguments object to snapshot fp's actual argument values. */
if (fp->hasArgsObj()) { if (fp->hasArgsObj()) {
if (!(fp->flags & JSFRAME_OVERRIDE_ARGS)) if (!fp->hasOverriddenArgs())
callobj->setSlot(JSSLOT_CALL_ARGUMENTS, ObjectOrNullValue(fp->getArgsObj())); callobj.setCallObjArguments(ObjectValue(fp->argsObj()));
js_PutArgsObject(cx, fp); js_PutArgsObject(cx, fp);
} }
JSFunction *fun = fp->getFunction(); JSFunction *fun = fp->fun();
JS_ASSERT(fun == js_GetCallObjectFunction(callobj)); JS_ASSERT(fun == callobj.getCallObjCalleeFunction());
uintN n = fun->countArgsAndVars(); uintN n = fun->countArgsAndVars();
/* /*
@ -1129,52 +1122,52 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
* arguments and variables straight into JSObject.dslots. * arguments and variables straight into JSObject.dslots.
*/ */
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS - JSSLOT_PRIVATE == JS_STATIC_ASSERT(JS_INITIAL_NSLOTS - JSSLOT_PRIVATE ==
1 + CALL_CLASS_RESERVED_SLOTS); 1 + JSObject::CALL_RESERVED_SLOTS);
if (n != 0) { if (n != 0) {
JS_ASSERT(JSFunction::FIRST_FREE_SLOT + n <= callobj->numSlots()); JS_ASSERT(JSFunction::FIRST_FREE_SLOT + n <= callobj.numSlots());
JSScript *script = fun->u.i.script;
uint32 nargs = fun->nargs; uint32 nargs = fun->nargs;
uint32 nvars = fun->u.i.nvars; uint32 nvars = fun->u.i.nvars;
#ifdef JS_METHODJIT #ifdef JS_METHODJIT
memcpy(callobj->dslots, fp->argv, nargs * sizeof(Value)); JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1);
JSScript *script = fun->u.i.script;
memcpy(callobj.dslots, fp->formalArgs(), nargs * sizeof(Value));
if (!script->jit || script->usesEval) { if (!script->jit || script->usesEval) {
memcpy(callobj->dslots + nargs, fp->slots(), nvars * sizeof(Value)); memcpy(callobj.dslots + nargs, fp->slots(), nvars * sizeof(Value));
} else if (script->jit) { } else if (script->jit) {
for (uint32 i = 0; i < script->jit->nescaping; i++) { for (uint32 i = 0; i < script->jit->nescaping; i++) {
uint32 e = script->jit->escaping[i]; uint32 e = script->jit->escaping[i];
callobj->dslots[nargs + e] = fp->slots()[e]; callobj.dslots[nargs + e] = fp->slots()[e];
} }
} }
#else #else
CopyValuesToCallObject(callobj, nargs, fp->argv, nvars, fp->slots()); CopyValuesToCallObject(callobj, nargs, fp->formalArgs(), nvars, fp->slots());
#endif #endif
} }
/* Clear private pointers to fp, which is about to go away (js_Invoke). */ /* Clear private pointers to fp, which is about to go away (js_Invoke). */
if (js_IsNamedLambda(fun)) { if (js_IsNamedLambda(fun)) {
JSObject *env = callobj->getParent(); JSObject *env = callobj.getParent();
JS_ASSERT(env->getClass() == &js_DeclEnvClass); JS_ASSERT(env->getClass() == &js_DeclEnvClass);
JS_ASSERT(env->getPrivate() == fp); JS_ASSERT(env->getPrivate() == fp);
env->setPrivate(NULL); env->setPrivate(NULL);
} }
callobj->setPrivate(NULL); callobj.setPrivate(NULL);
fp->setCallObj(NULL);
} }
JSBool JS_FASTCALL JSBool JS_FASTCALL
js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs, Value *argv, js_PutCallObjectOnTrace(JSContext *cx, JSObject *callobj, uint32 nargs, Value *argv,
uint32 nvars, Value *slots) uint32 nvars, Value *slots)
{ {
JS_ASSERT(scopeChain->hasClass(&js_CallClass)); JS_ASSERT(callobj->isCall());
JS_ASSERT(!scopeChain->getPrivate()); JS_ASSERT(!callobj->getPrivate());
uintN n = nargs + nvars; uintN n = nargs + nvars;
if (n != 0) if (n != 0)
CopyValuesToCallObject(scopeChain, nargs, argv, nvars, slots); CopyValuesToCallObject(*callobj, nargs, argv, nvars, slots);
return true; return true;
} }
@ -1203,17 +1196,17 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
Value *array; Value *array;
if (kind == JSCPK_UPVAR) { if (kind == JSCPK_UPVAR) {
JSObject *callee = &obj->getSlot(JSSLOT_CALLEE).toObject(); JSObject &callee = obj->getCallObjCallee();
#ifdef DEBUG #ifdef DEBUG
JSFunction *callee_fun = (JSFunction *) callee->getPrivate(); JSFunction *callee_fun = (JSFunction *) callee.getPrivate();
JS_ASSERT(FUN_FLAT_CLOSURE(callee_fun)); JS_ASSERT(FUN_FLAT_CLOSURE(callee_fun));
JS_ASSERT(i < callee_fun->u.i.nupvars); JS_ASSERT(i < callee_fun->u.i.nupvars);
#endif #endif
array = callee->getFlatClosureUpvars(); array = callee.getFlatClosureUpvars();
} else { } else {
JSFunction *fun = js_GetCallObjectFunction(obj); JSFunction *fun = obj->getCallObjCalleeFunction();
JS_ASSERT_IF(kind == JSCPK_ARG, i < fun->nargs); JS_ASSERT_IF(kind == JSCPK_ARG, i < fun->nargs);
JS_ASSERT_IF(kind == JSCPK_VAR, i < fun->u.i.nvars); JS_ASSERT_IF(kind == JSCPK_VAR, i < fun->u.i.nvars);
@ -1222,10 +1215,10 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
if (kind == JSCPK_ARGUMENTS) { if (kind == JSCPK_ARGUMENTS) {
if (setter) { if (setter) {
if (fp) if (fp)
fp->flags |= JSFRAME_OVERRIDE_ARGS; fp->setOverriddenArgs();
obj->setSlot(JSSLOT_CALL_ARGUMENTS, *vp); obj->setCallObjArguments(*vp);
} else { } else {
if (fp && !(fp->flags & JSFRAME_OVERRIDE_ARGS)) { if (fp && !fp->hasOverriddenArgs()) {
JSObject *argsobj; JSObject *argsobj;
argsobj = js_GetArgsObject(cx, fp); argsobj = js_GetArgsObject(cx, fp);
@ -1233,7 +1226,7 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
return false; return false;
vp->setObject(*argsobj); vp->setObject(*argsobj);
} else { } else {
*vp = obj->getSlot(JSSLOT_CALL_ARGUMENTS); *vp = obj->getCallObjArguments();
} }
} }
return true; return true;
@ -1245,13 +1238,13 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
else else
JS_ASSERT(kind == JSCPK_ARG); JS_ASSERT(kind == JSCPK_ARG);
const uintN first = JSSLOT_PRIVATE + CALL_CLASS_RESERVED_SLOTS + 1; const uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
JS_ASSERT(first == JSSLOT_FREE(&js_CallClass)); JS_ASSERT(first == JSSLOT_FREE(&js_CallClass));
JS_ASSERT(first <= JS_INITIAL_NSLOTS); JS_ASSERT(first <= JS_INITIAL_NSLOTS);
array = (i < JS_INITIAL_NSLOTS - first) ? obj->fslots : obj->dslots; array = (i < JS_INITIAL_NSLOTS - first) ? obj->fslots : obj->dslots;
} else if (kind == JSCPK_ARG) { } else if (kind == JSCPK_ARG) {
array = fp->argv; array = fp->formalArgs();
} else { } else {
JS_ASSERT(kind == JSCPK_VAR); JS_ASSERT(kind == JSCPK_VAR);
array = fp->slots(); array = fp->slots();
@ -1354,13 +1347,8 @@ call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
if (!JSID_IS_ATOM(id)) if (!JSID_IS_ATOM(id))
return JS_TRUE; return JS_TRUE;
const Value &callee = obj->getSlot(JSSLOT_CALLEE);
if (callee.isUndefined())
return JS_TRUE;
#ifdef DEBUG #ifdef DEBUG
JSFunction *fun; JSFunction *fun = obj->getCallObjCalleeFunction();
fun = GET_FUNCTION_PRIVATE(cx, &callee.toObject());
JS_ASSERT(fun->lookupLocal(cx, JSID_TO_ATOM(id), NULL) == JSLOCAL_NONE); JS_ASSERT(fun->lookupLocal(cx, JSID_TO_ATOM(id), NULL) == JSLOCAL_NONE);
#endif #endif
@ -1396,10 +1384,10 @@ call_trace(JSTracer *trc, JSObject *obj)
* cycles involving Call objects whose frames are active without this * cycles involving Call objects whose frames are active without this
* hiding hack. * hiding hack.
*/ */
uintN first = JSSLOT_PRIVATE + CALL_CLASS_RESERVED_SLOTS + 1; uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
JS_ASSERT(first <= JS_INITIAL_NSLOTS); JS_ASSERT(first <= JS_INITIAL_NSLOTS);
uintN count = fp->getFunction()->countArgsAndVars(); uintN count = fp->fun()->countArgsAndVars();
uintN fixed = JS_MIN(count, JS_INITIAL_NSLOTS - first); uintN fixed = JS_MIN(count, JS_INITIAL_NSLOTS - first);
SetValueRangeToUndefined(&obj->fslots[first], fixed); SetValueRangeToUndefined(&obj->fslots[first], fixed);
@ -1412,7 +1400,7 @@ call_trace(JSTracer *trc, JSObject *obj)
JS_PUBLIC_DATA(Class) js_CallClass = { JS_PUBLIC_DATA(Class) js_CallClass = {
"Call", "Call",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(CALL_CLASS_RESERVED_SLOTS) | JSCLASS_HAS_RESERVED_SLOTS(JSObject::CALL_RESERVED_SLOTS) |
JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE, JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE,
PropertyStub, /* addProperty */ PropertyStub, /* addProperty */
PropertyStub, /* delProperty */ PropertyStub, /* delProperty */
@ -1434,12 +1422,12 @@ JS_PUBLIC_DATA(Class) js_CallClass = {
bool bool
JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp) JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
{ {
if (!hasFunction()) { if (!isFunctionFrame()) {
*vp = argv ? argv[-2] : UndefinedValue(); vp->setUndefined();
return true; return true;
} }
JSFunction *fun = getFunction(); JSFunction *fun = this->fun();
/* /*
* See the equivalent condition in ArgGetter for the 'callee' id case, but * See the equivalent condition in ArgGetter for the 'callee' id case, but
@ -1455,19 +1443,20 @@ JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
return true; return true;
} }
JSObject *funobj = &calleeObject(); JSObject &funobj = callee();
vp->setObject(*funobj); vp->setObject(funobj);
/* /*
* Check for an escape attempt by a joined function object, which must go * Check for an escape attempt by a joined function object, which must go
* through the frame's |this| object's method read barrier for the method * through the frame's |this| object's method read barrier for the method
* atom by which it was uniquely associated with a property. * atom by which it was uniquely associated with a property.
*/ */
if (getThisValue().isObject()) { const Value &thisv = functionThis();
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun); if (thisv.isObject()) {
JS_ASSERT(funobj.getFunctionPrivate() == fun);
if (fun == funobj && fun->methodAtom()) { if (&fun->compiledFunObj() == &funobj && fun->methodAtom()) {
JSObject *thisp = &getThisValue().toObject(); JSObject *thisp = &thisv.toObject();
JS_ASSERT(thisp->canHaveMethodBarrier()); JS_ASSERT(thisp->canHaveMethodBarrier());
if (thisp->hasMethodBarrier()) { if (thisp->hasMethodBarrier()) {
@ -1486,10 +1475,10 @@ JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
* been replaced, or its value to have been overwritten. * been replaced, or its value to have been overwritten.
*/ */
if (shape) { if (shape) {
if (shape->isMethod() && &shape->methodObject() == funobj) { if (shape->isMethod() && &shape->methodObject() == &funobj) {
if (!thisp->methodReadBarrier(cx, *shape, vp)) if (!thisp->methodReadBarrier(cx, *shape, vp))
return false; return false;
setCalleeObject(vp->toObject()); calleeValue().setObject(vp->toObject());
return true; return true;
} }
if (shape->hasSlot()) { if (shape->hasSlot()) {
@ -1499,9 +1488,9 @@ JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
if (IsFunctionObject(v, &clone) && if (IsFunctionObject(v, &clone) &&
GET_FUNCTION_PRIVATE(cx, clone) == fun && GET_FUNCTION_PRIVATE(cx, clone) == fun &&
clone->hasMethodObj(*thisp)) { clone->hasMethodObj(*thisp)) {
JS_ASSERT(clone != funobj); JS_ASSERT(clone != &funobj);
*vp = v; *vp = v;
setCalleeObject(*clone); calleeValue().setObject(*clone);
return true; return true;
} }
} }
@ -1515,11 +1504,11 @@ JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
* access. It seems that there are no longer any properties * access. It seems that there are no longer any properties
* referring to fun. * referring to fun.
*/ */
funobj = CloneFunctionObject(cx, fun, fun->getParent()); JSObject *newfunobj = CloneFunctionObject(cx, fun, fun->getParent());
if (!funobj) if (!newfunobj)
return false; return false;
funobj->setMethodObj(*thisp); newfunobj->setMethodObj(*thisp);
setCalleeObject(*funobj); calleeValue().setObject(*newfunobj);
return true; return true;
} }
} }
@ -1579,8 +1568,8 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
/* Find fun's top-most activation record. */ /* Find fun's top-most activation record. */
JSStackFrame *fp; JSStackFrame *fp;
for (fp = js_GetTopStackFrame(cx); for (fp = js_GetTopStackFrame(cx);
fp && (fp->maybeFunction() != fun || (fp->flags & JSFRAME_SPECIAL)); fp && (fp->maybeFun() != fun || fp->isEvalOrDebuggerFrame());
fp = fp->down) { fp = fp->prev()) {
continue; continue;
} }
@ -1614,7 +1603,7 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
case FUN_CALLER: case FUN_CALLER:
vp->setNull(); vp->setNull();
if (fp && fp->down && !fp->down->getValidCalleeObject(cx, vp)) if (fp && fp->prev() && !fp->prev()->getValidCalleeObject(cx, vp))
return false; return false;
if (vp->isObject()) { if (vp->isObject()) {
@ -1633,8 +1622,8 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
default: default:
/* XXX fun[0] and fun.arguments[0] are equivalent. */ /* XXX fun[0] and fun.arguments[0] are equivalent. */
if (fp && fp->hasFunction() && uint16(slot) < fp->getFunction()->nargs) if (fp && fp->isFunctionFrame() && uint16(slot) < fp->numFormalArgs())
*vp = fp->argv[slot]; *vp = fp->formalArg(slot);
break; break;
} }
@ -2067,7 +2056,7 @@ fun_trace(JSTracer *trc, JSObject *obj)
if (fun != obj) { if (fun != obj) {
/* obj is a cloned function object, trace the clone-parent, fun. */ /* obj is a cloned function object, trace the clone-parent, fun. */
MarkObject(trc, fun, "private"); MarkObject(trc, *fun, "private");
/* The function could be a flat closure with upvar copies in the clone. */ /* The function could be a flat closure with upvar copies in the clone. */
if (FUN_FLAT_CLOSURE(fun) && fun->u.i.nupvars) if (FUN_FLAT_CLOSURE(fun) && fun->u.i.nupvars)
@ -2262,7 +2251,7 @@ js_fun_call(JSContext *cx, uintN argc, Value *vp)
/* Allocate stack space for fval, obj, and the args. */ /* Allocate stack space for fval, obj, and the args. */
InvokeArgsGuard args; InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, argc, args)) if (!cx->stack().pushInvokeArgs(cx, argc, &args))
return JS_FALSE; return JS_FALSE;
/* Push fval, obj, and the args. */ /* Push fval, obj, and the args. */
@ -2275,6 +2264,24 @@ js_fun_call(JSContext *cx, uintN argc, Value *vp)
return ok; return ok;
} }
namespace {
struct CopyNonHoleArgs
{
CopyNonHoleArgs(JSObject *aobj, Value *dst) : aobj(aobj), dst(dst) {}
JSObject *aobj;
Value *dst;
void operator()(uintN argi, Value *src) {
if (aobj->getArgsElement(argi).isMagic(JS_ARGS_HOLE))
dst->setUndefined();
else
*dst = *src;
++dst;
}
};
}
/* ES5 15.3.4.3 */ /* ES5 15.3.4.3 */
JSBool JSBool
js_fun_apply(JSContext *cx, uintN argc, Value *vp) js_fun_apply(JSContext *cx, uintN argc, Value *vp)
@ -2343,7 +2350,7 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp)
uintN n = uintN(JS_MIN(length, JS_ARGS_LENGTH_MAX)); uintN n = uintN(JS_MIN(length, JS_ARGS_LENGTH_MAX));
InvokeArgsGuard args; InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, n, args)) if (!cx->stack().pushInvokeArgs(cx, n, &args))
return false; return false;
/* Push fval, obj, and aobj's elements as args. */ /* Push fval, obj, and aobj's elements as args. */
@ -2361,11 +2368,8 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp)
JSStackFrame *fp = (JSStackFrame *) aobj->getPrivate(); JSStackFrame *fp = (JSStackFrame *) aobj->getPrivate();
Value *argv = args.argv(); Value *argv = args.argv();
if (fp) { if (fp) {
memcpy(argv, fp->argv, n * sizeof(Value)); JS_ASSERT(fp->numActualArgs() <= JS_ARGS_LENGTH_MAX);
for (uintN i = 0; i < n; i++) { fp->forEachCanonicalActualArg(CopyNonHoleArgs(aobj, argv));
if (aobj->getArgsElement(i).isMagic(JS_ARGS_HOLE)) // suppress deleted element
argv[i].setUndefined();
}
} else { } else {
for (uintN i = 0; i < n; i++) { for (uintN i = 0; i < n; i++) {
argv[i] = aobj->getArgsElement(i); argv[i] = aobj->getArgsElement(i);
@ -2489,7 +2493,7 @@ CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
const Value &boundThis = obj->getBoundFunctionThis(); const Value &boundThis = obj->getBoundFunctionThis();
InvokeArgsGuard args; InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, argc + argslen, args)) if (!cx->stack().pushInvokeArgs(cx, argc + argslen, &args))
return false; return false;
/* 15.3.4.5.1, 15.3.4.5.2 step 4. */ /* 15.3.4.5.1, 15.3.4.5.2 step 4. */
@ -2991,8 +2995,8 @@ js_NewFlatClosure(JSContext *cx, JSFunction *fun)
JSObject * JSObject *
js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun) js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun)
{ {
JS_ASSERT(cx->fp()->getFunction()->flags & JSFUN_HEAVYWEIGHT); JS_ASSERT(cx->fp()->fun()->flags & JSFUN_HEAVYWEIGHT);
JS_ASSERT(!cx->fp()->getFunction()->optimizedClosure()); JS_ASSERT(!cx->fp()->fun()->optimizedClosure());
JS_ASSERT(FUN_FLAT_CLOSURE(fun)); JS_ASSERT(FUN_FLAT_CLOSURE(fun));
return WrapEscapingClosure(cx, cx->fp(), fun); return WrapEscapingClosure(cx, cx->fp(), fun);
@ -3094,7 +3098,7 @@ js_ReportIsNotFunction(JSContext *cx, const Value *vp, uintN flags)
++i; ++i;
if (!i.done()) { if (!i.done()) {
uintN depth = js_ReconstructStackDepth(cx, i.fp()->getScript(), i.pc()); uintN depth = js_ReconstructStackDepth(cx, i.fp()->script(), i.pc());
Value *simsp = i.fp()->base() + depth; Value *simsp = i.fp()->base() + depth;
JS_ASSERT(simsp <= i.sp()); JS_ASSERT(simsp <= i.sp());
if (i.fp()->base() <= vp && vp < simsp) if (i.fp()->base() <= vp && vp < simsp)
@ -3143,7 +3147,7 @@ JSFunction::addLocal(JSContext *cx, JSAtom *atom, JSLocalKind kind)
uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED; uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED;
uint16 *indexp; uint16 *indexp;
PropertyOp getter, setter; PropertyOp getter, setter;
uint32 slot = JSSLOT_START(&js_CallClass) + CALL_CLASS_RESERVED_SLOTS; uint32 slot = JSSLOT_START(&js_CallClass) + JSObject::CALL_RESERVED_SLOTS;
if (kind == JSLOCAL_ARG) { if (kind == JSLOCAL_ARG) {
JS_ASSERT(u.i.nupvars == 0); JS_ASSERT(u.i.nupvars == 0);

Просмотреть файл

@ -169,7 +169,6 @@ struct JSFunction : public JSObject
bool isNative() const { return !FUN_INTERPRETED(this); } bool isNative() const { return !FUN_INTERPRETED(this); }
bool isConstructor() const { return flags & JSFUN_CONSTRUCTOR; } bool isConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); } bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
unsigned minArgs() const { return isInterpreted() ? nargs : 0; }
inline bool inStrictMode() const; inline bool inStrictMode() const;
@ -254,6 +253,10 @@ struct JSFunction : public JSObject
return flags & JSFUN_JOINABLE; return flags & JSFUN_JOINABLE;
} }
JSObject &compiledFunObj() {
return *this;
}
private: private:
/* /*
* js_FunctionClass reserves two slots, which are free in JSObject::fslots * js_FunctionClass reserves two slots, which are free in JSObject::fslots
@ -292,6 +295,11 @@ struct JSFunction : public JSObject
return isInterpreted() ? NULL : u.n.native; return isInterpreted() ? NULL : u.n.native;
} }
JSScript *script() const {
JS_ASSERT(isInterpreted());
return u.i.script;
}
/* Number of extra fixed function object slots besides JSSLOT_PRIVATE. */ /* Number of extra fixed function object slots besides JSSLOT_PRIVATE. */
static const uint32 CLASS_RESERVED_SLOTS = JSObject::FUN_CLASS_RESERVED_SLOTS; static const uint32 CLASS_RESERVED_SLOTS = JSObject::FUN_CLASS_RESERVED_SLOTS;
static const uint32 FIRST_FREE_SLOT = JSSLOT_PRIVATE + CLASS_RESERVED_SLOTS + 1; static const uint32 FIRST_FREE_SLOT = JSSLOT_PRIVATE + CLASS_RESERVED_SLOTS + 1;
@ -364,7 +372,6 @@ JSObject::isArguments() const
extern JS_PUBLIC_DATA(js::Class) js_CallClass; extern JS_PUBLIC_DATA(js::Class) js_CallClass;
extern JS_PUBLIC_DATA(js::Class) js_FunctionClass; extern JS_PUBLIC_DATA(js::Class) js_FunctionClass;
extern js::Class js_DeclEnvClass; extern js::Class js_DeclEnvClass;
extern const uint32 CALL_CLASS_RESERVED_SLOTS;
inline bool inline bool
JSObject::isCall() const JSObject::isCall() const
@ -551,9 +558,6 @@ extern JSBool JS_FASTCALL
js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs, js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs,
js::Value *argv, uint32 nvars, js::Value *slots); js::Value *argv, uint32 nvars, js::Value *slots);
extern JSFunction *
js_GetCallObjectFunction(JSObject *obj);
extern JSBool extern JSBool
js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);

Просмотреть файл

@ -87,6 +87,7 @@
#include "jsprobes.h" #include "jsprobes.h"
#include "jscntxtinlines.h" #include "jscntxtinlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jshashtable.h" #include "jshashtable.h"
@ -2032,18 +2033,19 @@ gc_lock_traversal(const GCLocks::Entry &entry, JSTracer *trc)
void void
js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
{ {
if (fp->hasCallObj()) MarkObject(trc, fp->scopeChain(), "scope chain");
JS_CALL_OBJECT_TRACER(trc, fp->getCallObj(), "call"); if (fp->isDummyFrame())
if (fp->hasArgsObj()) return;
JS_CALL_OBJECT_TRACER(trc, fp->getArgsObj(), "arguments");
if (fp->hasScript())
js_TraceScript(trc, fp->getScript());
/* Allow for primitive this parameter due to JSFUN_THISP_* flags. */ if (fp->hasCallObj())
MarkValue(trc, fp->getThisValue(), "this"); MarkObject(trc, fp->callObj(), "call");
MarkValue(trc, fp->getReturnValue(), "rval"); if (fp->hasArgsObj())
if (fp->hasScopeChain()) MarkObject(trc, fp->argsObj(), "arguments");
JS_CALL_OBJECT_TRACER(trc, fp->getScopeChain(), "scope chain"); if (fp->isScriptFrame())
js_TraceScript(trc, fp->script());
MarkValue(trc, fp->thisValue(), "this");
MarkValue(trc, fp->returnValue(), "rval");
} }
inline void inline void
@ -2094,12 +2096,12 @@ AutoGCRooter::trace(JSTracer *trc)
case DESCRIPTOR : { case DESCRIPTOR : {
PropertyDescriptor &desc = *static_cast<AutoPropertyDescriptorRooter *>(this); PropertyDescriptor &desc = *static_cast<AutoPropertyDescriptorRooter *>(this);
if (desc.obj) if (desc.obj)
MarkObject(trc, desc.obj, "Descriptor::obj"); MarkObject(trc, *desc.obj, "Descriptor::obj");
MarkValue(trc, desc.value, "Descriptor::value"); MarkValue(trc, desc.value, "Descriptor::value");
if ((desc.attrs & JSPROP_GETTER) && desc.getter) if ((desc.attrs & JSPROP_GETTER) && desc.getter)
MarkObject(trc, CastAsObject(desc.getter), "Descriptor::get"); MarkObject(trc, *CastAsObject(desc.getter), "Descriptor::get");
if (desc.attrs & JSPROP_SETTER && desc.setter) if (desc.attrs & JSPROP_SETTER && desc.setter)
MarkObject(trc, CastAsObject(desc.setter), "Descriptor::set"); MarkObject(trc, *CastAsObject(desc.setter), "Descriptor::set");
return; return;
} }
@ -2117,7 +2119,7 @@ AutoGCRooter::trace(JSTracer *trc)
case OBJECT: case OBJECT:
if (JSObject *obj = static_cast<AutoObjectRooter *>(this)->obj) if (JSObject *obj = static_cast<AutoObjectRooter *>(this)->obj)
MarkObject(trc, obj, "js::AutoObjectRooter.obj"); MarkObject(trc, *obj, "js::AutoObjectRooter.obj");
return; return;
case ID: case ID:

Просмотреть файл

@ -599,11 +599,10 @@ MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name)
} }
static inline void static inline void
MarkObject(JSTracer *trc, JSObject *obj, const char *name) MarkObject(JSTracer *trc, JSObject &obj, const char *name)
{ {
JS_ASSERT(obj);
JS_SET_TRACING_NAME(trc, name); JS_SET_TRACING_NAME(trc, name);
Mark(trc, obj, JSTRACE_OBJECT); Mark(trc, &obj, JSTRACE_OBJECT);
} }
static inline void static inline void

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

399
js/src/jsinterpinlines.h Normal file
Просмотреть файл

@ -0,0 +1,399 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is SpiderMonkey code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Luke Wagner <lw@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef jsinterpinlines_h__
#define jsinterpinlines_h__
inline void
JSStackFrame::initCallFrame(JSContext *cx, JSObject &callee, JSFunction *fun,
uint32 nactual, uint32 flagsArg)
{
JS_ASSERT((flagsArg & ~(JSFRAME_CONSTRUCTING |
JSFRAME_OVERFLOW_ARGS |
JSFRAME_UNDERFLOW_ARGS)) == 0);
JS_ASSERT(fun == callee.getFunctionPrivate());
/* Initialize stack frame members. */
flags_ = JSFRAME_FUNCTION | flagsArg;
exec.fun = fun;
args.nactual = nactual; /* only need to write if over/under-flow */
scopeChain_ = callee.getParent();
/* savedpc_, prev_ initialized by push*Frame */
JS_ASSERT(!hasImacropc());
JS_ASSERT(!hasHookData());
rval_.setUndefined();
blockChain_ = NULL;
JS_ASSERT(annotation() == NULL);
JS_ASSERT(!hasCallObj());
}
inline void
JSStackFrame::initCallFrameCallerHalf(JSContext *cx, JSObject &scopeChain,
uint32 nactual, uint32 flagsArg)
{
JS_ASSERT((flagsArg & ~(JSFRAME_CONSTRUCTING |
JSFRAME_FUNCTION |
JSFRAME_OVERFLOW_ARGS |
JSFRAME_UNDERFLOW_ARGS)) == 0);
JSFrameRegs *regs = cx->regs;
/* Save caller pc. */
regs->fp->savedpc_ = regs->pc;
/* Initialize the caller half of the stack frame members. */
flags_ = JSFRAME_FUNCTION | flagsArg;
args.nactual = nactual; /* only need to write if over/under-flow */
scopeChain_ = &scopeChain;
prev_ = regs->fp;
JS_ASSERT(!hasImacropc());
JS_ASSERT(!hasHookData());
JS_ASSERT(annotation() == NULL);
JS_ASSERT(!hasCallObj());
}
/*
* The "early prologue" refers to the members that are stored for the benefit
* of slow paths before initializing the rest of the members.
*/
inline void
JSStackFrame::initCallFrameEarlyPrologue(JSFunction *fun, void *ncode)
{
/* Initialize state that gets set early in a jitted function's prologue. */
exec.fun = fun;
ncode_ = ncode;
#ifdef DEBUG
savedpc_ = JSStackFrame::sInvalidpc;
#endif
}
/*
* The "late prologue" refers to the members that are stored after having
* checked for stack overflow and formal/actual arg mismatch.
*/
inline void
JSStackFrame::initCallFrameLatePrologue()
{
rval_.setUndefined();
blockChain_ = NULL;
callerVersion_ = prev_->callerVersion_; // WRONG
SetValueRangeToUndefined(slots(), script()->nfixed);
}
inline void
JSStackFrame::initEvalFrame(JSScript *script, JSStackFrame *downFrame, uint32 flagsArg)
{
JS_ASSERT(flagsArg & JSFRAME_EVAL);
JS_ASSERT((flagsArg & ~(JSFRAME_EVAL | JSFRAME_DEBUGGER)) == 0);
JS_ASSERT(downFrame->flags_ & (JSFRAME_FUNCTION | JSFRAME_GLOBAL));
/* Copy (callee, thisv). */
js::Value *dstvp = (js::Value *)this - 2;
js::Value *srcvp = downFrame->flags_ & (JSFRAME_GLOBAL | JSFRAME_EVAL)
? (js::Value *)downFrame - 2
: downFrame->formalArgs() - 2;
dstvp[0] = srcvp[0];
dstvp[1] = srcvp[1];
JS_ASSERT_IF(downFrame->flags_ & JSFRAME_FUNCTION,
dstvp[0].toObject().isFunction());
/* Initialize stack frame members. */
flags_ = flagsArg | (downFrame->flags_ & (JSFRAME_FUNCTION |
JSFRAME_GLOBAL |
JSFRAME_HAS_CALL_OBJ));
if (isFunctionFrame()) {
exec = downFrame->exec;
args.script = script;
} else {
exec.script = script;
}
scopeChain_ = &downFrame->scopeChain();
JS_ASSERT_IF(isFunctionFrame(), &callObj() == &downFrame->callObj());
/* savedpc initialized by pushExecuteFrame */
prev_ = downFrame;
JS_ASSERT(!hasImacropc());
JS_ASSERT(!hasHookData());
rval_.setUndefined();
blockChain_ = NULL;
setAnnotation(downFrame->annotation());
}
inline void
JSStackFrame::initGlobalFrame(JSScript *script, JSObject &chain, uint32 flagsArg)
{
JS_ASSERT((flagsArg & ~(JSFRAME_EVAL | JSFRAME_DEBUGGER)) == 0);
/* Initialize (callee, thisv). */
js::Value *vp = (js::Value *)this - 2;
vp[0].setUndefined();
vp[1].setUndefined(); /* Set after frame pushed using thisObject */
/* Initialize stack frame members. */
flags_ = flagsArg | JSFRAME_GLOBAL;
exec.script = script;
args.script = (JSScript *)0xbad;
scopeChain_ = &chain;
/* savedpc initialized by pushExecuteFrame */
prev_ = NULL;
JS_ASSERT(!hasImacropc());
JS_ASSERT(!hasHookData());
rval_.setUndefined();
blockChain_ = NULL;
JS_ASSERT(annotation() == NULL);
}
inline void
JSStackFrame::initDummyFrame(JSContext *cx, JSObject &chain)
{
js::PodZero(this);
flags_ = JSFRAME_DUMMY;
prev_ = cx->maybefp();
chain.isGlobal();
setScopeChainNoCallObj(chain);
}
inline void
JSStackFrame::stealFrameAndSlots(js::Value *vp, JSStackFrame *otherfp,
js::Value *othervp, js::Value *othersp)
{
JS_ASSERT(vp == (js::Value *)this - (otherfp->formalArgsEnd() - othervp));
JS_ASSERT(othervp == otherfp->actualArgs() - 2);
JS_ASSERT(othersp >= otherfp->slots());
JS_ASSERT(othersp <= otherfp->base() + otherfp->numSlots());
size_t nbytes = (othersp - othervp) * sizeof(js::Value);
memcpy(vp, othervp, nbytes);
JS_ASSERT(vp == actualArgs() - 2);
/*
* Repoint Call, Arguments, Block and With objects to the new live frame.
* Call and Arguments are done directly because we have pointers to them.
* Block and With objects are done indirectly through 'liveFrame'. See
* js_LiveFrameToFloating comment in jsiter.h.
*/
if (hasCallObj()) {
callObj().setPrivate(this);
otherfp->flags_ &= ~JSFRAME_HAS_CALL_OBJ;
}
if (hasArgsObj()) {
argsObj().setPrivate(this);
otherfp->flags_ &= ~JSFRAME_HAS_ARGS_OBJ;
}
}
inline js::Value &
JSStackFrame::canonicalActualArg(uintN i) const
{
if (i < numFormalArgs())
return formalArg(i);
JS_ASSERT(i < numActualArgs());
return actualArgs()[i];
}
template <class Op>
inline void
JSStackFrame::forEachCanonicalActualArg(Op op)
{
uintN nformal = fun()->nargs;
js::Value *formals = formalArgsEnd() - nformal;
uintN nactual = numActualArgs();
if (nactual <= nformal) {
uintN i = 0;
js::Value *actualsEnd = formals + nactual;
for (js::Value *p = formals; p != actualsEnd; ++p, ++i)
op(i, p);
} else {
uintN i = 0;
js::Value *formalsEnd = formalArgsEnd();
for (js::Value *p = formals; p != formalsEnd; ++p, ++i)
op(i, p);
js::Value *actuals = formalsEnd - (nactual + 2);
js::Value *actualsEnd = formals - 2;
for (js::Value *p = actuals; p != actualsEnd; ++p, ++i)
op(i, p);
}
}
template <class Op>
inline void
JSStackFrame::forEachFormalArg(Op op)
{
js::Value *formals = formalArgsEnd() - fun()->nargs;
js::Value *formalsEnd = formalArgsEnd();
uintN i = 0;
for (js::Value *p = formals; p != formalsEnd; ++p, ++i)
op(i, p);
}
inline JSObject *
JSStackFrame::computeThisObject(JSContext *cx)
{
js::Value &thisv = thisValue();
if (JS_LIKELY(!thisv.isPrimitive()))
return &thisv.toObject();
if (!js::ComputeThisFromArgv(cx, &thisv + 1))
return NULL;
JS_ASSERT(IsSaneThisObject(thisv.toObject()));
return &thisv.toObject();
}
inline JSObject &
JSStackFrame::varobj(js::StackSegment *seg) const
{
JS_ASSERT(seg->contains(this));
return isFunctionFrame() ? callObj() : seg->getInitialVarObj();
}
inline JSObject &
JSStackFrame::varobj(JSContext *cx) const
{
JS_ASSERT(cx->activeSegment()->contains(this));
return isFunctionFrame() ? callObj() : cx->activeSegment()->getInitialVarObj();
}
inline jsbytecode *
JSStackFrame::pc(JSContext *cx) const
{
JS_ASSERT(cx->regs && cx->containingSegment(this) != NULL);
return (cx->regs->fp == this) ? cx->regs->pc : savedpc_;
}
inline uintN
JSStackFrame::numActualArgs() const
{
JS_ASSERT(isFunctionFrame() && !isEvalFrame());
if (JS_UNLIKELY(flags_ & (JSFRAME_OVERFLOW_ARGS | JSFRAME_UNDERFLOW_ARGS)))
return hasArgsObj() ? argsObj().getArgsInitialLength() : args.nactual;
return numFormalArgs();
}
inline js::Value *
JSStackFrame::actualArgs() const
{
JS_ASSERT(isFunctionFrame() && !isEvalFrame());
js::Value *argv = formalArgsEnd() - numFormalArgs();
if (JS_UNLIKELY(flags_ & JSFRAME_OVERFLOW_ARGS)) {
uintN nactual = hasArgsObj() ? argsObj().getArgsInitialLength() : args.nactual;
return argv - (2 + nactual);
}
return argv;
}
inline js::Value *
JSStackFrame::actualArgsEnd() const
{
JS_ASSERT(isFunctionFrame() && !isEvalFrame());
if (JS_UNLIKELY(flags_ & JSFRAME_OVERFLOW_ARGS))
return formalArgsEnd() - (2 + numFormalArgs());
uintN argc = numActualArgs();
uintN nmissing = numFormalArgs() - argc;
return formalArgsEnd() - nmissing;
}
inline void
JSStackFrame::setArgsObj(JSObject &obj)
{
JS_ASSERT_IF(hasArgsObj(), &obj == args.obj);
JS_ASSERT_IF(!hasArgsObj(), numActualArgs() == obj.getArgsInitialLength());
args.obj = &obj;
flags_ |= JSFRAME_HAS_ARGS_OBJ;
}
inline void
JSStackFrame::setScopeChainNoCallObj(JSObject &obj)
{
#ifdef DEBUG
JS_ASSERT(&obj != NULL);
JSObject *callObjBefore = maybeCallObj();
if (!hasCallObj() && scopeChain_ != sInvalidScopeChain) {
for (JSObject *pobj = scopeChain_; pobj; pobj = pobj->getParent())
JS_ASSERT_IF(pobj->isCall(), pobj->getPrivate() != this);
}
#endif
scopeChain_ = &obj;
JS_ASSERT(callObjBefore == maybeCallObj());
}
inline void
JSStackFrame::setScopeChainAndCallObj(JSObject &obj)
{
JS_ASSERT(&obj != NULL);
JS_ASSERT(!hasCallObj() && obj.isCall() && obj.getPrivate() == this);
scopeChain_ = &obj;
flags_ |= JSFRAME_HAS_CALL_OBJ;
}
inline JSObject &
JSStackFrame::callObj() const
{
JS_ASSERT(hasCallObj());
JSObject *pobj = &scopeChain();
while (JS_UNLIKELY(pobj->getClass() != &js_CallClass)) {
JS_ASSERT(js_IsCacheableNonGlobalScope(pobj) || pobj->isWith());
pobj = pobj->getParent();
}
return *pobj;
}
inline JSObject *
JSStackFrame::maybeCallObj() const
{
return hasCallObj() ? &callObj() : NULL;
}
namespace js {
inline void
PutActivationObjects(JSContext *cx, JSStackFrame *fp)
{
JS_ASSERT(fp->isFunctionFrame() && !fp->isEvalFrame());
/* The order is important as js_PutCallObject needs to access argsObj. */
if (fp->hasCallObj()) {
js_PutCallObject(cx, fp);
} else if (fp->hasArgsObj()) {
js_PutArgsObject(cx, fp);
}
}
}
#endif /* jsinterpinlines_h__ */

Просмотреть файл

@ -76,6 +76,7 @@
#endif #endif
#include "jscntxtinlines.h" #include "jscntxtinlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jsstrinlines.h" #include "jsstrinlines.h"
@ -121,7 +122,7 @@ NativeIterator::mark(JSTracer *trc)
else else
MarkValueRange(trc, beginValue(), endValue(), "props"); MarkValueRange(trc, beginValue(), endValue(), "props");
if (obj) if (obj)
MarkObject(trc, obj, "obj"); MarkObject(trc, *obj, "obj");
} }
static void static void
@ -1088,11 +1089,11 @@ generator_trace(JSTracer *trc, JSObject *obj)
if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING)
return; return;
JSStackFrame *fp = gen->getFloatingFrame(); JSStackFrame *fp = gen->floatingFrame();
JS_ASSERT(gen->getLiveFrame() == fp); JS_ASSERT(gen->liveFrame() == fp);
MarkValueRange(trc, gen->floatingStack, fp->argEnd(), "generator slots"); MarkValueRange(trc, gen->floatingStack, fp->formalArgsEnd(), "generator slots");
js_TraceStackFrame(trc, fp); js_TraceStackFrame(trc, fp);
MarkValueRange(trc, fp->slots(), gen->savedRegs.sp, "generator slots"); MarkValueRange(trc, fp->slots(), gen->regs.sp, "generator slots");
} }
Class js_GeneratorClass = { Class js_GeneratorClass = {
@ -1123,6 +1124,13 @@ Class js_GeneratorClass = {
} }
}; };
static inline void
RebaseRegsFromTo(JSFrameRegs *regs, JSStackFrame *from, JSStackFrame *to)
{
regs->fp = to;
regs->sp = to->slots() + (regs->sp - from->slots());
}
/* /*
* Called from the JSOP_GENERATOR case in the interpreter, with fp referring * Called from the JSOP_GENERATOR case in the interpreter, with fp referring
* to the frame by which the generator function was activated. Create a new * to the frame by which the generator function was activated. Create a new
@ -1138,65 +1146,42 @@ js_NewGenerator(JSContext *cx)
if (!obj) if (!obj)
return NULL; return NULL;
JSStackFrame *stackfp = cx->fp();
JS_ASSERT(stackfp->base() == cx->regs->sp);
JS_ASSERT(stackfp->actualArgs() <= stackfp->formalArgs());
/* Load and compute stack slot counts. */ /* Load and compute stack slot counts. */
JSStackFrame *fp = cx->fp(); Value *stackvp = stackfp->actualArgs() - 2;
uintN argc = fp->numActualArgs(); uintN vplen = stackfp->formalArgsEnd() - stackvp;
uintN nargs = JS_MAX(argc, fp->numFormalArgs());
uintN vplen = 2 + nargs;
/* Compute JSGenerator size. */ /* Compute JSGenerator size. */
uintN nbytes = sizeof(JSGenerator) + uintN nbytes = sizeof(JSGenerator) +
(-1 + /* one Value included in JSGenerator */ (-1 + /* one Value included in JSGenerator */
vplen + vplen +
VALUES_PER_STACK_FRAME + VALUES_PER_STACK_FRAME +
fp->getSlotCount()) * sizeof(Value); stackfp->numSlots()) * sizeof(Value);
JSGenerator *gen = (JSGenerator *) cx->malloc(nbytes); JSGenerator *gen = (JSGenerator *) cx->malloc(nbytes);
if (!gen) if (!gen)
return NULL; return NULL;
/* Cut up floatingStack space. */ /* Cut up floatingStack space. */
Value *vp = gen->floatingStack; Value *genvp = gen->floatingStack;
JSStackFrame *newfp = reinterpret_cast<JSStackFrame *>(vp + vplen); JSStackFrame *genfp = reinterpret_cast<JSStackFrame *>(genvp + vplen);
Value *slots = newfp->slots();
/* Initialize JSGenerator. */ /* Initialize JSGenerator. */
gen->obj = obj; gen->obj = obj;
gen->state = JSGEN_NEWBORN; gen->state = JSGEN_NEWBORN;
gen->savedRegs.pc = cx->regs->pc;
JS_ASSERT(cx->regs->sp == fp->slots() + fp->getFixedCount());
gen->savedRegs.sp = slots + fp->getFixedCount();
gen->vplen = vplen;
gen->enumerators = NULL; gen->enumerators = NULL;
gen->liveFrame = newfp; gen->floating = genfp;
/* Copy generator's stack frame copy in from |cx->fp|. */ /* Initialize regs stored in generator. */
newfp->setCallObj(fp->maybeCallObj()); gen->regs = *cx->regs;
if (fp->hasCallObj()) { /* Steal call object. */ RebaseRegsFromTo(&gen->regs, stackfp, genfp);
fp->getCallObj()->setPrivate(newfp);
fp->setCallObj(NULL);
}
newfp->setArgsObj(fp->maybeArgsObj());
if (fp->hasArgsObj()) { /* Steal args object. */
fp->getArgsObj()->setPrivate(newfp);
fp->setArgsObj(NULL);
}
newfp->setScript(fp->getScript());
newfp->setFunction(fp->getFunction());
newfp->setThisValue(fp->getThisValue());
newfp->setNumActualArgs(fp->numActualArgs());
newfp->argv = vp + 2;
newfp->setReturnValue(fp->getReturnValue());
newfp->setAnnotation(NULL);
newfp->setScopeChain(fp->maybeScopeChain());
JS_ASSERT(!fp->hasBlockChain());
newfp->setBlockChain(NULL);
newfp->flags = fp->flags | JSFRAME_GENERATOR | JSFRAME_FLOATING_GENERATOR;
JS_ASSERT(!newfp->hasIMacroPC());
/* Copy in arguments and slots. */ /* Copy frame off the stack. */
memcpy(vp, fp->argv - 2, vplen * sizeof(Value)); genfp->stealFrameAndSlots(genvp, stackfp, stackvp, cx->regs->sp);
memcpy(slots, fp->slots(), fp->getFixedCount() * sizeof(Value)); genfp->initFloatingGenerator();
obj->setPrivate(gen); obj->setPrivate(gen);
return obj; return obj;
@ -1205,8 +1190,8 @@ js_NewGenerator(JSContext *cx)
JSGenerator * JSGenerator *
js_FloatingFrameToGenerator(JSStackFrame *fp) js_FloatingFrameToGenerator(JSStackFrame *fp)
{ {
JS_ASSERT(fp->isGenerator() && fp->isFloatingGenerator()); JS_ASSERT(fp->isGeneratorFrame() && fp->isFloatingGenerator());
char *floatingStackp = (char *)(fp->argv - 2); char *floatingStackp = (char *)(fp->actualArgs() - 2);
char *p = floatingStackp - offsetof(JSGenerator, floatingStack); char *p = floatingStackp - offsetof(JSGenerator, floatingStack);
return reinterpret_cast<JSGenerator *>(p); return reinterpret_cast<JSGenerator *>(p);
} }
@ -1229,7 +1214,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) { if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) {
js_ReportValueError(cx, JSMSG_NESTING_GENERATOR, js_ReportValueError(cx, JSMSG_NESTING_GENERATOR,
JSDVG_SEARCH_STACK, ObjectOrNullValue(obj), JSDVG_SEARCH_STACK, ObjectOrNullValue(obj),
JS_GetFunctionId(gen->getFloatingFrame()->getFunction())); JS_GetFunctionId(gen->floatingFrame()->fun()));
return JS_FALSE; return JS_FALSE;
} }
@ -1246,7 +1231,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
* Store the argument to send as the result of the yield * Store the argument to send as the result of the yield
* expression. * expression.
*/ */
gen->savedRegs.sp[-1] = arg; gen->regs.sp[-1] = arg;
} }
gen->state = JSGEN_RUNNING; gen->state = JSGEN_RUNNING;
break; break;
@ -1263,96 +1248,63 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
break; break;
} }
JSStackFrame *genfp = gen->getFloatingFrame(); JSStackFrame *genfp = gen->floatingFrame();
Value *genvp = gen->floatingStack;
uintN vplen = genfp->formalArgsEnd() - genvp;
JSStackFrame *stackfp;
Value *stackvp;
JSBool ok; JSBool ok;
{ {
Value *genVp = gen->floatingStack;
uintN vplen = gen->vplen;
uintN nfixed = genfp->getSlotCount();
/* /*
* Get a pointer to new frame/slots. This memory is not "claimed", so * Get a pointer to new frame/slots. This memory is not "claimed", so
* the code before pushExecuteFrame must not reenter the interpreter. * the code before pushExecuteFrame must not reenter the interpreter.
*/ */
FrameGuard frame; GeneratorFrameGuard frame;
if (!cx->stack().getExecuteFrame(cx, cx->maybefp(), vplen, nfixed, frame)) { if (!cx->stack().getGeneratorFrame(cx, vplen, genfp->numSlots(), &frame)) {
gen->state = JSGEN_CLOSED; gen->state = JSGEN_CLOSED;
return JS_FALSE; return JS_FALSE;
} }
stackfp = frame.fp();
stackvp = frame.vp();
Value *vp = frame.getvp(); /* Copy frame onto the stack. */
JSStackFrame *fp = frame.getFrame(); stackfp->stealFrameAndSlots(stackvp, genfp, genvp, gen->regs.sp);
stackfp->repointGeneratorFrameDown(cx->maybefp());
stackfp->unsetFloatingGenerator();
RebaseRegsFromTo(&gen->regs, genfp, stackfp);
MUST_FLOW_THROUGH("restore");
/* /* Officially push frame. frame's destructor pops. */
* Copy and rebase stack frame/args/slots. The "floating" flag must cx->stack().pushGeneratorFrame(cx, &gen->regs, &frame);
* only be set on the generator's frame. See args_or_call_trace.
*/
uintN usedBefore = gen->savedRegs.sp - genVp;
memcpy(vp, genVp, usedBefore * sizeof(Value));
fp->flags &= ~JSFRAME_FLOATING_GENERATOR;
fp->argv = vp + 2;
gen->savedRegs.sp = fp->slots() + (gen->savedRegs.sp - genfp->slots());
JS_ASSERT(uintN(gen->savedRegs.sp - fp->slots()) <= fp->getSlotCount());
#ifdef DEBUG cx->enterGenerator(gen); /* OOM check above. */
JSObject *callobjBefore = fp->maybeCallObj();
JSObject *argsobjBefore = fp->maybeArgsObj();
#endif
/*
* Repoint Call, Arguments, Block and With objects to the new live
* frame. Call and Arguments are done directly because we have
* pointers to them. Block and With objects are done indirectly through
* 'liveFrame'. See js_LiveFrameToFloating comment in jsiter.h.
*/
if (genfp->hasCallObj())
fp->getCallObj()->setPrivate(fp);
if (genfp->hasArgsObj())
fp->getArgsObj()->setPrivate(fp);
gen->liveFrame = fp;
(void)cx->enterGenerator(gen); /* OOM check above. */
/* Officially push |fp|. |frame|'s destructor pops. */
cx->stack().pushExecuteFrame(cx, frame, gen->savedRegs, NULL);
/* Swap the enumerators stack for the generator's stack. */
JSObject *enumerators = cx->enumerators; JSObject *enumerators = cx->enumerators;
cx->enumerators = gen->enumerators; cx->enumerators = gen->enumerators;
ok = RunScript(cx, fp->maybeScript(), fp->maybeFunction(), fp->getScopeChain()); ok = RunScript(cx, stackfp->script(), stackfp->fun(), stackfp->scopeChain());
/* Restore the original enumerators stack. */
gen->enumerators = cx->enumerators; gen->enumerators = cx->enumerators;
cx->enumerators = enumerators; cx->enumerators = enumerators;
/* Restore call/args/block objects. */
cx->leaveGenerator(gen); cx->leaveGenerator(gen);
gen->liveFrame = genfp;
if (fp->hasArgsObj())
fp->getArgsObj()->setPrivate(genfp);
if (fp->hasCallObj())
fp->getCallObj()->setPrivate(genfp);
JS_ASSERT_IF(argsobjBefore, argsobjBefore == fp->maybeArgsObj()); /*
JS_ASSERT_IF(callobjBefore, callobjBefore == fp->maybeCallObj()); * Copy the stack frame and rebase the regs, but not before popping
* the stack, since cx->regs == &gen->regs.
/* Copy and rebase stack frame/args/slots. Restore "floating" flag. */ */
JS_ASSERT(uintN(gen->savedRegs.sp - fp->slots()) <= fp->getSlotCount()); genfp->stealFrameAndSlots(genvp, stackfp, stackvp, gen->regs.sp);
uintN usedAfter = gen->savedRegs.sp - vp; genfp->setFloatingGenerator();
memcpy(genVp, vp, usedAfter * sizeof(Value));
genfp->flags |= JSFRAME_FLOATING_GENERATOR;
genfp->argv = genVp + 2;
gen->savedRegs.sp = genfp->slots() + (gen->savedRegs.sp - fp->slots());
JS_ASSERT(uintN(gen->savedRegs.sp - genfp->slots()) <= genfp->getSlotCount());
} }
MUST_FLOW_LABEL(restore)
RebaseRegsFromTo(&gen->regs, stackfp, genfp);
if (gen->getFloatingFrame()->flags & JSFRAME_YIELDING) { if (gen->floatingFrame()->isYielding()) {
/* Yield cannot fail, throw or be called on closing. */ /* Yield cannot fail, throw or be called on closing. */
JS_ASSERT(ok); JS_ASSERT(ok);
JS_ASSERT(!cx->throwing); JS_ASSERT(!cx->throwing);
JS_ASSERT(gen->state == JSGEN_RUNNING); JS_ASSERT(gen->state == JSGEN_RUNNING);
JS_ASSERT(op != JSGENOP_CLOSE); JS_ASSERT(op != JSGENOP_CLOSE);
genfp->flags &= ~JSFRAME_YIELDING; genfp->clearYielding();
gen->state = JSGEN_OPEN; gen->state = JSGEN_OPEN;
return JS_TRUE; return JS_TRUE;
} }
@ -1446,7 +1398,7 @@ generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc)
bool undef = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && argc != 0); bool undef = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && argc != 0);
if (!SendToGenerator(cx, op, obj, gen, undef ? vp[2] : UndefinedValue())) if (!SendToGenerator(cx, op, obj, gen, undef ? vp[2] : UndefinedValue()))
return JS_FALSE; return JS_FALSE;
*vp = gen->getFloatingFrame()->getReturnValue(); *vp = gen->floatingFrame()->returnValue();
return JS_TRUE; return JS_TRUE;
} }

Просмотреть файл

@ -201,20 +201,19 @@ typedef enum JSGeneratorState {
struct JSGenerator { struct JSGenerator {
JSObject *obj; JSObject *obj;
JSGeneratorState state; JSGeneratorState state;
JSFrameRegs savedRegs; JSFrameRegs regs;
uintN vplen;
JSStackFrame *liveFrame;
JSObject *enumerators; JSObject *enumerators;
JSStackFrame *floating;
js::Value floatingStack[1]; js::Value floatingStack[1];
JSStackFrame *getFloatingFrame() { JSStackFrame *floatingFrame() {
return reinterpret_cast<JSStackFrame *>(floatingStack + vplen); return floating;
} }
JSStackFrame *getLiveFrame() { JSStackFrame *liveFrame() {
JS_ASSERT((state == JSGEN_RUNNING || state == JSGEN_CLOSING) == JS_ASSERT((state == JSGEN_RUNNING || state == JSGEN_CLOSING) ==
(liveFrame != getFloatingFrame())); (regs.fp != floatingFrame()));
return liveFrame; return regs.fp;
} }
}; };
@ -236,8 +235,8 @@ inline JSStackFrame *
js_FloatingFrameIfGenerator(JSContext *cx, JSStackFrame *fp) js_FloatingFrameIfGenerator(JSContext *cx, JSStackFrame *fp)
{ {
JS_ASSERT(cx->stack().contains(fp)); JS_ASSERT(cx->stack().contains(fp));
if (JS_UNLIKELY(fp->isGenerator())) if (JS_UNLIKELY(fp->isGeneratorFrame()))
return cx->generatorFor(fp)->getFloatingFrame(); return cx->generatorFor(fp)->floatingFrame();
return fp; return fp;
} }
@ -248,9 +247,7 @@ js_FloatingFrameToGenerator(JSStackFrame *fp);
inline JSStackFrame * inline JSStackFrame *
js_LiveFrameIfGenerator(JSStackFrame *fp) js_LiveFrameIfGenerator(JSStackFrame *fp)
{ {
if (fp->flags & JSFRAME_GENERATOR) return fp->isGeneratorFrame() ? js_FloatingFrameToGenerator(fp)->liveFrame() : fp;
return js_FloatingFrameToGenerator(fp)->getLiveFrame();
return fp;
} }
#endif #endif

Просмотреть файл

@ -78,6 +78,7 @@
#include "jsdbgapi.h" #include "jsdbgapi.h"
#include "json.h" #include "json.h"
#include "jsinterpinlines.h"
#include "jsscopeinlines.h" #include "jsscopeinlines.h"
#include "jsscriptinlines.h" #include "jsscriptinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
@ -951,7 +952,7 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
#endif #endif
JS_ASSERT(principals || !(callbacks && callbacks->findObjectPrincipals)); JS_ASSERT(principals || !(callbacks && callbacks->findObjectPrincipals));
flags = JS_GetScriptFilenameFlags(caller->getScript()); flags = JS_GetScriptFilenameFlags(caller->script());
if ((flags & JSFILENAME_PROTECTED) && if ((flags & JSFILENAME_PROTECTED) &&
principals && principals &&
strcmp(principals->codebase, "[System Principal]")) { strcmp(principals->codebase, "[System Principal]")) {
@ -960,13 +961,13 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
} }
jsbytecode *pc = caller->pc(cx); jsbytecode *pc = caller->pc(cx);
if (pc && js_GetOpcode(cx, caller->getScript(), pc) == JSOP_EVAL) { if (pc && js_GetOpcode(cx, caller->script(), pc) == JSOP_EVAL) {
JS_ASSERT(js_GetOpcode(cx, caller->getScript(), pc + JSOP_EVAL_LENGTH) == JSOP_LINENO); JS_ASSERT(js_GetOpcode(cx, caller->script(), pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
*linenop = GET_UINT16(pc + JSOP_EVAL_LENGTH); *linenop = GET_UINT16(pc + JSOP_EVAL_LENGTH);
} else { } else {
*linenop = js_FramePCToLineNumber(cx, caller); *linenop = js_FramePCToLineNumber(cx, caller);
} }
return caller->getScript()->filename; return caller->script()->filename;
} }
#ifndef EVAL_CACHE_CHAIN_LIMIT #ifndef EVAL_CACHE_CHAIN_LIMIT
@ -1056,18 +1057,18 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
* when evaluating the code string. Warn when such uses are seen so that * when evaluating the code string. Warn when such uses are seen so that
* authors will know that support for eval(s, o) has been removed. * authors will know that support for eval(s, o) has been removed.
*/ */
if (argc > 1 && !caller->getScript()->warnedAboutTwoArgumentEval) { if (argc > 1 && !caller->script()->warnedAboutTwoArgumentEval) {
static const char TWO_ARGUMENT_WARNING[] = static const char TWO_ARGUMENT_WARNING[] =
"Support for eval(code, scopeObject) has been removed. " "Support for eval(code, scopeObject) has been removed. "
"Use |with (scopeObject) eval(code);| instead."; "Use |with (scopeObject) eval(code);| instead.";
if (!JS_ReportWarning(cx, TWO_ARGUMENT_WARNING)) if (!JS_ReportWarning(cx, TWO_ARGUMENT_WARNING))
return JS_FALSE; return JS_FALSE;
caller->getScript()->warnedAboutTwoArgumentEval = true; caller->script()->warnedAboutTwoArgumentEval = true;
} }
/* From here on, control must exit through label out with ok set. */ /* From here on, control must exit through label out with ok set. */
MUST_FLOW_THROUGH("out"); MUST_FLOW_THROUGH("out");
uintN staticLevel = caller->getScript()->staticLevel + 1; uintN staticLevel = caller->script()->staticLevel + 1;
/* /*
* Bring fp->scopeChain up to date. We're either going to use * Bring fp->scopeChain up to date. We're either going to use
@ -1104,7 +1105,7 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
* *
* NB: This means that the C API must not be used to call eval. * NB: This means that the C API must not be used to call eval.
*/ */
JS_ASSERT_IF(caller->argv, caller->hasCallObj()); JS_ASSERT_IF(caller->isFunctionFrame(), caller->hasCallObj());
scopeobj = callerScopeChain; scopeobj = callerScopeChain;
} }
#endif #endif
@ -1162,7 +1163,7 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
* calls to eval from global code are not cached. * calls to eval from global code are not cached.
*/ */
JSScript **bucket = EvalCacheHash(cx, str); JSScript **bucket = EvalCacheHash(cx, str);
if (!indirectCall && caller->hasFunction()) { if (!indirectCall && caller->isFunctionFrame()) {
uintN count = 0; uintN count = 0;
JSScript **scriptp = bucket; JSScript **scriptp = bucket;
@ -1180,7 +1181,7 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
*/ */
JSFunction *fun = script->getFunction(0); JSFunction *fun = script->getFunction(0);
if (fun == caller->getFunction()) { if (fun == caller->fun()) {
/* /*
* Get the source string passed for safekeeping in the * Get the source string passed for safekeeping in the
* atom map by the prior eval to Compiler::compileScript. * atom map by the prior eval to Compiler::compileScript.
@ -2727,10 +2728,10 @@ Detecting(JSContext *cx, jsbytecode *pc)
JSOp op; JSOp op;
JSAtom *atom; JSAtom *atom;
script = cx->fp()->getScript(); script = cx->fp()->script();
endpc = script->code + script->length; endpc = script->code + script->length;
for (;; pc += js_CodeSpec[op].length) { for (;; pc += js_CodeSpec[op].length) {
JS_ASSERT_IF(!cx->fp()->hasIMacroPC(), script->code <= pc && pc < endpc); JS_ASSERT_IF(!cx->fp()->hasImacropc(), script->code <= pc && pc < endpc);
/* General case: a branch or equality op follows the access. */ /* General case: a branch or equality op follows the access. */
op = js_GetOpcode(cx, script, pc); op = js_GetOpcode(cx, script, pc);
@ -2801,16 +2802,15 @@ js_InferFlags(JSContext *cx, uintN defaultFlags)
JSStackFrame *const fp = js_GetTopStackFrame(cx); JSStackFrame *const fp = js_GetTopStackFrame(cx);
if (!fp || !(pc = cx->regs->pc)) if (!fp || !(pc = cx->regs->pc))
return defaultFlags; return defaultFlags;
cs = &js_CodeSpec[js_GetOpcode(cx, fp->getScript(), 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)
flags |= JSRESOLVE_QUALIFIED; flags |= JSRESOLVE_QUALIFIED;
if ((format & (JOF_SET | JOF_FOR)) || if ((format & (JOF_SET | JOF_FOR)) || fp->isAssigning()) {
(fp->flags & JSFRAME_ASSIGNING)) {
flags |= JSRESOLVE_ASSIGNING; flags |= JSRESOLVE_ASSIGNING;
} else if (cs->length >= 0) { } else if (cs->length >= 0) {
pc += cs->length; pc += cs->length;
JSScript *script = cx->fp()->getScript(); JSScript *script = cx->fp()->script();
if (pc < script->code + script->length && Detecting(cx, pc)) if (pc < script->code + script->length && Detecting(cx, pc))
flags |= JSRESOLVE_DETECTING; flags |= JSRESOLVE_DETECTING;
} }
@ -2987,7 +2987,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2); JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2);
JSStackFrame *const fp = cx->fp(); JSStackFrame *const fp = cx->fp();
JSObject *obj = fp->getScopeChain(); JSObject *obj = &fp->scopeChain();
JS_ASSERT(obj->isClonedBlock()); JS_ASSERT(obj->isClonedBlock());
JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp())); JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()));
@ -3008,7 +3008,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
uintN flen = JS_MIN(count, JS_INITIAL_NSLOTS - slot); uintN flen = JS_MIN(count, JS_INITIAL_NSLOTS - slot);
uintN stop = slot + flen; uintN stop = slot + flen;
depth += fp->getFixedCount(); depth += fp->numFixed();
while (slot < stop) while (slot < stop)
obj->fslots[slot++] = fp->slots()[depth++]; obj->fslots[slot++] = fp->slots()[depth++];
count -= flen; count -= flen;
@ -3018,7 +3018,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
/* We must clear the private slot even with errors. */ /* We must clear the private slot even with errors. */
obj->setPrivate(NULL); obj->setPrivate(NULL);
fp->setScopeChain(obj->getParent()); fp->setScopeChainNoCallObj(*obj->getParent());
return normalUnwind; return normalUnwind;
} }
@ -3037,8 +3037,8 @@ block_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
if (fp) { if (fp) {
fp = js_LiveFrameIfGenerator(fp); fp = js_LiveFrameIfGenerator(fp);
index += fp->getFixedCount() + OBJ_BLOCK_DEPTH(cx, obj); index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj);
JS_ASSERT(index < fp->getSlotCount()); JS_ASSERT(index < fp->numSlots());
*vp = fp->slots()[index]; *vp = fp->slots()[index];
return true; return true;
} }
@ -3058,8 +3058,8 @@ block_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
if (fp) { if (fp) {
fp = js_LiveFrameIfGenerator(fp); fp = js_LiveFrameIfGenerator(fp);
index += fp->getFixedCount() + OBJ_BLOCK_DEPTH(cx, obj); index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj);
JS_ASSERT(index < fp->getSlotCount()); JS_ASSERT(index < fp->numSlots());
fp->slots()[index] = *vp; fp->slots()[index] = *vp;
return true; return true;
} }
@ -3741,7 +3741,7 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
*/ */
VOUCH_DOES_NOT_REQUIRE_STACK(); VOUCH_DOES_NOT_REQUIRE_STACK();
if (!start && (fp = cx->maybefp()) != NULL) if (!start && (fp = cx->maybefp()) != NULL)
start = fp->maybeScopeChain(); start = &fp->scopeChain();
if (start) { if (start) {
/* Find the topmost object in the scope chain. */ /* Find the topmost object in the scope chain. */
@ -4479,7 +4479,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult,
JSProperty *prop; JSProperty *prop;
JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx)); JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx));
scopeChain = js_GetTopStackFrame(cx)->getScopeChain(); scopeChain = &js_GetTopStackFrame(cx)->scopeChain();
/* Scan entries on the scope chain that we can cache across. */ /* Scan entries on the scope chain that we can cache across. */
entry = JS_NO_PROP_CACHE_FILL; entry = JS_NO_PROP_CACHE_FILL;
@ -4796,7 +4796,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
op = (JSOp) *pc; op = (JSOp) *pc;
if (op == JSOP_TRAP) { if (op == JSOP_TRAP) {
JS_ASSERT_NOT_ON_TRACE(cx); JS_ASSERT_NOT_ON_TRACE(cx);
op = JS_GetTrapOpcode(cx, cx->fp()->getScript(), pc); op = JS_GetTrapOpcode(cx, cx->fp()->script(), pc);
} }
if (op == JSOP_GETXPROP) { if (op == JSOP_GETXPROP) {
flags = JSREPORT_ERROR; flags = JSREPORT_ERROR;
@ -4888,7 +4888,7 @@ js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname)
return true; return true;
/* If neither cx nor the code is strict, then no check is needed. */ /* If neither cx nor the code is strict, then no check is needed. */
if (!(fp->hasScript() && fp->getScript()->strictModeCode) && if (!(fp->isScriptFrame() && fp->script()->strictModeCode) &&
!JS_HAS_STRICT_OPTION(cx)) { !JS_HAS_STRICT_OPTION(cx)) {
return true; return true;
} }
@ -5282,11 +5282,12 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval)
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
if (fun != funobj) { if (fun != funobj) {
for (JSStackFrame *fp = cx->maybefp(); fp; fp = fp->down) { for (JSStackFrame *fp = cx->maybefp(); fp; fp = fp->prev()) {
if (fp->callee() == fun && if (fp->isFunctionFrame() &&
fp->getThisValue().isObject() && &fp->callee() == &fun->compiledFunObj() &&
&fp->getThisValue().toObject() == obj) { fp->thisValue().isObject() &&
fp->setCalleeObject(*funobj); &fp->thisValue().toObject() == obj) {
fp->calleeValue().setObject(*funobj);
} }
} }
} }
@ -5579,7 +5580,7 @@ js_GetClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
if (protoKey != JSProto_Null) { if (protoKey != JSProto_Null) {
if (!scopeobj) { if (!scopeobj) {
if (cx->hasfp()) if (cx->hasfp())
scopeobj = cx->fp()->maybeScopeChain(); scopeobj = &cx->fp()->scopeChain();
if (!scopeobj) { if (!scopeobj) {
scopeobj = cx->globalObject; scopeobj = cx->globalObject;
if (!scopeobj) { if (!scopeobj) {
@ -6385,27 +6386,27 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
JSStackFrame *const fp = i.fp(); JSStackFrame *const fp = i.fp();
fprintf(stderr, "JSStackFrame at %p\n", (void *) fp); fprintf(stderr, "JSStackFrame at %p\n", (void *) fp);
if (fp->argv) { if (fp->isFunctionFrame()) {
fprintf(stderr, "callee: "); fprintf(stderr, "callee fun: ");
dumpValue(fp->argv[-2]); dumpValue(ObjectValue(fp->callee()));
} else { } else {
fprintf(stderr, "global frame, no callee"); fprintf(stderr, "global frame, no callee");
} }
fputc('\n', stderr); fputc('\n', stderr);
if (fp->hasScript()) { if (fp->isScriptFrame()) {
fprintf(stderr, "file %s line %u\n", fprintf(stderr, "file %s line %u\n",
fp->getScript()->filename, (unsigned) fp->getScript()->lineno); fp->script()->filename, (unsigned) fp->script()->lineno);
} }
if (jsbytecode *pc = i.pc()) { if (jsbytecode *pc = i.pc()) {
if (!fp->hasScript()) { if (!fp->isScriptFrame()) {
fprintf(stderr, "*** pc && !script, skipping frame\n\n"); fprintf(stderr, "*** pc && !script, skipping frame\n\n");
continue; continue;
} }
if (fp->hasIMacroPC()) { if (fp->hasImacropc()) {
fprintf(stderr, " pc in imacro at %p\n called from ", pc); fprintf(stderr, " pc in imacro at %p\n called from ", pc);
pc = fp->getIMacroPC(); pc = fp->imacropc();
} else { } else {
fprintf(stderr, " "); fprintf(stderr, " ");
} }
@ -6422,38 +6423,37 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
fputc('\n', stderr); fputc('\n', stderr);
} }
} }
fprintf(stderr, " argv: %p (argc: %u)\n", if (fp->isFunctionFrame() && !fp->isEvalFrame()) {
(void *) fp->argv, (unsigned) fp->numActualArgs()); fprintf(stderr, " actuals: %p (%u) ", (void *) fp->actualArgs(), (unsigned) fp->numActualArgs());
fprintf(stderr, " formals: %p (%u)\n", (void *) fp->formalArgs(), (unsigned) fp->numFormalArgs());
}
MaybeDumpObject("callobj", fp->maybeCallObj()); MaybeDumpObject("callobj", fp->maybeCallObj());
MaybeDumpObject("argsobj", fp->maybeArgsObj()); MaybeDumpObject("argsobj", fp->maybeArgsObj());
MaybeDumpValue("this", fp->getThisValue()); MaybeDumpValue("this", fp->thisValue());
fprintf(stderr, " rval: "); fprintf(stderr, " rval: ");
dumpValue(fp->getReturnValue()); dumpValue(fp->returnValue());
fputc('\n', stderr); fputc('\n', stderr);
fprintf(stderr, " flags:"); fprintf(stderr, " flags:");
if (fp->flags == 0) if (fp->isConstructing())
fprintf(stderr, " none");
if (fp->flags & JSFRAME_CONSTRUCTING)
fprintf(stderr, " constructing"); fprintf(stderr, " constructing");
if (fp->flags & JSFRAME_ASSIGNING) if (fp->hasOverriddenArgs())
fprintf(stderr, " assigning");
if (fp->flags & JSFRAME_DEBUGGER)
fprintf(stderr, " debugger");
if (fp->flags & JSFRAME_EVAL)
fprintf(stderr, " eval");
if (fp->flags & JSFRAME_YIELDING)
fprintf(stderr, " yielding");
if (fp->flags & JSFRAME_GENERATOR)
fprintf(stderr, " generator");
if (fp->flags & JSFRAME_OVERRIDE_ARGS)
fprintf(stderr, " overridden_args"); fprintf(stderr, " overridden_args");
if (fp->isAssigning())
fprintf(stderr, " assigning");
if (fp->isDebuggerFrame())
fprintf(stderr, " debugger");
if (fp->isEvalFrame())
fprintf(stderr, " eval");
if (fp->isYielding())
fprintf(stderr, " yielding");
if (fp->isGeneratorFrame())
fprintf(stderr, " generator");
fputc('\n', stderr); fputc('\n', stderr);
if (fp->hasScopeChain()) fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) &fp->scopeChain());
fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) fp->getScopeChain());
if (fp->hasBlockChain()) if (fp->hasBlockChain())
fprintf(stderr, " blockChain: (JSObject *) %p\n", (void *) fp->getBlockChain()); fprintf(stderr, " blockChain: (JSObject *) %p\n", (void *) fp->blockChain());
fputc('\n', stderr); fputc('\n', stderr);
} }

Просмотреть файл

@ -780,6 +780,25 @@ struct JSObject {
inline js::Value *addressOfArgsElement(uint32 i) const; inline js::Value *addressOfArgsElement(uint32 i) const;
inline void setArgsElement(uint32 i, const js::Value &v); inline void setArgsElement(uint32 i, const js::Value &v);
private:
/*
* Reserved slot structure for Arguments objects:
*
*/
static const uint32 JSSLOT_CALL_CALLEE = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_CALL_ARGUMENTS = JSSLOT_PRIVATE + 2;
public:
/* Number of extra fixed slots besides JSSLOT_PRIVATE. */
static const uint32 CALL_RESERVED_SLOTS = 2;
inline JSObject &getCallObjCallee() const;
inline JSFunction *getCallObjCalleeFunction() const;
inline void setCallObjCallee(JSObject &callee);
inline const js::Value &getCallObjArguments() const;
inline void setCallObjArguments(const js::Value &v);
/* /*
* Date-specific getters and setters. * Date-specific getters and setters.
*/ */

Просмотреть файл

@ -439,6 +439,42 @@ JSObject::setArgsElement(uint32 i, const js::Value &v)
getArgsData()->slots[i] = v; getArgsData()->slots[i] = v;
} }
inline void
JSObject::setCallObjCallee(JSObject &callee)
{
JS_ASSERT(isCall());
JS_ASSERT(callee.isFunction());
return fslots[JSSLOT_CALL_CALLEE].setObject(callee);
}
inline JSObject &
JSObject::getCallObjCallee() const
{
JS_ASSERT(isCall());
return fslots[JSSLOT_CALL_CALLEE].toObject();
}
inline JSFunction *
JSObject::getCallObjCalleeFunction() const
{
JS_ASSERT(isCall());
return fslots[JSSLOT_CALL_CALLEE].toObject().getFunctionPrivate();
}
inline const js::Value &
JSObject::getCallObjArguments() const
{
JS_ASSERT(isCall());
return fslots[JSSLOT_CALL_ARGUMENTS];
}
inline void
JSObject::setCallObjArguments(const js::Value &v)
{
JS_ASSERT(isCall());
fslots[JSSLOT_CALL_ARGUMENTS] = v;
}
inline const js::Value & inline const js::Value &
JSObject::getDateUTCTime() const JSObject::getDateUTCTime() const
{ {
@ -861,7 +897,7 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp)
if (!global) if (!global)
return NULL; return NULL;
} else { } else {
global = cx->fp()->getScopeChain()->getGlobal(); global = cx->fp()->scopeChain().getGlobal();
} }
JS_ASSERT(global->getClass()->flags & JSCLASS_IS_GLOBAL); JS_ASSERT(global->getClass()->flags & JSCLASS_IS_GLOBAL);

Просмотреть файл

@ -75,6 +75,8 @@
#include "jstracer.h" #include "jstracer.h"
#include "jsvector.h" #include "jsvector.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h"
#include "jsscriptinlines.h" #include "jsscriptinlines.h"
#include "jscntxtinlines.h" #include "jscntxtinlines.h"
@ -279,7 +281,7 @@ js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp)
JS_FRIEND_API(JSBool) JS_FRIEND_API(JSBool)
js_DumpPC(JSContext *cx) js_DumpPC(JSContext *cx)
{ {
return js_DisassembleAtPC(cx, cx->fp()->getScript(), true, stdout, cx->regs->pc); return js_DisassembleAtPC(cx, cx->fp()->script(), true, stdout, cx->regs->pc);
} }
JSBool JSBool
@ -2880,10 +2882,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
*/ */
JSStackFrame *fp = js_GetTopStackFrame(cx); JSStackFrame *fp = js_GetTopStackFrame(cx);
if (fp) { if (fp) {
while (!(fp->flags & JSFRAME_EVAL)) while (!fp->isEvalFrame())
fp = fp->down; fp = fp->prev();
JS_ASSERT(fp->getScript() == jp->script); JS_ASSERT(fp->script() == jp->script);
JS_ASSERT(fp->down->getFunction() == jp->fun); JS_ASSERT(fp->prev()->fun() == jp->fun);
JS_ASSERT(FUN_INTERPRETED(jp->fun)); JS_ASSERT(FUN_INTERPRETED(jp->fun));
JS_ASSERT(jp->script != jp->fun->u.i.script); JS_ASSERT(jp->script != jp->fun->u.i.script);
JS_ASSERT(jp->script->upvarsOffset != 0); JS_ASSERT(jp->script->upvarsOffset != 0);
@ -5089,8 +5091,8 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
JSString *fallback) JSString *fallback)
{ {
JSStackFrame *fp; JSStackFrame *fp;
jsbytecode *pc;
JSScript *script; JSScript *script;
jsbytecode *pc;
Value v = Valueify(v_in); Value v = Valueify(v_in);
@ -5100,17 +5102,12 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
LeaveTrace(cx); LeaveTrace(cx);
/* Get scripted caller */ if (!cx->regs || !cx->regs->fp || !cx->regs->fp->isScriptFrame())
FrameRegsIter i(cx);
while (!i.done() && !i.fp()->hasScript())
++i;
if (i.done() || !i.pc() || i.fp()->getSlotCount() == 0)
goto do_fallback; goto do_fallback;
fp = i.fp(); fp = cx->regs->fp;
script = fp->getScript(); script = fp->script();
pc = fp->hasIMacroPC() ? fp->getIMacroPC() : i.pc(); pc = fp->hasImacropc() ? fp->imacropc() : cx->regs->pc;
JS_ASSERT(pc >= script->main && pc < script->code + script->length); JS_ASSERT(pc >= script->main && pc < script->code + script->length);
if (spindex != JSDVG_IGNORE_STACK) { if (spindex != JSDVG_IGNORE_STACK) {
@ -5141,7 +5138,7 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
* it that caused exception, see bug 328664. * it that caused exception, see bug 328664.
*/ */
Value *stackBase = fp->base(); Value *stackBase = fp->base();
Value *sp = i.sp(); Value *sp = cx->regs->sp;
do { do {
if (sp == stackBase) { if (sp == stackBase) {
pcdepth = -1; pcdepth = -1;
@ -5172,15 +5169,11 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
} }
{ {
jsbytecode* savepc = i.pc(); jsbytecode* savedImacropc = fp->maybeImacropc();
jsbytecode* savedIMacroPC = fp->maybeIMacroPC(); if (savedImacropc) {
if (savedIMacroPC) {
JS_ASSERT(cx->hasfp()); JS_ASSERT(cx->hasfp());
if (fp == cx->fp()) cx->regs->pc = savedImacropc;
cx->regs->pc = savedIMacroPC; fp->clearImacropc();
else
fp->savedPC = savedIMacroPC;
fp->clearIMacroPC();
} }
/* /*
@ -5188,18 +5181,15 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
* value *inside* an imacro; this would confuse the decompiler. * value *inside* an imacro; this would confuse the decompiler.
*/ */
char *name; char *name;
if (savedIMacroPC && size_t(pc - script->code) >= script->length) if (savedImacropc && size_t(pc - script->code) >= script->length)
name = FAILED_EXPRESSION_DECOMPILER; name = FAILED_EXPRESSION_DECOMPILER;
else else
name = DecompileExpression(cx, script, fp->maybeFunction(), pc); name = DecompileExpression(cx, script, fp->maybeFun(), pc);
if (savedIMacroPC) { if (savedImacropc) {
JS_ASSERT(cx->hasfp()); JS_ASSERT(cx->hasfp());
if (fp == cx->fp()) cx->regs->pc = savedImacropc;
cx->regs->pc = savedIMacroPC; fp->setImacropc(savedImacropc);
else
fp->savedPC = savepc;
fp->setIMacroPC(savedIMacroPC);
} }
if (name != FAILED_EXPRESSION_DECOMPILER) if (name != FAILED_EXPRESSION_DECOMPILER)
@ -5492,8 +5482,8 @@ ReconstructImacroPCStack(JSContext *cx, JSScript *script,
* the state-of-the-world at the *start* of the imacro. * the state-of-the-world at the *start* of the imacro.
*/ */
JSStackFrame *fp = js_GetScriptedCaller(cx, NULL); JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
JS_ASSERT(fp->hasIMacroPC()); JS_ASSERT(fp->hasImacropc());
intN pcdepth = ReconstructPCStack(cx, script, fp->getIMacroPC(), pcstack); intN pcdepth = ReconstructPCStack(cx, script, fp->imacropc(), pcstack);
if (pcdepth < 0) if (pcdepth < 0)
return pcdepth; return pcdepth;
return SimulateImacroCFG(cx, script, pcdepth, imacstart, target, pcstack); return SimulateImacroCFG(cx, script, pcdepth, imacstart, target, pcstack);

Просмотреть файл

@ -89,6 +89,7 @@
#endif #endif
#include "jsatominlines.h" #include "jsatominlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jsregexpinlines.h" #include "jsregexpinlines.h"
@ -168,6 +169,25 @@ JSParseNode::clear()
pn_parens = false; pn_parens = false;
} }
Parser::Parser(JSContext *cx, JSPrincipals *prin, JSStackFrame *cfp)
: js::AutoGCRooter(cx, PARSER),
context(cx),
aleFreeList(NULL),
tokenStream(cx),
principals(NULL),
callerFrame(cfp),
callerVarObj(cfp ? &cfp->varobj(cx->containingSegment(cfp)) : NULL),
nodeList(NULL),
functionCount(0),
traceListHead(NULL),
tc(NULL),
keepAtoms(cx->runtime)
{
js::PodArrayZero(tempFreeList);
setPrincipals(prin);
JS_ASSERT_IF(cfp, cfp->isScriptFrame());
}
bool bool
Parser::init(const jschar *base, size_t length, Parser::init(const jschar *base, size_t length,
FILE *fp, const char *filename, uintN lineno) FILE *fp, const char *filename, uintN lineno)
@ -717,6 +737,11 @@ SetStaticLevel(JSTreeContext *tc, uintN staticLevel)
/* /*
* Compile a top-level script. * Compile a top-level script.
*/ */
Compiler::Compiler(JSContext *cx, JSPrincipals *prin, JSStackFrame *cfp)
: parser(cx, prin, cfp)
{
}
JSScript * JSScript *
Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame, Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,
JSPrincipals *principals, uint32 tcflags, JSPrincipals *principals, uint32 tcflags,
@ -792,8 +817,8 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
/* If this is a direct call to eval, inherit the caller's strictness. */ /* If this is a direct call to eval, inherit the caller's strictness. */
if (callerFrame && if (callerFrame &&
callerFrame->hasScript() && callerFrame->isScriptFrame() &&
callerFrame->getScript()->strictModeCode) { callerFrame->script()->strictModeCode) {
cg.flags |= TCF_STRICT_MODE_CODE; cg.flags |= TCF_STRICT_MODE_CODE;
tokenStream.setStrictMode(); tokenStream.setStrictMode();
} }
@ -816,13 +841,13 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
goto out; goto out;
} }
if (callerFrame && callerFrame->hasFunction()) { if (callerFrame && callerFrame->isFunctionFrame()) {
/* /*
* An eval script in a caller frame needs to have its enclosing * An eval script in a caller frame needs to have its enclosing
* function captured in case it refers to an upvar, and someone * function captured in case it refers to an upvar, and someone
* wishes to decompile it while it's running. * wishes to decompile it while it's running.
*/ */
funbox = parser.newObjectBox(FUN_OBJECT(callerFrame->getFunction())); funbox = parser.newObjectBox(FUN_OBJECT(callerFrame->fun()));
if (!funbox) if (!funbox)
goto out; goto out;
funbox->emitLink = cg.objectList.lastbox; funbox->emitLink = cg.objectList.lastbox;

Просмотреть файл

@ -998,18 +998,7 @@ struct Parser : private js::AutoGCRooter
/* Root atoms and objects allocated for the parsed tree. */ /* Root atoms and objects allocated for the parsed tree. */
js::AutoKeepAtoms keepAtoms; js::AutoKeepAtoms keepAtoms;
Parser(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL) Parser(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL);
: js::AutoGCRooter(cx, PARSER), context(cx),
aleFreeList(NULL), tokenStream(cx), principals(NULL), callerFrame(cfp),
callerVarObj(cfp ? cfp->varobj(cx->containingSegment(cfp)) : NULL),
nodeList(NULL), functionCount(0), traceListHead(NULL), tc(NULL),
keepAtoms(cx->runtime)
{
js::PodArrayZero(tempFreeList);
setPrincipals(prin);
JS_ASSERT_IF(cfp, cfp->hasScript());
}
~Parser(); ~Parser();
friend void js::AutoGCRooter::trace(JSTracer *trc); friend void js::AutoGCRooter::trace(JSTracer *trc);
@ -1155,10 +1144,7 @@ struct Compiler
Parser parser; Parser parser;
GlobalScope *globalScope; GlobalScope *globalScope;
Compiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL) Compiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL);
: parser(cx, prin, cfp)
{
}
/* /*
* Initialize a compiler. Parameters are passed on to init parser. * Initialize a compiler. Parameters are passed on to init parser.

Просмотреть файл

@ -127,7 +127,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI
* opcode format flags. * opcode format flags.
*/ */
pc = cx->regs->pc; pc = cx->regs->pc;
op = js_GetOpcode(cx, cx->fp()->getScript(), pc); op = js_GetOpcode(cx, cx->fp()->script(), pc);
cs = &js_CodeSpec[op]; cs = &js_CodeSpec[op];
kshape = 0; kshape = 0;
@ -304,7 +304,7 @@ GetAtomFromBytecode(JSContext *cx, jsbytecode *pc, JSOp op, const JSCodeSpec &cs
ptrdiff_t pcoff = (JOF_TYPE(cs.format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0; ptrdiff_t pcoff = (JOF_TYPE(cs.format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0;
JSAtom *atom; JSAtom *atom;
GET_ATOM_FROM_BYTECODE(cx->fp()->getScript(), pc, pcoff, atom); GET_ATOM_FROM_BYTECODE(cx->fp()->script(), pc, pcoff, atom);
return atom; return atom;
} }
@ -318,10 +318,10 @@ PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject
JSStackFrame *fp = cx->fp(); JSStackFrame *fp = cx->fp();
JS_ASSERT(this == &JS_PROPERTY_CACHE(cx)); JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
JS_ASSERT(uintN((fp->hasIMacroPC() ? fp->getIMacroPC() : pc) - fp->getScript()->code) JS_ASSERT(uintN((fp->hasImacropc() ? fp->imacropc() : pc) - fp->script()->code)
< fp->getScript()->length); < fp->script()->length);
JSOp op = js_GetOpcode(cx, fp->getScript(), pc); JSOp op = js_GetOpcode(cx, fp->script(), pc);
const JSCodeSpec &cs = js_CodeSpec[op]; const JSCodeSpec &cs = js_CodeSpec[op];
obj = *objp; obj = *objp;

Просмотреть файл

@ -131,6 +131,7 @@ class TraceRecorder;
struct TraceMonitor; struct TraceMonitor;
class StackSpace; class StackSpace;
class StackSegment; class StackSegment;
class FrameRegsIter;
struct Compiler; struct Compiler;
struct Parser; struct Parser;

Просмотреть файл

@ -2494,7 +2494,7 @@ ASTSerializer::literal(JSParseNode *pn, Value *dst)
LOCAL_ASSERT(re1 && re1->isRegExp()); LOCAL_ASSERT(re1 && re1->isRegExp());
JSObject *proto; JSObject *proto;
if (!js_GetClassPrototype(cx, cx->fp()->getScopeChain(), JSProto_RegExp, &proto)) if (!js_GetClassPrototype(cx, &cx->fp()->scopeChain(), JSProto_RegExp, &proto))
return false; return false;
JSObject *re2 = js_CloneRegExpObject(cx, re1, proto); JSObject *re2 = js_CloneRegExpObject(cx, re1, proto);

Просмотреть файл

@ -66,6 +66,7 @@
#endif #endif
#include "methodjit/MethodJIT.h" #include "methodjit/MethodJIT.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jsscriptinlines.h" #include "jsscriptinlines.h"
@ -1249,7 +1250,7 @@ js_DestroyScript(JSContext *cx, JSScript *script)
if (!cx->runtime->gcRunning) { if (!cx->runtime->gcRunning) {
JSStackFrame *fp = js_GetTopStackFrame(cx); JSStackFrame *fp = js_GetTopStackFrame(cx);
if (!(fp && (fp->flags & JSFRAME_EVAL))) { if (!(fp && fp->isEvalFrame())) {
JS_PROPERTY_CACHE(cx).purgeForScript(script); JS_PROPERTY_CACHE(cx).purgeForScript(script);
#ifdef CHECK_SCRIPT_OWNER #ifdef CHECK_SCRIPT_OWNER
@ -1434,8 +1435,8 @@ 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->getScript(), return js_PCToLineNumber(cx, fp->script(),
fp->hasIMacroPC() ? fp->getIMacroPC() : fp->pc(cx)); fp->hasImacropc() ? fp->imacropc() : fp->pc(cx));
} }
uintN uintN

Просмотреть файл

@ -2069,7 +2069,7 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
uintN p = statics.getParenCount(); uintN p = statics.getParenCount();
uintN argc = 1 + p + 2; uintN argc = 1 + p + 2;
if (!rdata.args.pushed() && !cx->stack().pushInvokeArgs(cx, argc, rdata.args)) if (!rdata.args.pushed() && !cx->stack().pushInvokeArgs(cx, argc, &rdata.args))
return false; return false;
PreserveRegExpStatics save(cx); PreserveRegExpStatics save(cx);
@ -2382,7 +2382,7 @@ str_replace_flat_lambda(JSContext *cx, uintN argc, Value *vp, ReplaceData &rdata
/* lambda(matchStr, matchStart, textstr) */ /* lambda(matchStr, matchStart, textstr) */
static const uint32 lambdaArgc = 3; static const uint32 lambdaArgc = 3;
if (!cx->stack().pushInvokeArgs(cx, lambdaArgc, rdata.args)) if (!cx->stack().pushInvokeArgs(cx, lambdaArgc, &rdata.args))
return false; return false;
CallArgs &args = rdata.args; CallArgs &args = rdata.args;

Просмотреть файл

@ -441,6 +441,20 @@ ForEach(InputIterT begin, InputIterT end, CallableT f)
f(*begin); f(*begin);
} }
template <class T>
static inline T
Min(T t1, T t2)
{
return t1 < t2 ? t1 : t2;
}
template <class T>
static inline T
Max(T t1, T t2)
{
return t1 > t2 ? t1 : t2;
}
} /* namespace js */ } /* namespace js */
#endif /* jstl_h_ */ #endif /* jstl_h_ */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -553,7 +553,7 @@ struct FrameInfo {
* Number of stack slots in the caller, not counting slots pushed when * Number of stack slots in the caller, not counting slots pushed when
* invoking the callee. That is, slots after JSOP_CALL completes but * invoking the callee. That is, slots after JSOP_CALL completes but
* without the return value. This is also equal to the number of slots * without the return value. This is also equal to the number of slots
* between fp->down->argv[-2] (calleR fp->callee) and fp->argv[-2] * between fp->prev->argv[-2] (calleR fp->callee) and fp->argv[-2]
* (calleE fp->callee). * (calleE fp->callee).
*/ */
uint32 callerHeight; uint32 callerHeight;
@ -1041,17 +1041,17 @@ class TraceRecorder
bool demote); bool demote);
#ifdef DEBUG #ifdef DEBUG
bool isValidFrameObjPtr(JSObject **obj); bool isValidFrameObjPtr(void *obj);
#endif #endif
JS_REQUIRES_STACK void setImpl(void* p, nanojit::LIns* l, bool demote = true); JS_REQUIRES_STACK void setImpl(void* p, nanojit::LIns* l, bool demote = true);
JS_REQUIRES_STACK void set(Value* p, nanojit::LIns* l, bool demote = true); JS_REQUIRES_STACK void set(Value* p, nanojit::LIns* l, bool demote = true);
JS_REQUIRES_STACK void setFrameObjPtr(JSObject** p, nanojit::LIns* l, bool demote = true); JS_REQUIRES_STACK void setFrameObjPtr(void* p, nanojit::LIns* l, bool demote = true);
nanojit::LIns* getFromTrackerImpl(const void *p); nanojit::LIns* getFromTrackerImpl(const void *p);
nanojit::LIns* getFromTracker(const Value* p); nanojit::LIns* getFromTracker(const Value* p);
JS_REQUIRES_STACK nanojit::LIns* getImpl(const void* p); JS_REQUIRES_STACK nanojit::LIns* getImpl(const void* p);
JS_REQUIRES_STACK nanojit::LIns* get(const Value* p); JS_REQUIRES_STACK nanojit::LIns* get(const Value* p);
JS_REQUIRES_STACK nanojit::LIns* getFrameObjPtr(JSObject** p); JS_REQUIRES_STACK nanojit::LIns* getFrameObjPtr(void* p);
JS_REQUIRES_STACK nanojit::LIns* attemptImport(const Value* p); JS_REQUIRES_STACK nanojit::LIns* attemptImport(const Value* p);
JS_REQUIRES_STACK nanojit::LIns* addr(Value* p); JS_REQUIRES_STACK nanojit::LIns* addr(Value* p);
@ -1179,7 +1179,6 @@ class TraceRecorder
nanojit::LIns* stobj_get_fslot_uint32(nanojit::LIns* obj_ins, unsigned slot); nanojit::LIns* stobj_get_fslot_uint32(nanojit::LIns* obj_ins, unsigned slot);
nanojit::LIns* stobj_set_fslot_uint32(nanojit::LIns* value_ins, nanojit::LIns* obj_ins, nanojit::LIns* stobj_set_fslot_uint32(nanojit::LIns* value_ins, nanojit::LIns* obj_ins,
unsigned slot); unsigned slot);
nanojit::LIns* stobj_get_fslot_ptr(nanojit::LIns* obj_ins, unsigned slot);
nanojit::LIns* unbox_slot(JSObject *obj, nanojit::LIns *obj_ins, uint32 slot, nanojit::LIns* unbox_slot(JSObject *obj, nanojit::LIns *obj_ins, uint32 slot,
VMSideExit *exit); VMSideExit *exit);
nanojit::LIns* stobj_get_parent(nanojit::LIns* obj_ins); nanojit::LIns* stobj_get_parent(nanojit::LIns* obj_ins);
@ -1317,10 +1316,7 @@ class TraceRecorder
nanojit::LIns* obj_ins, nanojit::LIns* obj_ins,
VMSideExit *exit); VMSideExit *exit);
JS_REQUIRES_STACK RecordingStatus guardNativeConversion(Value& v); JS_REQUIRES_STACK RecordingStatus guardNativeConversion(Value& v);
JS_REQUIRES_STACK JSStackFrame* entryFrame() const;
JS_REQUIRES_STACK void clearEntryFrameSlotsFromTracker(Tracker& which);
JS_REQUIRES_STACK void clearCurrentFrameSlotsFromTracker(Tracker& which); JS_REQUIRES_STACK void clearCurrentFrameSlotsFromTracker(Tracker& which);
JS_REQUIRES_STACK void clearFrameSlotsFromTracker(Tracker& which, JSStackFrame* fp, unsigned nslots);
JS_REQUIRES_STACK void putActivationObjects(); JS_REQUIRES_STACK void putActivationObjects();
JS_REQUIRES_STACK RecordingStatus guardCallee(Value& callee); JS_REQUIRES_STACK RecordingStatus guardCallee(Value& callee);
JS_REQUIRES_STACK JSStackFrame *guardArguments(JSObject *obj, nanojit::LIns* obj_ins, JS_REQUIRES_STACK JSStackFrame *guardArguments(JSObject *obj, nanojit::LIns* obj_ins,
@ -1424,6 +1420,7 @@ class TraceRecorder
friend TracePointAction MonitorTracePoint(JSContext*, uintN &inlineCallCount, friend TracePointAction MonitorTracePoint(JSContext*, uintN &inlineCallCount,
bool &blacklist); bool &blacklist);
friend void AbortRecording(JSContext*, const char*); friend void AbortRecording(JSContext*, const char*);
friend class BoxArg;
public: public:
static bool JS_REQUIRES_STACK static bool JS_REQUIRES_STACK

Просмотреть файл

@ -261,6 +261,7 @@ typedef enum JSWhyMagic
JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */ JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */
JS_NO_CONSTANT, /* compiler sentinel value */ JS_NO_CONSTANT, /* compiler sentinel value */
JS_THIS_POISON, /* used in debug builds to catch tracing errors */ JS_THIS_POISON, /* used in debug builds to catch tracing errors */
JS_ARG_POISON, /* used in debug builds to catch tracing errors */
JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */ JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */
JS_GENERIC_MAGIC /* for local use */ JS_GENERIC_MAGIC /* for local use */
} JSWhyMagic; } JSWhyMagic;

Просмотреть файл

@ -388,7 +388,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
* This loses us some transparency, and is generally very cheesy. * This loses us some transparency, and is generally very cheesy.
*/ */
JSObject *global = JSObject *global =
cx->hasfp() ? cx->fp()->getScopeChain()->getGlobal() : cx->globalObject; cx->hasfp() ? cx->fp()->scopeChain().getGlobal() : cx->globalObject;
wrapper->setParent(global); wrapper->setParent(global);
return true; return true;
} }
@ -535,7 +535,7 @@ AutoCompartment::enter()
context->compartment = destination; context->compartment = destination;
JSObject *scopeChain = target->getGlobal(); JSObject *scopeChain = target->getGlobal();
frame.construct(); frame.construct();
if (!context->stack().pushDummyFrame(context, frame.ref(), regs, scopeChain)) { if (!context->stack().pushDummyFrame(context, *scopeChain, &frame.ref())) {
frame.destroy(); frame.destroy();
context->compartment = origin; context->compartment = origin;
return false; return false;

Просмотреть файл

@ -152,7 +152,7 @@ class AutoCompartment
JSObject * const target; JSObject * const target;
JSCompartment * const destination; JSCompartment * const destination;
private: private:
LazilyConstructed<FrameGuard> frame; LazilyConstructed<DummyFrameGuard> frame;
JSFrameRegs regs; JSFrameRegs regs;
RegExpStatics statics; RegExpStatics statics;
AutoStringRooter input; AutoStringRooter input;

Просмотреть файл

@ -72,6 +72,7 @@
#include "jsatominlines.h" #include "jsatominlines.h"
#include "jscntxtinlines.h" #include "jscntxtinlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#ifdef DEBUG #ifdef DEBUG
@ -1715,14 +1716,14 @@ ParseXMLSource(JSContext *cx, JSString *src)
xml = NULL; xml = NULL;
FrameRegsIter i(cx); FrameRegsIter i(cx);
for (; !i.done() && !i.pc(); ++i) for (; !i.done() && !i.pc(); ++i)
JS_ASSERT(!i.fp()->hasScript()); JS_ASSERT(!i.fp()->isScriptFrame());
filename = NULL; filename = NULL;
lineno = 1; lineno = 1;
if (!i.done()) { if (!i.done()) {
JSStackFrame *fp = i.fp(); JSStackFrame *fp = i.fp();
op = (JSOp) *i.pc(); op = (JSOp) *i.pc();
if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) { if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) {
filename = fp->getScript()->filename; filename = fp->script()->filename;
lineno = js_FramePCToLineNumber(cx, fp); lineno = js_FramePCToLineNumber(cx, fp);
for (endp = srcp + srclen; srcp < endp; srcp++) { for (endp = srcp + srclen; srcp < endp; srcp++) {
if (*srcp == '\n') if (*srcp == '\n')
@ -1734,7 +1735,7 @@ ParseXMLSource(JSContext *cx, JSString *src)
{ {
Parser parser(cx); Parser parser(cx);
if (parser.init(chars, length, NULL, filename, lineno)) { if (parser.init(chars, length, NULL, filename, lineno)) {
JSObject *scopeChain = js_GetTopStackFrame(cx)->getScopeChain(); JSObject *scopeChain = &js_GetTopStackFrame(cx)->scopeChain();
JSParseNode *pn = parser.parseXMLText(scopeChain, false); JSParseNode *pn = parser.parseXMLText(scopeChain, false);
uintN flags; uintN flags;
if (pn && GetXMLSettingFlags(cx, &flags)) { if (pn && GetXMLSettingFlags(cx, &flags)) {
@ -7253,19 +7254,16 @@ JSBool
js_SetDefaultXMLNamespace(JSContext *cx, const Value &v) js_SetDefaultXMLNamespace(JSContext *cx, const Value &v)
{ {
Value argv[2]; Value argv[2];
JSObject *ns, *varobj;
JSStackFrame *fp;
argv[0].setString(cx->runtime->emptyString); argv[0].setString(cx->runtime->emptyString);
argv[1] = v; argv[1] = v;
ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, 2, argv); JSObject *ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, 2, argv);
if (!ns) if (!ns)
return JS_FALSE; return JS_FALSE;
fp = js_GetTopStackFrame(cx); JSStackFrame *fp = js_GetTopStackFrame(cx);
varobj = fp->varobj(cx); JSObject &varobj = fp->varobj(cx);
if (!varobj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns), if (!varobj.defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns),
PropertyStub, PropertyStub, JSPROP_PERMANENT)) { PropertyStub, PropertyStub, JSPROP_PERMANENT)) {
return JS_FALSE; return JS_FALSE;
} }
return JS_TRUE; return JS_TRUE;
@ -7436,7 +7434,7 @@ js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *i
if (!IsFunctionQName(cx, qn, &funid)) if (!IsFunctionQName(cx, qn, &funid))
return JS_FALSE; return JS_FALSE;
obj = js_GetTopStackFrame(cx)->getScopeChain(); obj = &js_GetTopStackFrame(cx)->scopeChain();
do { do {
/* Skip any With object that can wrap XML. */ /* Skip any With object that can wrap XML. */
target = obj; target = obj;

Просмотреть файл

@ -323,17 +323,17 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::ARMRegiste
{ {
#ifndef JS_CPU_ARM #ifndef JS_CPU_ARM
/* X86 and X64's "ret" instruction expects a return address on the stack. */ /* X86 and X64's "ret" instruction expects a return address on the stack. */
push(Address(JSFrameReg, offsetof(JSStackFrame, ncode))); push(Address(JSFrameReg, JSStackFrame::offsetOfncode()));
#else #else
/* ARM returns either using its link register (LR) or directly from the stack, but masm.ret() /* ARM returns either using its link register (LR) or directly from the stack, but masm.ret()
* always emits a return to LR. */ * always emits a return to LR. */
load32(Address(JSFrameReg, offsetof(JSStackFrame, ncode)), JSC::ARMRegisters::lr); load32(Address(JSFrameReg, JSStackFrame::offsetOfncode()), JSC::ARMRegisters::lr);
#endif #endif
} }
void saveReturnAddress(RegisterID reg) void saveReturnAddress(RegisterID reg)
{ {
storePtr(reg, Address(JSFrameReg, offsetof(JSStackFrame, ncode))); storePtr(reg, Address(JSFrameReg, JSStackFrame::offsetOfncode()));
} }
void finalize(uint8 *ncode) { void finalize(uint8 *ncode) {

Просмотреть файл

@ -212,11 +212,14 @@ mjit::Compiler::generatePrologue()
invokeLabel = masm.label(); invokeLabel = masm.label();
RegisterID retAddr = takeHWReturnAddress(masm); RegisterID retAddr = takeHWReturnAddress(masm);
masm.saveReturnAddress(retAddr); masm.saveReturnAddress(retAddr);
#ifdef DEBUG
masm.storePtr(ImmPtr(JSStackFrame::sInvalidpc), Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
#endif
Label fastPath = masm.label(); Label fastPath = masm.label();
/* Store these early on so slow paths can access them. */ /* Store these early on so slow paths can access them. */
masm.storePtr(ImmPtr(script), Address(JSFrameReg, JSStackFrame::offsetScript())); masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetOfExec()));
masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp))); masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
{ {
@ -229,14 +232,20 @@ mjit::Compiler::generatePrologue()
arityLabel = stubcc.masm.label(); arityLabel = stubcc.masm.label();
RegisterID retAddr = takeHWReturnAddress(stubcc.masm); RegisterID retAddr = takeHWReturnAddress(stubcc.masm);
stubcc.masm.saveReturnAddress(retAddr); stubcc.masm.saveReturnAddress(retAddr);
Jump argMatch = stubcc.masm.branch32(Assembler::AboveOrEqual, JSParamReg_Argc, #ifdef DEBUG
stubcc.masm.storePtr(ImmPtr(JSStackFrame::sInvalidpc), Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
#endif
Jump argMatch = stubcc.masm.branch32(Assembler::Equal, JSParamReg_Argc,
Imm32(fun->nargs)); Imm32(fun->nargs));
stubcc.crossJump(argMatch, fastPath); stubcc.crossJump(argMatch, fastPath);
if (JSParamReg_Argc != Registers::ArgReg1)
stubcc.masm.move(JSParamReg_Argc, Registers::ArgReg1);
/* Slow path - call the arity check function. Returns new fp. */ /* Slow path - call the arity check function. Returns new fp. */
stubcc.masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetFunction())); stubcc.masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetOfExec()));
stubcc.masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp))); stubcc.masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
stubcc.call(stubs::CheckArity); stubcc.call(stubs::FixupArity);
stubcc.masm.move(Registers::ReturnReg, JSFrameReg); stubcc.masm.move(Registers::ReturnReg, JSFrameReg);
stubcc.crossJump(stubcc.masm.jump(), fastPath); stubcc.crossJump(stubcc.masm.jump(), fastPath);
} }
@ -254,28 +263,16 @@ mjit::Compiler::generatePrologue()
/* If the stack check fails... */ /* If the stack check fails... */
{ {
stubcc.linkExitDirect(stackCheck, stubcc.masm.label()); stubcc.linkExitDirect(stackCheck, stubcc.masm.label());
stubcc.masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetFunction())); stubcc.call(stubs::HitStackQuota);
stubcc.call(stubs::CheckStackQuota);
stubcc.crossJump(stubcc.masm.jump(), masm.label()); stubcc.crossJump(stubcc.masm.jump(), masm.label());
} }
/* Easy frame members. Hard ones are in caller. */ /* Fill in the members that initCallFrameLatePrologue does. */
masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetFunction())); masm.storeValue(UndefinedValue(), Address(JSFrameReg, JSStackFrame::offsetOfReturnValue()));
masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetCallObj())); masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetOfBlockChain()));
masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetArgsObj()));
masm.storeValue(UndefinedValue(), Address(JSFrameReg, JSStackFrame::offsetReturnValue()));
masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetAnnotation()));
masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetBlockChain()));
if (script->debugMode)
masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetHookData()));
#ifdef DEBUG
masm.storePtr(ImmPtr(JSStackFrame::sInvalidPC),
Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
#endif
/* :TODO: This is entirely wrong. */ /* :TODO: This is entirely wrong. */
masm.store32(Imm32(cx->version), masm.store32(Imm32(cx->version), Address(JSFrameReg, JSStackFrame::offsetOfCallerVersion()));
Address(JSFrameReg, JSStackFrame::offsetCallerVersion()));
/* Set cx->fp */ /* Set cx->fp */
masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), Registers::ReturnReg); masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), Registers::ReturnReg);
@ -481,8 +478,6 @@ mjit::Compiler::finishThisUp()
script->callICs[i].funObjReg = callICs[i].funObjReg; script->callICs[i].funObjReg = callICs[i].funObjReg;
script->callICs[i].funPtrReg = callICs[i].funPtrReg; script->callICs[i].funPtrReg = callICs[i].funPtrReg;
script->callICs[i].frameDepth = callICs[i].frameDepth; script->callICs[i].frameDepth = callICs[i].frameDepth;
script->callICs[i].isConstantThis = callICs[i].isConstantThis;
script->callICs[i].constantThis = callICs[i].constantThis;
} }
#endif /* JS_MONOIC */ #endif /* JS_MONOIC */
@ -670,7 +665,7 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_SETRVAL) BEGIN_CASE(JSOP_SETRVAL)
{ {
FrameEntry *fe = frame.peek(-1); FrameEntry *fe = frame.peek(-1);
frame.storeTo(fe, Address(JSFrameReg, JSStackFrame::offsetReturnValue()), true); frame.storeTo(fe, Address(JSFrameReg, JSStackFrame::offsetOfReturnValue()), true);
frame.pop(); frame.pop();
} }
END_CASE(JSOP_POPV) END_CASE(JSOP_POPV)
@ -678,7 +673,7 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_RETURN) BEGIN_CASE(JSOP_RETURN)
{ {
FrameEntry *fe = frame.peek(-1); FrameEntry *fe = frame.peek(-1);
frame.storeTo(fe, Address(JSFrameReg, JSStackFrame::offsetReturnValue()), true); frame.storeTo(fe, Address(JSFrameReg, JSStackFrame::offsetOfReturnValue()), true);
frame.pop(); frame.pop();
emitReturn(); emitReturn();
} }
@ -1171,8 +1166,7 @@ mjit::Compiler::generateMethod()
bool popped = PC[JSOP_SETARG_LENGTH] == JSOP_POP; bool popped = PC[JSOP_SETARG_LENGTH] == JSOP_POP;
RegisterID reg = frame.allocReg(); RegisterID reg = frame.allocReg();
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, argv)), reg); Address address = Address(JSFrameReg, JSStackFrame::offsetOfFormalArg(fun, slot));
Address address = Address(reg, slot * sizeof(Value));
frame.storeTo(top, address, popped); frame.storeTo(top, address, popped);
frame.freeReg(reg); frame.freeReg(reg);
} }
@ -1386,8 +1380,7 @@ mjit::Compiler::generateMethod()
uintN index = GET_UINT16(PC); uintN index = GET_UINT16(PC);
// JSObject *obj = &fp->argv[-2].toObject(); // JSObject *obj = &fp->argv[-2].toObject();
RegisterID reg = frame.allocReg(); RegisterID reg = frame.allocReg();
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, argv)), reg); masm.loadPayload(Address(JSFrameReg, JSStackFrame::offsetOfCallee(fun)), reg);
masm.loadPayload(Address(reg, int32(sizeof(Value)) * -2), reg);
// obj->getFlatClosureUpvars() // obj->getFlatClosureUpvars()
Address upvarAddress(reg, offsetof(JSObject, fslots) + Address upvarAddress(reg, offsetof(JSObject, fslots) +
JSObject::JSSLOT_FLAT_CLOSURE_UPVARS * sizeof(Value)); JSObject::JSSLOT_FLAT_CLOSURE_UPVARS * sizeof(Value));
@ -1770,47 +1763,37 @@ mjit::Compiler::emitReturn()
stubCall(stubs::PutCallObject); stubCall(stubs::PutCallObject);
frame.throwaway(); frame.throwaway();
} else { } else {
/* if (callobj) ... */ /* if (hasCallObj() || hasArgsObj()) stubs::PutActivationObjects() */
Jump callObj = masm.branchPtr(Assembler::NotEqual, Jump putObjs = masm.branchTest32(Assembler::NonZero,
Address(JSFrameReg, JSStackFrame::offsetCallObj()), Address(JSFrameReg, JSStackFrame::offsetOfFlags()),
ImmPtr(0)); Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ));
stubcc.linkExit(callObj, Uses(frame.frameDepth())); stubcc.linkExit(putObjs, Uses(frame.frameDepth()));
frame.throwaway(); frame.throwaway();
stubcc.leave(); stubcc.leave();
stubcc.call(stubs::PutCallObject); stubcc.call(stubs::PutActivationObjects);
Jump j = stubcc.masm.jump();
/* if (arguments) ... */
Jump argsObj = masm.branchPtr(Assembler::NotEqual,
Address(JSFrameReg, JSStackFrame::offsetArgsObj()),
ImmIntPtr(0));
stubcc.linkExit(argsObj, Uses(0));
stubcc.call(stubs::PutArgsObject);
stubcc.rejoin(Changes(0)); stubcc.rejoin(Changes(0));
stubcc.crossJump(j, masm.label());
} }
} }
/* /*
* r = fp->down * r = fp->prev
* f.fp = r * f.fp = r
*/ */
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, down)), Registers::ReturnReg); masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), Registers::ReturnReg);
masm.storePtr(Registers::ReturnReg, FrameAddress(offsetof(VMFrame, regs.fp))); masm.storePtr(Registers::ReturnReg, FrameAddress(offsetof(VMFrame, regs.fp)));
JS_STATIC_ASSERT(Registers::ReturnReg != JSReturnReg_Data); JS_STATIC_ASSERT(Registers::ReturnReg != JSReturnReg_Data);
JS_STATIC_ASSERT(Registers::ReturnReg != JSReturnReg_Type); JS_STATIC_ASSERT(Registers::ReturnReg != JSReturnReg_Type);
Address rval(JSFrameReg, JSStackFrame::offsetReturnValue()); Address rval(JSFrameReg, JSStackFrame::offsetOfReturnValue());
masm.loadPayload(rval, JSReturnReg_Data); masm.loadPayload(rval, JSReturnReg_Data);
masm.loadTypeTag(rval, JSReturnReg_Type); masm.loadTypeTag(rval, JSReturnReg_Type);
masm.restoreReturnAddress(); masm.restoreReturnAddress();
masm.move(Registers::ReturnReg, JSFrameReg); masm.move(Registers::ReturnReg, JSFrameReg);
#ifdef DEBUG #ifdef DEBUG
masm.storePtr(ImmPtr(JSStackFrame::sInvalidPC), masm.storePtr(ImmPtr(JSStackFrame::sInvalidpc),
Address(JSFrameReg, offsetof(JSStackFrame, savedPC))); Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
#endif #endif
masm.ret(); masm.ret();
} }
@ -1925,11 +1908,6 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
* Save constant |this| to optimize thisv stores for common call cases * Save constant |this| to optimize thisv stores for common call cases
* like CALL[LOCAL, GLOBAL, ARG] which push NULL. * like CALL[LOCAL, GLOBAL, ARG] which push NULL.
*/ */
callIC.isConstantThis = false;
if (thisvFe->isConstant()) {
callIC.isConstantThis = true;
callIC.constantThis = thisvFe->getValue();
}
callIC.frameDepth = frame.frameDepth(); callIC.frameDepth = frame.frameDepth();
/* Grab type and data registers up-front. */ /* Grab type and data registers up-front. */
@ -3066,7 +3044,7 @@ mjit::Compiler::jsop_bindname(uint32 index)
pic.fastPathStart = masm.label(); pic.fastPathStart = masm.label();
Address parent(pic.objReg, offsetof(JSObject, parent)); Address parent(pic.objReg, offsetof(JSObject, parent));
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetScopeChain()), pic.objReg); masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
pic.shapeGuard = masm.label(); pic.shapeGuard = masm.label();
#if defined JS_NUNBOX32 #if defined JS_NUNBOX32
@ -3132,7 +3110,7 @@ void
mjit::Compiler::jsop_bindname(uint32 index) mjit::Compiler::jsop_bindname(uint32 index)
{ {
RegisterID reg = frame.allocReg(); RegisterID reg = frame.allocReg();
Address scopeChain(JSFrameReg, JSStackFrame::offsetScopeChain()); Address scopeChain(JSFrameReg, JSStackFrame::offsetOfScopeChain());
masm.loadPtr(scopeChain, reg); masm.loadPtr(scopeChain, reg);
Address address(reg, offsetof(JSObject, parent)); Address address(reg, offsetof(JSObject, parent));
@ -3152,16 +3130,13 @@ mjit::Compiler::jsop_bindname(uint32 index)
void void
mjit::Compiler::jsop_getarg(uint32 index) mjit::Compiler::jsop_getarg(uint32 index)
{ {
RegisterID reg = frame.allocReg(); frame.push(Address(JSFrameReg, JSStackFrame::offsetOfFormalArg(fun, index)));
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, argv)), reg);
frame.freeReg(reg);
frame.push(Address(reg, index * sizeof(Value)));
} }
void void
mjit::Compiler::jsop_this() mjit::Compiler::jsop_this()
{ {
Address thisvAddr(JSFrameReg, JSStackFrame::offsetThisValue()); Address thisvAddr(JSFrameReg, JSStackFrame::offsetOfThis(fun));
if (0 && !script->strictModeCode) { if (0 && !script->strictModeCode) {
Jump null = masm.testNull(Assembler::Equal, thisvAddr); Jump null = masm.testNull(Assembler::Equal, thisvAddr);
stubcc.linkExit(null, Uses(1)); stubcc.linkExit(null, Uses(1));

Просмотреть файл

@ -107,7 +107,7 @@ class Compiler
public: public:
struct CallGenInfo { struct CallGenInfo {
CallGenInfo(uint32 argc) CallGenInfo(uint32 argc)
: argc(argc), constantThis(UndefinedValue()) : argc(argc)
{ } { }
/* /*
@ -127,8 +127,6 @@ class Compiler
RegisterID funObjReg; RegisterID funObjReg;
RegisterID funPtrReg; RegisterID funPtrReg;
uint32 frameDepth; uint32 frameDepth;
bool isConstantThis;
Value constantThis;
}; };
private: private:

Просмотреть файл

@ -1132,21 +1132,16 @@ mjit::Compiler::jsop_arginc(JSOp op, uint32 slot, bool popped)
ovf = masm.branchSub32(Assembler::Overflow, Imm32(1), reg); ovf = masm.branchSub32(Assembler::Overflow, Imm32(1), reg);
stubcc.linkExit(ovf, Uses(0)); stubcc.linkExit(ovf, Uses(0));
Address argv(JSFrameReg, offsetof(JSStackFrame, argv));
stubcc.leave(); stubcc.leave();
stubcc.masm.loadPtr(argv, Registers::ArgReg1); stubcc.masm.addPtr(Imm32(JSStackFrame::offsetOfFormalArg(fun, slot)),
stubcc.masm.addPtr(Imm32(sizeof(Value) * slot), Registers::ArgReg1, Registers::ArgReg1); JSFrameReg, Registers::ArgReg1);
stubcc.vpInc(op, depth); stubcc.vpInc(op, depth);
frame.pushTypedPayload(JSVAL_TYPE_INT32, reg); frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
fe = frame.peek(-1); fe = frame.peek(-1);
reg = frame.allocReg(); Address address = Address(JSFrameReg, JSStackFrame::offsetOfFormalArg(fun, slot));
masm.loadPtr(argv, reg);
Address address = Address(reg, slot * sizeof(Value));
frame.storeTo(fe, address, popped); frame.storeTo(fe, address, popped);
frame.freeReg(reg);
if (post || popped) if (post || popped)
frame.pop(); frame.pop();

Просмотреть файл

@ -61,16 +61,8 @@ struct AdjustedFrame {
}; };
/* /*
* This is used for emitting code to inline callee-side frame creation. * This is used for emitting code to inline callee-side frame creation and
* Specifically, it initializes the following members: * should jit code equivalent to JSStackFrame::initCallFrameCallerHalf.
*
* savedPC
* argc
* flags
* scopeChain
* argv
* thisv
* down
* *
* Once finished, JSFrameReg is advanced to be the new fp. * Once finished, JSFrameReg is advanced to be the new fp.
*/ */
@ -81,8 +73,6 @@ class InlineFrameAssembler {
typedef JSC::MacroAssembler::ImmPtr ImmPtr; typedef JSC::MacroAssembler::ImmPtr ImmPtr;
Assembler &masm; Assembler &masm;
bool isConstantThis; // Is |thisv| constant?
Value constantThis; // If so, this is the value.
uint32 frameDepth; // script->nfixed + stack depth at caller call site uint32 frameDepth; // script->nfixed + stack depth at caller call site
uint32 argc; // number of args being passed to the function uint32 argc; // number of args being passed to the function
RegisterID funObjReg; // register containing the function object (callee) RegisterID funObjReg; // register containing the function object (callee)
@ -99,8 +89,6 @@ class InlineFrameAssembler {
InlineFrameAssembler(Assembler &masm, JSContext *cx, ic::CallICInfo &ic, uint32 flags) InlineFrameAssembler(Assembler &masm, JSContext *cx, ic::CallICInfo &ic, uint32 flags)
: masm(masm), flags(flags) : masm(masm), flags(flags)
{ {
isConstantThis = ic.isConstantThis;
constantThis = ic.constantThis;
frameDepth = ic.frameDepth; frameDepth = ic.frameDepth;
argc = ic.argc; argc = ic.argc;
funObjReg = ic.funObjReg; funObjReg = ic.funObjReg;
@ -112,8 +100,6 @@ class InlineFrameAssembler {
InlineFrameAssembler(Assembler &masm, Compiler::CallGenInfo &gen, jsbytecode *pc, uint32 flags) InlineFrameAssembler(Assembler &masm, Compiler::CallGenInfo &gen, jsbytecode *pc, uint32 flags)
: masm(masm), pc(pc), flags(flags) : masm(masm), pc(pc), flags(flags)
{ {
isConstantThis = gen.isConstantThis;
constantThis = gen.constantThis;
frameDepth = gen.frameDepth; frameDepth = gen.frameDepth;
argc = gen.argc; argc = gen.argc;
funObjReg = gen.funObjReg; funObjReg = gen.funObjReg;
@ -122,38 +108,17 @@ class InlineFrameAssembler {
inline void assemble() inline void assemble()
{ {
JS_ASSERT((flags & ~JSFRAME_CONSTRUCTING) == 0);
RegisterID t0 = tempRegs.takeAnyReg(); RegisterID t0 = tempRegs.takeAnyReg();
/* Note: savedPC goes into the down frame. */ masm.storePtr(ImmPtr(pc), Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
masm.storePtr(ImmPtr(pc), Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
AdjustedFrame adj(sizeof(JSStackFrame) + frameDepth * sizeof(Value)); AdjustedFrame adj(sizeof(JSStackFrame) + frameDepth * sizeof(Value));
masm.store32(Imm32(argc), adj.addrOf(offsetof(JSStackFrame, argc))); masm.store32(Imm32(JSFRAME_FUNCTION | flags), adj.addrOf(JSStackFrame::offsetOfFlags()));
masm.store32(Imm32(flags), adj.addrOf(offsetof(JSStackFrame, flags)));
masm.loadPtr(Address(funObjReg, offsetof(JSObject, parent)), t0); masm.loadPtr(Address(funObjReg, offsetof(JSObject, parent)), t0);
masm.storePtr(t0, adj.addrOf(JSStackFrame::offsetScopeChain())); masm.storePtr(t0, adj.addrOf(JSStackFrame::offsetOfScopeChain()));
masm.addPtr(Imm32(adj.baseOffset - (argc * sizeof(Value))), JSFrameReg, t0); masm.storePtr(JSFrameReg, adj.addrOf(JSStackFrame::offsetOfPrev()));
masm.storePtr(t0, adj.addrOf(offsetof(JSStackFrame, argv)));
Address targetThis = adj.addrOf(JSStackFrame::offsetThisValue());
if (isConstantThis) {
masm.storeValue(constantThis, targetThis);
} else {
Address thisvAddr = Address(t0, -int32(sizeof(Value) * 1));
#ifdef JS_NUNBOX32
RegisterID t1 = tempRegs.takeAnyReg();
masm.loadPayload(thisvAddr, t1);
masm.storePayload(t1, targetThis);
masm.loadTypeTag(thisvAddr, t1);
masm.storeTypeTag(t1, targetThis);
tempRegs.putReg(t1);
#elif JS_PUNBOX64
masm.loadPtr(thisvAddr, t0);
masm.storePtr(t0, targetThis);
#endif
}
masm.storePtr(JSFrameReg, adj.addrOf(offsetof(JSStackFrame, down)));
/* Adjust JSFrameReg. Callee fills in the rest. */ /* Adjust JSFrameReg. Callee fills in the rest. */
masm.addPtr(Imm32(sizeof(JSStackFrame) + sizeof(Value) * frameDepth), JSFrameReg); masm.addPtr(Imm32(sizeof(JSStackFrame) + sizeof(Value) * frameDepth), JSFrameReg);

Просмотреть файл

@ -57,6 +57,7 @@
#include "jspropertycache.h" #include "jspropertycache.h"
#include "methodjit/MonoIC.h" #include "methodjit/MonoIC.h"
#include "jsinterpinlines.h"
#include "jspropertycacheinlines.h" #include "jspropertycacheinlines.h"
#include "jsscopeinlines.h" #include "jsscopeinlines.h"
#include "jsscriptinlines.h" #include "jsscriptinlines.h"
@ -92,7 +93,7 @@ static jsbytecode *
FindExceptionHandler(JSContext *cx) FindExceptionHandler(JSContext *cx)
{ {
JSStackFrame *fp = cx->fp(); JSStackFrame *fp = cx->fp();
JSScript *script = fp->getScript(); JSScript *script = fp->script();
top: top:
if (cx->throwing && script->trynotesOffset) { if (cx->throwing && script->trynotesOffset) {
@ -129,7 +130,7 @@ top:
switch (tn->kind) { switch (tn->kind) {
case JSTRY_CATCH: case JSTRY_CATCH:
JS_ASSERT(js_GetOpcode(cx, fp->getScript(), pc) == JSOP_ENTERBLOCK); JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENTERBLOCK);
#if JS_HAS_GENERATORS #if JS_HAS_GENERATORS
/* Catch cannot intercept the closing of a generator. */ /* Catch cannot intercept the closing of a generator. */
@ -165,7 +166,7 @@ top:
* pending exception. * pending exception.
*/ */
AutoValueRooter tvr(cx, cx->exception); AutoValueRooter tvr(cx, cx->exception);
JS_ASSERT(js_GetOpcode(cx, fp->getScript(), pc) == JSOP_ENDITER); JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENDITER);
cx->throwing = JS_FALSE; cx->throwing = JS_FALSE;
ok = !!js_CloseIterator(cx, &cx->regs->sp[-1].toObject()); ok = !!js_CloseIterator(cx, &cx->regs->sp[-1].toObject());
cx->regs->sp -= 1; cx->regs->sp -= 1;
@ -190,7 +191,7 @@ InlineReturn(VMFrame &f, JSBool ok)
JS_ASSERT(f.fp() != f.entryFp); JS_ASSERT(f.fp() != f.entryFp);
JS_ASSERT(!fp->hasBlockChain()); JS_ASSERT(!fp->hasBlockChain());
JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->getScopeChain(), 0)); JS_ASSERT(!js_IsActiveWithOrBlock(cx, &fp->scopeChain(), 0));
// Marker for debug support. // Marker for debug support.
if (JS_UNLIKELY(fp->hasHookData())) { if (JS_UNLIKELY(fp->hasHookData())) {
@ -204,27 +205,22 @@ InlineReturn(VMFrame &f, JSBool ok)
* optimizations and uninitialised warnings. * optimizations and uninitialised warnings.
*/ */
status = ok; status = ok;
hook(cx, fp, JS_FALSE, &status, fp->getHookData()); hook(cx, fp, JS_FALSE, &status, fp->hookData());
ok = (status == JS_TRUE); ok = (status == JS_TRUE);
// CHECK_INTERRUPT_HANDLER(); // CHECK_INTERRUPT_HANDLER();
} }
} }
fp->putActivationObjects(cx); PutActivationObjects(cx, fp);
/* :TODO: version stuff */ /* :TODO: version stuff */
if (fp->flags & JSFRAME_CONSTRUCTING && fp->getReturnValue().isPrimitive()) if (fp->isConstructing() && fp->returnValue().isPrimitive())
fp->setReturnValue(fp->getThisValue()); fp->setReturnValue(fp->thisValue());
Value *newsp = fp->argv - 1; Value *newsp = fp->actualArgs() - 1;
newsp[-1] = fp->returnValue();
cx->stack().popInlineFrame(cx, fp, fp->down); cx->stack().popInlineFrame(cx, fp->prev(), newsp);
cx->regs->sp = newsp;
cx->regs->sp[-1] = fp->getReturnValue();
JS_ASSERT(cx->regs->pc != JSStackFrame::sInvalidPC);
return ok; return ok;
} }
@ -271,84 +267,82 @@ stubs::SlowNew(VMFrame &f, uint32 argc)
THROW(); THROW();
} }
/*
* This function must only be called after the early prologue, since it depends
* on fp->exec.fun.
*/
static inline void static inline void
RemovePartialFrame(VMFrame &f) RemovePartialFrame(JSContext *cx, JSStackFrame *fp)
{ {
/* Unwind the half-pushed frame. */ JSStackFrame *prev = fp->prev();
f.regs.pc = f.fp()->down->savedPC; Value *newsp = (Value *)fp;
f.regs.sp = f.fp()->argv + f.fp()->argc; cx->stack().popInlineFrame(cx, prev, newsp);
#ifdef DEBUG
f.fp()->down->savedPC = JSStackFrame::sInvalidPC;
#endif
f.regs.fp = f.fp()->down;
} }
/*
* HitStackQuota is called after the early prologue pushing the new frame would
* overflow f.stackLimit.
*/
void JS_FASTCALL void JS_FASTCALL
stubs::CheckStackQuota(VMFrame &f) stubs::HitStackQuota(VMFrame &f)
{ {
if (JS_LIKELY(f.ensureSpace(0, f.fp()->getScript()->nslots))) /* Include space to push another frame. */
uintN nvals = f.fp()->script()->nslots + VALUES_PER_STACK_FRAME;
JS_ASSERT(f.regs.sp == f.fp()->base());
if (f.cx->stack().bumpCommitAndLimit(f.entryFp, f.regs.sp, nvals, &f.stackLimit))
return; return;
RemovePartialFrame(f); /* Remove the current partially-constructed frame before throwing. */
RemovePartialFrame(f.cx, f.fp());
js_ReportOverRecursed(f.cx); js_ReportOverRecursed(f.cx);
THROW(); THROW();
} }
/*
* This function must only be called after the early prologue, since it depends
* on fp->exec.fun.
*/
void * JS_FASTCALL void * JS_FASTCALL
stubs::CheckArity(VMFrame &f) stubs::FixupArity(VMFrame &f, uint32 nactual)
{ {
JSContext *cx = f.cx; JSContext *cx = f.cx;
JSStackFrame *fp = f.fp(); JSStackFrame *oldfp = f.fp();
uint32 argc = fp->argc;
JSFunction *fun = fp->getFunction();
JS_ASSERT(argc < fun->nargs); JS_ASSERT(nactual != oldfp->numFormalArgs());
/* /*
* Grossssss! *move* the stack frame. If this ends up being perf-critical, * Grossssss! *move* the stack frame. If this ends up being perf-critical,
* we can figure out how to spot-optimize it. As the frame shrinks it will * we can figure out how to spot-optimize it. Be careful to touch only the
* matter less. * members that have been initialized by initCallFrameCallerHalf and the
* early prologue.
*/ */
uint32 flags = fp->flags; uint32 flags = oldfp->isConstructingFlag();
JSObject *scopeChain = fp->getScopeChain(); JSObject &scopeChain = oldfp->scopeChain();
Value *argv = fp->argv; JSFunction *fun = oldfp->fun();
JSStackFrame *down = fp->down; void *ncode = oldfp->nativeReturnAddress();
void *ncode = fp->ncode;
/* Pop the inline frame. */ /* Pop the inline frame. */
RemovePartialFrame(f); RemovePartialFrame(cx, oldfp);
uint32 missing = fun->nargs - argc; /* Reserve enough space for a callee frame. */
JSStackFrame *newfp = cx->stack().getInlineFrameWithinLimit(cx, cx->regs->sp, nactual,
/* Include an extra stack frame for callees. */ fun, fun->script(), &flags,
if (!f.ensureSpace(missing, fun->u.i.script->nslots + VALUES_PER_STACK_FRAME)) { f.entryFp, &f.stackLimit);
js_ReportOverRecursed(cx); if (!newfp)
THROWV(NULL); THROWV(NULL);
}
#ifdef DEBUG /* Reset the part of the stack frame set by the caller. */
down->savedPC = f.regs.pc; newfp->initCallFrameCallerHalf(cx, scopeChain, nactual, flags);
#endif
SetValueRangeToUndefined(f.regs.sp, missing); /* Reset the part of the stack frame set by the prologue up to now. */
f.regs.sp += missing; newfp->initCallFrameEarlyPrologue(fun, ncode);
JSStackFrame *newfp = (JSStackFrame *)f.regs.sp;
newfp->argc = argc;
newfp->setFunction(fun);
newfp->flags = flags;
newfp->argv = argv;
newfp->setScopeChain(scopeChain);
newfp->down = down;
newfp->ncode = ncode;
newfp->setThisValue(argv[-1]);
/* The caller takes care of assigning fp to regs. */
return newfp; return newfp;
} }
void * JS_FASTCALL void * JS_FASTCALL
stubs::CompileFunction(VMFrame &f) stubs::CompileFunction(VMFrame &f, uint32 nactual)
{ {
/* /*
* We have a partially constructed frame. That's not really good enough to * We have a partially constructed frame. That's not really good enough to
@ -356,56 +350,53 @@ stubs::CompileFunction(VMFrame &f)
*/ */
JSContext *cx = f.cx; JSContext *cx = f.cx;
JSStackFrame *fp = f.fp(); JSStackFrame *fp = f.fp();
uint32 argc = fp->argc;
JSObject *obj = &fp->argv[-2].toObject(); /*
JSFunction *fun = obj->getFunctionPrivate(); * Since we can only use members set by initCallFrameCallerHalf,
JSScript *script = fun->u.i.script; * we must carefully extract the callee from the nactual.
*/
JSObject &callee = fp->formalArgsEnd()[-(int(nactual) + 2)].toObject();
JSFunction *fun = callee.getFunctionPrivate();
JSScript *script = fun->script();
bool callingNew = !!(fp->flags & JSFRAME_CONSTRUCTING); /*
* FixupArity/RemovePartialFrame expect to be called after the early
* prologue. Pass null for ncode: either we will jump into jit code, which
* will set ncode, or we will jump into js::Interpret, which does not care
* about ncode.
*/
fp->initCallFrameEarlyPrologue(fun, NULL);
/* Empty script does nothing. */ /* Empty script does nothing. */
if (script->isEmpty()) { if (script->isEmpty()) {
RemovePartialFrame(f); bool callingNew = fp->isConstructing();
Value *vp = f.regs.sp - argc; RemovePartialFrame(cx, fp);
Value *vp = f.regs.sp - (nactual + 2);
if (callingNew) if (callingNew)
vp[-2] = vp[-1]; vp[0] = vp[1];
else else
vp[-2].setUndefined(); vp[0].setUndefined();
return NULL; return NULL;
} }
/* CheckArity expects fun to be set. */ if (nactual != fp->numFormalArgs()) {
fp->setFunction(fun); fp = (JSStackFrame *)FixupArity(f, nactual);
if (argc < fun->nargs) {
fp = (JSStackFrame *)CheckArity(f);
if (!fp) if (!fp)
return NULL; return NULL;
} }
fp->setCallObj(NULL); /* Finish frame initialization. */
fp->setArgsObj(NULL); fp->initCallFrameLatePrologue();
fp->setBlockChain(NULL);
fp->setHookData(NULL);
fp->setAnnotation(NULL);
fp->setCallerVersion(fp->down->getCallerVersion());
fp->setScript(script);
fp->clearReturnValue();
#ifdef DEBUG
fp->savedPC = JSStackFrame::sInvalidPC;
#endif
/* These would have been initialized by the prologue. */
f.regs.fp = fp; f.regs.fp = fp;
f.regs.sp = fp->base(); f.regs.sp = fp->base();
f.regs.pc = script->code; f.regs.pc = script->code;
SetValueRangeToUndefined(fp->slots(), script->nfixed);
if (fun->isHeavyweight() && !js_GetCallObject(cx, fp)) if (fun->isHeavyweight() && !js_GetCallObject(cx, fp))
THROWV(NULL); THROWV(NULL);
CompileStatus status = CanMethodJIT(cx, script, fun, fp->getScopeChain()); CompileStatus status = CanMethodJIT(cx, script, fun, &fp->scopeChain());
if (status == Compile_Okay) if (status == Compile_Okay)
return script->jit->invoke; return script->jit->invoke;
@ -419,112 +410,63 @@ stubs::CompileFunction(VMFrame &f)
return NULL; return NULL;
} }
/* Preserved for when calls need to be slow (debug mode, no ICs) */ static inline bool
static bool UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
CreateFrame(VMFrame &f, uint32 flags, uint32 argc)
{ {
JSContext *cx = f.cx; JSContext *cx = f.cx;
JSStackFrame *fp = f.fp(); JSStackFrame *fp = f.fp();
Value *vp = f.regs.sp - (argc + 2); Value *vp = f.regs.sp - (argc + 2);
JSObject *funobj = &vp->toObject(); JSObject &callee = vp->toObject();
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); JSFunction *newfun = callee.getFunctionPrivate();
JSScript *newscript = newfun->script();
JS_ASSERT(FUN_INTERPRETED(fun)); /* Get pointer to new frame/slots, prepare arguments. */
JSScript *newscript = fun->u.i.script;
/* Allocate the frame. */
StackSpace &stack = cx->stack(); StackSpace &stack = cx->stack();
uintN nslots = newscript->nslots; JSStackFrame *newfp = stack.getInlineFrameWithinLimit(cx, f.regs.sp, argc,
uintN funargs = fun->nargs; newfun, newscript, &flags,
Value *argv = vp + 2; f.entryFp, &f.stackLimit);
JSStackFrame *newfp; if (JS_UNLIKELY(!newfp))
if (argc < funargs) {
uintN missing = funargs - argc;
if (!f.ensureSpace(missing, nslots))
return false;
newfp = stack.getInlineFrameUnchecked(cx, f.regs.sp, missing);
if (!newfp)
return false;
for (Value *v = argv + argc, *end = v + missing; v != end; ++v)
v->setUndefined();
} else {
if (!f.ensureSpace(0, nslots))
return false;
newfp = stack.getInlineFrameUnchecked(cx, f.regs.sp, 0);
if (!newfp)
return false;
}
/* Initialize the frame. */
newfp->ncode = NULL;
newfp->setCallObj(NULL);
newfp->setArgsObj(NULL);
newfp->setScript(newscript);
newfp->setFunction(fun);
newfp->argc = argc;
newfp->argv = vp + 2;
newfp->clearReturnValue();
newfp->setAnnotation(NULL);
newfp->setScopeChain(funobj->getParent());
newfp->flags = flags;
newfp->setBlockChain(NULL);
newfp->setThisValue(vp[1]);
JS_ASSERT(!fp->hasIMacroPC());
/* Push void to initialize local variables. */
Value *newslots = newfp->slots();
Value *newsp = newslots + fun->u.i.nvars;
for (Value *v = newslots; v != newsp; ++v)
v->setUndefined();
/* Scope with a call object parented by callee's parent. */
if (fun->isHeavyweight() && !js_GetCallObject(cx, newfp))
return false; return false;
JS_ASSERT_IF(!vp[1].isPrimitive(), IsSaneThisObject(vp[1].toObject()));
/* Initialize frame, locals. */
newfp->initCallFrame(cx, callee, newfun, argc, flags);
SetValueRangeToUndefined(newfp->slots(), newscript->nfixed);
/* :TODO: Switch version if currentVersion wasn't overridden. */ /* :TODO: Switch version if currentVersion wasn't overridden. */
newfp->setCallerVersion((JSVersion)cx->version); newfp->setCallerVersion((JSVersion)cx->version);
// Marker for debug support. /* Officially push the frame. */
stack.pushInlineFrame(cx, newscript, newfp, &f.regs);
JS_ASSERT(newfp == f.regs.fp);
/* Scope with a call object parented by callee's parent. */
if (newfun->isHeavyweight() && !js_GetCallObject(cx, newfp))
return false;
/* Marker for debug support. */
if (JSInterpreterHook hook = cx->debugHooks->callHook) { if (JSInterpreterHook hook = cx->debugHooks->callHook) {
newfp->setHookData(hook(cx, fp, JS_TRUE, 0, newfp->setHookData(hook(cx, fp, JS_TRUE, 0,
cx->debugHooks->callHookData)); cx->debugHooks->callHookData));
} else {
newfp->setHookData(NULL);
} }
stack.pushInlineFrame(cx, fp, cx->regs->pc, newfp); /* Try to compile if not already compiled. */
f.regs.fp = newfp; if (!newscript->ncode) {
if (mjit::TryCompile(cx, newscript, newfp->fun(), &newfp->scopeChain()) == Compile_Error) {
return true; /* A runtime exception was thrown, get out. */
} InlineReturn(f, JS_FALSE);
return false;
static inline bool
UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
{
if (!CreateFrame(f, flags, argc))
return false;
JSContext *cx = f.cx;
JSStackFrame *fp = cx->fp();
JSScript *script = fp->getScript();
f.regs.pc = script->code;
f.regs.sp = fp->base();
if (cx->options & JSOPTION_METHODJIT) {
if (!script->ncode) {
if (mjit::TryCompile(cx, script, fp->getFunction(), fp->getScopeChain()) == Compile_Error) {
InlineReturn(f, JS_FALSE);
return false;
}
}
JS_ASSERT(script->ncode);
if (script->ncode != JS_UNJITTABLE_METHOD) {
*pret = script->jit->invoke;
return true;
} }
} }
/* If newscript was successfully compiled, run it. */
JS_ASSERT(newscript->ncode);
if (newscript->ncode != JS_UNJITTABLE_METHOD) {
*pret = newscript->jit->invoke;
return true;
}
/* Otherwise, run newscript in the interpreter. */
bool ok = !!Interpret(cx, cx->fp()); bool ok = !!Interpret(cx, cx->fp());
InlineReturn(f, JS_TRUE); InlineReturn(f, JS_TRUE);
@ -536,43 +478,19 @@ void * JS_FASTCALL
stubs::UncachedNew(VMFrame &f, uint32 argc) stubs::UncachedNew(VMFrame &f, uint32 argc)
{ {
JSContext *cx = f.cx; JSContext *cx = f.cx;
Value *vp = f.regs.sp - (argc + 2); Value *vp = f.regs.sp - (argc + 2);
JSObject *obj; /* Try to do a fast inline call before the general Invoke path. */
if (IsFunctionObject(*vp, &obj)) { JSFunction *fun;
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj); if (IsFunctionObject(*vp, &fun) && fun->isInterpreted() && !fun->script()->isEmpty()) {
void *ret;
if (fun->isInterpreted()) { if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ret, argc))
JSScript *script = fun->u.i.script; THROWV(NULL);
if (!stubs::NewObject(f, argc)) return ret;
THROWV(NULL);
if (script->isEmpty()) {
vp[0] = vp[1];
return NULL;
}
void *ret;
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ret, argc))
THROWV(NULL);
return ret;
}
if (fun->isConstructor()) {
vp[1].setMagicWithObjectOrNullPayload(NULL);
Native fn = fun->u.n.native;
if (!fn(cx, argc, vp))
THROWV(NULL);
JS_ASSERT(!vp->isPrimitive());
return NULL;
}
} }
if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc))) if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
THROWV(NULL); THROWV(NULL);
return NULL; return NULL;
} }
@ -620,13 +538,13 @@ stubs::PutCallObject(VMFrame &f)
{ {
JS_ASSERT(f.fp()->hasCallObj()); JS_ASSERT(f.fp()->hasCallObj());
js_PutCallObject(f.cx, f.fp()); js_PutCallObject(f.cx, f.fp());
JS_ASSERT(!f.fp()->hasArgsObj());
} }
void JS_FASTCALL void JS_FASTCALL
stubs::PutArgsObject(VMFrame &f) stubs::PutActivationObjects(VMFrame &f)
{ {
js_PutArgsObject(f.cx, f.fp()); JS_ASSERT(f.fp()->hasCallObj() || f.fp()->hasArgsObj());
js::PutActivationObjects(f.cx, f.fp());
} }
extern "C" void * extern "C" void *
@ -641,7 +559,7 @@ js_InternalThrow(VMFrame &f)
JSThrowHook handler = f.cx->debugHooks->throwHook; JSThrowHook handler = f.cx->debugHooks->throwHook;
if (handler) { if (handler) {
Value rval; Value rval;
switch (handler(cx, cx->fp()->getScript(), cx->regs->pc, Jsvalify(&rval), switch (handler(cx, cx->fp()->script(), cx->regs->pc, Jsvalify(&rval),
cx->debugHooks->throwHookData)) { cx->debugHooks->throwHookData)) {
case JSTRAP_ERROR: case JSTRAP_ERROR:
cx->throwing = JS_FALSE; cx->throwing = JS_FALSE;
@ -686,13 +604,13 @@ js_InternalThrow(VMFrame &f)
if (!pc) if (!pc)
return NULL; return NULL;
return cx->fp()->getScript()->pcToNative(pc); return cx->fp()->script()->pcToNative(pc);
} }
void JS_FASTCALL void JS_FASTCALL
stubs::GetCallObject(VMFrame &f) stubs::GetCallObject(VMFrame &f)
{ {
JS_ASSERT(f.fp()->getFunction()->isHeavyweight()); JS_ASSERT(f.fp()->fun()->isHeavyweight());
if (!js_GetCallObject(f.cx, f.fp())) if (!js_GetCallObject(f.cx, f.fp()))
THROW(); THROW();
} }
@ -721,13 +639,13 @@ SwallowErrors(VMFrame &f, JSStackFrame *stopFp)
JSStackFrame *fp = cx->fp(); JSStackFrame *fp = cx->fp();
/* Look for an imacro with hard-coded exception handlers. */ /* Look for an imacro with hard-coded exception handlers. */
if (fp->hasIMacroPC() && cx->throwing) { if (fp->hasImacropc() && cx->throwing) {
cx->regs->pc = fp->getIMacroPC(); cx->regs->pc = fp->imacropc();
fp->clearIMacroPC(); fp->clearImacropc();
if (ok) if (ok)
break; break;
} }
JS_ASSERT(!fp->hasIMacroPC()); JS_ASSERT(!fp->hasImacropc());
/* If there's an exception and a handler, set the pc and leave. */ /* If there's an exception and a handler, set the pc and leave. */
jsbytecode *pc = FindExceptionHandler(cx); jsbytecode *pc = FindExceptionHandler(cx);
@ -757,10 +675,10 @@ static inline bool
AtSafePoint(JSContext *cx) AtSafePoint(JSContext *cx)
{ {
JSStackFrame *fp = cx->fp(); JSStackFrame *fp = cx->fp();
if (fp->hasIMacroPC()) if (fp->hasImacropc())
return false; return false;
JSScript *script = fp->getScript(); JSScript *script = fp->script();
if (!script->nmap) if (!script->nmap)
return false; return false;
@ -774,14 +692,12 @@ PartialInterpret(VMFrame &f)
JSContext *cx = f.cx; JSContext *cx = f.cx;
JSStackFrame *fp = cx->fp(); JSStackFrame *fp = cx->fp();
JS_ASSERT(fp->hasIMacroPC() || !fp->getScript()->nmap || JS_ASSERT(fp->hasImacropc() || !fp->script()->nmap ||
!fp->getScript()->nmap[cx->regs->pc - fp->getScript()->code]); !fp->script()->nmap[cx->regs->pc - fp->script()->code]);
JSBool ok = JS_TRUE; JSBool ok = JS_TRUE;
ok = Interpret(cx, fp, 0, JSINTERP_SAFEPOINT); ok = Interpret(cx, fp, 0, JSINTERP_SAFEPOINT);
f.fp() = cx->fp();
return ok; return ok;
} }
@ -802,11 +718,11 @@ static bool
RemoveExcessFrames(VMFrame &f, JSStackFrame *entryFrame) RemoveExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
{ {
JSContext *cx = f.cx; JSContext *cx = f.cx;
while (cx->fp() != entryFrame || entryFrame->hasIMacroPC()) { while (cx->fp() != entryFrame || entryFrame->hasImacropc()) {
JSStackFrame *fp = cx->fp(); JSStackFrame *fp = cx->fp();
if (AtSafePoint(cx)) { if (AtSafePoint(cx)) {
JSScript *script = fp->getScript(); JSScript *script = fp->script();
if (!JaegerShotAtSafePoint(cx, script->nmap[cx->regs->pc - script->code])) { if (!JaegerShotAtSafePoint(cx, script->nmap[cx->regs->pc - script->code])) {
if (!SwallowErrors(f, entryFrame)) if (!SwallowErrors(f, entryFrame))
return false; return false;
@ -825,10 +741,10 @@ RemoveExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
* Partial interpret could have dropped us anywhere. Deduce the * Partial interpret could have dropped us anywhere. Deduce the
* edge case: at a RETURN, needing to pop a frame. * edge case: at a RETURN, needing to pop a frame.
*/ */
JS_ASSERT(!cx->fp()->hasIMacroPC()); JS_ASSERT(!cx->fp()->hasImacropc());
if (FrameIsFinished(cx)) { if (FrameIsFinished(cx)) {
JSOp op = JSOp(*cx->regs->pc); JSOp op = JSOp(*cx->regs->pc);
if (op == JSOP_RETURN && !(cx->fp()->flags & JSFRAME_BAILED_AT_RETURN)) if (op == JSOP_RETURN && !cx->fp()->isBailedAtReturn())
cx->fp()->setReturnValue(f.regs.sp[-1]); cx->fp()->setReturnValue(f.regs.sp[-1]);
InlineReturn(f, JS_TRUE); InlineReturn(f, JS_TRUE);
AdvanceReturnPC(cx); AdvanceReturnPC(cx);
@ -909,7 +825,7 @@ RunTracer(VMFrame &f)
case TPA_Error: case TPA_Error:
if (!SwallowErrors(f, entryFrame)) if (!SwallowErrors(f, entryFrame))
THROWV(NULL); THROWV(NULL);
JS_ASSERT(!cx->fp()->hasIMacroPC()); JS_ASSERT(!cx->fp()->hasImacropc());
break; break;
case TPA_RanStuff: case TPA_RanStuff:
@ -945,19 +861,19 @@ RunTracer(VMFrame &f)
THROWV(NULL); THROWV(NULL);
/* IMacros are guaranteed to have been removed by now. */ /* IMacros are guaranteed to have been removed by now. */
JS_ASSERT(!entryFrame->hasIMacroPC()); JS_ASSERT(!entryFrame->hasImacropc());
/* Step 2. If entryFrame is at a safe point, just leave. */ /* Step 2. If entryFrame is at a safe point, just leave. */
if (AtSafePoint(cx)) { if (AtSafePoint(cx)) {
uint32 offs = uint32(cx->regs->pc - entryFrame->getScript()->code); uint32 offs = uint32(cx->regs->pc - entryFrame->script()->code);
JS_ASSERT(entryFrame->getScript()->nmap[offs]); JS_ASSERT(entryFrame->script()->nmap[offs]);
return entryFrame->getScript()->nmap[offs]; return entryFrame->script()->nmap[offs];
} }
/* Step 3. If entryFrame is at a RETURN, then leave slightly differently. */ /* Step 3. If entryFrame is at a RETURN, then leave slightly differently. */
if (JSOp op = FrameIsFinished(cx)) { if (JSOp op = FrameIsFinished(cx)) {
/* We're not guaranteed that the RETURN was run. */ /* We're not guaranteed that the RETURN was run. */
if (op == JSOP_RETURN && !(entryFrame->flags & JSFRAME_BAILED_AT_RETURN)) if (op == JSOP_RETURN && !entryFrame->isBailedAtReturn())
entryFrame->setReturnValue(f.regs.sp[-1]); entryFrame->setReturnValue(f.regs.sp[-1]);
/* Don't pop the frame if it's maybe owned by an Invoke. */ /* Don't pop the frame if it's maybe owned by an Invoke. */
@ -986,7 +902,7 @@ RunTracer(VMFrame &f)
void *JS_FASTCALL void *JS_FASTCALL
stubs::InvokeTracer(VMFrame &f, uint32 index) stubs::InvokeTracer(VMFrame &f, uint32 index)
{ {
JSScript *script = f.fp()->getScript(); JSScript *script = f.fp()->script();
ic::MICInfo &mic = script->mics[index]; ic::MICInfo &mic = script->mics[index];
JS_ASSERT(mic.kind == ic::MICInfo::TRACER); JS_ASSERT(mic.kind == ic::MICInfo::TRACER);

Просмотреть файл

@ -49,6 +49,25 @@
using namespace js; using namespace js;
using namespace js::mjit; using namespace js::mjit;
void
JSStackFrame::methodjitStaticAsserts()
{
/* Static assert for x86 trampolines in MethodJIT.cpp. */
#if defined(JS_CPU_X86)
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 0x18);
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) + 4 == 0x1C);
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 0x2C);
/* ARM uses decimal literals. */
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 24);
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) + 4 == 28);
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 44);
#elif defined(JS_CPU_X64)
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 0x30);
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 0x50);
#endif
}
/* /*
* Explanation of VMFrame activation and various helper thunks below. * Explanation of VMFrame activation and various helper thunks below.
* *
@ -254,7 +273,6 @@ SYMBOL_STRING(JaegerThrowpoline) ":" "\n"
"ret" "\n" "ret" "\n"
); );
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode) == 0x60);
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38); JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38);
asm volatile ( asm volatile (
@ -262,7 +280,7 @@ asm volatile (
".globl " SYMBOL_STRING(SafePointTrampoline) "\n" ".globl " SYMBOL_STRING(SafePointTrampoline) "\n"
SYMBOL_STRING(SafePointTrampoline) ":" "\n" SYMBOL_STRING(SafePointTrampoline) ":" "\n"
"popq %rax" "\n" "popq %rax" "\n"
"movq %rax, 0x60(%rbx)" "\n" "movq %rax, 0x50(%rbx)" "\n"
"jmp *8(%rsp)" "\n" "jmp *8(%rsp)" "\n"
); );
@ -270,8 +288,8 @@ asm volatile (
".text\n" ".text\n"
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n" ".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
SYMBOL_STRING(InjectJaegerReturn) ":" "\n" SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
"movq 0x40(%rbx), %rcx" "\n" /* load Value into typeReg */ "movq 0x30(%rbx), %rcx" "\n" /* load fp->rval_ into typeReg */
"movq 0x60(%rbx), %rax" "\n" /* fp->ncode */ "movq 0x50(%rbx), %rax" "\n" /* fp->ncode_ */
/* Reimplementation of PunboxAssembler::loadValueAsComponents() */ /* Reimplementation of PunboxAssembler::loadValueAsComponents() */
"movq %r14, %rdx" "\n" /* payloadReg = payloadMaskReg */ "movq %r14, %rdx" "\n" /* payloadReg = payloadMaskReg */
@ -363,16 +381,15 @@ SYMBOL_STRING(JaegerThrowpoline) ":" "\n"
"ret" "\n" "ret" "\n"
); );
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode) == 0x3C);
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x1C); JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x1C);
asm volatile ( asm volatile (
".text\n" ".text\n"
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n" ".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
SYMBOL_STRING(InjectJaegerReturn) ":" "\n" SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
"movl 0x28(%ebx), %edx" "\n" /* fp->rval data */ "movl 0x18(%ebx), %edx" "\n" /* fp->rval_ data */
"movl 0x2C(%ebx), %ecx" "\n" /* fp->rval type */ "movl 0x1C(%ebx), %ecx" "\n" /* fp->rval_ type */
"movl 0x3C(%ebx), %eax" "\n" /* fp->ncode */ "movl 0x2C(%ebx), %eax" "\n" /* fp->ncode_ */
"movl 0x1C(%esp), %ebx" "\n" /* f.fp */ "movl 0x1C(%esp), %ebx" "\n" /* f.fp */
"pushl %eax" "\n" "pushl %eax" "\n"
"ret" "\n" "ret" "\n"
@ -387,7 +404,7 @@ asm volatile (
".globl " SYMBOL_STRING(SafePointTrampoline) "\n" ".globl " SYMBOL_STRING(SafePointTrampoline) "\n"
SYMBOL_STRING(SafePointTrampoline) ":" "\n" SYMBOL_STRING(SafePointTrampoline) ":" "\n"
"popl %eax" "\n" "popl %eax" "\n"
"movl %eax, 0x3C(%ebx)" "\n" "movl %eax, 0x2C(%ebx)" "\n"
"jmp *24(%ebp)" "\n" "jmp *24(%ebp)" "\n"
); );
@ -401,7 +418,6 @@ JS_STATIC_ASSERT(offsetof(VMFrame, cx) == (4*8));
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == (4*7)); JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == (4*7));
JS_STATIC_ASSERT(offsetof(VMFrame, unused) == (4*4)); JS_STATIC_ASSERT(offsetof(VMFrame, unused) == (4*4));
JS_STATIC_ASSERT(offsetof(VMFrame, previous) == (4*3)); JS_STATIC_ASSERT(offsetof(VMFrame, previous) == (4*3));
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode) == 60);
JS_STATIC_ASSERT(JSFrameReg == JSC::ARMRegisters::r11); JS_STATIC_ASSERT(JSFrameReg == JSC::ARMRegisters::r11);
JS_STATIC_ASSERT(JSReturnReg_Data == JSC::ARMRegisters::r1); JS_STATIC_ASSERT(JSReturnReg_Data == JSC::ARMRegisters::r1);
@ -412,9 +428,9 @@ asm volatile (
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n" ".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
SYMBOL_STRING(InjectJaegerReturn) ":" "\n" SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
/* Restore frame regs. */ /* Restore frame regs. */
"ldr lr, [r11, #60]" "\n" /* fp->ncode */ "ldr lr, [r11, #44]" "\n" /* fp->ncode */
"ldr r1, [r11, #40]" "\n" /* fp->rval data */ "ldr r1, [r11, #24]" "\n" /* fp->rval data */
"ldr r2, [r11, #44]" "\n" /* fp->rval type */ "ldr r2, [r11, #28]" "\n" /* fp->rval type */
"ldr r11, [sp, #28]" "\n" /* load f.fp */ "ldr r11, [sp, #28]" "\n" /* load f.fp */
"bx lr" "\n" "bx lr" "\n"
); );
@ -430,7 +446,7 @@ SYMBOL_STRING(SafePointTrampoline) ":"
*/ */
"ldr ip, [sp, #80]" "\n" "ldr ip, [sp, #80]" "\n"
/* Save the return address (in JaegerTrampoline) to fp->ncode. */ /* Save the return address (in JaegerTrampoline) to fp->ncode. */
"str lr, [r11, #60]" "\n" "str lr, [r11, #44]" "\n"
/* Jump to 'safePoint' via 'ip' because a load into the PC from an address on /* Jump to 'safePoint' via 'ip' because a load into the PC from an address on
* the stack looks like a return, and may upset return stack prediction. */ * the stack looks like a return, and may upset return stack prediction. */
"bx ip" "\n" "bx ip" "\n"
@ -566,9 +582,9 @@ extern "C" {
__declspec(naked) void InjectJaegerReturn() __declspec(naked) void InjectJaegerReturn()
{ {
__asm { __asm {
mov edx, [ebx + 0x28]; mov edx, [ebx + 0x18];
mov ecx, [ebx + 0x2C]; mov ecx, [ebx + 0x1C];
mov eax, [ebx + 0x3C]; mov eax, [ebx + 0x2C];
mov ebx, [esp + 0x1C]; mov ebx, [esp + 0x1C];
push eax; push eax;
ret; ret;
@ -579,7 +595,7 @@ extern "C" {
{ {
__asm { __asm {
pop eax; pop eax;
mov [ebx + 0x3C], eax; mov [ebx + 0x2C], eax;
jmp [ebp + 24]; jmp [ebp + 24];
} }
} }
@ -666,7 +682,6 @@ extern "C" {
*/ */
JS_STATIC_ASSERT(offsetof(VMFrame, savedRBX) == 0x58); JS_STATIC_ASSERT(offsetof(VMFrame, savedRBX) == 0x58);
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38); JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38);
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode) == 0x60);
JS_STATIC_ASSERT(JSVAL_TAG_MASK == 0xFFFF800000000000LL); JS_STATIC_ASSERT(JSVAL_TAG_MASK == 0xFFFF800000000000LL);
JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL); JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL);
@ -728,7 +743,7 @@ EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, void *safePoint)
#ifdef JS_METHODJIT_SPEW #ifdef JS_METHODJIT_SPEW
Profiler prof; Profiler prof;
JSScript *script = fp->getScript(); JSScript *script = fp->script();
JaegerSpew(JSpew_Prof, "%s jaeger script: %s, line %d\n", JaegerSpew(JSpew_Prof, "%s jaeger script: %s, line %d\n",
safePoint ? "dropping" : "entering", safePoint ? "dropping" : "entering",
@ -740,19 +755,9 @@ EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, void *safePoint)
JSStackFrame *checkFp = fp; JSStackFrame *checkFp = fp;
#endif #endif
Value *fpAsVp = reinterpret_cast<Value*>(fp); Value *stackLimit = cx->stack().getStackLimit(cx);
StackSpace &stack = cx->stack(); if (!stackLimit)
Value *stackLimit = stack.makeStackLimit(fpAsVp);
/*
* We ensure that there is always enough space to speculatively create a
* stack frame. By passing nslots = 0, we ensure only sizeof(JSStackFrame).
*/
if (fpAsVp + VALUES_PER_STACK_FRAME >= stackLimit &&
!stack.ensureSpace(cx, fpAsVp, cx->regs->sp, stackLimit, 0)) {
js_ReportOutOfScriptQuota(cx);
return false; return false;
}
JSFrameRegs *oldRegs = cx->regs; JSFrameRegs *oldRegs = cx->regs;
@ -774,7 +779,7 @@ EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, void *safePoint)
JSBool JSBool
mjit::JaegerShot(JSContext *cx) mjit::JaegerShot(JSContext *cx)
{ {
JSScript *script = cx->fp()->getScript(); JSScript *script = cx->fp()->script();
JS_ASSERT(script->ncode && script->ncode != JS_UNJITTABLE_METHOD); JS_ASSERT(script->ncode && script->ncode != JS_UNJITTABLE_METHOD);
@ -867,10 +872,3 @@ mjit::ProfileStubCall(VMFrame &f)
} }
#endif #endif
bool
VMFrame::slowEnsureSpace(uint32 nslots)
{
return cx->stack().ensureSpace(cx, reinterpret_cast<Value*>(entryFp), regs.sp,
stackLimit, nslots + VALUES_PER_STACK_FRAME);
}

Просмотреть файл

@ -132,17 +132,6 @@ struct VMFrame
JSRuntime *runtime() { return cx->runtime; } JSRuntime *runtime() { return cx->runtime; }
JSStackFrame *&fp() { return regs.fp; } JSStackFrame *&fp() { return regs.fp; }
bool slowEnsureSpace(uint32 nslots);
bool ensureSpace(uint32 nmissing, uint32 nslots) {
/* Fast check - if it's below the limit, it's safe to just get a frame. */
if (JS_LIKELY(regs.sp + VALUES_PER_STACK_FRAME + nmissing + nslots < stackLimit))
return true;
/* Slower check that might have to commit memory or throw an error. */
return slowEnsureSpace(nmissing + nslots);
}
}; };
#ifdef JS_CPU_ARM #ifdef JS_CPU_ARM

Просмотреть файл

@ -50,6 +50,8 @@
#include "methodjit/Compiler.h" #include "methodjit/Compiler.h"
#include "InlineFrameAssembler.h" #include "InlineFrameAssembler.h"
#include "jsobj.h" #include "jsobj.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jsscopeinlines.h" #include "jsscopeinlines.h"
#include "jsscriptinlines.h" #include "jsscriptinlines.h"
@ -78,9 +80,9 @@ PatchGetFallback(VMFrame &f, ic::MICInfo &mic)
void JS_FASTCALL void JS_FASTCALL
ic::GetGlobalName(VMFrame &f, uint32 index) ic::GetGlobalName(VMFrame &f, uint32 index)
{ {
JSObject *obj = f.fp()->getScopeChain()->getGlobal(); JSObject *obj = f.fp()->scopeChain().getGlobal();
ic::MICInfo &mic = f.fp()->getScript()->mics[index]; ic::MICInfo &mic = f.fp()->script()->mics[index];
JSAtom *atom = f.fp()->getScript()->getAtom(GET_INDEX(f.regs.pc)); JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc));
jsid id = ATOM_TO_JSID(atom); jsid id = ATOM_TO_JSID(atom);
JS_ASSERT(mic.kind == ic::MICInfo::GET); JS_ASSERT(mic.kind == ic::MICInfo::GET);
@ -129,7 +131,7 @@ ic::GetGlobalName(VMFrame &f, uint32 index)
static void JS_FASTCALL static void JS_FASTCALL
SetGlobalNameSlow(VMFrame &f, uint32 index) SetGlobalNameSlow(VMFrame &f, uint32 index)
{ {
JSAtom *atom = f.fp()->getScript()->getAtom(GET_INDEX(f.regs.pc)); JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc));
stubs::SetGlobalName(f, atom); stubs::SetGlobalName(f, atom);
} }
@ -154,9 +156,9 @@ GetStubForSetGlobalName(VMFrame &f)
void JS_FASTCALL void JS_FASTCALL
ic::SetGlobalName(VMFrame &f, uint32 index) ic::SetGlobalName(VMFrame &f, uint32 index)
{ {
JSObject *obj = f.fp()->getScopeChain()->getGlobal(); JSObject *obj = f.fp()->scopeChain().getGlobal();
ic::MICInfo &mic = f.fp()->getScript()->mics[index]; ic::MICInfo &mic = f.fp()->script()->mics[index];
JSAtom *atom = f.fp()->getScript()->getAtom(GET_INDEX(f.regs.pc)); JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc));
jsid id = ATOM_TO_JSID(atom); jsid id = ATOM_TO_JSID(atom);
JS_ASSERT(mic.kind == ic::MICInfo::SET); JS_ASSERT(mic.kind == ic::MICInfo::SET);
@ -213,7 +215,7 @@ ic::SetGlobalName(VMFrame &f, uint32 index)
static void * JS_FASTCALL static void * JS_FASTCALL
SlowCallFromIC(VMFrame &f, uint32 index) SlowCallFromIC(VMFrame &f, uint32 index)
{ {
JSScript *oldscript = f.fp()->getScript(); JSScript *oldscript = f.fp()->script();
CallICInfo &ic= oldscript->callICs[index]; CallICInfo &ic= oldscript->callICs[index];
stubs::SlowCall(f, ic.argc); stubs::SlowCall(f, ic.argc);
@ -224,7 +226,7 @@ SlowCallFromIC(VMFrame &f, uint32 index)
static void * JS_FASTCALL static void * JS_FASTCALL
SlowNewFromIC(VMFrame &f, uint32 index) SlowNewFromIC(VMFrame &f, uint32 index)
{ {
JSScript *oldscript = f.fp()->getScript(); JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index]; CallICInfo &ic = oldscript->callICs[index];
stubs::SlowNew(f, ic.argc); stubs::SlowNew(f, ic.argc);
@ -297,23 +299,6 @@ class CallCompiler
return ep; return ep;
} }
inline void pushFrameFromCaller(JSObject *scopeChain, uint32 flags)
{
JSStackFrame *fp = (JSStackFrame *)f.regs.sp;
fp->argc = ic.argc;
fp->argv = vp + 2;
fp->flags = flags;
fp->setScopeChain(scopeChain);
fp->setThisValue(vp[1]);
fp->down = f.fp();
fp->savedPC = f.regs.pc;
fp->down->savedPC = f.regs.pc;
#ifdef DEBUG
fp->savedPC = JSStackFrame::sInvalidPC;
#endif
f.regs.fp = fp;
}
bool generateFullCallStub(JSScript *script, uint32 flags) bool generateFullCallStub(JSScript *script, uint32 flags)
{ {
/* /*
@ -344,6 +329,7 @@ class CallCompiler
/* Try and compile. On success we get back the nmap pointer. */ /* Try and compile. On success we get back the nmap pointer. */
masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp))); masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
masm.move(Imm32(ic.argc), Registers::ArgReg1);
JSC::MacroAssembler::Call tryCompile = JSC::MacroAssembler::Call tryCompile =
masm.stubCall(JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction), masm.stubCall(JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction),
script->code, ic.frameDepth); script->code, ic.frameDepth);
@ -648,7 +634,7 @@ class CallCompiler
stubs::NewObject(f, ic.argc); stubs::NewObject(f, ic.argc);
if (!ic.hit) { if (!ic.hit) {
if (ic.argc < fun->nargs) { if (ic.argc != fun->nargs) {
if (!generateFullCallStub(script, flags)) if (!generateFullCallStub(script, flags))
THROWV(NULL); THROWV(NULL);
} else { } else {
@ -672,9 +658,18 @@ class CallCompiler
ic.hit = true; ic.hit = true;
} }
/* We'll still return to the OOL path, so make sure a frame exists. */ /*
pushFrameFromCaller(scopeChain, flags); * We are about to jump into the callee's prologue, so push the frame as
if (ic.argc >= fun->nargs) * if we had been executing in the caller's inline call path. In theory,
* we could actually jump to the inline call path, but doing it from
* C++ allows JSStackFrame::initCallFrameCallerHalf to serve as a
* reference for what the jitted path should be doing.
*/
JSStackFrame *fp = (JSStackFrame *)f.regs.sp;
fp->initCallFrameCallerHalf(cx, *scopeChain, ic.argc, flags);
f.regs.fp = fp;
if (ic.argc == fun->nargs)
return script->ncode; return script->ncode;
return script->jit->arityCheck; return script->jit->arityCheck;
} }
@ -683,7 +678,7 @@ class CallCompiler
void * JS_FASTCALL void * JS_FASTCALL
ic::Call(VMFrame &f, uint32 index) ic::Call(VMFrame &f, uint32 index)
{ {
JSScript *oldscript = f.fp()->getScript(); JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index]; CallICInfo &ic = oldscript->callICs[index];
CallCompiler cc(f, ic, false); CallCompiler cc(f, ic, false);
return cc.update(); return cc.update();
@ -692,7 +687,7 @@ ic::Call(VMFrame &f, uint32 index)
void * JS_FASTCALL void * JS_FASTCALL
ic::New(VMFrame &f, uint32 index) ic::New(VMFrame &f, uint32 index)
{ {
JSScript *oldscript = f.fp()->getScript(); JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index]; CallICInfo &ic = oldscript->callICs[index];
CallCompiler cc(f, ic, true); CallCompiler cc(f, ic, true);
return cc.update(); return cc.update();
@ -701,7 +696,7 @@ ic::New(VMFrame &f, uint32 index)
void JS_FASTCALL void JS_FASTCALL
ic::NativeCall(VMFrame &f, uint32 index) ic::NativeCall(VMFrame &f, uint32 index)
{ {
JSScript *oldscript = f.fp()->getScript(); JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index]; CallICInfo &ic = oldscript->callICs[index];
CallCompiler cc(f, ic, false); CallCompiler cc(f, ic, false);
if (!cc.generateNativeStub()) if (!cc.generateNativeStub())
@ -711,7 +706,7 @@ ic::NativeCall(VMFrame &f, uint32 index)
void JS_FASTCALL void JS_FASTCALL
ic::NativeNew(VMFrame &f, uint32 index) ic::NativeNew(VMFrame &f, uint32 index)
{ {
JSScript *oldscript = f.fp()->getScript(); JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index]; CallICInfo &ic = oldscript->callICs[index];
CallCompiler cc(f, ic, true); CallCompiler cc(f, ic, true);
if (!cc.generateNativeStub()) if (!cc.generateNativeStub())

Просмотреть файл

@ -124,7 +124,6 @@ struct CallICInfo {
/* Used for rooting and reification. */ /* Used for rooting and reification. */
JSObject *fastGuardedObject; JSObject *fastGuardedObject;
JSObject *fastGuardedNative; JSObject *fastGuardedNative;
Value constantThis;
uint32 argc : 16; uint32 argc : 16;
uint32 frameDepth : 16; uint32 frameDepth : 16;
@ -156,7 +155,6 @@ struct CallICInfo {
RegisterID funObjReg : 5; RegisterID funObjReg : 5;
RegisterID funPtrReg : 5; RegisterID funPtrReg : 5;
bool isConstantThis : 1;
bool hit : 1; bool hit : 1;
bool hasJsFunCheck : 1; bool hasJsFunCheck : 1;

Просмотреть файл

@ -467,6 +467,14 @@ class SetPropCompiler : public PICStubCompiler
emitStore(masm, address); emitStore(masm, address);
} else { } else {
// \ / In general, two function objects with different JSFunctions
// # can have the same shape, thus we must not rely on the identity
// >--+--< of 'fun' remaining the same. However, since:
// ||| 1. the shape includes all arguments and locals and their setters
// \\ V and getters, and
// \===/ 2. arguments and locals have different getters
// then we can rely on fun->nargs remaining invariant.
JSFunction *fun = obj->getCallObjCalleeFunction();
uint16 slot = uint16(shape->shortid); uint16 slot = uint16(shape->shortid);
/* Guard that the call object has a frame. */ /* Guard that the call object has a frame. */
@ -474,22 +482,17 @@ class SetPropCompiler : public PICStubCompiler
Jump escapedFrame = masm.branchTestPtr(Assembler::Zero, pic.shapeReg, pic.shapeReg); Jump escapedFrame = masm.branchTestPtr(Assembler::Zero, pic.shapeReg, pic.shapeReg);
{ {
uint32 bias = 0; Address addr(pic.shapeReg, shape->setterOp() == SetCallArg
if (shape->setterOp() == SetCallArg) ? JSStackFrame::offsetOfFormalArg(fun, slot)
masm.loadPtr(Address(pic.shapeReg, offsetof(JSStackFrame, argv)), pic.shapeReg); : JSStackFrame::offsetOfFixed(slot));
else emitStore(masm, addr);
bias = sizeof(JSStackFrame);
Address address(pic.shapeReg, bias + slot * sizeof(Value));
emitStore(masm, address);
skipOver = masm.jump(); skipOver = masm.jump();
} }
escapedFrame.linkTo(masm.label(), &masm); escapedFrame.linkTo(masm.label(), &masm);
{ {
if (shape->setterOp() == SetCallVar) { if (shape->setterOp() == SetCallVar)
JSFunction *fun = js_GetCallObjectFunction(obj);
slot += fun->nargs; slot += fun->nargs;
}
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg); masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
Address dslot(pic.objReg, slot * sizeof(Value)); Address dslot(pic.objReg, slot * sizeof(Value));
@ -874,7 +877,7 @@ class GetPropCompiler : public PICStubCompiler
JS_ASSERT(pic.hasTypeCheck()); JS_ASSERT(pic.hasTypeCheck());
JS_ASSERT(pic.kind == ic::PICInfo::CALL); JS_ASSERT(pic.kind == ic::PICInfo::CALL);
if (!f.fp()->getScript()->compileAndGo) if (!f.fp()->script()->compileAndGo)
return disable("String.prototype without compile-and-go"); return disable("String.prototype without compile-and-go");
JSObject *holder; JSObject *holder;
@ -1656,7 +1659,7 @@ class ScopeNameCompiler : public PICStubCompiler
Assembler masm; Assembler masm;
JumpList fails(f.cx); JumpList fails(f.cx);
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetScopeChain()), pic.objReg); masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
JS_ASSERT(obj == holder); JS_ASSERT(obj == holder);
JS_ASSERT(holder == scopeChain->getGlobal()); JS_ASSERT(holder == scopeChain->getGlobal());
@ -1729,7 +1732,7 @@ class ScopeNameCompiler : public PICStubCompiler
Assembler masm; Assembler masm;
Vector<Jump, 8, ContextAllocPolicy> fails(f.cx); Vector<Jump, 8, ContextAllocPolicy> fails(f.cx);
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetScopeChain()), pic.objReg); masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
JS_ASSERT(obj == holder); JS_ASSERT(obj == holder);
JS_ASSERT(holder != scopeChain->getGlobal()); JS_ASSERT(holder != scopeChain->getGlobal());
@ -1756,6 +1759,7 @@ class ScopeNameCompiler : public PICStubCompiler
/* Get callobj's stack frame. */ /* Get callobj's stack frame. */
masm.loadFunctionPrivate(pic.objReg, pic.shapeReg); masm.loadFunctionPrivate(pic.objReg, pic.shapeReg);
JSFunction *fun = holder->getCallObjCalleeFunction();
uint16 slot = uint16(shape->shortid); uint16 slot = uint16(shape->shortid);
Jump skipOver; Jump skipOver;
@ -1763,12 +1767,8 @@ class ScopeNameCompiler : public PICStubCompiler
/* Not-escaped case. */ /* Not-escaped case. */
{ {
uint32 bias = 0; Address addr(pic.shapeReg, kind == ARG ? JSStackFrame::offsetOfFormalArg(fun, slot)
if (kind == ARG) : JSStackFrame::offsetOfFixed(slot));
masm.loadPtr(Address(pic.shapeReg, offsetof(JSStackFrame, argv)), pic.shapeReg);
else
bias = sizeof(JSStackFrame);
Address addr(pic.shapeReg, bias + slot * sizeof(Value));
masm.loadPayload(addr, pic.objReg); masm.loadPayload(addr, pic.objReg);
masm.loadTypeTag(addr, pic.shapeReg); masm.loadTypeTag(addr, pic.shapeReg);
skipOver = masm.jump(); skipOver = masm.jump();
@ -1779,7 +1779,6 @@ class ScopeNameCompiler : public PICStubCompiler
{ {
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg); masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
JSFunction *fun = js_GetCallObjectFunction(holder);
if (kind == VAR) if (kind == VAR)
slot += fun->nargs; slot += fun->nargs;
Address dslot(pic.objReg, slot * sizeof(Value)); Address dslot(pic.objReg, slot * sizeof(Value));
@ -1914,7 +1913,7 @@ class BindNameCompiler : public PICStubCompiler
js::Vector<Jump, 8, ContextAllocPolicy> fails(f.cx); js::Vector<Jump, 8, ContextAllocPolicy> fails(f.cx);
/* Guard on the shape of the scope chain. */ /* Guard on the shape of the scope chain. */
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetScopeChain()), pic.objReg); masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
masm.loadShape(pic.objReg, pic.shapeReg); masm.loadShape(pic.objReg, pic.shapeReg);
Jump firstShape = masm.branch32(Assembler::NotEqual, pic.shapeReg, Jump firstShape = masm.branch32(Assembler::NotEqual, pic.shapeReg,
Imm32(scopeChain->shape())); Imm32(scopeChain->shape()));
@ -2008,7 +2007,7 @@ class BindNameCompiler : public PICStubCompiler
void JS_FASTCALL void JS_FASTCALL
ic::GetProp(VMFrame &f, uint32 index) ic::GetProp(VMFrame &f, uint32 index)
{ {
JSScript *script = f.fp()->getScript(); JSScript *script = f.fp()->script();
PICInfo &pic = script->pics[index]; PICInfo &pic = script->pics[index];
JSAtom *atom = pic.atom; JSAtom *atom = pic.atom;
@ -2066,7 +2065,7 @@ ic::GetProp(VMFrame &f, uint32 index)
void JS_FASTCALL void JS_FASTCALL
ic::GetElem(VMFrame &f, uint32 picIndex) ic::GetElem(VMFrame &f, uint32 picIndex)
{ {
JSScript *script = f.fp()->getScript(); JSScript *script = f.fp()->script();
PICInfo &pic = script->pics[picIndex]; PICInfo &pic = script->pics[picIndex];
JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]); JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
@ -2096,7 +2095,7 @@ ic::GetElem(VMFrame &f, uint32 picIndex)
void JS_FASTCALL void JS_FASTCALL
ic::SetPropDumb(VMFrame &f, uint32 index) ic::SetPropDumb(VMFrame &f, uint32 index)
{ {
JSScript *script = f.fp()->getScript(); JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index]; ic::PICInfo &pic = script->pics[index];
JS_ASSERT(pic.isSet()); JS_ASSERT(pic.isSet());
JSAtom *atom = pic.atom; JSAtom *atom = pic.atom;
@ -2113,7 +2112,7 @@ ic::SetPropDumb(VMFrame &f, uint32 index)
static void JS_FASTCALL static void JS_FASTCALL
SetPropSlow(VMFrame &f, uint32 index) SetPropSlow(VMFrame &f, uint32 index)
{ {
JSScript *script = f.fp()->getScript(); JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index]; ic::PICInfo &pic = script->pics[index];
JS_ASSERT(pic.isSet()); JS_ASSERT(pic.isSet());
@ -2128,7 +2127,7 @@ ic::SetProp(VMFrame &f, uint32 index)
if (!obj) if (!obj)
THROW(); THROW();
JSScript *script = f.fp()->getScript(); JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index]; ic::PICInfo &pic = script->pics[index];
JSAtom *atom = pic.atom; JSAtom *atom = pic.atom;
JS_ASSERT(pic.isSet()); JS_ASSERT(pic.isSet());
@ -2172,7 +2171,7 @@ ic::SetProp(VMFrame &f, uint32 index)
static void JS_FASTCALL static void JS_FASTCALL
CallPropSlow(VMFrame &f, uint32 index) CallPropSlow(VMFrame &f, uint32 index)
{ {
JSScript *script = f.fp()->getScript(); JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index]; ic::PICInfo &pic = script->pics[index];
stubs::CallProp(f, pic.atom); stubs::CallProp(f, pic.atom);
} }
@ -2183,7 +2182,7 @@ ic::CallProp(VMFrame &f, uint32 index)
JSContext *cx = f.cx; JSContext *cx = f.cx;
JSFrameRegs &regs = f.regs; JSFrameRegs &regs = f.regs;
JSScript *script = f.fp()->getScript(); JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index]; ic::PICInfo &pic = script->pics[index];
JSAtom *origAtom = pic.atom; JSAtom *origAtom = pic.atom;
@ -2320,11 +2319,11 @@ SlowName(VMFrame &f, uint32 index)
void JS_FASTCALL void JS_FASTCALL
ic::Name(VMFrame &f, uint32 index) ic::Name(VMFrame &f, uint32 index)
{ {
JSScript *script = f.fp()->getScript(); JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index]; ic::PICInfo &pic = script->pics[index];
JSAtom *atom = pic.atom; JSAtom *atom = pic.atom;
ScopeNameCompiler cc(f, script, f.fp()->getScopeChain(), pic, atom, SlowName); ScopeNameCompiler cc(f, script, &f.fp()->scopeChain(), pic, atom, SlowName);
if (!cc.update()) { if (!cc.update()) {
cc.disable("error"); cc.disable("error");
@ -2340,7 +2339,7 @@ ic::Name(VMFrame &f, uint32 index)
if (!cc.prop) { if (!cc.prop) {
/* Kludge to allow (typeof foo == "undefined") tests. */ /* Kludge to allow (typeof foo == "undefined") tests. */
cc.disable("property not found"); cc.disable("property not found");
JSOp op2 = js_GetOpcode(f.cx, f.fp()->getScript(), f.regs.pc + JSOP_NAME_LENGTH); JSOp op2 = js_GetOpcode(f.cx, f.fp()->script(), f.regs.pc + JSOP_NAME_LENGTH);
if (op2 == JSOP_TYPEOF) { if (op2 == JSOP_TYPEOF) {
f.regs.sp[0].setUndefined(); f.regs.sp[0].setUndefined();
return; return;
@ -2369,11 +2368,11 @@ SlowBindName(VMFrame &f, uint32 index)
void JS_FASTCALL void JS_FASTCALL
ic::BindName(VMFrame &f, uint32 index) ic::BindName(VMFrame &f, uint32 index)
{ {
JSScript *script = f.fp()->getScript(); JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index]; ic::PICInfo &pic = script->pics[index];
JSAtom *atom = pic.atom; JSAtom *atom = pic.atom;
BindNameCompiler cc(f, script, f.fp()->getScopeChain(), pic, atom, SlowBindName); BindNameCompiler cc(f, script, &f.fp()->scopeChain(), pic, atom, SlowBindName);
JSObject *obj = cc.update(); JSObject *obj = cc.update();
if (!obj) { if (!obj) {

Просмотреть файл

@ -125,8 +125,8 @@ Recompiler::recompile()
for (AllFramesIter i(cx); !i.done(); ++i) { for (AllFramesIter i(cx); !i.done(); ++i) {
if (!firstFrame && i.fp()->maybeScript() == script) if (!firstFrame && i.fp()->maybeScript() == script)
firstFrame = i.fp(); firstFrame = i.fp();
if (script->isValidJitCode(i.fp()->ncode)) { if (script->isValidJitCode(i.fp()->nativeReturnAddress())) {
if (!toPatch.append(findPatch(&i.fp()->ncode))) if (!toPatch.append(findPatch(i.fp()->addressOfNativeReturnAddress())))
return false; return false;
} }
} }
@ -152,7 +152,7 @@ Recompiler::recompile()
/* If we get this far, the script is live, and we better be safe to re-jit. */ /* If we get this far, the script is live, and we better be safe to re-jit. */
JS_ASSERT(cx->compartment->debugMode); JS_ASSERT(cx->compartment->debugMode);
Compiler c(cx, script, firstFrame->getFunction(), firstFrame->getScopeChain()); Compiler c(cx, script, firstFrame->fun(), &firstFrame->scopeChain());
if (c.Compile() != Compile_Okay) if (c.Compile() != Compile_Okay)
return false; return false;

Просмотреть файл

@ -53,6 +53,8 @@
#include "methodjit/Compiler.h" #include "methodjit/Compiler.h"
#include "methodjit/StubCalls.h" #include "methodjit/StubCalls.h"
#include "jstracer.h" #include "jstracer.h"
#include "jsinterpinlines.h"
#include "jspropertycache.h" #include "jspropertycache.h"
#include "jspropertycacheinlines.h" #include "jspropertycacheinlines.h"
#include "jsscopeinlines.h" #include "jsscopeinlines.h"
@ -78,16 +80,16 @@ stubs::BindName(VMFrame &f)
PropertyCacheEntry *entry; PropertyCacheEntry *entry;
/* Fast-path should have caught this. See comment in interpreter. */ /* Fast-path should have caught this. See comment in interpreter. */
JS_ASSERT(f.fp()->getScopeChain()->getParent()); JS_ASSERT(f.fp()->scopeChain().getParent());
JSAtom *atom; JSAtom *atom;
JSObject *obj2; JSObject *obj2;
JSContext *cx = f.cx; JSContext *cx = f.cx;
JSObject *obj = f.fp()->getScopeChain(); JSObject *obj = &f.fp()->scopeChain();
JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom); JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom);
if (atom) { if (atom) {
jsid id = ATOM_TO_JSID(atom); jsid id = ATOM_TO_JSID(atom);
obj = js_FindIdentifierBase(cx, f.fp()->getScopeChain(), id); obj = js_FindIdentifierBase(cx, &f.fp()->scopeChain(), id);
if (!obj) if (!obj)
THROW(); THROW();
} }
@ -98,7 +100,7 @@ stubs::BindName(VMFrame &f)
JSObject * JS_FASTCALL JSObject * JS_FASTCALL
stubs::BindGlobalName(VMFrame &f) stubs::BindGlobalName(VMFrame &f)
{ {
return f.fp()->getScopeChain()->getGlobal(); return f.fp()->scopeChain().getGlobal();
} }
void JS_FASTCALL void JS_FASTCALL
@ -353,7 +355,7 @@ NameOp(VMFrame &f, JSObject *obj, bool callname = false)
return NULL; return NULL;
if (!prop) { if (!prop) {
/* Kludge to allow (typeof foo == "undefined") tests. */ /* Kludge to allow (typeof foo == "undefined") tests. */
JSOp op2 = js_GetOpcode(cx, f.fp()->getScript(), f.regs.pc + JSOP_NAME_LENGTH); JSOp op2 = js_GetOpcode(cx, f.fp()->script(), f.regs.pc + JSOP_NAME_LENGTH);
if (op2 == JSOP_TYPEOF) { if (op2 == JSOP_TYPEOF) {
f.regs.sp++; f.regs.sp++;
f.regs.sp[-1].setUndefined(); f.regs.sp[-1].setUndefined();
@ -401,14 +403,14 @@ NameOp(VMFrame &f, JSObject *obj, bool callname = false)
void JS_FASTCALL void JS_FASTCALL
stubs::Name(VMFrame &f) stubs::Name(VMFrame &f)
{ {
if (!NameOp(f, f.fp()->getScopeChain())) if (!NameOp(f, &f.fp()->scopeChain()))
THROW(); THROW();
} }
void JS_FASTCALL void JS_FASTCALL
stubs::GetGlobalName(VMFrame &f) stubs::GetGlobalName(VMFrame &f)
{ {
JSObject *globalObj = f.fp()->getScopeChain()->getGlobal(); JSObject *globalObj = f.fp()->scopeChain().getGlobal();
if (!NameOp(f, globalObj)) if (!NameOp(f, globalObj))
THROW(); THROW();
} }
@ -507,7 +509,7 @@ stubs::GetElem(VMFrame &f)
if (arg < obj->getArgsInitialLength()) { if (arg < obj->getArgsInitialLength()) {
JSStackFrame *afp = (JSStackFrame *) obj->getPrivate(); JSStackFrame *afp = (JSStackFrame *) obj->getPrivate();
if (afp) { if (afp) {
copyFrom = &afp->argv[arg]; copyFrom = &afp->canonicalActualArg(arg);
goto end_getelem; goto end_getelem;
} }
@ -629,7 +631,7 @@ stubs::SetElem(VMFrame &f)
void JS_FASTCALL void JS_FASTCALL
stubs::CallName(VMFrame &f) stubs::CallName(VMFrame &f)
{ {
JSObject *obj = NameOp(f, f.fp()->getScopeChain(), true); JSObject *obj = NameOp(f, &f.fp()->scopeChain(), true);
if (!obj) if (!obj)
THROW(); THROW();
} }
@ -843,7 +845,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
* FIXME: bug 476950, although debugger users may also demand some kind * FIXME: bug 476950, although debugger users may also demand some kind
* of scope link for debugger-assisted eval-in-frame. * of scope link for debugger-assisted eval-in-frame.
*/ */
obj2 = fp->getScopeChain(); obj2 = &fp->scopeChain();
} else { } else {
JS_ASSERT(!FUN_FLAT_CLOSURE(fun)); JS_ASSERT(!FUN_FLAT_CLOSURE(fun));
@ -852,7 +854,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
* top-level function. * top-level function.
*/ */
if (!fp->hasBlockChain()) { if (!fp->hasBlockChain()) {
obj2 = fp->getScopeChain(); obj2 = &fp->scopeChain();
} else { } else {
obj2 = js_GetScopeChain(cx, fp); obj2 = js_GetScopeChain(cx, fp);
if (!obj2) if (!obj2)
@ -875,21 +877,11 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
THROW(); THROW();
} }
/*
* Protect obj from any GC hiding below JSObject::setProperty or
* JSObject::defineProperty. All paths from here must flow through the
* fp->scopeChain code below the parent->defineProperty call.
*/
MUST_FLOW_THROUGH("restore_scope");
fp->setScopeChain(obj);
Value rval = ObjectValue(*obj);
/* /*
* ECMA requires functions defined when entering Eval code to be * ECMA requires functions defined when entering Eval code to be
* impermanent. * impermanent.
*/ */
uintN attrs = (fp->flags & JSFRAME_EVAL) uintN attrs = fp->isEvalFrame()
? JSPROP_ENUMERATE ? JSPROP_ENUMERATE
: JSPROP_ENUMERATE | JSPROP_PERMANENT; : JSPROP_ENUMERATE | JSPROP_PERMANENT;
@ -898,8 +890,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
* current scope chain even for the case of function expression statements * current scope chain even for the case of function expression statements
* and functions defined by eval inside let or with blocks. * and functions defined by eval inside let or with blocks.
*/ */
JSObject *parent = fp->varobj(cx); JSObject *parent = &fp->varobj(cx);
JS_ASSERT(parent);
uint32 old; uint32 old;
bool doSet; bool doSet;
@ -914,7 +905,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
JSObject *pobj; JSObject *pobj;
JSBool ok = CheckRedeclaration(cx, parent, id, attrs, &pobj, &prop); JSBool ok = CheckRedeclaration(cx, parent, id, attrs, &pobj, &prop);
if (!ok) if (!ok)
goto restore_scope; THROW();
/* /*
* We deviate from 10.1.2 in ECMA 262 v3 and under eval use for function * We deviate from 10.1.2 in ECMA 262 v3 and under eval use for function
@ -928,7 +919,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
* see bug 467495. * see bug 467495.
*/ */
doSet = (attrs == JSPROP_ENUMERATE); doSet = (attrs == JSPROP_ENUMERATE);
JS_ASSERT_IF(doSet, fp->flags & JSFRAME_EVAL); JS_ASSERT_IF(doSet, fp->isEvalFrame());
if (prop) { if (prop) {
if (parent == pobj && if (parent == pobj &&
parent->isCall() && parent->isCall() &&
@ -945,13 +936,10 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
} }
pobj->dropProperty(cx, prop); pobj->dropProperty(cx, prop);
} }
Value rval = ObjectValue(*obj);
ok = doSet ok = doSet
? parent->setProperty(cx, id, &rval) ? parent->setProperty(cx, id, &rval)
: parent->defineProperty(cx, id, rval, PropertyStub, PropertyStub, attrs); : parent->defineProperty(cx, id, rval, PropertyStub, PropertyStub, attrs);
restore_scope:
/* Restore fp->scopeChain now that obj is defined in fp->callobj. */
fp->setScopeChain(obj2);
if (!ok) if (!ok)
THROW(); THROW();
} }
@ -1325,7 +1313,7 @@ stubs::Debugger(VMFrame &f, jsbytecode *pc)
JSDebuggerHandler handler = f.cx->debugHooks->debuggerHandler; JSDebuggerHandler handler = f.cx->debugHooks->debuggerHandler;
if (handler) { if (handler) {
Value rval; Value rval;
switch (handler(f.cx, f.cx->fp()->getScript(), pc, Jsvalify(&rval), switch (handler(f.cx, f.cx->fp()->script(), pc, Jsvalify(&rval),
f.cx->debugHooks->debuggerHandlerData)) { f.cx->debugHooks->debuggerHandlerData)) {
case JSTRAP_THROW: case JSTRAP_THROW:
f.cx->throwing = JS_TRUE; f.cx->throwing = JS_TRUE;
@ -1366,7 +1354,7 @@ stubs::Trap(VMFrame &f, jsbytecode *pc)
{ {
Value rval; Value rval;
switch (JS_HandleTrap(f.cx, f.cx->fp()->getScript(), pc, Jsvalify(&rval))) { switch (JS_HandleTrap(f.cx, f.cx->fp()->script(), pc, Jsvalify(&rval))) {
case JSTRAP_THROW: case JSTRAP_THROW:
f.cx->throwing = JS_TRUE; f.cx->throwing = JS_TRUE;
f.cx->exception = rval; f.cx->exception = rval;
@ -1396,15 +1384,16 @@ stubs::Trap(VMFrame &f, jsbytecode *pc)
void JS_FASTCALL void JS_FASTCALL
stubs::This(VMFrame &f) stubs::This(VMFrame &f)
{ {
if (!f.fp()->getThisObject(f.cx)) JSObject *obj = f.fp()->computeThisObject(f.cx);
if (!obj)
THROW(); THROW();
f.regs.sp[-1] = f.fp()->getThisValue(); f.regs.sp[-1].setObject(*obj);
} }
void JS_FASTCALL void JS_FASTCALL
stubs::ComputeThis(VMFrame &f) stubs::ComputeThis(VMFrame &f)
{ {
if (!f.fp()->getThisObject(f.cx)) if (!f.fp()->computeThisObject(f.cx))
THROW(); THROW();
} }
@ -1488,7 +1477,7 @@ void JS_FASTCALL
stubs::GetUpvar(VMFrame &f, uint32 ck) stubs::GetUpvar(VMFrame &f, uint32 ck)
{ {
/* :FIXME: We can do better, this stub isn't needed. */ /* :FIXME: We can do better, this stub isn't needed. */
uint32 staticLevel = f.fp()->getScript()->staticLevel; uint32 staticLevel = f.fp()->script()->staticLevel;
UpvarCookie cookie; UpvarCookie cookie;
cookie.fromInteger(ck); cookie.fromInteger(ck);
f.regs.sp[0] = GetUpvar(f.cx, staticLevel, cookie); f.regs.sp[0] = GetUpvar(f.cx, staticLevel, cookie);
@ -1509,7 +1498,7 @@ stubs::DefLocalFun(VMFrame &f, JSFunction *fun)
JSObject *obj = FUN_OBJECT(fun); JSObject *obj = FUN_OBJECT(fun);
if (FUN_NULL_CLOSURE(fun)) { if (FUN_NULL_CLOSURE(fun)) {
obj = CloneFunctionObject(f.cx, fun, f.fp()->getScopeChain()); obj = CloneFunctionObject(f.cx, fun, &f.fp()->scopeChain());
if (!obj) if (!obj)
THROWV(NULL); THROWV(NULL);
} else { } else {
@ -1544,11 +1533,11 @@ stubs::RegExp(VMFrame &f, JSObject *regex)
* bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was * bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was
* flouted by many browser-based implementations. * flouted by many browser-based implementations.
* *
* We avoid the js_GetScopeChain call here and pass fp->getScopeChain() as * We avoid the js_GetScopeChain call here and pass fp->scopeChain() as
* js_GetClassPrototype uses the latter only to locate the global. * js_GetClassPrototype uses the latter only to locate the global.
*/ */
JSObject *proto; JSObject *proto;
if (!js_GetClassPrototype(f.cx, f.fp()->getScopeChain(), JSProto_RegExp, &proto)) if (!js_GetClassPrototype(f.cx, &f.fp()->scopeChain(), JSProto_RegExp, &proto))
THROWV(NULL); THROWV(NULL);
JS_ASSERT(proto); JS_ASSERT(proto);
JSObject *obj = js_CloneRegExpObject(f.cx, regex, proto); JSObject *obj = js_CloneRegExpObject(f.cx, regex, proto);
@ -1561,8 +1550,8 @@ JSObject * JS_FASTCALL
stubs::LambdaForInit(VMFrame &f, JSFunction *fun) stubs::LambdaForInit(VMFrame &f, JSFunction *fun)
{ {
JSObject *obj = FUN_OBJECT(fun); JSObject *obj = FUN_OBJECT(fun);
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == f.fp()->getScopeChain()) { if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
fun->setMethodAtom(f.fp()->getScript()->getAtom(GET_SLOTNO(f.regs.pc + JSOP_LAMBDA_LENGTH))); fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(f.regs.pc + JSOP_LAMBDA_LENGTH)));
return obj; return obj;
} }
return Lambda(f, fun); return Lambda(f, fun);
@ -1572,10 +1561,10 @@ JSObject * JS_FASTCALL
stubs::LambdaForSet(VMFrame &f, JSFunction *fun) stubs::LambdaForSet(VMFrame &f, JSFunction *fun)
{ {
JSObject *obj = FUN_OBJECT(fun); JSObject *obj = FUN_OBJECT(fun);
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == f.fp()->getScopeChain()) { if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
const Value &lref = f.regs.sp[-1]; const Value &lref = f.regs.sp[-1];
if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) { if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) {
fun->setMethodAtom(f.fp()->getScript()->getAtom(GET_SLOTNO(f.regs.pc + JSOP_LAMBDA_LENGTH))); fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(f.regs.pc + JSOP_LAMBDA_LENGTH)));
return obj; return obj;
} }
} }
@ -1586,7 +1575,7 @@ JSObject * JS_FASTCALL
stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *fun) stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *fun)
{ {
JSObject *obj = FUN_OBJECT(fun); JSObject *obj = FUN_OBJECT(fun);
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == f.fp()->getScopeChain()) { if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
/* /*
* Array.prototype.sort and String.prototype.replace are * Array.prototype.sort and String.prototype.replace are
* optimized as if they are special form. We know that they * optimized as if they are special form. We know that they
@ -1623,7 +1612,7 @@ JSObject * JS_FASTCALL
stubs::LambdaJoinableForNull(VMFrame &f, JSFunction *fun) stubs::LambdaJoinableForNull(VMFrame &f, JSFunction *fun)
{ {
JSObject *obj = FUN_OBJECT(fun); JSObject *obj = FUN_OBJECT(fun);
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == f.fp()->getScopeChain()) { if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
jsbytecode *pc2 = f.regs.pc + JSOP_LAMBDA_LENGTH + JSOP_NULL_LENGTH; jsbytecode *pc2 = f.regs.pc + JSOP_LAMBDA_LENGTH + JSOP_NULL_LENGTH;
JSOp op2 = JSOp(*pc2); JSOp op2 = JSOp(*pc2);
@ -1640,7 +1629,7 @@ stubs::Lambda(VMFrame &f, JSFunction *fun)
JSObject *parent; JSObject *parent;
if (FUN_NULL_CLOSURE(fun)) { if (FUN_NULL_CLOSURE(fun)) {
parent = f.fp()->getScopeChain(); parent = &f.fp()->scopeChain();
} else { } else {
parent = js_GetScopeChain(f.cx, f.fp()); parent = js_GetScopeChain(f.cx, f.fp());
if (!parent) if (!parent)
@ -1680,9 +1669,9 @@ ObjIncOp(VMFrame &f, JSObject *obj, jsid id)
ref.getInt32Ref() = tmp + N; ref.getInt32Ref() = tmp + N;
else else
ref.getInt32Ref() = tmp += N; ref.getInt32Ref() = tmp += N;
fp->flags |= JSFRAME_ASSIGNING; fp->setAssigning();
JSBool ok = obj->setProperty(cx, id, &ref); JSBool ok = obj->setProperty(cx, id, &ref);
fp->flags &= ~JSFRAME_ASSIGNING; fp->clearAssigning();
if (!ok) if (!ok)
return false; return false;
@ -1704,9 +1693,9 @@ ObjIncOp(VMFrame &f, JSObject *obj, jsid id)
ref.setDouble(d); ref.setDouble(d);
} }
v.setDouble(d); v.setDouble(d);
fp->flags |= JSFRAME_ASSIGNING; fp->setAssigning();
JSBool ok = obj->setProperty(cx, id, &v); JSBool ok = obj->setProperty(cx, id, &v);
fp->flags &= ~JSFRAME_ASSIGNING; fp->clearAssigning();
if (!ok) if (!ok)
return false; return false;
} }
@ -1857,7 +1846,7 @@ stubs::DecElem(VMFrame &f)
void JS_FASTCALL void JS_FASTCALL
stubs::NameInc(VMFrame &f, JSAtom *atom) stubs::NameInc(VMFrame &f, JSAtom *atom)
{ {
JSObject *obj = f.fp()->getScopeChain(); JSObject *obj = &f.fp()->scopeChain();
if (!NameIncDec<1, true>(f, obj, atom)) if (!NameIncDec<1, true>(f, obj, atom))
THROW(); THROW();
} }
@ -1865,7 +1854,7 @@ stubs::NameInc(VMFrame &f, JSAtom *atom)
void JS_FASTCALL void JS_FASTCALL
stubs::NameDec(VMFrame &f, JSAtom *atom) stubs::NameDec(VMFrame &f, JSAtom *atom)
{ {
JSObject *obj = f.fp()->getScopeChain(); JSObject *obj = &f.fp()->scopeChain();
if (!NameIncDec<-1, true>(f, obj, atom)) if (!NameIncDec<-1, true>(f, obj, atom))
THROW(); THROW();
} }
@ -1873,7 +1862,7 @@ stubs::NameDec(VMFrame &f, JSAtom *atom)
void JS_FASTCALL void JS_FASTCALL
stubs::IncName(VMFrame &f, JSAtom *atom) stubs::IncName(VMFrame &f, JSAtom *atom)
{ {
JSObject *obj = f.fp()->getScopeChain(); JSObject *obj = &f.fp()->scopeChain();
if (!NameIncDec<1, false>(f, obj, atom)) if (!NameIncDec<1, false>(f, obj, atom))
THROW(); THROW();
} }
@ -1881,7 +1870,7 @@ stubs::IncName(VMFrame &f, JSAtom *atom)
void JS_FASTCALL void JS_FASTCALL
stubs::DecName(VMFrame &f, JSAtom *atom) stubs::DecName(VMFrame &f, JSAtom *atom)
{ {
JSObject *obj = f.fp()->getScopeChain(); JSObject *obj = &f.fp()->scopeChain();
if (!NameIncDec<-1, false>(f, obj, atom)) if (!NameIncDec<-1, false>(f, obj, atom))
THROW(); THROW();
} }
@ -1889,7 +1878,7 @@ stubs::DecName(VMFrame &f, JSAtom *atom)
void JS_FASTCALL void JS_FASTCALL
stubs::GlobalNameInc(VMFrame &f, JSAtom *atom) stubs::GlobalNameInc(VMFrame &f, JSAtom *atom)
{ {
JSObject *obj = f.fp()->getScopeChain()->getGlobal(); JSObject *obj = f.fp()->scopeChain().getGlobal();
if (!NameIncDec<1, true>(f, obj, atom)) if (!NameIncDec<1, true>(f, obj, atom))
THROW(); THROW();
} }
@ -1897,7 +1886,7 @@ stubs::GlobalNameInc(VMFrame &f, JSAtom *atom)
void JS_FASTCALL void JS_FASTCALL
stubs::GlobalNameDec(VMFrame &f, JSAtom *atom) stubs::GlobalNameDec(VMFrame &f, JSAtom *atom)
{ {
JSObject *obj = f.fp()->getScopeChain()->getGlobal(); JSObject *obj = f.fp()->scopeChain().getGlobal();
if (!NameIncDec<-1, true>(f, obj, atom)) if (!NameIncDec<-1, true>(f, obj, atom))
THROW(); THROW();
} }
@ -1905,7 +1894,7 @@ stubs::GlobalNameDec(VMFrame &f, JSAtom *atom)
void JS_FASTCALL void JS_FASTCALL
stubs::IncGlobalName(VMFrame &f, JSAtom *atom) stubs::IncGlobalName(VMFrame &f, JSAtom *atom)
{ {
JSObject *obj = f.fp()->getScopeChain()->getGlobal(); JSObject *obj = f.fp()->scopeChain().getGlobal();
if (!NameIncDec<1, false>(f, obj, atom)) if (!NameIncDec<1, false>(f, obj, atom))
THROW(); THROW();
} }
@ -1913,7 +1902,7 @@ stubs::IncGlobalName(VMFrame &f, JSAtom *atom)
void JS_FASTCALL void JS_FASTCALL
stubs::DecGlobalName(VMFrame &f, JSAtom *atom) stubs::DecGlobalName(VMFrame &f, JSAtom *atom)
{ {
JSObject *obj = f.fp()->getScopeChain()->getGlobal(); JSObject *obj = f.fp()->scopeChain().getGlobal();
if (!NameIncDec<-1, false>(f, obj, atom)) if (!NameIncDec<-1, false>(f, obj, atom))
THROW(); THROW();
} }
@ -1953,7 +1942,7 @@ InlineGetProp(VMFrame &f)
JS_ASSERT(entry->vword.isShape()); JS_ASSERT(entry->vword.isShape());
const Shape *shape = entry->vword.toShape(); const Shape *shape = entry->vword.toShape();
NATIVE_GET(cx, obj, obj2, shape, NATIVE_GET(cx, obj, obj2, shape,
f.fp()->hasIMacroPC() ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER, f.fp()->hasImacropc() ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER,
&rval, return false); &rval, return false);
} }
break; break;
@ -1962,7 +1951,7 @@ InlineGetProp(VMFrame &f)
jsid id = ATOM_TO_JSID(atom); jsid id = ATOM_TO_JSID(atom);
if (JS_LIKELY(!aobj->getOps()->getProperty) if (JS_LIKELY(!aobj->getOps()->getProperty)
? !js_GetPropertyHelper(cx, obj, id, ? !js_GetPropertyHelper(cx, obj, id,
f.fp()->hasIMacroPC() f.fp()->hasImacropc()
? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
: JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER, : JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
&rval) &rval)
@ -2386,7 +2375,7 @@ stubs::EnterBlock(VMFrame &f, JSObject *obj)
JS_ASSERT(fp->base() + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp); JS_ASSERT(fp->base() + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp);
Value *vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj); Value *vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj);
JS_ASSERT(regs.sp < vp); JS_ASSERT(regs.sp < vp);
JS_ASSERT(vp <= fp->slots() + fp->getScript()->nslots); JS_ASSERT(vp <= fp->slots() + fp->script()->nslots);
SetValueRangeToUndefined(regs.sp, vp); SetValueRangeToUndefined(regs.sp, vp);
regs.sp = vp; regs.sp = vp;
@ -2395,13 +2384,13 @@ stubs::EnterBlock(VMFrame &f, JSObject *obj)
JS_ASSERT(fp->maybeBlockChain() == obj->getParent()); JS_ASSERT(fp->maybeBlockChain() == obj->getParent());
/* /*
* The young end of fp->getScopeChain() may omit blocks if we haven't closed * The young end of fp->scopeChain() may omit blocks if we haven't closed
* over them, but if there are any closure blocks on fp->getScopeChain(), they'd * over them, but if there are any closure blocks on fp->scopeChain(), they'd
* better be (clones of) ancestors of the block we're entering now; * better be (clones of) ancestors of the block we're entering now;
* anything else we should have popped off fp->getScopeChain() when we left its * anything else we should have popped off fp->scopeChain() when we left its
* static scope. * static scope.
*/ */
JSObject *obj2 = fp->getScopeChain(); JSObject *obj2 = &fp->scopeChain();
Class *clasp; Class *clasp;
while ((clasp = obj2->getClass()) == &js_WithClass) while ((clasp = obj2->getClass()) == &js_WithClass)
obj2 = obj2->getParent(); obj2 = obj2->getParent();
@ -2425,32 +2414,32 @@ stubs::LeaveBlock(VMFrame &f)
JSStackFrame *fp = f.fp(); JSStackFrame *fp = f.fp();
#ifdef DEBUG #ifdef DEBUG
JS_ASSERT(fp->getBlockChain()->getClass() == &js_BlockClass); JS_ASSERT(fp->blockChain()->getClass() == &js_BlockClass);
uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->getBlockChain()); uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->blockChain());
JS_ASSERT(blockDepth <= StackDepth(fp->getScript())); JS_ASSERT(blockDepth <= StackDepth(fp->script()));
#endif #endif
/* /*
* If we're about to leave the dynamic scope of a block that has been * If we're about to leave the dynamic scope of a block that has been
* cloned onto fp->getScopeChain(), clear its private data, move its locals from * cloned onto fp->scopeChain(), clear its private data, move its locals from
* the stack into the clone, and pop it off the chain. * the stack into the clone, and pop it off the chain.
*/ */
JSObject *obj = fp->getScopeChain(); JSObject *obj = &fp->scopeChain();
if (obj->getProto() == fp->getBlockChain()) { if (obj->getProto() == fp->blockChain()) {
JS_ASSERT(obj->getClass() == &js_BlockClass); JS_ASSERT(obj->getClass() == &js_BlockClass);
if (!js_PutBlockObject(cx, JS_TRUE)) if (!js_PutBlockObject(cx, JS_TRUE))
THROW(); THROW();
} }
/* Pop the block chain, too. */ /* Pop the block chain, too. */
fp->setBlockChain(fp->getBlockChain()->getParent()); fp->setBlockChain(fp->blockChain()->getParent());
} }
void * JS_FASTCALL void * JS_FASTCALL
stubs::LookupSwitch(VMFrame &f, jsbytecode *pc) stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
{ {
jsbytecode *jpc = pc; jsbytecode *jpc = pc;
JSScript *script = f.fp()->getScript(); JSScript *script = f.fp()->script();
/* This is correct because the compiler adjusts the stack beforehand. */ /* This is correct because the compiler adjusts the stack beforehand. */
Value lval = f.regs.sp[-1]; Value lval = f.regs.sp[-1];
@ -2519,7 +2508,7 @@ stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
{ {
jsbytecode * const originalPC = origPc; jsbytecode * const originalPC = origPc;
jsbytecode *pc = originalPC; jsbytecode *pc = originalPC;
JSScript *script = f.fp()->getScript(); JSScript *script = f.fp()->script();
uint32 jumpOffset = GET_JUMP_OFFSET(pc); uint32 jumpOffset = GET_JUMP_OFFSET(pc);
pc += JUMP_OFFSET_LEN; pc += JUMP_OFFSET_LEN;

Просмотреть файл

@ -59,9 +59,9 @@ void JS_FASTCALL InitElem(VMFrame &f, uint32 last);
void JS_FASTCALL InitProp(VMFrame &f, JSAtom *atom); void JS_FASTCALL InitProp(VMFrame &f, JSAtom *atom);
void JS_FASTCALL InitMethod(VMFrame &f, JSAtom *atom); void JS_FASTCALL InitMethod(VMFrame &f, JSAtom *atom);
void JS_FASTCALL CheckStackQuota(VMFrame &f); void JS_FASTCALL HitStackQuota(VMFrame &f);
void * JS_FASTCALL CheckArity(VMFrame &f); void * JS_FASTCALL FixupArity(VMFrame &f, uint32 argc);
void * JS_FASTCALL CompileFunction(VMFrame &f); void * JS_FASTCALL CompileFunction(VMFrame &f, uint32 argc);
void JS_FASTCALL SlowNew(VMFrame &f, uint32 argc); void JS_FASTCALL SlowNew(VMFrame &f, uint32 argc);
void JS_FASTCALL SlowCall(VMFrame &f, uint32 argc); void JS_FASTCALL SlowCall(VMFrame &f, uint32 argc);
void * JS_FASTCALL UncachedNew(VMFrame &f, uint32 argc); void * JS_FASTCALL UncachedNew(VMFrame &f, uint32 argc);
@ -70,7 +70,7 @@ void * JS_FASTCALL UncachedCall(VMFrame &f, uint32 argc);
JSBool JS_FASTCALL NewObject(VMFrame &f, uint32 argc); JSBool JS_FASTCALL NewObject(VMFrame &f, uint32 argc);
void JS_FASTCALL Throw(VMFrame &f); void JS_FASTCALL Throw(VMFrame &f);
void JS_FASTCALL PutCallObject(VMFrame &f); void JS_FASTCALL PutCallObject(VMFrame &f);
void JS_FASTCALL PutArgsObject(VMFrame &f); void JS_FASTCALL PutActivationObjects(VMFrame &f);
void JS_FASTCALL GetCallObject(VMFrame &f); void JS_FASTCALL GetCallObject(VMFrame &f);
void JS_FASTCALL WrapPrimitiveThis(VMFrame &f); void JS_FASTCALL WrapPrimitiveThis(VMFrame &f);
#if JS_MONOIC #if JS_MONOIC

Просмотреть файл

@ -117,28 +117,21 @@ TrampolineCompiler::compileTrampoline(void **where, JSC::ExecutablePool **pool,
bool bool
TrampolineCompiler::generateForceReturn(Assembler &masm) TrampolineCompiler::generateForceReturn(Assembler &masm)
{ {
/* if (!callobj) stubs::PutCallObject */ /* if (hasArgsObj() || hasCallObj()) stubs::PutActivationObjects() */
Jump noCallObj = masm.branchPtr(Assembler::Equal, Jump noActObjs = masm.branchTest32(Assembler::Zero,
Address(JSFrameReg, JSStackFrame::offsetCallObj()), Address(JSFrameReg, JSStackFrame::offsetOfFlags()),
ImmPtr(0)); Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ));
masm.stubCall(stubs::PutCallObject, NULL, 0); masm.stubCall(stubs::PutActivationObjects, NULL, 0);
noCallObj.linkTo(masm.label(), &masm); noActObjs.linkTo(masm.label(), &masm);
/* if (arguments) stubs::PutArgsObject */
Jump noArgsObj = masm.branchPtr(Assembler::Equal,
Address(JSFrameReg, JSStackFrame::offsetArgsObj()),
ImmIntPtr(0));
masm.stubCall(stubs::PutArgsObject, NULL, 0);
noArgsObj.linkTo(masm.label(), &masm);
/* /*
* r = fp->down * r = fp->prev
* f.fp = r * f.fp = r
*/ */
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, down)), Registers::ReturnReg); masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), Registers::ReturnReg);
masm.storePtr(Registers::ReturnReg, FrameAddress(offsetof(VMFrame, regs.fp))); masm.storePtr(Registers::ReturnReg, FrameAddress(offsetof(VMFrame, regs.fp)));
Address rval(JSFrameReg, JSStackFrame::offsetReturnValue()); Address rval(JSFrameReg, JSStackFrame::offsetOfReturnValue());
masm.loadPayload(rval, JSReturnReg_Data); masm.loadPayload(rval, JSReturnReg_Data);
masm.loadTypeTag(rval, JSReturnReg_Type); masm.loadTypeTag(rval, JSReturnReg_Type);
@ -146,8 +139,8 @@ TrampolineCompiler::generateForceReturn(Assembler &masm)
masm.move(Registers::ReturnReg, JSFrameReg); masm.move(Registers::ReturnReg, JSFrameReg);
#ifdef DEBUG #ifdef DEBUG
masm.storePtr(ImmPtr(JSStackFrame::sInvalidPC), masm.storePtr(ImmPtr(JSStackFrame::sInvalidpc),
Address(JSFrameReg, offsetof(JSStackFrame, savedPC))); Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
#endif #endif
masm.ret(); masm.ret();

Просмотреть файл

@ -154,7 +154,7 @@ JaegerThrowpoline ENDP
SafePointTrampoline PROC FRAME SafePointTrampoline PROC FRAME
.ENDPROLOG .ENDPROLOG
pop rax pop rax
mov qword ptr [rbx+60h], rax mov qword ptr [rbx+50h], rax ; fp->ncode_
jmp qword ptr [rsp+8] jmp qword ptr [rsp+8]
SafePointTrampoline ENDP SafePointTrampoline ENDP
@ -162,8 +162,8 @@ SafePointTrampoline ENDP
; void InjectJaegerReturn(); ; void InjectJaegerReturn();
InjectJaegerReturn PROC FRAME InjectJaegerReturn PROC FRAME
.ENDPROLOG .ENDPROLOG
mov rcx, qword ptr [rbx+40h] ; load value into typeReg mov rcx, qword ptr [rbx+30h] ; load fp->rval_ into typeReg
mov rax, qword ptr [rbx+60h] ; fp->ncode mov rax, qword ptr [rbx+50h] ; fp->ncode_
; Reimplementation of PunboxAssembler::loadValueAsComponents() ; Reimplementation of PunboxAssembler::loadValueAsComponents()
mov rdx, r14 mov rdx, r14

Просмотреть файл

@ -121,9 +121,9 @@ throwpoline_exit:
.global InjectJaegerReturn .global InjectJaegerReturn
.type InjectJaegerReturn, @function .type InjectJaegerReturn, @function
InjectJaegerReturn: InjectJaegerReturn:
movl 0x24(%ebx), %edx /* fp->rval data */ movl 0x18(%ebx), %edx /* fp->rval_ data */
movl 0x28(%ebx), %ecx /* fp->rval type */ movl 0x1C(%ebx), %ecx /* fp->rval_ type */
movl 0x38(%ebx), %eax /* fp->ncode */ movl 0x2c(%ebx), %eax /* fp->ncode_ */
/* For Sun Studio there is no fast call. */ /* For Sun Studio there is no fast call. */
/* We add the stack by 8 before. */ /* We add the stack by 8 before. */
addl $0x8, %esp addl $0x8, %esp
@ -141,6 +141,6 @@ InjectJaegerReturn:
.type SafePointTrampoline, @function .type SafePointTrampoline, @function
SafePointTrampoline: SafePointTrampoline:
popl %eax popl %eax
movl %eax, 0x38(%ebx) movl %eax, 0x2c(%ebx)
jmp *24(%ebp) jmp *24(%ebp)
.size SafePointTrampoline, . - SafePointTrampoline .size SafePointTrampoline, . - SafePointTrampoline

Просмотреть файл

@ -92,6 +92,7 @@
#include "jsworkers.h" #include "jsworkers.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h" #include "jsobjinlines.h"
#include "jsscriptinlines.h" #include "jsscriptinlines.h"
@ -1172,7 +1173,7 @@ AssertJit(JSContext *cx, uintN argc, jsval *vp)
{ {
#ifdef JS_METHODJIT #ifdef JS_METHODJIT
if (JS_GetOptions(cx) & JSOPTION_METHODJIT) { if (JS_GetOptions(cx) & JSOPTION_METHODJIT) {
if (cx->fp()->getScript()->nmap == NULL) { if (cx->fp()->script()->nmap == NULL) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_ASSERT_JIT_FAILED); JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_ASSERT_JIT_FAILED);
return JS_FALSE; return JS_FALSE;
} }
@ -1459,7 +1460,7 @@ ValueToScript(JSContext *cx, jsval v)
script = (JSScript *) JS_GetPrivate(cx, obj); script = (JSScript *) JS_GetPrivate(cx, obj);
} else if (clasp == Jsvalify(&js_GeneratorClass)) { } else if (clasp == Jsvalify(&js_GeneratorClass)) {
JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj); JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj);
fun = gen->getFloatingFrame()->getFunction(); fun = gen->floatingFrame()->fun();
script = FUN_SCRIPT(fun); script = FUN_SCRIPT(fun);
} }
} }
@ -1501,7 +1502,7 @@ GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp,
uintN intarg; uintN intarg;
JSScript *script; JSScript *script;
*scriptp = JS_GetScriptedCaller(cx, NULL)->getScript(); *scriptp = JS_GetScriptedCaller(cx, NULL)->script();
*ip = 0; *ip = 0;
if (argc != 0) { if (argc != 0) {
v = argv[0]; v = argv[0];
@ -1531,8 +1532,8 @@ TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
JSStackFrame *caller = JS_GetScriptedCaller(cx, NULL); JSStackFrame *caller = JS_GetScriptedCaller(cx, NULL);
if (!JS_EvaluateUCInStackFrame(cx, caller, if (!JS_EvaluateUCInStackFrame(cx, caller,
JS_GetStringChars(str), JS_GetStringLength(str), JS_GetStringChars(str), JS_GetStringLength(str),
caller->getScript()->filename, caller->script()->filename,
caller->getScript()->lineno, caller->script()->lineno,
rval)) { rval)) {
return JSTRAP_ERROR; return JSTRAP_ERROR;
} }
@ -1634,7 +1635,7 @@ LineToPC(JSContext *cx, uintN argc, jsval *vp)
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE); JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE);
return JS_FALSE; return JS_FALSE;
} }
script = JS_GetScriptedCaller(cx, NULL)->getScript(); script = JS_GetScriptedCaller(cx, NULL)->script();
if (!GetTrapArgs(cx, argc, JS_ARGV(cx, vp), &script, &i)) if (!GetTrapArgs(cx, argc, JS_ARGV(cx, vp), &script, &i))
return JS_FALSE; return JS_FALSE;
lineno = (i == 0) ? script->lineno : (uintN)i; lineno = (i == 0) ? script->lineno : (uintN)i;
@ -3203,8 +3204,8 @@ EvalInContext(JSContext *cx, uintN argc, jsval *vp)
return false; return false;
} }
if (!JS_EvaluateUCScript(cx, sobj, src, srclen, if (!JS_EvaluateUCScript(cx, sobj, src, srclen,
fp->getScript()->filename, fp->script()->filename,
JS_PCToLineNumber(cx, fp->getScript(), fp->pc(cx)), JS_PCToLineNumber(cx, fp->script(), fp->pc(cx)),
vp)) { vp)) {
return false; return false;
} }
@ -3234,12 +3235,12 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
FrameRegsIter fi(cx); FrameRegsIter fi(cx);
for (uint32 i = 0; i < upCount; ++i, ++fi) { for (uint32 i = 0; i < upCount; ++i, ++fi) {
if (!fi.fp()->down) if (!fi.fp()->prev())
break; break;
} }
JSStackFrame *const fp = fi.fp(); JSStackFrame *const fp = fi.fp();
if (!fp->hasScript()) { if (!JS_IsScriptFrame(cx, fp)) {
JS_ReportError(cx, "cannot eval in non-script frame"); JS_ReportError(cx, "cannot eval in non-script frame");
return JS_FALSE; return JS_FALSE;
} }
@ -3249,8 +3250,8 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
oldfp = JS_SaveFrameChain(cx); oldfp = JS_SaveFrameChain(cx);
JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, str->chars(), str->length(), JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, str->chars(), str->length(),
fp->getScript()->filename, fp->script()->filename,
JS_PCToLineNumber(cx, fp->getScript(), JS_PCToLineNumber(cx, fp->script(),
fi.pc()), fi.pc()),
vp); vp);
@ -3975,9 +3976,9 @@ Snarf(JSContext *cx, uintN argc, jsval *vp)
/* Get the currently executing script's name. */ /* Get the currently executing script's name. */
fp = JS_GetScriptedCaller(cx, NULL); fp = JS_GetScriptedCaller(cx, NULL);
JS_ASSERT(fp && fp->getScript()->filename); JS_ASSERT(fp && fp->script()->filename);
#ifdef XP_UNIX #ifdef XP_UNIX
pathname = MakeAbsolutePathname(cx, fp->getScript()->filename, filename); pathname = MakeAbsolutePathname(cx, fp->script()->filename, filename);
if (!pathname) if (!pathname)
return JS_FALSE; return JS_FALSE;
#else #else

Просмотреть файл

@ -0,0 +1,12 @@
var o = {x:42};
function f(index,param) {
arguments[1] = 0;
var ret = 0;
for (var i = 0; i < 5; ++i)
ret = arguments[index].x;
return ret;
}
assertEq(f(2,o,o), 42);
assertEq(f(1,o,o), undefined);

Просмотреть файл

@ -1,3 +1,4 @@
var escape;
function testBug458838() { function testBug458838() {
var a = 1; var a = 1;
function g() { function g() {

Просмотреть файл

@ -0,0 +1,4 @@
function f(x,y) {
eval("assertEq(arguments.callee, f)");
}
f(1,2);

Просмотреть файл

@ -1,24 +1,13 @@
// Fun.apply ignores arguments past JS_ARGS_LENGTH_MAX = 2^19 - 1024
const numFatArgs = Math.pow(2,19) - 1024; const numFatArgs = Math.pow(2,19) - 1024;
// Recursion on trace is limited to MAX_CALL_STACK_ENTRIES = 500
const traceDepth = 490;
var trace = true; function fun(x) {
function doEval() {
eval("");
}
function maybeTrace(x) {
if (!trace)
doEval();
if (x <= 0) if (x <= 0)
return 0; return 0;
return maybeTrace(x-1); return fun(x-1);
} }
function fatStack() { function fatStack() {
return maybeTrace(traceDepth); return fun(10000);
} }
function assertRightFailure(e) { function assertRightFailure(e) {
@ -27,8 +16,6 @@ function assertRightFailure(e) {
true); true);
} }
// This tests that we conservatively guard against stack space exhaustion
// before entering trace.
exception = false; exception = false;
try { try {
fatStack.apply(null, new Array(numFatArgs)); fatStack.apply(null, new Array(numFatArgs));
@ -40,14 +27,3 @@ assertEq(exception, true);
// No more trace recursion w/ JM // No more trace recursion w/ JM
checkStats({traceCompleted:0}); checkStats({traceCompleted:0});
// This tests that, without tracing, we exhaust stack space.
trace = false;
var exception = false;
try {
fatStack.apply(null, new Array(numFatArgs));
} catch (e) {
assertRightFailure(e);
exception = true;
}
assertEq(exception, true);

Просмотреть файл

@ -200,7 +200,7 @@ AllowedToAct(JSContext *cx, jsid id)
// Some code is running, we can't make the assumption, as above, but we // Some code is running, we can't make the assumption, as above, but we
// can't use a native frame, so clear fp. // can't use a native frame, so clear fp.
fp = nsnull; fp = nsnull;
} else if (!fp->hasScript()) { } else if (!JS_IsScriptFrame(cx, fp)) {
fp = nsnull; fp = nsnull;
} }
@ -215,7 +215,7 @@ AllowedToAct(JSContext *cx, jsid id)
// if they've been cloned into less privileged contexts. // if they've been cloned into less privileged contexts.
const char *filename; const char *filename;
if (fp && if (fp &&
(filename = fp->getScript()->filename) && (filename = JS_GetFrameScript(cx, fp)->filename) &&
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) { !strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
return JS_TRUE; return JS_TRUE;
} }
@ -246,7 +246,7 @@ CheckFilename(JSContext *cx, jsid id, JSStackFrame *fp)
{ {
const char *filename; const char *filename;
if (fp && if (fp &&
(filename = fp->getScript()->filename) && (filename = JS_GetFrameScript(cx, fp)->filename) &&
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) { !strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
return JS_TRUE; return JS_TRUE;
} }

Просмотреть файл

@ -1310,8 +1310,8 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
JSStackFrame* fp = JS_GetScriptedCaller(cx, NULL); JSStackFrame* fp = JS_GetScriptedCaller(cx, NULL);
if(fp) if(fp)
{ {
script = fp->maybeScript(); script = JS_GetFrameScript(cx, fp);
callee = fp->callee(); callee = JS_GetFrameCalleeObject(cx, fp);
} }
} }
else if(ccx.GetXPCContext()->CallerTypeIsNative()) else if(ccx.GetXPCContext()->CallerTypeIsNative())

Просмотреть файл

@ -141,9 +141,9 @@ XPCJSStackFrame::CreateStack(JSContext* cx, JSStackFrame* fp,
{ {
NS_ADDREF(self); NS_ADDREF(self);
if(fp->down) if(fp->prev())
{ {
if(NS_FAILED(CreateStack(cx, fp->down, if(NS_FAILED(CreateStack(cx, fp->prev(),
(XPCJSStackFrame**) &self->mCaller))) (XPCJSStackFrame**) &self->mCaller)))
failed = JS_TRUE; failed = JS_TRUE;
} }

Просмотреть файл

@ -207,7 +207,7 @@ AccessCheck::isSystemOnlyAccessPermitted(JSContext *cx)
// Some code is running, we can't make the assumption, as above, but we // Some code is running, we can't make the assumption, as above, but we
// can't use a native frame, so clear fp. // can't use a native frame, so clear fp.
fp = NULL; fp = NULL;
} else if (!fp->hasScript()) { } else if (!JS_IsScriptFrame(cx, fp)) {
fp = NULL; fp = NULL;
} }
@ -222,7 +222,7 @@ AccessCheck::isSystemOnlyAccessPermitted(JSContext *cx)
static const char prefix[] = "chrome://global/"; static const char prefix[] = "chrome://global/";
const char *filename; const char *filename;
if (fp && if (fp &&
(filename = fp->getScript()->filename) && (filename = JS_GetFrameScript(cx, fp)->filename) &&
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) { !strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
return true; return true;
} }