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
// can't use a native frame, so clear fp.
fp = nsnull;
} else if (!fp->hasScript()) {
} else if (!JS_IsScriptFrame(cx, fp)) {
fp = nsnull;
}
@ -5447,8 +5447,8 @@ nsContentUtils::CanAccessNativeAnon()
// if they've been cloned into less privileged contexts.
static const char prefix[] = "chrome://global/";
const char *filename;
if (fp && fp->hasScript() &&
(filename = fp->getScript()->filename) &&
if (fp && JS_IsScriptFrame(cx, fp) &&
(filename = JS_GetFrameScript(cx, fp)->filename) &&
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
return PR_TRUE;
}

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

@ -90,6 +90,7 @@
#include "jsatominlines.h"
#include "jscntxtinlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h"
#include "jsscopeinlines.h"
#include "jscntxtinlines.h"
@ -1795,7 +1796,7 @@ JS_GetGlobalForScopeChain(JSContext *cx)
VOUCH_DOES_NOT_REQUIRE_STACK();
if (cx->hasfp())
return cx->fp()->getScopeChain()->getGlobal();
return cx->fp()->scopeChain().getGlobal();
JSObject *scope = cx->globalObject;
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,
// among other details. js_InvokeConstructor does the hard work.
InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, argc, args))
if (!cx->stack().pushInvokeArgs(cx, argc, &args))
return NULL;
args.callee().setObject(*ctor);
@ -4836,7 +4837,7 @@ JS_IsRunning(JSContext *cx)
#endif
JSStackFrame *fp = cx->maybefp();
while (fp && fp->isDummyFrame())
fp = fp->down;
fp = fp->prev();
return fp != NULL;
}

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

@ -1350,7 +1350,7 @@ array_toString(JSContext *cx, uintN argc, Value *vp)
LeaveTrace(cx);
InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, 0, args))
if (!cx->stack().pushInvokeArgs(cx, 0, &args))
return false;
args.callee() = join;
@ -1954,7 +1954,7 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp)
LeaveTrace(cx);
CompareArgs ca(cx, fval);
if (!cx->stack().pushInvokeArgs(cx, 2, ca.args))
if (!cx->stack().pushInvokeArgs(cx, 2, &ca.args))
return false;
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);
InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, argc, args))
if (!cx->stack().pushInvokeArgs(cx, argc, &args))
return JS_FALSE;
MUST_FLOW_THROUGH("out");

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

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

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

@ -76,6 +76,8 @@
#include "jstracer.h"
#include "jscntxtinlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h"
#ifdef XP_WIN
# include "jswin.h"
@ -112,13 +114,13 @@ StackSegment::contains(const JSStackFrame *fp) const
if (isActive()) {
JS_ASSERT(cx->hasfp());
start = cx->fp();
stop = cx->activeSegment()->initialFrame->down;
stop = cx->activeSegment()->initialFrame->prev();
} else {
JS_ASSERT(suspendedRegs && 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)
return true;
}
@ -199,7 +201,7 @@ StackSpace::bumpCommit(Value *from, ptrdiff_t nvals) const
}
#endif
JS_REQUIRES_STACK void
void
StackSpace::mark(JSTracer *trc)
{
/*
@ -215,33 +217,33 @@ StackSpace::mark(JSTracer *trc)
for (StackSegment *seg = currentSegment; seg; seg = seg->getPreviousInMemory()) {
if (seg->inContext()) {
/* This may be the only pointer to the initialVarObj. */
if (JSObject *varobj = seg->getInitialVarObj())
JS_CALL_OBJECT_TRACER(trc, varobj, "varobj");
if (seg->hasInitialVarObj())
MarkObject(trc, seg->getInitialVarObj(), "varobj");
/* Mark slots/args trailing off of the last stack frame. */
JSStackFrame *fp = seg->getCurrentFrame();
MarkStackRangeConservatively(trc, fp->slots(), end);
/* Mark stack frames and slots/args between stack frames. */
JSStackFrame *initialFrame = seg->getInitialFrame();
for (JSStackFrame *f = fp; f != initialFrame; f = f->down) {
JSStackFrame *initial = seg->getInitialFrame();
for (JSStackFrame *f = fp; f != initial; f = f->prev()) {
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. */
js_TraceStackFrame(trc, initialFrame);
MarkValueRange(trc, seg->getInitialArgBegin(), initialFrame->argEnd(), "stack");
/* Mark initial stack frame and leading args. */
js_TraceStackFrame(trc, initial);
MarkStackRangeConservatively(trc, seg->valueRangeBegin(), (Value *)initial);
} else {
/* 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
StackSpace::pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard &ag)
bool
StackSpace::pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard *ag)
{
Value *start = firstUnused();
ptrdiff_t nvals = VALUES_PER_STACK_SEGMENT + 2 + argc;
@ -252,24 +254,24 @@ StackSpace::pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard &ag)
seg->setPreviousInMemory(currentSegment);
currentSegment = seg;
ag.cx = cx;
ag.seg = seg;
ag.argv_ = seg->getInitialArgBegin() + 2;
ag.argc_ = argc;
ag->cx = cx;
ag->seg = seg;
ag->argv_ = seg->valueRangeBegin() + 2;
ag->argc_ = argc;
/* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */
#ifdef DEBUG
ag.prevInvokeSegment = invokeSegment;
ag->prevInvokeSegment = invokeSegment;
invokeSegment = seg;
ag.prevInvokeFrame = invokeFrame;
ag->prevInvokeFrame = invokeFrame;
invokeFrame = NULL;
#endif
ag.prevInvokeArgEnd = invokeArgEnd;
invokeArgEnd = ag.argv() + ag.argc();
ag->prevInvokeArgEnd = invokeArgEnd;
invokeArgEnd = ag->argv() + ag->argc();
return true;
}
JS_REQUIRES_STACK void
void
StackSpace::popSegmentForInvoke(const InvokeArgsGuard &ag)
{
JS_ASSERT(!currentSegment->inContext());
@ -286,44 +288,41 @@ StackSpace::popSegmentForInvoke(const InvokeArgsGuard &ag)
invokeArgEnd = ag.prevInvokeArgEnd;
}
/*
* Always push a segment when starting a new execute frame since segments
* provide initialVarObj, which may change.
*/
JS_REQUIRES_STACK bool
StackSpace::getExecuteFrame(JSContext *cx, JSStackFrame *down,
uintN vplen, uintN nfixed,
FrameGuard &fg) const
bool
StackSpace::getSegmentAndFrame(JSContext *cx, uintN vplen, uintN nfixed,
FrameGuard *fg) const
{
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))
return false;
fg.seg = new(start) StackSegment;
fg.vp = start + VALUES_PER_STACK_SEGMENT;
fg.fp = reinterpret_cast<JSStackFrame *>(fg.vp + vplen);
fg.down = down;
fg->seg_ = new(start) StackSegment;
fg->vp_ = start + VALUES_PER_STACK_SEGMENT;
fg->fp_ = reinterpret_cast<JSStackFrame *>(fg->vp() + vplen);
return true;
}
JS_REQUIRES_STACK void
StackSpace::pushExecuteFrame(JSContext *cx, FrameGuard &fg,
JSFrameRegs &regs, JSObject *initialVarObj)
void
StackSpace::pushSegmentAndFrame(JSContext *cx, JSObject *initialVarObj,
JSFrameRegs *regs, FrameGuard *fg)
{
fg.fp->down = fg.down;
StackSegment *seg = fg.seg;
/* Caller should have already initialized regs. */
JS_ASSERT(regs->fp == fg->fp());
/* Push segment. */
StackSegment *seg = fg->segment();
seg->setPreviousInMemory(currentSegment);
currentSegment = seg;
regs.fp = fg.fp;
cx->pushSegmentAndFrame(seg, regs);
/* Push frame. */
cx->pushSegmentAndFrame(seg, *regs);
seg->setInitialVarObj(initialVarObj);
fg.cx = cx;
fg->cx_ = cx;
}
JS_REQUIRES_STACK void
StackSpace::popFrame(JSContext *cx)
void
StackSpace::popSegmentAndFrame(JSContext *cx)
{
JS_ASSERT(isCurrentAndActive(cx));
JS_ASSERT(cx->hasActiveSegment());
@ -331,34 +330,78 @@ StackSpace::popFrame(JSContext *cx)
currentSegment = currentSegment->getPreviousInMemory();
}
JS_REQUIRES_STACK
FrameGuard::~FrameGuard()
{
if (!pushed())
return;
JS_ASSERT(cx->activeSegment() == seg);
JS_ASSERT(cx->maybefp() == fp);
cx->stack().popFrame(cx);
JS_ASSERT(cx_->activeSegment() == segment());
JS_ASSERT(cx_->maybefp() == fp());
cx_->stack().popSegmentAndFrame(cx_);
}
JS_REQUIRES_STACK bool
StackSpace::pushDummyFrame(JSContext *cx, FrameGuard &fg, JSFrameRegs &regs, JSObject *scopeChain)
bool
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;
JSStackFrame *fp = fg.getFrame();
PodZero(fp);
fp->setScopeChain(scopeChain);
fp->flags = JSFRAME_DUMMY;
regs.pc = NULL;
regs.sp = fp->slots();
pushExecuteFrame(cx, fg, regs, NULL);
fg->fp()->initDummyFrame(cx, scopeChain);
fg->regs_.fp = fg->fp();
fg->regs_.pc = NULL;
fg->regs_.sp = fg->fp()->slots();
pushSegmentAndFrame(cx, NULL /*varobj*/, &fg->regs_, fg);
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
FrameRegsIter::initSlow()
{
@ -377,35 +420,35 @@ FrameRegsIter::initSlow()
/*
* 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
* up-frame's address is the top of the down-frame's stack, modulo missing
* when a pair of prev-linked stack frames are in the same segment, the
* first frame's address is the top of the prev-frame's stack, modulo missing
* arguments.
*/
void
FrameRegsIter::incSlow(JSStackFrame *up, JSStackFrame *down)
FrameRegsIter::incSlow(JSStackFrame *fp, JSStackFrame *prev)
{
JS_ASSERT(down);
JS_ASSERT(curpc == down->savedPC);
JS_ASSERT(up == curseg->getInitialFrame());
JS_ASSERT(prev);
JS_ASSERT(curpc == prev->savedpc_);
JS_ASSERT(fp == curseg->getInitialFrame());
/*
* If the up-frame is in csup and the down-frame is in csdown, it is not
* necessarily the case that |csup->getPreviousInContext == csdown| or that
* |csdown->getSuspendedFrame == down| (because of indirect eval and
* JS_EvaluateInStackFrame). To compute down's sp, we need to do a linear
* scan, keeping track of what is immediately after down in memory.
* If fp is in cs and the prev-frame is in csprev, it is not necessarily
* the case that |cs->getPreviousInContext == csprev| or that
* |csprev->getSuspendedFrame == prev| (because of indirect eval and
* JS_EvaluateInStackFrame). To compute prev's sp, we need to do a linear
* scan, keeping track of what is immediately after prev in memory.
*/
curseg = curseg->getPreviousInContext();
cursp = curseg->getSuspendedRegs()->sp;
JSStackFrame *f = curseg->getSuspendedFrame();
while (f != down) {
while (f != prev) {
if (f == curseg->getInitialFrame()) {
curseg = curseg->getPreviousInContext();
cursp = curseg->getSuspendedRegs()->sp;
f = curseg->getSuspendedFrame();
} else {
cursp = contiguousDownFrameSP(f);
f = f->down;
cursp = f->formalArgsEnd();
f = f->prev();
}
}
}
@ -424,7 +467,7 @@ AllFramesIter::operator++()
curcs = curcs->getPreviousInMemory();
curfp = curcs ? curcs->getCurrentFrame() : NULL;
} else {
curfp = curfp->down;
curfp = curfp->prev();
}
return *this;
}
@ -1346,9 +1389,9 @@ PopulateReportBlame(JSContext *cx, JSErrorReport *report)
* Walk stack until we find a frame that is associated with some script
* 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)) {
report->filename = fp->getScript()->filename;
report->filename = fp->script()->filename;
report->lineno = js_FramePCToLineNumber(cx, fp);
break;
}
@ -1442,7 +1485,7 @@ checkReportFlags(JSContext *cx, uintN *flags)
* the nearest scripted frame is strict, see bug 536306.
*/
JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
if (fp && fp->getScript()->strictModeCode)
if (fp && fp->script()->strictModeCode)
*flags &= ~JSREPORT_WARNING;
else if (JS_HAS_STRICT_OPTION(cx))
*flags |= JSREPORT_WARNING;
@ -1917,8 +1960,8 @@ js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
if (!fp)
fp = js_GetTopStackFrame(cx);
while (fp && fp->isDummyFrame())
fp = fp->down;
JS_ASSERT_IF(fp, fp->hasScript());
fp = fp->prev();
JS_ASSERT_IF(fp, fp->isScriptFrame());
return fp;
}
@ -1938,7 +1981,7 @@ js_GetCurrentBytecodePC(JSContext* cx)
pc = cx->regs ? cx->regs->pc : NULL;
if (!pc)
return NULL;
imacpc = cx->fp()->maybeIMacroPC();
imacpc = cx->fp()->maybeImacropc();
}
/*
@ -1956,7 +1999,7 @@ js_CurrentPCIsInImacro(JSContext *cx)
VOUCH_DOES_NOT_REQUIRE_STACK();
if (JS_ON_TRACE(cx))
return cx->bailExit->imacpc != NULL;
return cx->fp()->hasIMacroPC();
return cx->fp()->hasImacropc();
#else
return false;
#endif
@ -2009,15 +2052,16 @@ JSContext::JSContext(JSRuntime *rt)
void
JSContext::pushSegmentAndFrame(js::StackSegment *newseg, JSFrameRegs &newregs)
{
JS_ASSERT(regs != &newregs);
if (hasActiveSegment()) {
JS_ASSERT(regs->fp->savedPC == JSStackFrame::sInvalidPC);
regs->fp->savedPC = regs->pc;
JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
regs->fp->savedpc_ = regs->pc;
currentSegment->suspend(regs);
}
newseg->setPreviousInContext(currentSegment);
currentSegment = newseg;
#ifdef DEBUG
newregs.fp->savedPC = JSStackFrame::sInvalidPC;
newregs.fp->savedpc_ = JSStackFrame::sInvalidpc;
#endif
setCurrentRegs(&newregs);
newseg->joinContext(this, newregs.fp);
@ -2028,7 +2072,7 @@ JSContext::popSegmentAndFrame()
{
JS_ASSERT(currentSegment->maybeContext() == this);
JS_ASSERT(currentSegment->getInitialFrame() == regs->fp);
JS_ASSERT(regs->fp->savedPC == JSStackFrame::sInvalidPC);
JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
currentSegment->leaveContext();
currentSegment = currentSegment->getPreviousInContext();
if (currentSegment) {
@ -2038,11 +2082,11 @@ JSContext::popSegmentAndFrame()
setCurrentRegs(currentSegment->getSuspendedRegs());
currentSegment->resume();
#ifdef DEBUG
regs->fp->savedPC = JSStackFrame::sInvalidPC;
regs->fp->savedpc_ = JSStackFrame::sInvalidpc;
#endif
}
} else {
JS_ASSERT(regs->fp->down == NULL);
JS_ASSERT(regs->fp->prev() == NULL);
setCurrentRegs(NULL);
}
}
@ -2052,8 +2096,8 @@ JSContext::saveActiveSegment()
{
JS_ASSERT(hasActiveSegment());
currentSegment->save(regs);
JS_ASSERT(regs->fp->savedPC == JSStackFrame::sInvalidPC);
regs->fp->savedPC = regs->pc;
JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
regs->fp->savedpc_ = regs->pc;
setCurrentRegs(NULL);
}
@ -2064,23 +2108,23 @@ JSContext::restoreSegment()
setCurrentRegs(ccs->getSuspendedRegs());
ccs->restore();
#ifdef DEBUG
regs->fp->savedPC = JSStackFrame::sInvalidPC;
regs->fp->savedpc_ = JSStackFrame::sInvalidpc;
#endif
}
JSGenerator *
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(!genStack.empty());
if (JS_LIKELY(fp == genStack.back()->liveFrame))
if (JS_LIKELY(fp == genStack.back()->liveFrame()))
return genStack.back();
/* General case; should only be needed for debug APIs. */
for (size_t i = 0; i < genStack.length(); ++i) {
if (genStack[i]->liveFrame == fp)
if (genStack[i]->liveFrame() == fp)
return genStack[i];
}
JS_NOT_REACHED("no matching generator");
@ -2100,8 +2144,8 @@ JSContext::containingSegment(const JSStackFrame *target)
JS_ASSERT(regs->fp);
JS_ASSERT(activeSegment() == seg);
JSStackFrame *f = regs->fp;
JSStackFrame *stop = seg->getInitialFrame()->down;
for (; f != stop; f = f->down) {
JSStackFrame *stop = seg->getInitialFrame()->prev();
for (; f != stop; f = f->prev()) {
if (f == target)
return seg;
}
@ -2111,8 +2155,8 @@ JSContext::containingSegment(const JSStackFrame *target)
/* A suspended segment's top frame is its suspended frame. */
for (; seg; seg = seg->getPreviousInContext()) {
JSStackFrame *f = seg->getSuspendedFrame();
JSStackFrame *stop = seg->getInitialFrame()->down;
for (; f != stop; f = f->down) {
JSStackFrame *stop = seg->getInitialFrame()->prev();
for (; f != stop; f = f->prev()) {
if (f == target)
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
* 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
* down-linked frames are adjacent in memory, separated only by the values that
* constitute the locals and expression stack of the down-frame and arguments
* of the up-frame.
* prev-linked frames are adjacent in memory, separated only by the values that
* constitute the locals and expression stack of the prev-frame.
*
* 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
* 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,
* for a segment |ss|, |ss->getInitialFrame()->down| may be non-null and in a
* are prev-linked, not all prev-linked frames are in the same segment. Hence,
* 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
* 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
@ -372,11 +371,7 @@ class StackSegment
/* Safe casts guaranteed by the contiguous-stack layout. */
Value *previousSegmentEnd() const {
return (Value *)this;
}
Value *getInitialArgBegin() const {
Value *valueRangeBegin() const {
return (Value *)(this + 1);
}
@ -515,9 +510,14 @@ class StackSegment
initialVarObj = obj;
}
JSObject *getInitialVarObj() const {
bool hasInitialVarObj() {
JS_ASSERT(inContext());
return initialVarObj;
return initialVarObj != NULL;
}
JSObject &getInitialVarObj() const {
JS_ASSERT(inContext() && initialVarObj);
return *initialVarObj;
}
#ifdef DEBUG
@ -559,33 +559,51 @@ struct InvokeArgsAlreadyOnTheStack : CallArgs
class InvokeFrameGuard
{
friend class StackSpace;
JSContext *cx; /* null implies nothing pushed */
JSFrameRegs regs;
JSFrameRegs *prevRegs;
JSContext *cx_; /* null implies nothing pushed */
JSFrameRegs regs_;
JSFrameRegs *prevRegs_;
public:
InvokeFrameGuard() : cx(NULL) {}
InvokeFrameGuard() : cx_(NULL) {}
JS_REQUIRES_STACK ~InvokeFrameGuard();
bool pushed() const { return cx != NULL; }
JSFrameRegs &getRegs() { return regs; }
bool pushed() const { return cx_ != NULL; }
JSStackFrame *fp() const { return regs_.fp; }
};
/* See StackSpace::pushExecuteFrame. */
/* Reusable base; not for direct use. */
class FrameGuard
{
friend class StackSpace;
JSContext *cx; /* null implies nothing pushed */
StackSegment *seg;
Value *vp;
JSStackFrame *fp;
JSStackFrame *down;
JSContext *cx_; /* null implies nothing pushed */
StackSegment *seg_;
Value *vp_;
JSStackFrame *fp_;
public:
FrameGuard() : cx(NULL), vp(NULL), fp(NULL) {}
FrameGuard() : cx_(NULL), vp_(NULL), fp_(NULL) {}
JS_REQUIRES_STACK ~FrameGuard();
bool pushed() const { return cx != NULL; }
Value *getvp() const { return vp; }
JSStackFrame *getFrame() const { return fp; }
bool pushed() const { return cx_ != NULL; }
StackSegment *segment() const { return seg_; }
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
*
@ -610,7 +628,7 @@ class FrameGuard
* |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
* Values that are marked during GC:
@ -653,7 +671,7 @@ class FrameGuard
* preserves order (in terms of previousInContext and previousInMemory,
* respectively).
* 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
{
@ -674,23 +692,42 @@ class StackSpace
#endif
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;
JS_REQUIRES_STACK inline void popInvokeArgs(const InvokeArgsGuard &args);
friend class InvokeFrameGuard;
JS_REQUIRES_STACK void popInvokeFrame(const InvokeFrameGuard &ag);
friend class FrameGuard;
JS_REQUIRES_STACK void popFrame(JSContext *cx);
/* Return a pointer to the first unused slot. */
JS_REQUIRES_STACK
bool pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard *ag);
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 bool isCurrentAndActive(JSContext *cx) const;
@ -714,6 +751,19 @@ class StackSpace
static const size_t COMMIT_VALS = 16 * 1024;
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. */
bool init();
void finish();
@ -735,6 +785,9 @@ class StackSpace
*/
inline bool ensureEnoughSpaceToEnterTrace();
/* See stubs::HitStackQuota. */
inline bool bumpCommitEnd(Value *from, uintN nslots);
/* +1 for slow native's stack frame. */
static const ptrdiff_t MAX_TRACE_SPACE_VALS =
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);
/*
* For all four use cases below:
* For all five use cases below:
* - The boolean-valued functions call js_ReportOutOfScriptQuota on OOM.
* - The "get*Frame" functions do not change any global state, they just
* check OOM and return pointers to an uninitialized frame with the
* requested missing arguments/slots. Only once the "push*Frame"
* function has been called is global state updated. Thus, between
* "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
* to pop the allocation. The caller must ensure the guard has the
* appropriate lifetime.
@ -765,66 +818,54 @@ class StackSpace
* Invoke calls. The InvokeArgumentsGuard passed to Invoke must come from
* 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. */
bool getInvokeFrame(JSContext *cx, const CallArgs &args,
uintN nmissing, uintN nfixed,
InvokeFrameGuard &fg) const;
bool getInvokeFrame(JSContext *cx, const CallArgs &args, JSFunction *fun,
JSScript *script, uint32 *flags, InvokeFrameGuard *fg) const;
JS_REQUIRES_STACK
void pushInvokeFrame(JSContext *cx, const CallArgs &args, InvokeFrameGuard &fg);
void pushInvokeFrame(JSContext *cx, const CallArgs &args, InvokeFrameGuard *fg);
/*
* For the simpler case when arguments are allocated at the same time as
* the frame and it is not necessary to have rooted argument values before
* 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);
/* These functions are called inside Execute, not Execute clients. */
bool getExecuteFrame(JSContext *cx, JSScript *script, ExecuteFrameGuard *fg) const;
void pushExecuteFrame(JSContext *cx, JSObject *initialVarObj, ExecuteFrameGuard *fg);
/*
* Since RAII cannot be used for inline frames, callers must manually
* call pushInlineFrame/popInlineFrame.
*/
JS_REQUIRES_STACK
inline JSStackFrame *getInlineFrame(JSContext *cx, Value *sp,
uintN nmissing, uintN nfixed) const;
inline JSStackFrame *getInlineFrame(JSContext *cx, Value *sp, uintN nactual,
JSFunction *fun, JSScript *script,
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
inline JSStackFrame *getInlineFrameUnchecked(JSContext *cx, Value *sp,
uintN nmissing) const;
/* These functions are called inside SendToGenerator. */
bool getGeneratorFrame(JSContext *cx, uintN vplen, uintN nfixed,
GeneratorFrameGuard *fg);
void pushGeneratorFrame(JSContext *cx, JSFrameRegs *regs, GeneratorFrameGuard *fg);
JS_REQUIRES_STACK
inline void pushInlineFrame(JSContext *cx, JSStackFrame *fp, jsbytecode *pc,
JSStackFrame *newfp);
/* Pushes a JSStackFrame::isDummyFrame. */
bool pushDummyFrame(JSContext *cx, JSObject &scopeChain, DummyFrameGuard *fg);
JS_REQUIRES_STACK
inline void popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down);
/* Check and bump the given stack limit. */
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
bool pushDummyFrame(JSContext *cx, FrameGuard &fg, JSFrameRegs &regs, JSObject *scopeChain);
inline Value *getStackLimit(JSContext *cx);
/*
* 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,
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;
bool bumpCommitAndLimit(JSStackFrame *base, Value *from, uintN nvals, Value **limit) const;
};
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
* 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|.
*
* Usage:
@ -847,8 +888,7 @@ class FrameRegsIter
jsbytecode *curpc;
void initSlow();
void incSlow(JSStackFrame *up, JSStackFrame *down);
static inline Value *contiguousDownFrameSP(JSStackFrame *up);
void incSlow(JSStackFrame *fp, JSStackFrame *prev);
public:
JS_REQUIRES_STACK inline FrameRegsIter(JSContext *cx);
@ -2155,10 +2195,10 @@ struct JSContext
JSStackFrame *findFrameAtLevel(uintN targetLevel) {
JSStackFrame *fp = this->regs->fp;
while (true) {
JS_ASSERT(fp && fp->hasScript());
if (fp->getScript()->staticLevel == targetLevel)
JS_ASSERT(fp && fp->isScriptFrame());
if (fp->script()->staticLevel == targetLevel)
break;
fp = fp->down;
fp = fp->prev();
}
return fp;
}
@ -2373,27 +2413,6 @@ js_TraceRegExpStatics(JSTracer *trc, JSContext *acx)
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
# define JS_THREAD_ID(cx) ((cx)->thread ? (cx)->thread->id : 0)
#endif
@ -2428,16 +2447,16 @@ class AutoCheckRequestDepth {
static inline uintN
FramePCOffset(JSContext *cx, JSStackFrame* fp)
{
jsbytecode *pc = fp->hasIMacroPC() ? fp->getIMacroPC() : fp->pc(cx);
return uintN(pc - fp->getScript()->code);
jsbytecode *pc = fp->hasImacropc() ? fp->imacropc() : fp->pc(cx);
return uintN(pc - fp->script()->code);
}
static inline JSAtom **
FrameAtomBase(JSContext *cx, JSStackFrame *fp)
{
return fp->hasIMacroPC()
return fp->hasImacropc()
? COMMON_ATOMS_START(&cx->runtime->atomState)
: fp->getScript()->atomMap.vector;
: fp->script()->atomMap.vector;
}
namespace js {

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

@ -108,63 +108,14 @@ StackSpace::isCurrentAndActive(JSContext *cx) const
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
StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
{
JS_ASSERT(from == firstUnused());
#ifdef XP_WIN
JS_ASSERT(from <= commitEnd);
if (commitEnd - from >= nvals)
return true;
if (JS_LIKELY(commitEnd - from >= nvals))
goto success;
if (end - from < nvals) {
if (maybecx)
js_ReportOutOfScriptQuota(maybecx);
@ -175,15 +126,20 @@ StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
js_ReportOutOfScriptQuota(maybecx);
return false;
}
return true;
goto success;
#else
if (end - from < nvals) {
if (JS_LIKELY(end - from < nvals)) {
if (maybecx)
js_ReportOutOfScriptQuota(maybecx);
return false;
}
return true;
goto success;
#endif
success:
#ifdef DEBUG
memset(from, 0xde, nvals * sizeof(js::Value));
#endif
return true;
}
JS_ALWAYS_INLINE bool
@ -195,8 +151,29 @@ StackSpace::ensureEnoughSpaceToEnterTrace()
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
StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard &ag)
StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard *ag)
{
if (JS_UNLIKELY(!isCurrentAndActive(cx)))
return pushSegmentForInvoke(cx, argc, ag);
@ -213,18 +190,18 @@ StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard &ag)
MakeValueRangeGCSafe(vp, vpend);
/* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */
ag.prevInvokeArgEnd = invokeArgEnd;
ag->prevInvokeArgEnd = invokeArgEnd;
invokeArgEnd = vpend;
#ifdef DEBUG
ag.prevInvokeSegment = invokeSegment;
ag->prevInvokeSegment = invokeSegment;
invokeSegment = currentSegment;
ag.prevInvokeFrame = invokeFrame;
ag->prevInvokeFrame = invokeFrame;
invokeFrame = cx->maybefp();
#endif
ag.cx = cx;
ag.argv_ = vp + 2;
ag.argc_ = argc;
ag->cx = cx;
ag->argv_ = vp + 2;
ag->argc_ = argc;
return true;
}
@ -256,61 +233,99 @@ InvokeArgsGuard::~InvokeArgsGuard()
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
StackSpace::getInvokeFrame(JSContext *cx, const CallArgs &args,
uintN nmissing, uintN nfixed,
InvokeFrameGuard &fg) const
JSFunction *fun, JSScript *script,
uint32 *flags, InvokeFrameGuard *fg) const
{
JS_ASSERT(firstUnused() == args.argv() + args.argc());
Value *start = args.argv() + args.argc();
ptrdiff_t nvals = nmissing + VALUES_PER_STACK_FRAME + nfixed;
if (!ensureSpace(cx, start, nvals))
return false;
fg.regs.fp = reinterpret_cast<JSStackFrame *>(start + nmissing);
return true;
Value *firstUnused = args.argv() + args.argc();
fg->regs_.fp = getCallFrame(cx, firstUnused, args.argc(), fun, script, flags,
EnsureSpaceCheck());
fg->regs_.sp = fg->regs_.fp->slots() + script->nfixed;
fg->regs_.pc = script->code;
return fg->regs_.fp != NULL;
}
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
StackSpace::pushInvokeFrame(JSContext *cx, const CallArgs &args,
InvokeFrameGuard &fg)
InvokeFrameGuard *fg)
{
JS_ASSERT(firstUnused() == args.argv() + args.argc());
JSStackFrame *fp = fg.regs.fp;
JSStackFrame *down = cx->maybefp();
fp->down = down;
JSStackFrame *fp = fg->regs_.fp;
JSStackFrame *prev = cx->maybefp();
fp->prev_ = prev;
if (JS_UNLIKELY(!currentSegment->inContext())) {
cx->pushSegmentAndFrame(currentSegment, fg.regs);
cx->pushSegmentAndFrame(currentSegment, fg->regs_);
} else {
#ifdef DEBUG
fp->savedPC = JSStackFrame::sInvalidPC;
JS_ASSERT(down->savedPC == JSStackFrame::sInvalidPC);
fp->savedpc_ = JSStackFrame::sInvalidpc;
JS_ASSERT(prev->savedpc_ == JSStackFrame::sInvalidpc);
#endif
down->savedPC = cx->regs->pc;
fg.prevRegs = cx->regs;
cx->setCurrentRegs(&fg.regs);
prev->savedpc_ = cx->regs->pc;
fg->prevRegs_ = cx->regs;
cx->setCurrentRegs(&fg->regs_);
}
fg.cx = cx;
fg->cx_ = cx;
JS_ASSERT(isCurrentAndActive(cx));
}
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
StackSpace::popInvokeFrame(const InvokeFrameGuard &fg)
{
JSContext *cx = fg.cx;
JSStackFrame *fp = fg.regs.fp;
JSContext *cx = fg.cx_;
JSStackFrame *fp = fg.regs_.fp;
JS_ASSERT(isCurrentAndActive(cx));
if (JS_UNLIKELY(currentSegment->getInitialFrame() == fp)) {
cx->popSegmentAndFrame();
} else {
JS_ASSERT(&fg.regs == cx->regs);
JS_ASSERT(fp->down == fg.prevRegs->fp);
cx->setCurrentRegs(fg.prevRegs);
JS_ASSERT(&fg.regs_ == cx->regs);
JS_ASSERT(fp->prev_ == fg.prevRegs_->fp);
cx->setCurrentRegs(fg.prevRegs_);
#ifdef DEBUG
cx->fp()->savedPC = JSStackFrame::sInvalidPC;
cx->fp()->savedpc_ = JSStackFrame::sInvalidpc;
#endif
}
}
@ -320,60 +335,92 @@ InvokeFrameGuard::~InvokeFrameGuard()
{
if (JS_UNLIKELY(!pushed()))
return;
cx->stack().popInvokeFrame(*this);
cx_->stack().popInvokeFrame(*this);
}
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
StackSpace::getInlineFrameUnchecked(JSContext *cx, Value *sp,
uintN nmissing) const
StackSpace::getInlineFrame(JSContext *cx, Value *sp, uintN nactual,
JSFunction *fun, JSScript *script, uint32 *flags) const
{
JS_ASSERT(isCurrentAndActive(cx));
JS_ASSERT(cx->hasActiveSegment());
JS_ASSERT(cx->regs->sp == sp);
JSStackFrame *fp = reinterpret_cast<JSStackFrame *>(sp + nmissing);
return fp;
return getCallFrame(cx, sp, nactual, fun, script, flags, EnsureSpaceCheck());
}
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
StackSpace::getInlineFrame(JSContext *cx, Value *sp,
uintN nmissing, uintN nfixed) 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)
StackSpace::getInlineFrameWithinLimit(JSContext *cx, Value *sp, uintN nactual,
JSFunction *fun, JSScript *script, uint32 *flags,
JSStackFrame *base, Value **limit) const
{
JS_ASSERT(isCurrentAndActive(cx));
JS_ASSERT(cx->hasActiveSegment());
JS_ASSERT(cx->regs->fp == up && up->down == down);
JS_ASSERT(up->savedPC == JSStackFrame::sInvalidPC);
JS_ASSERT(!up->hasIMacroPC());
JS_ASSERT(cx->regs->sp == sp);
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;
regs->fp = down;
regs->pc = down->savedPC;
regs->fp = prev;
regs->pc = prev->savedpc_;
regs->sp = newsp;
#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
}
@ -392,42 +439,22 @@ FrameRegsIter::FrameRegsIter(JSContext *cx)
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 &
FrameRegsIter::operator++()
{
JSStackFrame *up = curfp;
JSStackFrame *down = curfp = curfp->down;
if (!down)
JSStackFrame *fp = curfp;
JSStackFrame *prev = curfp = curfp->prev();
if (!prev)
return *this;
curpc = down->savedPC;
curpc = prev->savedpc_;
if (JS_UNLIKELY(up == curseg->getInitialFrame())) {
incSlow(up, down);
if (JS_UNLIKELY(fp == curseg->getInitialFrame())) {
incSlow(fp, prev);
return *this;
}
cursp = contiguousDownFrameSP(up);
cursp = fp->formalArgsEnd();
return *this;
}

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

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

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

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

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

@ -1894,7 +1894,7 @@ static bool
MakeUpvarForEval(JSParseNode *pn, JSCodeGenerator *cg)
{
JSContext *cx = cg->parser->context;
JSFunction *fun = cg->parser->callerFrame->getFunction();
JSFunction *fun = cg->parser->callerFrame->fun();
uintN upvarLevel = fun->u.i.script->staticLevel;
JSFunctionBox *funbox = cg->funbox;
@ -2077,8 +2077,8 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (cg->flags & TCF_IN_FOR_INIT)
return JS_TRUE;
JS_ASSERT(caller->hasScript());
if (!caller->hasFunction())
JS_ASSERT(caller->isScriptFrame());
if (!caller->isFunctionFrame())
return JS_TRUE;
/*
@ -2107,7 +2107,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
* defeats the display optimization to static link searching used
* 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);
unsigned skip = cg->staticLevel - fun->u.i.script->staticLevel;
if (cg->skipSpansGenerator(skip))
@ -2202,8 +2202,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
#ifdef DEBUG
JSStackFrame *caller = cg->parser->callerFrame;
#endif
JS_ASSERT(caller);
JS_ASSERT(caller->hasScript());
JS_ASSERT(caller->isScriptFrame());
JSTreeContext *tc = cg;
while (tc->staticLevel != level)
@ -2212,7 +2211,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
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

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

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

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

@ -88,6 +88,7 @@
#include "jsatominlines.h"
#include "jscntxtinlines.h"
#include "jsfuninlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h"
using namespace js;
@ -103,10 +104,10 @@ js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp)
{
JSObject *argsobj;
if (fp->flags & JSFRAME_OVERRIDE_ARGS) {
if (fp->hasOverriddenArgs()) {
JS_ASSERT(fp->hasCallObj());
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);
if (!argsobj)
@ -118,12 +119,14 @@ js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp)
JSBool
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());
jsid argumentsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
Value v;
if (!fp->getCallObj()->getProperty(cx, argumentsid, &v))
if (!fp->callObj().getProperty(cx, argumentsid, &v))
return false;
JSObject *obj;
@ -146,7 +149,7 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp)
if (argsobj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
return argsobj->getProperty(cx, id, vp);
}
*vp = fp->argv[arg];
*vp = fp->canonicalActualArg(arg);
} else {
/*
* 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 *
NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
{
JSObject *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);
/* Can't fail from here on, so initialize everything in argsobj. */
argsobj->init(callee->getFunctionPrivate()->inStrictMode()
argsobj->init(callee.getFunctionPrivate()->inStrictMode()
? &StrictArgumentsClass
: &js_ArgumentsClass,
proto, parent, NULL, cx);
@ -199,21 +202,24 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
argsobj->setArgsLength(argc);
argsobj->setArgsData(data);
data->callee = ObjectValue(*callee);
data->callee.setObject(callee);
return argsobj;
}
static void
PutArguments(JSContext *cx, JSObject *argsobj, Value *args)
namespace {
struct PutArg
{
JS_ASSERT(argsobj->isNormalArguments());
uint32 argc = argsobj->getArgsInitialLength();
ArgumentsData *data = argsobj->getArgsData();
for (uint32 i = 0; i != argc; ++i) {
if (!data->slots[i].isMagic(JS_ARGS_HOLE))
data->slots[i] = args[i];
PutArg(Value *dst) : dst(dst) {}
Value *dst;
void operator()(uintN, Value *src) {
if (!dst->isMagic(JS_ARGS_HOLE))
*dst = *src;
++dst;
}
};
}
JSObject *
@ -223,21 +229,18 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
* We must be in a function activation; the function must be lightweight
* or else fp must have a variable object.
*/
JS_ASSERT(fp->hasFunction());
JS_ASSERT_IF(fp->getFunction()->flags & JSFUN_HEAVYWEIGHT,
fp->varobj(cx->containingSegment(fp)));
JS_ASSERT_IF(fp->fun()->isHeavyweight(), fp->hasCallObj());
/* Skip eval and debugger frames. */
while (fp->flags & JSFRAME_SPECIAL)
fp = fp->down;
while (fp->isEvalOrDebuggerFrame())
fp = fp->prev();
/* Create an arguments object for fp only if it lacks one. */
if (fp->hasArgsObj())
return fp->getArgsObj();
return &fp->argsObj();
/* Compute the arguments object's parent slot from fp's scope chain. */
JSObject *global = fp->getScopeChain()->getGlobal();
JSObject *argsobj = NewArguments(cx, global, fp->numActualArgs(), &fp->argv[-2].toObject());
JSObject *global = fp->scopeChain().getGlobal();
JSObject *argsobj = NewArguments(cx, global, fp->numActualArgs(), fp->callee());
if (!argsobj)
return argsobj;
@ -251,26 +254,25 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
* retrieve up-to-date parameter values.
*/
if (argsobj->isStrictArguments())
memcpy(argsobj->getArgsData()->slots, fp->argv, fp->numActualArgs() * sizeof(Value));
fp->forEachCanonicalActualArg(PutArg(argsobj->getArgsData()->slots));
else
argsobj->setPrivate(fp);
fp->setArgsObj(argsobj);
fp->setArgsObj(*argsobj);
return argsobj;
}
void
js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
{
JSObject *argsobj = fp->getArgsObj();
if (argsobj->isNormalArguments()) {
JS_ASSERT(argsobj->getPrivate() == fp);
PutArguments(cx, argsobj, fp->argv);
argsobj->setPrivate(NULL);
JSObject &argsobj = fp->argsObj();
if (argsobj.isNormalArguments()) {
JS_ASSERT(argsobj.getPrivate() == fp);
fp->forEachCanonicalActualArg(PutArg(argsobj.getArgsData()->slots));
argsobj.setPrivate(NULL);
} else {
JS_ASSERT(!argsobj->getPrivate());
JS_ASSERT(!argsobj.getPrivate());
}
fp->setArgsObj(NULL);
}
#ifdef JS_TRACER
@ -279,9 +281,9 @@ js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
* Traced versions of js_GetArgsObject and js_PutArgsObject.
*/
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)
return NULL;
@ -297,20 +299,32 @@ js_Arguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
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)
/* FIXME change the return type to void. */
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->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);
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)
#endif /* JS_TRACER */
@ -496,7 +510,8 @@ ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
if (arg < obj->getArgsInitialLength()) {
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
if (fp) {
*vp = fp->argv[arg];
JS_ASSERT(fp->numActualArgs() == obj->getArgsInitialLength());
*vp = fp->canonicalActualArg(arg);
} else {
const Value &v = obj->getArgsElement(arg);
if (!v.isMagic(JS_ARGS_HOLE))
@ -551,7 +566,7 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
if (arg < obj->getArgsInitialLength()) {
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
if (fp) {
fp->argv[arg] = *vp;
fp->canonicalActualArg(arg) = *vp;
return true;
}
}
@ -800,7 +815,7 @@ MaybeMarkGenerator(JSTracer *trc, JSObject *obj)
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
if (fp && fp->isFloatingGenerator()) {
JSObject *genobj = js_FloatingFrameToGenerator(fp)->obj;
MarkObject(trc, genobj, "generator object");
MarkObject(trc, *genobj, "generator object");
}
#endif
}
@ -816,7 +831,7 @@ args_trace(JSTracer *trc, JSObject *obj)
ArgumentsData *data = obj->getArgsData();
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);
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
* 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 *
NewCallObject(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
NewCallObject(JSContext *cx, JSFunction *fun, JSObject &scopeChain, JSObject &callee)
{
JSObject *callobj = js_NewGCObject(cx);
if (!callobj)
return NULL;
callobj->init(&js_CallClass, NULL, scopeChain, NULL, cx);
callobj->init(&js_CallClass, NULL, &scopeChain, NULL, cx);
callobj->setMap(fun->u.i.names);
/* This must come after callobj->lastProp has been set. */
@ -973,6 +984,8 @@ NewCallObject(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
}
}
#endif
callobj->setCallObjCallee(callee);
return callobj;
}
@ -983,7 +996,7 @@ NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
if (!envobj)
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);
return envobj;
}
@ -992,17 +1005,17 @@ JSObject *
js_GetCallObject(JSContext *cx, JSStackFrame *fp)
{
/* Create a call object for fp only if it lacks one. */
JS_ASSERT(fp->hasFunction());
JS_ASSERT(fp->isFunctionFrame());
if (fp->hasCallObj())
return fp->getCallObj();
return &fp->callObj();
#ifdef DEBUG
/* 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)
JS_ASSERT(fp->getScopeChain()->getPrivate() != js_FloatingFrameIfGenerator(cx, fp));
JS_ASSERT(fp->scopeChain().getPrivate() != js_FloatingFrameIfGenerator(cx, fp));
else if (clasp == &js_CallClass)
JS_ASSERT(fp->getScopeChain()->getPrivate() != fp);
JS_ASSERT(fp->scopeChain().getPrivate() != fp);
#endif
/*
@ -1012,17 +1025,16 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
* function's name.
*/
JSAtom *lambdaName =
(fp->getFunction()->flags & JSFUN_LAMBDA) ? fp->getFunction()->atom : NULL;
(fp->fun()->flags & JSFUN_LAMBDA) ? fp->fun()->atom : NULL;
if (lambdaName) {
JSObject *envobj = NewDeclEnvObject(cx, fp);
if (!envobj)
return NULL;
/* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */
fp->setScopeChain(envobj);
JS_ASSERT(fp->argv);
if (!js_DefineNativeProperty(cx, fp->getScopeChain(), ATOM_TO_JSID(lambdaName),
fp->calleeValue(),
fp->setScopeChainNoCallObj(*envobj);
if (!js_DefineNativeProperty(cx, &fp->scopeChain(), ATOM_TO_JSID(lambdaName),
ObjectValue(fp->callee()),
CalleeGetter, NULL,
JSPROP_PERMANENT | JSPROP_READONLY,
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)
return NULL;
callobj->setPrivate(fp);
JS_ASSERT(fp->argv);
JS_ASSERT(fp->getFunction() == GET_FUNCTION_PRIVATE(cx, fp->callee()));
callobj->setSlot(JSSLOT_CALLEE, fp->calleeValue());
fp->setCallObj(callobj);
JS_ASSERT(fp->fun() == fp->callee().getFunctionPrivate());
/*
* Push callobj on the top of the scope chain, and make it the
* variables object.
*/
fp->setScopeChain(callobj);
fp->setScopeChainAndCallObj(*callobj);
return callobj;
}
@ -1052,38 +1061,22 @@ JSObject * JS_FASTCALL
js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain)
{
JS_ASSERT(!js_IsNamedLambda(fun));
JSObject *callobj = NewCallObject(cx, fun, scopeChain);
if (!callobj)
return NULL;
callobj->setSlot(JSSLOT_CALLEE, ObjectValue(*callee));
return callobj;
JS_ASSERT(scopeChain);
return NewCallObject(cx, fun, *scopeChain, *callee);
}
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTION, OBJECT, OBJECT,
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
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. */
uintN first = JSSLOT_PRIVATE + CALL_CLASS_RESERVED_SLOTS + 1;
uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
Value *vp = &callobj->fslots[first];
uintN len = JS_MIN(nargs, JS_INITIAL_NSLOTS - first);
Value *vp = &callobj.fslots[first];
uintN len = Min(nargs, uintN(JS_INITIAL_NSLOTS) - first);
memcpy(vp, argv, len * sizeof(Value));
vp += len;
@ -1091,7 +1084,7 @@ CopyValuesToCallObject(JSObject *callobj, uintN nargs, Value *argv, uintN nvars,
nargs -= len;
if (nargs != 0) {
/* Copy any remaining args into dslots. */
vp = callobj->dslots;
vp = callobj.dslots;
memcpy(vp, argv + len, nargs * sizeof(Value));
vp += nargs;
} else {
@ -1101,7 +1094,7 @@ CopyValuesToCallObject(JSObject *callobj, uintN nargs, Value *argv, uintN nvars,
memcpy(vp, slots, len * sizeof(Value));
slots += len;
nvars -= len;
vp = callobj->dslots;
vp = callobj.dslots;
}
/* Copy any remaining vars into dslots. */
@ -1111,17 +1104,17 @@ CopyValuesToCallObject(JSObject *callobj, uintN nargs, Value *argv, uintN nvars,
void
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. */
if (fp->hasArgsObj()) {
if (!(fp->flags & JSFRAME_OVERRIDE_ARGS))
callobj->setSlot(JSSLOT_CALL_ARGUMENTS, ObjectOrNullValue(fp->getArgsObj()));
if (!fp->hasOverriddenArgs())
callobj.setCallObjArguments(ObjectValue(fp->argsObj()));
js_PutArgsObject(cx, fp);
}
JSFunction *fun = fp->getFunction();
JS_ASSERT(fun == js_GetCallObjectFunction(callobj));
JSFunction *fun = fp->fun();
JS_ASSERT(fun == callobj.getCallObjCalleeFunction());
uintN n = fun->countArgsAndVars();
/*
@ -1129,52 +1122,52 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
* arguments and variables straight into JSObject.dslots.
*/
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS - JSSLOT_PRIVATE ==
1 + CALL_CLASS_RESERVED_SLOTS);
1 + JSObject::CALL_RESERVED_SLOTS);
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 nvars = fun->u.i.nvars;
#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) {
memcpy(callobj->dslots + nargs, fp->slots(), nvars * sizeof(Value));
memcpy(callobj.dslots + nargs, fp->slots(), nvars * sizeof(Value));
} else if (script->jit) {
for (uint32 i = 0; i < script->jit->nescaping; i++) {
uint32 e = script->jit->escaping[i];
callobj->dslots[nargs + e] = fp->slots()[e];
callobj.dslots[nargs + e] = fp->slots()[e];
}
}
#else
CopyValuesToCallObject(callobj, nargs, fp->argv, nvars, fp->slots());
CopyValuesToCallObject(callobj, nargs, fp->formalArgs(), nvars, fp->slots());
#endif
}
/* Clear private pointers to fp, which is about to go away (js_Invoke). */
if (js_IsNamedLambda(fun)) {
JSObject *env = callobj->getParent();
JSObject *env = callobj.getParent();
JS_ASSERT(env->getClass() == &js_DeclEnvClass);
JS_ASSERT(env->getPrivate() == fp);
env->setPrivate(NULL);
}
callobj->setPrivate(NULL);
fp->setCallObj(NULL);
callobj.setPrivate(NULL);
}
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)
{
JS_ASSERT(scopeChain->hasClass(&js_CallClass));
JS_ASSERT(!scopeChain->getPrivate());
JS_ASSERT(callobj->isCall());
JS_ASSERT(!callobj->getPrivate());
uintN n = nargs + nvars;
if (n != 0)
CopyValuesToCallObject(scopeChain, nargs, argv, nvars, slots);
CopyValuesToCallObject(*callobj, nargs, argv, nvars, slots);
return true;
}
@ -1203,17 +1196,17 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
Value *array;
if (kind == JSCPK_UPVAR) {
JSObject *callee = &obj->getSlot(JSSLOT_CALLEE).toObject();
JSObject &callee = obj->getCallObjCallee();
#ifdef DEBUG
JSFunction *callee_fun = (JSFunction *) callee->getPrivate();
JSFunction *callee_fun = (JSFunction *) callee.getPrivate();
JS_ASSERT(FUN_FLAT_CLOSURE(callee_fun));
JS_ASSERT(i < callee_fun->u.i.nupvars);
#endif
array = callee->getFlatClosureUpvars();
array = callee.getFlatClosureUpvars();
} else {
JSFunction *fun = js_GetCallObjectFunction(obj);
JSFunction *fun = obj->getCallObjCalleeFunction();
JS_ASSERT_IF(kind == JSCPK_ARG, i < fun->nargs);
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 (setter) {
if (fp)
fp->flags |= JSFRAME_OVERRIDE_ARGS;
obj->setSlot(JSSLOT_CALL_ARGUMENTS, *vp);
fp->setOverriddenArgs();
obj->setCallObjArguments(*vp);
} else {
if (fp && !(fp->flags & JSFRAME_OVERRIDE_ARGS)) {
if (fp && !fp->hasOverriddenArgs()) {
JSObject *argsobj;
argsobj = js_GetArgsObject(cx, fp);
@ -1233,7 +1226,7 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
return false;
vp->setObject(*argsobj);
} else {
*vp = obj->getSlot(JSSLOT_CALL_ARGUMENTS);
*vp = obj->getCallObjArguments();
}
}
return true;
@ -1245,13 +1238,13 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
else
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 <= JS_INITIAL_NSLOTS);
array = (i < JS_INITIAL_NSLOTS - first) ? obj->fslots : obj->dslots;
} else if (kind == JSCPK_ARG) {
array = fp->argv;
array = fp->formalArgs();
} else {
JS_ASSERT(kind == JSCPK_VAR);
array = fp->slots();
@ -1354,13 +1347,8 @@ call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
if (!JSID_IS_ATOM(id))
return JS_TRUE;
const Value &callee = obj->getSlot(JSSLOT_CALLEE);
if (callee.isUndefined())
return JS_TRUE;
#ifdef DEBUG
JSFunction *fun;
fun = GET_FUNCTION_PRIVATE(cx, &callee.toObject());
JSFunction *fun = obj->getCallObjCalleeFunction();
JS_ASSERT(fun->lookupLocal(cx, JSID_TO_ATOM(id), NULL) == JSLOCAL_NONE);
#endif
@ -1396,10 +1384,10 @@ call_trace(JSTracer *trc, JSObject *obj)
* cycles involving Call objects whose frames are active without this
* 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);
uintN count = fp->getFunction()->countArgsAndVars();
uintN count = fp->fun()->countArgsAndVars();
uintN fixed = JS_MIN(count, JS_INITIAL_NSLOTS - first);
SetValueRangeToUndefined(&obj->fslots[first], fixed);
@ -1412,7 +1400,7 @@ call_trace(JSTracer *trc, JSObject *obj)
JS_PUBLIC_DATA(Class) js_CallClass = {
"Call",
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,
PropertyStub, /* addProperty */
PropertyStub, /* delProperty */
@ -1434,12 +1422,12 @@ JS_PUBLIC_DATA(Class) js_CallClass = {
bool
JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
{
if (!hasFunction()) {
*vp = argv ? argv[-2] : UndefinedValue();
if (!isFunctionFrame()) {
vp->setUndefined();
return true;
}
JSFunction *fun = getFunction();
JSFunction *fun = this->fun();
/*
* See the equivalent condition in ArgGetter for the 'callee' id case, but
@ -1455,19 +1443,20 @@ JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
return true;
}
JSObject *funobj = &calleeObject();
vp->setObject(*funobj);
JSObject &funobj = callee();
vp->setObject(funobj);
/*
* 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
* atom by which it was uniquely associated with a property.
*/
if (getThisValue().isObject()) {
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
const Value &thisv = functionThis();
if (thisv.isObject()) {
JS_ASSERT(funobj.getFunctionPrivate() == fun);
if (fun == funobj && fun->methodAtom()) {
JSObject *thisp = &getThisValue().toObject();
if (&fun->compiledFunObj() == &funobj && fun->methodAtom()) {
JSObject *thisp = &thisv.toObject();
JS_ASSERT(thisp->canHaveMethodBarrier());
if (thisp->hasMethodBarrier()) {
@ -1486,10 +1475,10 @@ JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
* been replaced, or its value to have been overwritten.
*/
if (shape) {
if (shape->isMethod() && &shape->methodObject() == funobj) {
if (shape->isMethod() && &shape->methodObject() == &funobj) {
if (!thisp->methodReadBarrier(cx, *shape, vp))
return false;
setCalleeObject(vp->toObject());
calleeValue().setObject(vp->toObject());
return true;
}
if (shape->hasSlot()) {
@ -1499,9 +1488,9 @@ JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
if (IsFunctionObject(v, &clone) &&
GET_FUNCTION_PRIVATE(cx, clone) == fun &&
clone->hasMethodObj(*thisp)) {
JS_ASSERT(clone != funobj);
JS_ASSERT(clone != &funobj);
*vp = v;
setCalleeObject(*clone);
calleeValue().setObject(*clone);
return true;
}
}
@ -1515,11 +1504,11 @@ JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
* access. It seems that there are no longer any properties
* referring to fun.
*/
funobj = CloneFunctionObject(cx, fun, fun->getParent());
if (!funobj)
JSObject *newfunobj = CloneFunctionObject(cx, fun, fun->getParent());
if (!newfunobj)
return false;
funobj->setMethodObj(*thisp);
setCalleeObject(*funobj);
newfunobj->setMethodObj(*thisp);
calleeValue().setObject(*newfunobj);
return true;
}
}
@ -1579,8 +1568,8 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
/* Find fun's top-most activation record. */
JSStackFrame *fp;
for (fp = js_GetTopStackFrame(cx);
fp && (fp->maybeFunction() != fun || (fp->flags & JSFRAME_SPECIAL));
fp = fp->down) {
fp && (fp->maybeFun() != fun || fp->isEvalOrDebuggerFrame());
fp = fp->prev()) {
continue;
}
@ -1614,7 +1603,7 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
case FUN_CALLER:
vp->setNull();
if (fp && fp->down && !fp->down->getValidCalleeObject(cx, vp))
if (fp && fp->prev() && !fp->prev()->getValidCalleeObject(cx, vp))
return false;
if (vp->isObject()) {
@ -1633,8 +1622,8 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
default:
/* XXX fun[0] and fun.arguments[0] are equivalent. */
if (fp && fp->hasFunction() && uint16(slot) < fp->getFunction()->nargs)
*vp = fp->argv[slot];
if (fp && fp->isFunctionFrame() && uint16(slot) < fp->numFormalArgs())
*vp = fp->formalArg(slot);
break;
}
@ -2067,7 +2056,7 @@ fun_trace(JSTracer *trc, JSObject *obj)
if (fun != obj) {
/* 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. */
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. */
InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, argc, args))
if (!cx->stack().pushInvokeArgs(cx, argc, &args))
return JS_FALSE;
/* Push fval, obj, and the args. */
@ -2275,6 +2264,24 @@ js_fun_call(JSContext *cx, uintN argc, Value *vp)
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 */
JSBool
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));
InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, n, args))
if (!cx->stack().pushInvokeArgs(cx, n, &args))
return false;
/* 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();
Value *argv = args.argv();
if (fp) {
memcpy(argv, fp->argv, n * sizeof(Value));
for (uintN i = 0; i < n; i++) {
if (aobj->getArgsElement(i).isMagic(JS_ARGS_HOLE)) // suppress deleted element
argv[i].setUndefined();
}
JS_ASSERT(fp->numActualArgs() <= JS_ARGS_LENGTH_MAX);
fp->forEachCanonicalActualArg(CopyNonHoleArgs(aobj, argv));
} else {
for (uintN i = 0; i < n; i++) {
argv[i] = aobj->getArgsElement(i);
@ -2489,7 +2493,7 @@ CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
const Value &boundThis = obj->getBoundFunctionThis();
InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, argc + argslen, args))
if (!cx->stack().pushInvokeArgs(cx, argc + argslen, &args))
return false;
/* 15.3.4.5.1, 15.3.4.5.2 step 4. */
@ -2991,8 +2995,8 @@ js_NewFlatClosure(JSContext *cx, JSFunction *fun)
JSObject *
js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun)
{
JS_ASSERT(cx->fp()->getFunction()->flags & JSFUN_HEAVYWEIGHT);
JS_ASSERT(!cx->fp()->getFunction()->optimizedClosure());
JS_ASSERT(cx->fp()->fun()->flags & JSFUN_HEAVYWEIGHT);
JS_ASSERT(!cx->fp()->fun()->optimizedClosure());
JS_ASSERT(FUN_FLAT_CLOSURE(fun));
return WrapEscapingClosure(cx, cx->fp(), fun);
@ -3094,7 +3098,7 @@ js_ReportIsNotFunction(JSContext *cx, const Value *vp, uintN flags)
++i;
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;
JS_ASSERT(simsp <= i.sp());
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;
uint16 *indexp;
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) {
JS_ASSERT(u.i.nupvars == 0);

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

@ -169,7 +169,6 @@ struct JSFunction : public JSObject
bool isNative() const { return !FUN_INTERPRETED(this); }
bool isConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
unsigned minArgs() const { return isInterpreted() ? nargs : 0; }
inline bool inStrictMode() const;
@ -254,6 +253,10 @@ struct JSFunction : public JSObject
return flags & JSFUN_JOINABLE;
}
JSObject &compiledFunObj() {
return *this;
}
private:
/*
* 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;
}
JSScript *script() const {
JS_ASSERT(isInterpreted());
return u.i.script;
}
/* Number of extra fixed function object slots besides JSSLOT_PRIVATE. */
static const uint32 CLASS_RESERVED_SLOTS = JSObject::FUN_CLASS_RESERVED_SLOTS;
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_FunctionClass;
extern js::Class js_DeclEnvClass;
extern const uint32 CALL_CLASS_RESERVED_SLOTS;
inline bool
JSObject::isCall() const
@ -551,9 +558,6 @@ extern JSBool JS_FASTCALL
js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs,
js::Value *argv, uint32 nvars, js::Value *slots);
extern JSFunction *
js_GetCallObjectFunction(JSObject *obj);
extern JSBool
js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);

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

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

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

@ -599,11 +599,10 @@ MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name)
}
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);
Mark(trc, obj, JSTRACE_OBJECT);
Mark(trc, &obj, JSTRACE_OBJECT);
}
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
#include "jscntxtinlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h"
#include "jsstrinlines.h"
@ -121,7 +122,7 @@ NativeIterator::mark(JSTracer *trc)
else
MarkValueRange(trc, beginValue(), endValue(), "props");
if (obj)
MarkObject(trc, obj, "obj");
MarkObject(trc, *obj, "obj");
}
static void
@ -1088,11 +1089,11 @@ generator_trace(JSTracer *trc, JSObject *obj)
if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING)
return;
JSStackFrame *fp = gen->getFloatingFrame();
JS_ASSERT(gen->getLiveFrame() == fp);
MarkValueRange(trc, gen->floatingStack, fp->argEnd(), "generator slots");
JSStackFrame *fp = gen->floatingFrame();
JS_ASSERT(gen->liveFrame() == fp);
MarkValueRange(trc, gen->floatingStack, fp->formalArgsEnd(), "generator slots");
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 = {
@ -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
* to the frame by which the generator function was activated. Create a new
@ -1138,65 +1146,42 @@ js_NewGenerator(JSContext *cx)
if (!obj)
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. */
JSStackFrame *fp = cx->fp();
uintN argc = fp->numActualArgs();
uintN nargs = JS_MAX(argc, fp->numFormalArgs());
uintN vplen = 2 + nargs;
Value *stackvp = stackfp->actualArgs() - 2;
uintN vplen = stackfp->formalArgsEnd() - stackvp;
/* Compute JSGenerator size. */
uintN nbytes = sizeof(JSGenerator) +
(-1 + /* one Value included in JSGenerator */
vplen +
VALUES_PER_STACK_FRAME +
fp->getSlotCount()) * sizeof(Value);
stackfp->numSlots()) * sizeof(Value);
JSGenerator *gen = (JSGenerator *) cx->malloc(nbytes);
if (!gen)
return NULL;
/* Cut up floatingStack space. */
Value *vp = gen->floatingStack;
JSStackFrame *newfp = reinterpret_cast<JSStackFrame *>(vp + vplen);
Value *slots = newfp->slots();
Value *genvp = gen->floatingStack;
JSStackFrame *genfp = reinterpret_cast<JSStackFrame *>(genvp + vplen);
/* Initialize JSGenerator. */
gen->obj = obj;
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->liveFrame = newfp;
gen->floating = genfp;
/* Copy generator's stack frame copy in from |cx->fp|. */
newfp->setCallObj(fp->maybeCallObj());
if (fp->hasCallObj()) { /* Steal call object. */
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());
/* Initialize regs stored in generator. */
gen->regs = *cx->regs;
RebaseRegsFromTo(&gen->regs, stackfp, genfp);
/* Copy in arguments and slots. */
memcpy(vp, fp->argv - 2, vplen * sizeof(Value));
memcpy(slots, fp->slots(), fp->getFixedCount() * sizeof(Value));
/* Copy frame off the stack. */
genfp->stealFrameAndSlots(genvp, stackfp, stackvp, cx->regs->sp);
genfp->initFloatingGenerator();
obj->setPrivate(gen);
return obj;
@ -1205,8 +1190,8 @@ js_NewGenerator(JSContext *cx)
JSGenerator *
js_FloatingFrameToGenerator(JSStackFrame *fp)
{
JS_ASSERT(fp->isGenerator() && fp->isFloatingGenerator());
char *floatingStackp = (char *)(fp->argv - 2);
JS_ASSERT(fp->isGeneratorFrame() && fp->isFloatingGenerator());
char *floatingStackp = (char *)(fp->actualArgs() - 2);
char *p = floatingStackp - offsetof(JSGenerator, floatingStack);
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) {
js_ReportValueError(cx, JSMSG_NESTING_GENERATOR,
JSDVG_SEARCH_STACK, ObjectOrNullValue(obj),
JS_GetFunctionId(gen->getFloatingFrame()->getFunction()));
JS_GetFunctionId(gen->floatingFrame()->fun()));
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
* expression.
*/
gen->savedRegs.sp[-1] = arg;
gen->regs.sp[-1] = arg;
}
gen->state = JSGEN_RUNNING;
break;
@ -1263,96 +1248,63 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
break;
}
JSStackFrame *genfp = gen->getFloatingFrame();
JSStackFrame *genfp = gen->floatingFrame();
Value *genvp = gen->floatingStack;
uintN vplen = genfp->formalArgsEnd() - genvp;
JSStackFrame *stackfp;
Value *stackvp;
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
* the code before pushExecuteFrame must not reenter the interpreter.
*/
FrameGuard frame;
if (!cx->stack().getExecuteFrame(cx, cx->maybefp(), vplen, nfixed, frame)) {
GeneratorFrameGuard frame;
if (!cx->stack().getGeneratorFrame(cx, vplen, genfp->numSlots(), &frame)) {
gen->state = JSGEN_CLOSED;
return JS_FALSE;
}
stackfp = frame.fp();
stackvp = frame.vp();
Value *vp = frame.getvp();
JSStackFrame *fp = frame.getFrame();
/* Copy frame onto the stack. */
stackfp->stealFrameAndSlots(stackvp, genfp, genvp, gen->regs.sp);
stackfp->repointGeneratorFrameDown(cx->maybefp());
stackfp->unsetFloatingGenerator();
RebaseRegsFromTo(&gen->regs, genfp, stackfp);
MUST_FLOW_THROUGH("restore");
/*
* Copy and rebase stack frame/args/slots. The "floating" flag must
* 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());
/* Officially push frame. frame's destructor pops. */
cx->stack().pushGeneratorFrame(cx, &gen->regs, &frame);
#ifdef DEBUG
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. */
cx->enterGenerator(gen); /* OOM check above. */
JSObject *enumerators = cx->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;
cx->enumerators = enumerators;
/* Restore call/args/block objects. */
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 and rebase stack frame/args/slots. Restore "floating" flag. */
JS_ASSERT(uintN(gen->savedRegs.sp - fp->slots()) <= fp->getSlotCount());
uintN usedAfter = gen->savedRegs.sp - vp;
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());
/*
* Copy the stack frame and rebase the regs, but not before popping
* the stack, since cx->regs == &gen->regs.
*/
genfp->stealFrameAndSlots(genvp, stackfp, stackvp, gen->regs.sp);
genfp->setFloatingGenerator();
}
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. */
JS_ASSERT(ok);
JS_ASSERT(!cx->throwing);
JS_ASSERT(gen->state == JSGEN_RUNNING);
JS_ASSERT(op != JSGENOP_CLOSE);
genfp->flags &= ~JSFRAME_YIELDING;
genfp->clearYielding();
gen->state = JSGEN_OPEN;
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);
if (!SendToGenerator(cx, op, obj, gen, undef ? vp[2] : UndefinedValue()))
return JS_FALSE;
*vp = gen->getFloatingFrame()->getReturnValue();
*vp = gen->floatingFrame()->returnValue();
return JS_TRUE;
}

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

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

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

@ -78,6 +78,7 @@
#include "jsdbgapi.h"
#include "json.h"
#include "jsinterpinlines.h"
#include "jsscopeinlines.h"
#include "jsscriptinlines.h"
#include "jsobjinlines.h"
@ -951,7 +952,7 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
#endif
JS_ASSERT(principals || !(callbacks && callbacks->findObjectPrincipals));
flags = JS_GetScriptFilenameFlags(caller->getScript());
flags = JS_GetScriptFilenameFlags(caller->script());
if ((flags & JSFILENAME_PROTECTED) &&
principals &&
strcmp(principals->codebase, "[System Principal]")) {
@ -960,13 +961,13 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
}
jsbytecode *pc = caller->pc(cx);
if (pc && js_GetOpcode(cx, caller->getScript(), pc) == JSOP_EVAL) {
JS_ASSERT(js_GetOpcode(cx, caller->getScript(), pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
if (pc && js_GetOpcode(cx, caller->script(), pc) == JSOP_EVAL) {
JS_ASSERT(js_GetOpcode(cx, caller->script(), pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
*linenop = GET_UINT16(pc + JSOP_EVAL_LENGTH);
} else {
*linenop = js_FramePCToLineNumber(cx, caller);
}
return caller->getScript()->filename;
return caller->script()->filename;
}
#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
* 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[] =
"Support for eval(code, scopeObject) has been removed. "
"Use |with (scopeObject) eval(code);| instead.";
if (!JS_ReportWarning(cx, TWO_ARGUMENT_WARNING))
return JS_FALSE;
caller->getScript()->warnedAboutTwoArgumentEval = true;
caller->script()->warnedAboutTwoArgumentEval = true;
}
/* From here on, control must exit through label out with ok set. */
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
@ -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.
*/
JS_ASSERT_IF(caller->argv, caller->hasCallObj());
JS_ASSERT_IF(caller->isFunctionFrame(), caller->hasCallObj());
scopeobj = callerScopeChain;
}
#endif
@ -1162,7 +1163,7 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
* calls to eval from global code are not cached.
*/
JSScript **bucket = EvalCacheHash(cx, str);
if (!indirectCall && caller->hasFunction()) {
if (!indirectCall && caller->isFunctionFrame()) {
uintN count = 0;
JSScript **scriptp = bucket;
@ -1180,7 +1181,7 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
*/
JSFunction *fun = script->getFunction(0);
if (fun == caller->getFunction()) {
if (fun == caller->fun()) {
/*
* Get the source string passed for safekeeping in the
* atom map by the prior eval to Compiler::compileScript.
@ -2727,10 +2728,10 @@ Detecting(JSContext *cx, jsbytecode *pc)
JSOp op;
JSAtom *atom;
script = cx->fp()->getScript();
script = cx->fp()->script();
endpc = script->code + script->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. */
op = js_GetOpcode(cx, script, pc);
@ -2801,16 +2802,15 @@ js_InferFlags(JSContext *cx, uintN defaultFlags)
JSStackFrame *const fp = js_GetTopStackFrame(cx);
if (!fp || !(pc = cx->regs->pc))
return defaultFlags;
cs = &js_CodeSpec[js_GetOpcode(cx, fp->getScript(), pc)];
cs = &js_CodeSpec[js_GetOpcode(cx, fp->script(), pc)];
format = cs->format;
if (JOF_MODE(format) != JOF_NAME)
flags |= JSRESOLVE_QUALIFIED;
if ((format & (JOF_SET | JOF_FOR)) ||
(fp->flags & JSFRAME_ASSIGNING)) {
if ((format & (JOF_SET | JOF_FOR)) || fp->isAssigning()) {
flags |= JSRESOLVE_ASSIGNING;
} else if (cs->length >= 0) {
pc += cs->length;
JSScript *script = cx->fp()->getScript();
JSScript *script = cx->fp()->script();
if (pc < script->code + script->length && Detecting(cx, pc))
flags |= JSRESOLVE_DETECTING;
}
@ -2987,7 +2987,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2);
JSStackFrame *const fp = cx->fp();
JSObject *obj = fp->getScopeChain();
JSObject *obj = &fp->scopeChain();
JS_ASSERT(obj->isClonedBlock());
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 stop = slot + flen;
depth += fp->getFixedCount();
depth += fp->numFixed();
while (slot < stop)
obj->fslots[slot++] = fp->slots()[depth++];
count -= flen;
@ -3018,7 +3018,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
/* We must clear the private slot even with errors. */
obj->setPrivate(NULL);
fp->setScopeChain(obj->getParent());
fp->setScopeChainNoCallObj(*obj->getParent());
return normalUnwind;
}
@ -3037,8 +3037,8 @@ block_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
if (fp) {
fp = js_LiveFrameIfGenerator(fp);
index += fp->getFixedCount() + OBJ_BLOCK_DEPTH(cx, obj);
JS_ASSERT(index < fp->getSlotCount());
index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj);
JS_ASSERT(index < fp->numSlots());
*vp = fp->slots()[index];
return true;
}
@ -3058,8 +3058,8 @@ block_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
if (fp) {
fp = js_LiveFrameIfGenerator(fp);
index += fp->getFixedCount() + OBJ_BLOCK_DEPTH(cx, obj);
JS_ASSERT(index < fp->getSlotCount());
index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj);
JS_ASSERT(index < fp->numSlots());
fp->slots()[index] = *vp;
return true;
}
@ -3741,7 +3741,7 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
*/
VOUCH_DOES_NOT_REQUIRE_STACK();
if (!start && (fp = cx->maybefp()) != NULL)
start = fp->maybeScopeChain();
start = &fp->scopeChain();
if (start) {
/* Find the topmost object in the scope chain. */
@ -4479,7 +4479,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult,
JSProperty *prop;
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. */
entry = JS_NO_PROP_CACHE_FILL;
@ -4796,7 +4796,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
op = (JSOp) *pc;
if (op == JSOP_TRAP) {
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) {
flags = JSREPORT_ERROR;
@ -4888,7 +4888,7 @@ js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname)
return true;
/* 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)) {
return true;
}
@ -5282,11 +5282,12 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval)
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
if (fun != funobj) {
for (JSStackFrame *fp = cx->maybefp(); fp; fp = fp->down) {
if (fp->callee() == fun &&
fp->getThisValue().isObject() &&
&fp->getThisValue().toObject() == obj) {
fp->setCalleeObject(*funobj);
for (JSStackFrame *fp = cx->maybefp(); fp; fp = fp->prev()) {
if (fp->isFunctionFrame() &&
&fp->callee() == &fun->compiledFunObj() &&
fp->thisValue().isObject() &&
&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 (!scopeobj) {
if (cx->hasfp())
scopeobj = cx->fp()->maybeScopeChain();
scopeobj = &cx->fp()->scopeChain();
if (!scopeobj) {
scopeobj = cx->globalObject;
if (!scopeobj) {
@ -6385,27 +6386,27 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
JSStackFrame *const fp = i.fp();
fprintf(stderr, "JSStackFrame at %p\n", (void *) fp);
if (fp->argv) {
fprintf(stderr, "callee: ");
dumpValue(fp->argv[-2]);
if (fp->isFunctionFrame()) {
fprintf(stderr, "callee fun: ");
dumpValue(ObjectValue(fp->callee()));
} else {
fprintf(stderr, "global frame, no callee");
}
fputc('\n', stderr);
if (fp->hasScript()) {
if (fp->isScriptFrame()) {
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 (!fp->hasScript()) {
if (!fp->isScriptFrame()) {
fprintf(stderr, "*** pc && !script, skipping frame\n\n");
continue;
}
if (fp->hasIMacroPC()) {
if (fp->hasImacropc()) {
fprintf(stderr, " pc in imacro at %p\n called from ", pc);
pc = fp->getIMacroPC();
pc = fp->imacropc();
} else {
fprintf(stderr, " ");
}
@ -6422,38 +6423,37 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
fputc('\n', stderr);
}
}
fprintf(stderr, " argv: %p (argc: %u)\n",
(void *) fp->argv, (unsigned) fp->numActualArgs());
if (fp->isFunctionFrame() && !fp->isEvalFrame()) {
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("argsobj", fp->maybeArgsObj());
MaybeDumpValue("this", fp->getThisValue());
MaybeDumpValue("this", fp->thisValue());
fprintf(stderr, " rval: ");
dumpValue(fp->getReturnValue());
dumpValue(fp->returnValue());
fputc('\n', stderr);
fprintf(stderr, " flags:");
if (fp->flags == 0)
fprintf(stderr, " none");
if (fp->flags & JSFRAME_CONSTRUCTING)
if (fp->isConstructing())
fprintf(stderr, " constructing");
if (fp->flags & JSFRAME_ASSIGNING)
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)
if (fp->hasOverriddenArgs())
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);
if (fp->hasScopeChain())
fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) fp->getScopeChain());
fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) &fp->scopeChain());
if (fp->hasBlockChain())
fprintf(stderr, " blockChain: (JSObject *) %p\n", (void *) fp->getBlockChain());
fprintf(stderr, " blockChain: (JSObject *) %p\n", (void *) fp->blockChain());
fputc('\n', stderr);
}

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

@ -780,6 +780,25 @@ struct JSObject {
inline js::Value *addressOfArgsElement(uint32 i) const;
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.
*/

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

@ -439,6 +439,42 @@ JSObject::setArgsElement(uint32 i, const js::Value &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 &
JSObject::getDateUTCTime() const
{
@ -861,7 +897,7 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp)
if (!global)
return NULL;
} else {
global = cx->fp()->getScopeChain()->getGlobal();
global = cx->fp()->scopeChain().getGlobal();
}
JS_ASSERT(global->getClass()->flags & JSCLASS_IS_GLOBAL);

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

@ -75,6 +75,8 @@
#include "jstracer.h"
#include "jsvector.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h"
#include "jsscriptinlines.h"
#include "jscntxtinlines.h"
@ -279,7 +281,7 @@ js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp)
JS_FRIEND_API(JSBool)
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
@ -2880,10 +2882,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
*/
JSStackFrame *fp = js_GetTopStackFrame(cx);
if (fp) {
while (!(fp->flags & JSFRAME_EVAL))
fp = fp->down;
JS_ASSERT(fp->getScript() == jp->script);
JS_ASSERT(fp->down->getFunction() == jp->fun);
while (!fp->isEvalFrame())
fp = fp->prev();
JS_ASSERT(fp->script() == jp->script);
JS_ASSERT(fp->prev()->fun() == jp->fun);
JS_ASSERT(FUN_INTERPRETED(jp->fun));
JS_ASSERT(jp->script != jp->fun->u.i.script);
JS_ASSERT(jp->script->upvarsOffset != 0);
@ -5089,8 +5091,8 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
JSString *fallback)
{
JSStackFrame *fp;
jsbytecode *pc;
JSScript *script;
jsbytecode *pc;
Value v = Valueify(v_in);
@ -5100,17 +5102,12 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
LeaveTrace(cx);
/* Get scripted caller */
FrameRegsIter i(cx);
while (!i.done() && !i.fp()->hasScript())
++i;
if (i.done() || !i.pc() || i.fp()->getSlotCount() == 0)
if (!cx->regs || !cx->regs->fp || !cx->regs->fp->isScriptFrame())
goto do_fallback;
fp = i.fp();
script = fp->getScript();
pc = fp->hasIMacroPC() ? fp->getIMacroPC() : i.pc();
fp = cx->regs->fp;
script = fp->script();
pc = fp->hasImacropc() ? fp->imacropc() : cx->regs->pc;
JS_ASSERT(pc >= script->main && pc < script->code + script->length);
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.
*/
Value *stackBase = fp->base();
Value *sp = i.sp();
Value *sp = cx->regs->sp;
do {
if (sp == stackBase) {
pcdepth = -1;
@ -5172,15 +5169,11 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
}
{
jsbytecode* savepc = i.pc();
jsbytecode* savedIMacroPC = fp->maybeIMacroPC();
if (savedIMacroPC) {
jsbytecode* savedImacropc = fp->maybeImacropc();
if (savedImacropc) {
JS_ASSERT(cx->hasfp());
if (fp == cx->fp())
cx->regs->pc = savedIMacroPC;
else
fp->savedPC = savedIMacroPC;
fp->clearIMacroPC();
cx->regs->pc = 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.
*/
char *name;
if (savedIMacroPC && size_t(pc - script->code) >= script->length)
if (savedImacropc && size_t(pc - script->code) >= script->length)
name = FAILED_EXPRESSION_DECOMPILER;
else
name = DecompileExpression(cx, script, fp->maybeFunction(), pc);
name = DecompileExpression(cx, script, fp->maybeFun(), pc);
if (savedIMacroPC) {
if (savedImacropc) {
JS_ASSERT(cx->hasfp());
if (fp == cx->fp())
cx->regs->pc = savedIMacroPC;
else
fp->savedPC = savepc;
fp->setIMacroPC(savedIMacroPC);
cx->regs->pc = savedImacropc;
fp->setImacropc(savedImacropc);
}
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.
*/
JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
JS_ASSERT(fp->hasIMacroPC());
intN pcdepth = ReconstructPCStack(cx, script, fp->getIMacroPC(), pcstack);
JS_ASSERT(fp->hasImacropc());
intN pcdepth = ReconstructPCStack(cx, script, fp->imacropc(), pcstack);
if (pcdepth < 0)
return pcdepth;
return SimulateImacroCFG(cx, script, pcdepth, imacstart, target, pcstack);

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

@ -89,6 +89,7 @@
#endif
#include "jsatominlines.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h"
#include "jsregexpinlines.h"
@ -168,6 +169,25 @@ JSParseNode::clear()
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
Parser::init(const jschar *base, size_t length,
FILE *fp, const char *filename, uintN lineno)
@ -717,6 +737,11 @@ SetStaticLevel(JSTreeContext *tc, uintN staticLevel)
/*
* Compile a top-level script.
*/
Compiler::Compiler(JSContext *cx, JSPrincipals *prin, JSStackFrame *cfp)
: parser(cx, prin, cfp)
{
}
JSScript *
Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,
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 (callerFrame &&
callerFrame->hasScript() &&
callerFrame->getScript()->strictModeCode) {
callerFrame->isScriptFrame() &&
callerFrame->script()->strictModeCode) {
cg.flags |= TCF_STRICT_MODE_CODE;
tokenStream.setStrictMode();
}
@ -816,13 +841,13 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
goto out;
}
if (callerFrame && callerFrame->hasFunction()) {
if (callerFrame && callerFrame->isFunctionFrame()) {
/*
* An eval script in a caller frame needs to have its enclosing
* function captured in case it refers to an upvar, and someone
* wishes to decompile it while it's running.
*/
funbox = parser.newObjectBox(FUN_OBJECT(callerFrame->getFunction()));
funbox = parser.newObjectBox(FUN_OBJECT(callerFrame->fun()));
if (!funbox)
goto out;
funbox->emitLink = cg.objectList.lastbox;

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

@ -998,18 +998,7 @@ struct Parser : private js::AutoGCRooter
/* Root atoms and objects allocated for the parsed tree. */
js::AutoKeepAtoms keepAtoms;
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(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL);
~Parser();
friend void js::AutoGCRooter::trace(JSTracer *trc);
@ -1155,10 +1144,7 @@ struct Compiler
Parser parser;
GlobalScope *globalScope;
Compiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL)
: parser(cx, prin, cfp)
{
}
Compiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL);
/*
* 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.
*/
pc = cx->regs->pc;
op = js_GetOpcode(cx, cx->fp()->getScript(), pc);
op = js_GetOpcode(cx, cx->fp()->script(), pc);
cs = &js_CodeSpec[op];
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;
JSAtom *atom;
GET_ATOM_FROM_BYTECODE(cx->fp()->getScript(), pc, pcoff, atom);
GET_ATOM_FROM_BYTECODE(cx->fp()->script(), pc, pcoff, atom);
return atom;
}
@ -318,10 +318,10 @@ PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject
JSStackFrame *fp = cx->fp();
JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
JS_ASSERT(uintN((fp->hasIMacroPC() ? fp->getIMacroPC() : pc) - fp->getScript()->code)
< fp->getScript()->length);
JS_ASSERT(uintN((fp->hasImacropc() ? fp->imacropc() : pc) - fp->script()->code)
< 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];
obj = *objp;

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

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

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

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

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

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

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

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

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

@ -441,6 +441,20 @@ ForEach(InputIterT begin, InputIterT end, CallableT f)
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 */
#endif /* jstl_h_ */

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

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

@ -553,7 +553,7 @@ struct FrameInfo {
* Number of stack slots in the caller, not counting slots pushed when
* invoking the callee. That is, slots after JSOP_CALL completes but
* 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).
*/
uint32 callerHeight;
@ -1041,17 +1041,17 @@ class TraceRecorder
bool demote);
#ifdef DEBUG
bool isValidFrameObjPtr(JSObject **obj);
bool isValidFrameObjPtr(void *obj);
#endif
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 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* getFromTracker(const Value* p);
JS_REQUIRES_STACK nanojit::LIns* getImpl(const void* 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* addr(Value* p);
@ -1179,7 +1179,6 @@ class TraceRecorder
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,
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,
VMSideExit *exit);
nanojit::LIns* stobj_get_parent(nanojit::LIns* obj_ins);
@ -1317,10 +1316,7 @@ class TraceRecorder
nanojit::LIns* obj_ins,
VMSideExit *exit);
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 clearFrameSlotsFromTracker(Tracker& which, JSStackFrame* fp, unsigned nslots);
JS_REQUIRES_STACK void putActivationObjects();
JS_REQUIRES_STACK RecordingStatus guardCallee(Value& callee);
JS_REQUIRES_STACK JSStackFrame *guardArguments(JSObject *obj, nanojit::LIns* obj_ins,
@ -1424,6 +1420,7 @@ class TraceRecorder
friend TracePointAction MonitorTracePoint(JSContext*, uintN &inlineCallCount,
bool &blacklist);
friend void AbortRecording(JSContext*, const char*);
friend class BoxArg;
public:
static bool JS_REQUIRES_STACK

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

@ -261,6 +261,7 @@ typedef enum JSWhyMagic
JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */
JS_NO_CONSTANT, /* compiler sentinel value */
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_GENERIC_MAGIC /* for local use */
} JSWhyMagic;

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

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

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

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

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

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

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

@ -323,17 +323,17 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::ARMRegiste
{
#ifndef JS_CPU_ARM
/* 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
/* ARM returns either using its link register (LR) or directly from the stack, but masm.ret()
* always emits a return to LR. */
load32(Address(JSFrameReg, offsetof(JSStackFrame, ncode)), JSC::ARMRegisters::lr);
load32(Address(JSFrameReg, JSStackFrame::offsetOfncode()), JSC::ARMRegisters::lr);
#endif
}
void saveReturnAddress(RegisterID reg)
{
storePtr(reg, Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
storePtr(reg, Address(JSFrameReg, JSStackFrame::offsetOfncode()));
}
void finalize(uint8 *ncode) {

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

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

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

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

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

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

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

@ -61,16 +61,8 @@ struct AdjustedFrame {
};
/*
* This is used for emitting code to inline callee-side frame creation.
* Specifically, it initializes the following members:
*
* savedPC
* argc
* flags
* scopeChain
* argv
* thisv
* down
* This is used for emitting code to inline callee-side frame creation and
* should jit code equivalent to JSStackFrame::initCallFrameCallerHalf.
*
* Once finished, JSFrameReg is advanced to be the new fp.
*/
@ -81,8 +73,6 @@ class InlineFrameAssembler {
typedef JSC::MacroAssembler::ImmPtr ImmPtr;
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 argc; // number of args being passed to the function
RegisterID funObjReg; // register containing the function object (callee)
@ -99,8 +89,6 @@ class InlineFrameAssembler {
InlineFrameAssembler(Assembler &masm, JSContext *cx, ic::CallICInfo &ic, uint32 flags)
: masm(masm), flags(flags)
{
isConstantThis = ic.isConstantThis;
constantThis = ic.constantThis;
frameDepth = ic.frameDepth;
argc = ic.argc;
funObjReg = ic.funObjReg;
@ -112,8 +100,6 @@ class InlineFrameAssembler {
InlineFrameAssembler(Assembler &masm, Compiler::CallGenInfo &gen, jsbytecode *pc, uint32 flags)
: masm(masm), pc(pc), flags(flags)
{
isConstantThis = gen.isConstantThis;
constantThis = gen.constantThis;
frameDepth = gen.frameDepth;
argc = gen.argc;
funObjReg = gen.funObjReg;
@ -122,38 +108,17 @@ class InlineFrameAssembler {
inline void assemble()
{
JS_ASSERT((flags & ~JSFRAME_CONSTRUCTING) == 0);
RegisterID t0 = tempRegs.takeAnyReg();
/* Note: savedPC goes into the down frame. */
masm.storePtr(ImmPtr(pc), Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
masm.storePtr(ImmPtr(pc), Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
AdjustedFrame adj(sizeof(JSStackFrame) + frameDepth * sizeof(Value));
masm.store32(Imm32(argc), adj.addrOf(offsetof(JSStackFrame, argc)));
masm.store32(Imm32(flags), adj.addrOf(offsetof(JSStackFrame, flags)));
masm.store32(Imm32(JSFRAME_FUNCTION | flags), adj.addrOf(JSStackFrame::offsetOfFlags()));
masm.loadPtr(Address(funObjReg, offsetof(JSObject, parent)), t0);
masm.storePtr(t0, adj.addrOf(JSStackFrame::offsetScopeChain()));
masm.addPtr(Imm32(adj.baseOffset - (argc * sizeof(Value))), JSFrameReg, t0);
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)));
masm.storePtr(t0, adj.addrOf(JSStackFrame::offsetOfScopeChain()));
masm.storePtr(JSFrameReg, adj.addrOf(JSStackFrame::offsetOfPrev()));
/* Adjust JSFrameReg. Callee fills in the rest. */
masm.addPtr(Imm32(sizeof(JSStackFrame) + sizeof(Value) * frameDepth), JSFrameReg);

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

@ -57,6 +57,7 @@
#include "jspropertycache.h"
#include "methodjit/MonoIC.h"
#include "jsinterpinlines.h"
#include "jspropertycacheinlines.h"
#include "jsscopeinlines.h"
#include "jsscriptinlines.h"
@ -92,7 +93,7 @@ static jsbytecode *
FindExceptionHandler(JSContext *cx)
{
JSStackFrame *fp = cx->fp();
JSScript *script = fp->getScript();
JSScript *script = fp->script();
top:
if (cx->throwing && script->trynotesOffset) {
@ -129,7 +130,7 @@ top:
switch (tn->kind) {
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
/* Catch cannot intercept the closing of a generator. */
@ -165,7 +166,7 @@ top:
* pending 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;
ok = !!js_CloseIterator(cx, &cx->regs->sp[-1].toObject());
cx->regs->sp -= 1;
@ -190,7 +191,7 @@ InlineReturn(VMFrame &f, JSBool ok)
JS_ASSERT(f.fp() != f.entryFp);
JS_ASSERT(!fp->hasBlockChain());
JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->getScopeChain(), 0));
JS_ASSERT(!js_IsActiveWithOrBlock(cx, &fp->scopeChain(), 0));
// Marker for debug support.
if (JS_UNLIKELY(fp->hasHookData())) {
@ -204,27 +205,22 @@ InlineReturn(VMFrame &f, JSBool ok)
* optimizations and uninitialised warnings.
*/
status = ok;
hook(cx, fp, JS_FALSE, &status, fp->getHookData());
hook(cx, fp, JS_FALSE, &status, fp->hookData());
ok = (status == JS_TRUE);
// CHECK_INTERRUPT_HANDLER();
}
}
fp->putActivationObjects(cx);
PutActivationObjects(cx, fp);
/* :TODO: version stuff */
if (fp->flags & JSFRAME_CONSTRUCTING && fp->getReturnValue().isPrimitive())
fp->setReturnValue(fp->getThisValue());
if (fp->isConstructing() && fp->returnValue().isPrimitive())
fp->setReturnValue(fp->thisValue());
Value *newsp = fp->argv - 1;
cx->stack().popInlineFrame(cx, fp, fp->down);
cx->regs->sp = newsp;
cx->regs->sp[-1] = fp->getReturnValue();
JS_ASSERT(cx->regs->pc != JSStackFrame::sInvalidPC);
Value *newsp = fp->actualArgs() - 1;
newsp[-1] = fp->returnValue();
cx->stack().popInlineFrame(cx, fp->prev(), newsp);
return ok;
}
@ -271,84 +267,82 @@ stubs::SlowNew(VMFrame &f, uint32 argc)
THROW();
}
/*
* This function must only be called after the early prologue, since it depends
* on fp->exec.fun.
*/
static inline void
RemovePartialFrame(VMFrame &f)
RemovePartialFrame(JSContext *cx, JSStackFrame *fp)
{
/* Unwind the half-pushed frame. */
f.regs.pc = f.fp()->down->savedPC;
f.regs.sp = f.fp()->argv + f.fp()->argc;
#ifdef DEBUG
f.fp()->down->savedPC = JSStackFrame::sInvalidPC;
#endif
f.regs.fp = f.fp()->down;
JSStackFrame *prev = fp->prev();
Value *newsp = (Value *)fp;
cx->stack().popInlineFrame(cx, prev, newsp);
}
/*
* HitStackQuota is called after the early prologue pushing the new frame would
* overflow f.stackLimit.
*/
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;
RemovePartialFrame(f);
/* Remove the current partially-constructed frame before throwing. */
RemovePartialFrame(f.cx, f.fp());
js_ReportOverRecursed(f.cx);
THROW();
}
/*
* This function must only be called after the early prologue, since it depends
* on fp->exec.fun.
*/
void * JS_FASTCALL
stubs::CheckArity(VMFrame &f)
stubs::FixupArity(VMFrame &f, uint32 nactual)
{
JSContext *cx = f.cx;
JSStackFrame *fp = f.fp();
uint32 argc = fp->argc;
JSFunction *fun = fp->getFunction();
JSStackFrame *oldfp = f.fp();
JS_ASSERT(argc < fun->nargs);
JS_ASSERT(nactual != oldfp->numFormalArgs());
/*
* 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
* matter less.
* we can figure out how to spot-optimize it. Be careful to touch only the
* members that have been initialized by initCallFrameCallerHalf and the
* early prologue.
*/
uint32 flags = fp->flags;
JSObject *scopeChain = fp->getScopeChain();
Value *argv = fp->argv;
JSStackFrame *down = fp->down;
void *ncode = fp->ncode;
uint32 flags = oldfp->isConstructingFlag();
JSObject &scopeChain = oldfp->scopeChain();
JSFunction *fun = oldfp->fun();
void *ncode = oldfp->nativeReturnAddress();
/* Pop the inline frame. */
RemovePartialFrame(f);
RemovePartialFrame(cx, oldfp);
uint32 missing = fun->nargs - argc;
/* Include an extra stack frame for callees. */
if (!f.ensureSpace(missing, fun->u.i.script->nslots + VALUES_PER_STACK_FRAME)) {
js_ReportOverRecursed(cx);
/* Reserve enough space for a callee frame. */
JSStackFrame *newfp = cx->stack().getInlineFrameWithinLimit(cx, cx->regs->sp, nactual,
fun, fun->script(), &flags,
f.entryFp, &f.stackLimit);
if (!newfp)
THROWV(NULL);
}
#ifdef DEBUG
down->savedPC = f.regs.pc;
#endif
/* Reset the part of the stack frame set by the caller. */
newfp->initCallFrameCallerHalf(cx, scopeChain, nactual, flags);
SetValueRangeToUndefined(f.regs.sp, missing);
f.regs.sp += missing;
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]);
/* Reset the part of the stack frame set by the prologue up to now. */
newfp->initCallFrameEarlyPrologue(fun, ncode);
/* The caller takes care of assigning fp to regs. */
return newfp;
}
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
@ -356,56 +350,53 @@ stubs::CompileFunction(VMFrame &f)
*/
JSContext *cx = f.cx;
JSStackFrame *fp = f.fp();
uint32 argc = fp->argc;
JSObject *obj = &fp->argv[-2].toObject();
JSFunction *fun = obj->getFunctionPrivate();
JSScript *script = fun->u.i.script;
/*
* Since we can only use members set by initCallFrameCallerHalf,
* 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. */
if (script->isEmpty()) {
RemovePartialFrame(f);
Value *vp = f.regs.sp - argc;
bool callingNew = fp->isConstructing();
RemovePartialFrame(cx, fp);
Value *vp = f.regs.sp - (nactual + 2);
if (callingNew)
vp[-2] = vp[-1];
vp[0] = vp[1];
else
vp[-2].setUndefined();
vp[0].setUndefined();
return NULL;
}
/* CheckArity expects fun to be set. */
fp->setFunction(fun);
if (argc < fun->nargs) {
fp = (JSStackFrame *)CheckArity(f);
if (nactual != fp->numFormalArgs()) {
fp = (JSStackFrame *)FixupArity(f, nactual);
if (!fp)
return NULL;
}
fp->setCallObj(NULL);
fp->setArgsObj(NULL);
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
/* Finish frame initialization. */
fp->initCallFrameLatePrologue();
/* These would have been initialized by the prologue. */
f.regs.fp = fp;
f.regs.sp = fp->base();
f.regs.pc = script->code;
SetValueRangeToUndefined(fp->slots(), script->nfixed);
if (fun->isHeavyweight() && !js_GetCallObject(cx, fp))
THROWV(NULL);
CompileStatus status = CanMethodJIT(cx, script, fun, fp->getScopeChain());
CompileStatus status = CanMethodJIT(cx, script, fun, &fp->scopeChain());
if (status == Compile_Okay)
return script->jit->invoke;
@ -419,112 +410,63 @@ stubs::CompileFunction(VMFrame &f)
return NULL;
}
/* Preserved for when calls need to be slow (debug mode, no ICs) */
static bool
CreateFrame(VMFrame &f, uint32 flags, uint32 argc)
static inline bool
UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
{
JSContext *cx = f.cx;
JSStackFrame *fp = f.fp();
Value *vp = f.regs.sp - (argc + 2);
JSObject *funobj = &vp->toObject();
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
JSObject &callee = vp->toObject();
JSFunction *newfun = callee.getFunctionPrivate();
JSScript *newscript = newfun->script();
JS_ASSERT(FUN_INTERPRETED(fun));
JSScript *newscript = fun->u.i.script;
/* Allocate the frame. */
/* Get pointer to new frame/slots, prepare arguments. */
StackSpace &stack = cx->stack();
uintN nslots = newscript->nslots;
uintN funargs = fun->nargs;
Value *argv = vp + 2;
JSStackFrame *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))
JSStackFrame *newfp = stack.getInlineFrameWithinLimit(cx, f.regs.sp, argc,
newfun, newscript, &flags,
f.entryFp, &f.stackLimit);
if (JS_UNLIKELY(!newfp))
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. */
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) {
newfp->setHookData(hook(cx, fp, JS_TRUE, 0,
cx->debugHooks->callHookData));
} else {
newfp->setHookData(NULL);
}
stack.pushInlineFrame(cx, fp, cx->regs->pc, newfp);
f.regs.fp = newfp;
return true;
}
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;
/* Try to compile if not already compiled. */
if (!newscript->ncode) {
if (mjit::TryCompile(cx, newscript, newfp->fun(), &newfp->scopeChain()) == Compile_Error) {
/* A runtime exception was thrown, get out. */
InlineReturn(f, JS_FALSE);
return false;
}
}
/* 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());
InlineReturn(f, JS_TRUE);
@ -536,43 +478,19 @@ void * JS_FASTCALL
stubs::UncachedNew(VMFrame &f, uint32 argc)
{
JSContext *cx = f.cx;
Value *vp = f.regs.sp - (argc + 2);
JSObject *obj;
if (IsFunctionObject(*vp, &obj)) {
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
if (fun->isInterpreted()) {
JSScript *script = fun->u.i.script;
if (!stubs::NewObject(f, argc))
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;
}
/* Try to do a fast inline call before the general Invoke path. */
JSFunction *fun;
if (IsFunctionObject(*vp, &fun) && fun->isInterpreted() && !fun->script()->isEmpty()) {
void *ret;
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ret, argc))
THROWV(NULL);
return ret;
}
if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
THROWV(NULL);
return NULL;
}
@ -620,13 +538,13 @@ stubs::PutCallObject(VMFrame &f)
{
JS_ASSERT(f.fp()->hasCallObj());
js_PutCallObject(f.cx, f.fp());
JS_ASSERT(!f.fp()->hasArgsObj());
}
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 *
@ -641,7 +559,7 @@ js_InternalThrow(VMFrame &f)
JSThrowHook handler = f.cx->debugHooks->throwHook;
if (handler) {
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)) {
case JSTRAP_ERROR:
cx->throwing = JS_FALSE;
@ -686,13 +604,13 @@ js_InternalThrow(VMFrame &f)
if (!pc)
return NULL;
return cx->fp()->getScript()->pcToNative(pc);
return cx->fp()->script()->pcToNative(pc);
}
void JS_FASTCALL
stubs::GetCallObject(VMFrame &f)
{
JS_ASSERT(f.fp()->getFunction()->isHeavyweight());
JS_ASSERT(f.fp()->fun()->isHeavyweight());
if (!js_GetCallObject(f.cx, f.fp()))
THROW();
}
@ -721,13 +639,13 @@ SwallowErrors(VMFrame &f, JSStackFrame *stopFp)
JSStackFrame *fp = cx->fp();
/* Look for an imacro with hard-coded exception handlers. */
if (fp->hasIMacroPC() && cx->throwing) {
cx->regs->pc = fp->getIMacroPC();
fp->clearIMacroPC();
if (fp->hasImacropc() && cx->throwing) {
cx->regs->pc = fp->imacropc();
fp->clearImacropc();
if (ok)
break;
}
JS_ASSERT(!fp->hasIMacroPC());
JS_ASSERT(!fp->hasImacropc());
/* If there's an exception and a handler, set the pc and leave. */
jsbytecode *pc = FindExceptionHandler(cx);
@ -757,10 +675,10 @@ static inline bool
AtSafePoint(JSContext *cx)
{
JSStackFrame *fp = cx->fp();
if (fp->hasIMacroPC())
if (fp->hasImacropc())
return false;
JSScript *script = fp->getScript();
JSScript *script = fp->script();
if (!script->nmap)
return false;
@ -774,14 +692,12 @@ PartialInterpret(VMFrame &f)
JSContext *cx = f.cx;
JSStackFrame *fp = cx->fp();
JS_ASSERT(fp->hasIMacroPC() || !fp->getScript()->nmap ||
!fp->getScript()->nmap[cx->regs->pc - fp->getScript()->code]);
JS_ASSERT(fp->hasImacropc() || !fp->script()->nmap ||
!fp->script()->nmap[cx->regs->pc - fp->script()->code]);
JSBool ok = JS_TRUE;
ok = Interpret(cx, fp, 0, JSINTERP_SAFEPOINT);
f.fp() = cx->fp();
return ok;
}
@ -802,11 +718,11 @@ static bool
RemoveExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
{
JSContext *cx = f.cx;
while (cx->fp() != entryFrame || entryFrame->hasIMacroPC()) {
while (cx->fp() != entryFrame || entryFrame->hasImacropc()) {
JSStackFrame *fp = cx->fp();
if (AtSafePoint(cx)) {
JSScript *script = fp->getScript();
JSScript *script = fp->script();
if (!JaegerShotAtSafePoint(cx, script->nmap[cx->regs->pc - script->code])) {
if (!SwallowErrors(f, entryFrame))
return false;
@ -825,10 +741,10 @@ RemoveExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
* Partial interpret could have dropped us anywhere. Deduce the
* edge case: at a RETURN, needing to pop a frame.
*/
JS_ASSERT(!cx->fp()->hasIMacroPC());
JS_ASSERT(!cx->fp()->hasImacropc());
if (FrameIsFinished(cx)) {
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]);
InlineReturn(f, JS_TRUE);
AdvanceReturnPC(cx);
@ -909,7 +825,7 @@ RunTracer(VMFrame &f)
case TPA_Error:
if (!SwallowErrors(f, entryFrame))
THROWV(NULL);
JS_ASSERT(!cx->fp()->hasIMacroPC());
JS_ASSERT(!cx->fp()->hasImacropc());
break;
case TPA_RanStuff:
@ -945,19 +861,19 @@ RunTracer(VMFrame &f)
THROWV(NULL);
/* 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. */
if (AtSafePoint(cx)) {
uint32 offs = uint32(cx->regs->pc - entryFrame->getScript()->code);
JS_ASSERT(entryFrame->getScript()->nmap[offs]);
return entryFrame->getScript()->nmap[offs];
uint32 offs = uint32(cx->regs->pc - entryFrame->script()->code);
JS_ASSERT(entryFrame->script()->nmap[offs]);
return entryFrame->script()->nmap[offs];
}
/* Step 3. If entryFrame is at a RETURN, then leave slightly differently. */
if (JSOp op = FrameIsFinished(cx)) {
/* 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]);
/* Don't pop the frame if it's maybe owned by an Invoke. */
@ -986,7 +902,7 @@ RunTracer(VMFrame &f)
void *JS_FASTCALL
stubs::InvokeTracer(VMFrame &f, uint32 index)
{
JSScript *script = f.fp()->getScript();
JSScript *script = f.fp()->script();
ic::MICInfo &mic = script->mics[index];
JS_ASSERT(mic.kind == ic::MICInfo::TRACER);

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

@ -49,6 +49,25 @@
using namespace js;
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.
*
@ -254,7 +273,6 @@ SYMBOL_STRING(JaegerThrowpoline) ":" "\n"
"ret" "\n"
);
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode) == 0x60);
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38);
asm volatile (
@ -262,7 +280,7 @@ asm volatile (
".globl " SYMBOL_STRING(SafePointTrampoline) "\n"
SYMBOL_STRING(SafePointTrampoline) ":" "\n"
"popq %rax" "\n"
"movq %rax, 0x60(%rbx)" "\n"
"movq %rax, 0x50(%rbx)" "\n"
"jmp *8(%rsp)" "\n"
);
@ -270,8 +288,8 @@ asm volatile (
".text\n"
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
"movq 0x40(%rbx), %rcx" "\n" /* load Value into typeReg */
"movq 0x60(%rbx), %rax" "\n" /* fp->ncode */
"movq 0x30(%rbx), %rcx" "\n" /* load fp->rval_ into typeReg */
"movq 0x50(%rbx), %rax" "\n" /* fp->ncode_ */
/* Reimplementation of PunboxAssembler::loadValueAsComponents() */
"movq %r14, %rdx" "\n" /* payloadReg = payloadMaskReg */
@ -363,16 +381,15 @@ SYMBOL_STRING(JaegerThrowpoline) ":" "\n"
"ret" "\n"
);
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode) == 0x3C);
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x1C);
asm volatile (
".text\n"
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
"movl 0x28(%ebx), %edx" "\n" /* fp->rval data */
"movl 0x2C(%ebx), %ecx" "\n" /* fp->rval type */
"movl 0x3C(%ebx), %eax" "\n" /* fp->ncode */
"movl 0x18(%ebx), %edx" "\n" /* fp->rval_ data */
"movl 0x1C(%ebx), %ecx" "\n" /* fp->rval_ type */
"movl 0x2C(%ebx), %eax" "\n" /* fp->ncode_ */
"movl 0x1C(%esp), %ebx" "\n" /* f.fp */
"pushl %eax" "\n"
"ret" "\n"
@ -387,7 +404,7 @@ asm volatile (
".globl " SYMBOL_STRING(SafePointTrampoline) "\n"
SYMBOL_STRING(SafePointTrampoline) ":" "\n"
"popl %eax" "\n"
"movl %eax, 0x3C(%ebx)" "\n"
"movl %eax, 0x2C(%ebx)" "\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, unused) == (4*4));
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(JSReturnReg_Data == JSC::ARMRegisters::r1);
@ -412,9 +428,9 @@ asm volatile (
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
/* Restore frame regs. */
"ldr lr, [r11, #60]" "\n" /* fp->ncode */
"ldr r1, [r11, #40]" "\n" /* fp->rval data */
"ldr r2, [r11, #44]" "\n" /* fp->rval type */
"ldr lr, [r11, #44]" "\n" /* fp->ncode */
"ldr r1, [r11, #24]" "\n" /* fp->rval data */
"ldr r2, [r11, #28]" "\n" /* fp->rval type */
"ldr r11, [sp, #28]" "\n" /* load f.fp */
"bx lr" "\n"
);
@ -430,7 +446,7 @@ SYMBOL_STRING(SafePointTrampoline) ":"
*/
"ldr ip, [sp, #80]" "\n"
/* 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
* the stack looks like a return, and may upset return stack prediction. */
"bx ip" "\n"
@ -566,9 +582,9 @@ extern "C" {
__declspec(naked) void InjectJaegerReturn()
{
__asm {
mov edx, [ebx + 0x28];
mov ecx, [ebx + 0x2C];
mov eax, [ebx + 0x3C];
mov edx, [ebx + 0x18];
mov ecx, [ebx + 0x1C];
mov eax, [ebx + 0x2C];
mov ebx, [esp + 0x1C];
push eax;
ret;
@ -579,7 +595,7 @@ extern "C" {
{
__asm {
pop eax;
mov [ebx + 0x3C], eax;
mov [ebx + 0x2C], eax;
jmp [ebp + 24];
}
}
@ -666,7 +682,6 @@ extern "C" {
*/
JS_STATIC_ASSERT(offsetof(VMFrame, savedRBX) == 0x58);
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_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL);
@ -728,7 +743,7 @@ EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, void *safePoint)
#ifdef JS_METHODJIT_SPEW
Profiler prof;
JSScript *script = fp->getScript();
JSScript *script = fp->script();
JaegerSpew(JSpew_Prof, "%s jaeger script: %s, line %d\n",
safePoint ? "dropping" : "entering",
@ -740,19 +755,9 @@ EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, void *safePoint)
JSStackFrame *checkFp = fp;
#endif
Value *fpAsVp = reinterpret_cast<Value*>(fp);
StackSpace &stack = cx->stack();
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);
Value *stackLimit = cx->stack().getStackLimit(cx);
if (!stackLimit)
return false;
}
JSFrameRegs *oldRegs = cx->regs;
@ -774,7 +779,7 @@ EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, void *safePoint)
JSBool
mjit::JaegerShot(JSContext *cx)
{
JSScript *script = cx->fp()->getScript();
JSScript *script = cx->fp()->script();
JS_ASSERT(script->ncode && script->ncode != JS_UNJITTABLE_METHOD);
@ -867,10 +872,3 @@ mjit::ProfileStubCall(VMFrame &f)
}
#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; }
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

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

@ -50,6 +50,8 @@
#include "methodjit/Compiler.h"
#include "InlineFrameAssembler.h"
#include "jsobj.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h"
#include "jsscopeinlines.h"
#include "jsscriptinlines.h"
@ -78,9 +80,9 @@ PatchGetFallback(VMFrame &f, ic::MICInfo &mic)
void JS_FASTCALL
ic::GetGlobalName(VMFrame &f, uint32 index)
{
JSObject *obj = f.fp()->getScopeChain()->getGlobal();
ic::MICInfo &mic = f.fp()->getScript()->mics[index];
JSAtom *atom = f.fp()->getScript()->getAtom(GET_INDEX(f.regs.pc));
JSObject *obj = f.fp()->scopeChain().getGlobal();
ic::MICInfo &mic = f.fp()->script()->mics[index];
JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc));
jsid id = ATOM_TO_JSID(atom);
JS_ASSERT(mic.kind == ic::MICInfo::GET);
@ -129,7 +131,7 @@ ic::GetGlobalName(VMFrame &f, uint32 index)
static void JS_FASTCALL
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);
}
@ -154,9 +156,9 @@ GetStubForSetGlobalName(VMFrame &f)
void JS_FASTCALL
ic::SetGlobalName(VMFrame &f, uint32 index)
{
JSObject *obj = f.fp()->getScopeChain()->getGlobal();
ic::MICInfo &mic = f.fp()->getScript()->mics[index];
JSAtom *atom = f.fp()->getScript()->getAtom(GET_INDEX(f.regs.pc));
JSObject *obj = f.fp()->scopeChain().getGlobal();
ic::MICInfo &mic = f.fp()->script()->mics[index];
JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc));
jsid id = ATOM_TO_JSID(atom);
JS_ASSERT(mic.kind == ic::MICInfo::SET);
@ -213,7 +215,7 @@ ic::SetGlobalName(VMFrame &f, uint32 index)
static void * JS_FASTCALL
SlowCallFromIC(VMFrame &f, uint32 index)
{
JSScript *oldscript = f.fp()->getScript();
JSScript *oldscript = f.fp()->script();
CallICInfo &ic= oldscript->callICs[index];
stubs::SlowCall(f, ic.argc);
@ -224,7 +226,7 @@ SlowCallFromIC(VMFrame &f, uint32 index)
static void * JS_FASTCALL
SlowNewFromIC(VMFrame &f, uint32 index)
{
JSScript *oldscript = f.fp()->getScript();
JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index];
stubs::SlowNew(f, ic.argc);
@ -297,23 +299,6 @@ class CallCompiler
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)
{
/*
@ -344,6 +329,7 @@ class CallCompiler
/* Try and compile. On success we get back the nmap pointer. */
masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
masm.move(Imm32(ic.argc), Registers::ArgReg1);
JSC::MacroAssembler::Call tryCompile =
masm.stubCall(JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction),
script->code, ic.frameDepth);
@ -648,7 +634,7 @@ class CallCompiler
stubs::NewObject(f, ic.argc);
if (!ic.hit) {
if (ic.argc < fun->nargs) {
if (ic.argc != fun->nargs) {
if (!generateFullCallStub(script, flags))
THROWV(NULL);
} else {
@ -672,9 +658,18 @@ class CallCompiler
ic.hit = true;
}
/* We'll still return to the OOL path, so make sure a frame exists. */
pushFrameFromCaller(scopeChain, flags);
if (ic.argc >= fun->nargs)
/*
* We are about to jump into the callee's prologue, so push the frame as
* 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->jit->arityCheck;
}
@ -683,7 +678,7 @@ class CallCompiler
void * JS_FASTCALL
ic::Call(VMFrame &f, uint32 index)
{
JSScript *oldscript = f.fp()->getScript();
JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index];
CallCompiler cc(f, ic, false);
return cc.update();
@ -692,7 +687,7 @@ ic::Call(VMFrame &f, uint32 index)
void * JS_FASTCALL
ic::New(VMFrame &f, uint32 index)
{
JSScript *oldscript = f.fp()->getScript();
JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index];
CallCompiler cc(f, ic, true);
return cc.update();
@ -701,7 +696,7 @@ ic::New(VMFrame &f, uint32 index)
void JS_FASTCALL
ic::NativeCall(VMFrame &f, uint32 index)
{
JSScript *oldscript = f.fp()->getScript();
JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index];
CallCompiler cc(f, ic, false);
if (!cc.generateNativeStub())
@ -711,7 +706,7 @@ ic::NativeCall(VMFrame &f, uint32 index)
void JS_FASTCALL
ic::NativeNew(VMFrame &f, uint32 index)
{
JSScript *oldscript = f.fp()->getScript();
JSScript *oldscript = f.fp()->script();
CallICInfo &ic = oldscript->callICs[index];
CallCompiler cc(f, ic, true);
if (!cc.generateNativeStub())

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

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

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

@ -467,6 +467,14 @@ class SetPropCompiler : public PICStubCompiler
emitStore(masm, address);
} 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);
/* 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);
{
uint32 bias = 0;
if (shape->setterOp() == SetCallArg)
masm.loadPtr(Address(pic.shapeReg, offsetof(JSStackFrame, argv)), pic.shapeReg);
else
bias = sizeof(JSStackFrame);
Address address(pic.shapeReg, bias + slot * sizeof(Value));
emitStore(masm, address);
Address addr(pic.shapeReg, shape->setterOp() == SetCallArg
? JSStackFrame::offsetOfFormalArg(fun, slot)
: JSStackFrame::offsetOfFixed(slot));
emitStore(masm, addr);
skipOver = masm.jump();
}
escapedFrame.linkTo(masm.label(), &masm);
{
if (shape->setterOp() == SetCallVar) {
JSFunction *fun = js_GetCallObjectFunction(obj);
if (shape->setterOp() == SetCallVar)
slot += fun->nargs;
}
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
Address dslot(pic.objReg, slot * sizeof(Value));
@ -874,7 +877,7 @@ class GetPropCompiler : public PICStubCompiler
JS_ASSERT(pic.hasTypeCheck());
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");
JSObject *holder;
@ -1656,7 +1659,7 @@ class ScopeNameCompiler : public PICStubCompiler
Assembler masm;
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(holder == scopeChain->getGlobal());
@ -1729,7 +1732,7 @@ class ScopeNameCompiler : public PICStubCompiler
Assembler masm;
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(holder != scopeChain->getGlobal());
@ -1756,6 +1759,7 @@ class ScopeNameCompiler : public PICStubCompiler
/* Get callobj's stack frame. */
masm.loadFunctionPrivate(pic.objReg, pic.shapeReg);
JSFunction *fun = holder->getCallObjCalleeFunction();
uint16 slot = uint16(shape->shortid);
Jump skipOver;
@ -1763,12 +1767,8 @@ class ScopeNameCompiler : public PICStubCompiler
/* Not-escaped case. */
{
uint32 bias = 0;
if (kind == ARG)
masm.loadPtr(Address(pic.shapeReg, offsetof(JSStackFrame, argv)), pic.shapeReg);
else
bias = sizeof(JSStackFrame);
Address addr(pic.shapeReg, bias + slot * sizeof(Value));
Address addr(pic.shapeReg, kind == ARG ? JSStackFrame::offsetOfFormalArg(fun, slot)
: JSStackFrame::offsetOfFixed(slot));
masm.loadPayload(addr, pic.objReg);
masm.loadTypeTag(addr, pic.shapeReg);
skipOver = masm.jump();
@ -1779,7 +1779,6 @@ class ScopeNameCompiler : public PICStubCompiler
{
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
JSFunction *fun = js_GetCallObjectFunction(holder);
if (kind == VAR)
slot += fun->nargs;
Address dslot(pic.objReg, slot * sizeof(Value));
@ -1914,7 +1913,7 @@ class BindNameCompiler : public PICStubCompiler
js::Vector<Jump, 8, ContextAllocPolicy> fails(f.cx);
/* 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);
Jump firstShape = masm.branch32(Assembler::NotEqual, pic.shapeReg,
Imm32(scopeChain->shape()));
@ -2008,7 +2007,7 @@ class BindNameCompiler : public PICStubCompiler
void JS_FASTCALL
ic::GetProp(VMFrame &f, uint32 index)
{
JSScript *script = f.fp()->getScript();
JSScript *script = f.fp()->script();
PICInfo &pic = script->pics[index];
JSAtom *atom = pic.atom;
@ -2066,7 +2065,7 @@ ic::GetProp(VMFrame &f, uint32 index)
void JS_FASTCALL
ic::GetElem(VMFrame &f, uint32 picIndex)
{
JSScript *script = f.fp()->getScript();
JSScript *script = f.fp()->script();
PICInfo &pic = script->pics[picIndex];
JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
@ -2096,7 +2095,7 @@ ic::GetElem(VMFrame &f, uint32 picIndex)
void JS_FASTCALL
ic::SetPropDumb(VMFrame &f, uint32 index)
{
JSScript *script = f.fp()->getScript();
JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index];
JS_ASSERT(pic.isSet());
JSAtom *atom = pic.atom;
@ -2113,7 +2112,7 @@ ic::SetPropDumb(VMFrame &f, uint32 index)
static void JS_FASTCALL
SetPropSlow(VMFrame &f, uint32 index)
{
JSScript *script = f.fp()->getScript();
JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index];
JS_ASSERT(pic.isSet());
@ -2128,7 +2127,7 @@ ic::SetProp(VMFrame &f, uint32 index)
if (!obj)
THROW();
JSScript *script = f.fp()->getScript();
JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index];
JSAtom *atom = pic.atom;
JS_ASSERT(pic.isSet());
@ -2172,7 +2171,7 @@ ic::SetProp(VMFrame &f, uint32 index)
static void JS_FASTCALL
CallPropSlow(VMFrame &f, uint32 index)
{
JSScript *script = f.fp()->getScript();
JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index];
stubs::CallProp(f, pic.atom);
}
@ -2183,7 +2182,7 @@ ic::CallProp(VMFrame &f, uint32 index)
JSContext *cx = f.cx;
JSFrameRegs &regs = f.regs;
JSScript *script = f.fp()->getScript();
JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index];
JSAtom *origAtom = pic.atom;
@ -2320,11 +2319,11 @@ SlowName(VMFrame &f, uint32 index)
void JS_FASTCALL
ic::Name(VMFrame &f, uint32 index)
{
JSScript *script = f.fp()->getScript();
JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index];
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()) {
cc.disable("error");
@ -2340,7 +2339,7 @@ ic::Name(VMFrame &f, uint32 index)
if (!cc.prop) {
/* Kludge to allow (typeof foo == "undefined") tests. */
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) {
f.regs.sp[0].setUndefined();
return;
@ -2369,11 +2368,11 @@ SlowBindName(VMFrame &f, uint32 index)
void JS_FASTCALL
ic::BindName(VMFrame &f, uint32 index)
{
JSScript *script = f.fp()->getScript();
JSScript *script = f.fp()->script();
ic::PICInfo &pic = script->pics[index];
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();
if (!obj) {

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

@ -125,8 +125,8 @@ Recompiler::recompile()
for (AllFramesIter i(cx); !i.done(); ++i) {
if (!firstFrame && i.fp()->maybeScript() == script)
firstFrame = i.fp();
if (script->isValidJitCode(i.fp()->ncode)) {
if (!toPatch.append(findPatch(&i.fp()->ncode)))
if (script->isValidJitCode(i.fp()->nativeReturnAddress())) {
if (!toPatch.append(findPatch(i.fp()->addressOfNativeReturnAddress())))
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. */
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)
return false;

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

@ -53,6 +53,8 @@
#include "methodjit/Compiler.h"
#include "methodjit/StubCalls.h"
#include "jstracer.h"
#include "jsinterpinlines.h"
#include "jspropertycache.h"
#include "jspropertycacheinlines.h"
#include "jsscopeinlines.h"
@ -78,16 +80,16 @@ stubs::BindName(VMFrame &f)
PropertyCacheEntry *entry;
/* Fast-path should have caught this. See comment in interpreter. */
JS_ASSERT(f.fp()->getScopeChain()->getParent());
JS_ASSERT(f.fp()->scopeChain().getParent());
JSAtom *atom;
JSObject *obj2;
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);
if (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)
THROW();
}
@ -98,7 +100,7 @@ stubs::BindName(VMFrame &f)
JSObject * JS_FASTCALL
stubs::BindGlobalName(VMFrame &f)
{
return f.fp()->getScopeChain()->getGlobal();
return f.fp()->scopeChain().getGlobal();
}
void JS_FASTCALL
@ -353,7 +355,7 @@ NameOp(VMFrame &f, JSObject *obj, bool callname = false)
return NULL;
if (!prop) {
/* 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) {
f.regs.sp++;
f.regs.sp[-1].setUndefined();
@ -401,14 +403,14 @@ NameOp(VMFrame &f, JSObject *obj, bool callname = false)
void JS_FASTCALL
stubs::Name(VMFrame &f)
{
if (!NameOp(f, f.fp()->getScopeChain()))
if (!NameOp(f, &f.fp()->scopeChain()))
THROW();
}
void JS_FASTCALL
stubs::GetGlobalName(VMFrame &f)
{
JSObject *globalObj = f.fp()->getScopeChain()->getGlobal();
JSObject *globalObj = f.fp()->scopeChain().getGlobal();
if (!NameOp(f, globalObj))
THROW();
}
@ -507,7 +509,7 @@ stubs::GetElem(VMFrame &f)
if (arg < obj->getArgsInitialLength()) {
JSStackFrame *afp = (JSStackFrame *) obj->getPrivate();
if (afp) {
copyFrom = &afp->argv[arg];
copyFrom = &afp->canonicalActualArg(arg);
goto end_getelem;
}
@ -629,7 +631,7 @@ stubs::SetElem(VMFrame &f)
void JS_FASTCALL
stubs::CallName(VMFrame &f)
{
JSObject *obj = NameOp(f, f.fp()->getScopeChain(), true);
JSObject *obj = NameOp(f, &f.fp()->scopeChain(), true);
if (!obj)
THROW();
}
@ -843,7 +845,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
* FIXME: bug 476950, although debugger users may also demand some kind
* of scope link for debugger-assisted eval-in-frame.
*/
obj2 = fp->getScopeChain();
obj2 = &fp->scopeChain();
} else {
JS_ASSERT(!FUN_FLAT_CLOSURE(fun));
@ -852,7 +854,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
* top-level function.
*/
if (!fp->hasBlockChain()) {
obj2 = fp->getScopeChain();
obj2 = &fp->scopeChain();
} else {
obj2 = js_GetScopeChain(cx, fp);
if (!obj2)
@ -875,21 +877,11 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
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
* impermanent.
*/
uintN attrs = (fp->flags & JSFRAME_EVAL)
uintN attrs = fp->isEvalFrame()
? JSPROP_ENUMERATE
: 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
* and functions defined by eval inside let or with blocks.
*/
JSObject *parent = fp->varobj(cx);
JS_ASSERT(parent);
JSObject *parent = &fp->varobj(cx);
uint32 old;
bool doSet;
@ -914,7 +905,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
JSObject *pobj;
JSBool ok = CheckRedeclaration(cx, parent, id, attrs, &pobj, &prop);
if (!ok)
goto restore_scope;
THROW();
/*
* 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.
*/
doSet = (attrs == JSPROP_ENUMERATE);
JS_ASSERT_IF(doSet, fp->flags & JSFRAME_EVAL);
JS_ASSERT_IF(doSet, fp->isEvalFrame());
if (prop) {
if (parent == pobj &&
parent->isCall() &&
@ -945,13 +936,10 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
}
pobj->dropProperty(cx, prop);
}
Value rval = ObjectValue(*obj);
ok = doSet
? parent->setProperty(cx, id, &rval)
: 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)
THROW();
}
@ -1325,7 +1313,7 @@ stubs::Debugger(VMFrame &f, jsbytecode *pc)
JSDebuggerHandler handler = f.cx->debugHooks->debuggerHandler;
if (handler) {
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)) {
case JSTRAP_THROW:
f.cx->throwing = JS_TRUE;
@ -1366,7 +1354,7 @@ stubs::Trap(VMFrame &f, jsbytecode *pc)
{
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:
f.cx->throwing = JS_TRUE;
f.cx->exception = rval;
@ -1396,15 +1384,16 @@ stubs::Trap(VMFrame &f, jsbytecode *pc)
void JS_FASTCALL
stubs::This(VMFrame &f)
{
if (!f.fp()->getThisObject(f.cx))
JSObject *obj = f.fp()->computeThisObject(f.cx);
if (!obj)
THROW();
f.regs.sp[-1] = f.fp()->getThisValue();
f.regs.sp[-1].setObject(*obj);
}
void JS_FASTCALL
stubs::ComputeThis(VMFrame &f)
{
if (!f.fp()->getThisObject(f.cx))
if (!f.fp()->computeThisObject(f.cx))
THROW();
}
@ -1488,7 +1477,7 @@ void JS_FASTCALL
stubs::GetUpvar(VMFrame &f, uint32 ck)
{
/* :FIXME: We can do better, this stub isn't needed. */
uint32 staticLevel = f.fp()->getScript()->staticLevel;
uint32 staticLevel = f.fp()->script()->staticLevel;
UpvarCookie cookie;
cookie.fromInteger(ck);
f.regs.sp[0] = GetUpvar(f.cx, staticLevel, cookie);
@ -1509,7 +1498,7 @@ stubs::DefLocalFun(VMFrame &f, JSFunction *fun)
JSObject *obj = FUN_OBJECT(fun);
if (FUN_NULL_CLOSURE(fun)) {
obj = CloneFunctionObject(f.cx, fun, f.fp()->getScopeChain());
obj = CloneFunctionObject(f.cx, fun, &f.fp()->scopeChain());
if (!obj)
THROWV(NULL);
} 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
* 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.
*/
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);
JS_ASSERT(proto);
JSObject *obj = js_CloneRegExpObject(f.cx, regex, proto);
@ -1561,8 +1550,8 @@ JSObject * JS_FASTCALL
stubs::LambdaForInit(VMFrame &f, JSFunction *fun)
{
JSObject *obj = FUN_OBJECT(fun);
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == f.fp()->getScopeChain()) {
fun->setMethodAtom(f.fp()->getScript()->getAtom(GET_SLOTNO(f.regs.pc + JSOP_LAMBDA_LENGTH)));
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(f.regs.pc + JSOP_LAMBDA_LENGTH)));
return obj;
}
return Lambda(f, fun);
@ -1572,10 +1561,10 @@ JSObject * JS_FASTCALL
stubs::LambdaForSet(VMFrame &f, JSFunction *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];
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;
}
}
@ -1586,7 +1575,7 @@ JSObject * JS_FASTCALL
stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *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
* optimized as if they are special form. We know that they
@ -1623,7 +1612,7 @@ JSObject * JS_FASTCALL
stubs::LambdaJoinableForNull(VMFrame &f, JSFunction *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;
JSOp op2 = JSOp(*pc2);
@ -1640,7 +1629,7 @@ stubs::Lambda(VMFrame &f, JSFunction *fun)
JSObject *parent;
if (FUN_NULL_CLOSURE(fun)) {
parent = f.fp()->getScopeChain();
parent = &f.fp()->scopeChain();
} else {
parent = js_GetScopeChain(f.cx, f.fp());
if (!parent)
@ -1680,9 +1669,9 @@ ObjIncOp(VMFrame &f, JSObject *obj, jsid id)
ref.getInt32Ref() = tmp + N;
else
ref.getInt32Ref() = tmp += N;
fp->flags |= JSFRAME_ASSIGNING;
fp->setAssigning();
JSBool ok = obj->setProperty(cx, id, &ref);
fp->flags &= ~JSFRAME_ASSIGNING;
fp->clearAssigning();
if (!ok)
return false;
@ -1704,9 +1693,9 @@ ObjIncOp(VMFrame &f, JSObject *obj, jsid id)
ref.setDouble(d);
}
v.setDouble(d);
fp->flags |= JSFRAME_ASSIGNING;
fp->setAssigning();
JSBool ok = obj->setProperty(cx, id, &v);
fp->flags &= ~JSFRAME_ASSIGNING;
fp->clearAssigning();
if (!ok)
return false;
}
@ -1857,7 +1846,7 @@ stubs::DecElem(VMFrame &f)
void JS_FASTCALL
stubs::NameInc(VMFrame &f, JSAtom *atom)
{
JSObject *obj = f.fp()->getScopeChain();
JSObject *obj = &f.fp()->scopeChain();
if (!NameIncDec<1, true>(f, obj, atom))
THROW();
}
@ -1865,7 +1854,7 @@ stubs::NameInc(VMFrame &f, JSAtom *atom)
void JS_FASTCALL
stubs::NameDec(VMFrame &f, JSAtom *atom)
{
JSObject *obj = f.fp()->getScopeChain();
JSObject *obj = &f.fp()->scopeChain();
if (!NameIncDec<-1, true>(f, obj, atom))
THROW();
}
@ -1873,7 +1862,7 @@ stubs::NameDec(VMFrame &f, JSAtom *atom)
void JS_FASTCALL
stubs::IncName(VMFrame &f, JSAtom *atom)
{
JSObject *obj = f.fp()->getScopeChain();
JSObject *obj = &f.fp()->scopeChain();
if (!NameIncDec<1, false>(f, obj, atom))
THROW();
}
@ -1881,7 +1870,7 @@ stubs::IncName(VMFrame &f, JSAtom *atom)
void JS_FASTCALL
stubs::DecName(VMFrame &f, JSAtom *atom)
{
JSObject *obj = f.fp()->getScopeChain();
JSObject *obj = &f.fp()->scopeChain();
if (!NameIncDec<-1, false>(f, obj, atom))
THROW();
}
@ -1889,7 +1878,7 @@ stubs::DecName(VMFrame &f, JSAtom *atom)
void JS_FASTCALL
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))
THROW();
}
@ -1897,7 +1886,7 @@ stubs::GlobalNameInc(VMFrame &f, JSAtom *atom)
void JS_FASTCALL
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))
THROW();
}
@ -1905,7 +1894,7 @@ stubs::GlobalNameDec(VMFrame &f, JSAtom *atom)
void JS_FASTCALL
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))
THROW();
}
@ -1913,7 +1902,7 @@ stubs::IncGlobalName(VMFrame &f, JSAtom *atom)
void JS_FASTCALL
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))
THROW();
}
@ -1953,7 +1942,7 @@ InlineGetProp(VMFrame &f)
JS_ASSERT(entry->vword.isShape());
const Shape *shape = entry->vword.toShape();
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);
}
break;
@ -1962,7 +1951,7 @@ InlineGetProp(VMFrame &f)
jsid id = ATOM_TO_JSID(atom);
if (JS_LIKELY(!aobj->getOps()->getProperty)
? !js_GetPropertyHelper(cx, obj, id,
f.fp()->hasIMacroPC()
f.fp()->hasImacropc()
? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
: JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
&rval)
@ -2386,7 +2375,7 @@ stubs::EnterBlock(VMFrame &f, JSObject *obj)
JS_ASSERT(fp->base() + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp);
Value *vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj);
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);
regs.sp = vp;
@ -2395,13 +2384,13 @@ stubs::EnterBlock(VMFrame &f, JSObject *obj)
JS_ASSERT(fp->maybeBlockChain() == obj->getParent());
/*
* The young end of fp->getScopeChain() may omit blocks if we haven't closed
* over them, but if there are any closure blocks on fp->getScopeChain(), they'd
* 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->scopeChain(), they'd
* 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.
*/
JSObject *obj2 = fp->getScopeChain();
JSObject *obj2 = &fp->scopeChain();
Class *clasp;
while ((clasp = obj2->getClass()) == &js_WithClass)
obj2 = obj2->getParent();
@ -2425,32 +2414,32 @@ stubs::LeaveBlock(VMFrame &f)
JSStackFrame *fp = f.fp();
#ifdef DEBUG
JS_ASSERT(fp->getBlockChain()->getClass() == &js_BlockClass);
uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->getBlockChain());
JS_ASSERT(fp->blockChain()->getClass() == &js_BlockClass);
uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->blockChain());
JS_ASSERT(blockDepth <= StackDepth(fp->getScript()));
JS_ASSERT(blockDepth <= StackDepth(fp->script()));
#endif
/*
* 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.
*/
JSObject *obj = fp->getScopeChain();
if (obj->getProto() == fp->getBlockChain()) {
JSObject *obj = &fp->scopeChain();
if (obj->getProto() == fp->blockChain()) {
JS_ASSERT(obj->getClass() == &js_BlockClass);
if (!js_PutBlockObject(cx, JS_TRUE))
THROW();
}
/* Pop the block chain, too. */
fp->setBlockChain(fp->getBlockChain()->getParent());
fp->setBlockChain(fp->blockChain()->getParent());
}
void * JS_FASTCALL
stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
{
jsbytecode *jpc = pc;
JSScript *script = f.fp()->getScript();
JSScript *script = f.fp()->script();
/* This is correct because the compiler adjusts the stack beforehand. */
Value lval = f.regs.sp[-1];
@ -2519,7 +2508,7 @@ stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
{
jsbytecode * const originalPC = origPc;
jsbytecode *pc = originalPC;
JSScript *script = f.fp()->getScript();
JSScript *script = f.fp()->script();
uint32 jumpOffset = GET_JUMP_OFFSET(pc);
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 InitMethod(VMFrame &f, JSAtom *atom);
void JS_FASTCALL CheckStackQuota(VMFrame &f);
void * JS_FASTCALL CheckArity(VMFrame &f);
void * JS_FASTCALL CompileFunction(VMFrame &f);
void JS_FASTCALL HitStackQuota(VMFrame &f);
void * JS_FASTCALL FixupArity(VMFrame &f, uint32 argc);
void * JS_FASTCALL CompileFunction(VMFrame &f, uint32 argc);
void JS_FASTCALL SlowNew(VMFrame &f, uint32 argc);
void JS_FASTCALL SlowCall(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);
void JS_FASTCALL Throw(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 WrapPrimitiveThis(VMFrame &f);
#if JS_MONOIC

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

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

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

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

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

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

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

@ -92,6 +92,7 @@
#include "jsworkers.h"
#include "jsinterpinlines.h"
#include "jsobjinlines.h"
#include "jsscriptinlines.h"
@ -1172,7 +1173,7 @@ AssertJit(JSContext *cx, uintN argc, jsval *vp)
{
#ifdef JS_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);
return JS_FALSE;
}
@ -1459,7 +1460,7 @@ ValueToScript(JSContext *cx, jsval v)
script = (JSScript *) JS_GetPrivate(cx, obj);
} else if (clasp == Jsvalify(&js_GeneratorClass)) {
JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj);
fun = gen->getFloatingFrame()->getFunction();
fun = gen->floatingFrame()->fun();
script = FUN_SCRIPT(fun);
}
}
@ -1501,7 +1502,7 @@ GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp,
uintN intarg;
JSScript *script;
*scriptp = JS_GetScriptedCaller(cx, NULL)->getScript();
*scriptp = JS_GetScriptedCaller(cx, NULL)->script();
*ip = 0;
if (argc != 0) {
v = argv[0];
@ -1531,8 +1532,8 @@ TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
JSStackFrame *caller = JS_GetScriptedCaller(cx, NULL);
if (!JS_EvaluateUCInStackFrame(cx, caller,
JS_GetStringChars(str), JS_GetStringLength(str),
caller->getScript()->filename,
caller->getScript()->lineno,
caller->script()->filename,
caller->script()->lineno,
rval)) {
return JSTRAP_ERROR;
}
@ -1634,7 +1635,7 @@ LineToPC(JSContext *cx, uintN argc, jsval *vp)
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE);
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))
return JS_FALSE;
lineno = (i == 0) ? script->lineno : (uintN)i;
@ -3203,8 +3204,8 @@ EvalInContext(JSContext *cx, uintN argc, jsval *vp)
return false;
}
if (!JS_EvaluateUCScript(cx, sobj, src, srclen,
fp->getScript()->filename,
JS_PCToLineNumber(cx, fp->getScript(), fp->pc(cx)),
fp->script()->filename,
JS_PCToLineNumber(cx, fp->script(), fp->pc(cx)),
vp)) {
return false;
}
@ -3234,12 +3235,12 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
FrameRegsIter fi(cx);
for (uint32 i = 0; i < upCount; ++i, ++fi) {
if (!fi.fp()->down)
if (!fi.fp()->prev())
break;
}
JSStackFrame *const fp = fi.fp();
if (!fp->hasScript()) {
if (!JS_IsScriptFrame(cx, fp)) {
JS_ReportError(cx, "cannot eval in non-script frame");
return JS_FALSE;
}
@ -3249,8 +3250,8 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
oldfp = JS_SaveFrameChain(cx);
JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, str->chars(), str->length(),
fp->getScript()->filename,
JS_PCToLineNumber(cx, fp->getScript(),
fp->script()->filename,
JS_PCToLineNumber(cx, fp->script(),
fi.pc()),
vp);
@ -3975,9 +3976,9 @@ Snarf(JSContext *cx, uintN argc, jsval *vp)
/* Get the currently executing script's name. */
fp = JS_GetScriptedCaller(cx, NULL);
JS_ASSERT(fp && fp->getScript()->filename);
JS_ASSERT(fp && fp->script()->filename);
#ifdef XP_UNIX
pathname = MakeAbsolutePathname(cx, fp->getScript()->filename, filename);
pathname = MakeAbsolutePathname(cx, fp->script()->filename, filename);
if (!pathname)
return JS_FALSE;
#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() {
var a = 1;
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;
// Recursion on trace is limited to MAX_CALL_STACK_ENTRIES = 500
const traceDepth = 490;
var trace = true;
function doEval() {
eval("");
}
function maybeTrace(x) {
if (!trace)
doEval();
function fun(x) {
if (x <= 0)
return 0;
return maybeTrace(x-1);
return fun(x-1);
}
function fatStack() {
return maybeTrace(traceDepth);
return fun(10000);
}
function assertRightFailure(e) {
@ -27,8 +16,6 @@ function assertRightFailure(e) {
true);
}
// This tests that we conservatively guard against stack space exhaustion
// before entering trace.
exception = false;
try {
fatStack.apply(null, new Array(numFatArgs));
@ -40,14 +27,3 @@ assertEq(exception, true);
// No more trace recursion w/ JM
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
// can't use a native frame, so clear fp.
fp = nsnull;
} else if (!fp->hasScript()) {
} else if (!JS_IsScriptFrame(cx, fp)) {
fp = nsnull;
}
@ -215,7 +215,7 @@ AllowedToAct(JSContext *cx, jsid id)
// if they've been cloned into less privileged contexts.
const char *filename;
if (fp &&
(filename = fp->getScript()->filename) &&
(filename = JS_GetFrameScript(cx, fp)->filename) &&
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
return JS_TRUE;
}
@ -246,7 +246,7 @@ CheckFilename(JSContext *cx, jsid id, JSStackFrame *fp)
{
const char *filename;
if (fp &&
(filename = fp->getScript()->filename) &&
(filename = JS_GetFrameScript(cx, fp)->filename) &&
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
return JS_TRUE;
}

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

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

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

@ -141,9 +141,9 @@ XPCJSStackFrame::CreateStack(JSContext* cx, JSStackFrame* fp,
{
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)))
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
// can't use a native frame, so clear fp.
fp = NULL;
} else if (!fp->hasScript()) {
} else if (!JS_IsScriptFrame(cx, fp)) {
fp = NULL;
}
@ -222,7 +222,7 @@ AccessCheck::isSystemOnlyAccessPermitted(JSContext *cx)
static const char prefix[] = "chrome://global/";
const char *filename;
if (fp &&
(filename = fp->getScript()->filename) &&
(filename = JS_GetFrameScript(cx, fp)->filename) &&
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
return true;
}