зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
de7daf410d
Коммит
dc78a5f3d3
|
@ -5432,7 +5432,7 @@ nsContentUtils::CanAccessNativeAnon()
|
||||||
// Some code is running, we can't make the assumption, as above, but we
|
// Some code is running, we can't make the assumption, as above, but we
|
||||||
// can't use a native frame, so clear fp.
|
// can't use a native frame, so clear fp.
|
||||||
fp = nsnull;
|
fp = nsnull;
|
||||||
} else if (!fp->hasScript()) {
|
} else if (!JS_IsScriptFrame(cx, fp)) {
|
||||||
fp = nsnull;
|
fp = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5447,8 +5447,8 @@ nsContentUtils::CanAccessNativeAnon()
|
||||||
// if they've been cloned into less privileged contexts.
|
// if they've been cloned into less privileged contexts.
|
||||||
static const char prefix[] = "chrome://global/";
|
static const char prefix[] = "chrome://global/";
|
||||||
const char *filename;
|
const char *filename;
|
||||||
if (fp && fp->hasScript() &&
|
if (fp && JS_IsScriptFrame(cx, fp) &&
|
||||||
(filename = fp->getScript()->filename) &&
|
(filename = JS_GetFrameScript(cx, fp)->filename) &&
|
||||||
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
|
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,7 @@
|
||||||
|
|
||||||
#include "jsatominlines.h"
|
#include "jsatominlines.h"
|
||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsscopeinlines.h"
|
#include "jsscopeinlines.h"
|
||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
|
@ -1795,7 +1796,7 @@ JS_GetGlobalForScopeChain(JSContext *cx)
|
||||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||||
|
|
||||||
if (cx->hasfp())
|
if (cx->hasfp())
|
||||||
return cx->fp()->getScopeChain()->getGlobal();
|
return cx->fp()->scopeChain().getGlobal();
|
||||||
|
|
||||||
JSObject *scope = cx->globalObject;
|
JSObject *scope = cx->globalObject;
|
||||||
if (!scope) {
|
if (!scope) {
|
||||||
|
@ -4760,7 +4761,7 @@ JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv)
|
||||||
// of object to create, create it, and clamp the return value to an object,
|
// of object to create, create it, and clamp the return value to an object,
|
||||||
// among other details. js_InvokeConstructor does the hard work.
|
// among other details. js_InvokeConstructor does the hard work.
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, argc, args))
|
if (!cx->stack().pushInvokeArgs(cx, argc, &args))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
args.callee().setObject(*ctor);
|
args.callee().setObject(*ctor);
|
||||||
|
@ -4836,7 +4837,7 @@ JS_IsRunning(JSContext *cx)
|
||||||
#endif
|
#endif
|
||||||
JSStackFrame *fp = cx->maybefp();
|
JSStackFrame *fp = cx->maybefp();
|
||||||
while (fp && fp->isDummyFrame())
|
while (fp && fp->isDummyFrame())
|
||||||
fp = fp->down;
|
fp = fp->prev();
|
||||||
return fp != NULL;
|
return fp != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1350,7 +1350,7 @@ array_toString(JSContext *cx, uintN argc, Value *vp)
|
||||||
|
|
||||||
LeaveTrace(cx);
|
LeaveTrace(cx);
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, 0, args))
|
if (!cx->stack().pushInvokeArgs(cx, 0, &args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
args.callee() = join;
|
args.callee() = join;
|
||||||
|
@ -1954,7 +1954,7 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp)
|
||||||
LeaveTrace(cx);
|
LeaveTrace(cx);
|
||||||
|
|
||||||
CompareArgs ca(cx, fval);
|
CompareArgs ca(cx, fval);
|
||||||
if (!cx->stack().pushInvokeArgs(cx, 2, ca.args))
|
if (!cx->stack().pushInvokeArgs(cx, 2, &ca.args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!js_MergeSort(vec, size_t(newlen), sizeof(Value),
|
if (!js_MergeSort(vec, size_t(newlen), sizeof(Value),
|
||||||
|
@ -2743,7 +2743,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
|
||||||
argc = 3 + REDUCE_MODE(mode);
|
argc = 3 + REDUCE_MODE(mode);
|
||||||
|
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, argc, args))
|
if (!cx->stack().pushInvokeArgs(cx, argc, &args))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
MUST_FLOW_THROUGH("out");
|
MUST_FLOW_THROUGH("out");
|
||||||
|
|
|
@ -598,13 +598,13 @@ JS_DECLARE_CALLINFO(js_NewNullClosure)
|
||||||
|
|
||||||
/* Defined in jsfun.cpp. */
|
/* Defined in jsfun.cpp. */
|
||||||
JS_DECLARE_CALLINFO(js_AllocFlatClosure)
|
JS_DECLARE_CALLINFO(js_AllocFlatClosure)
|
||||||
JS_DECLARE_CALLINFO(js_PutArguments)
|
JS_DECLARE_CALLINFO(js_PutArgumentsOnTrace)
|
||||||
JS_DECLARE_CALLINFO(js_PutCallObjectOnTrace)
|
JS_DECLARE_CALLINFO(js_PutCallObjectOnTrace)
|
||||||
JS_DECLARE_CALLINFO(js_SetCallVar)
|
JS_DECLARE_CALLINFO(js_SetCallVar)
|
||||||
JS_DECLARE_CALLINFO(js_SetCallArg)
|
JS_DECLARE_CALLINFO(js_SetCallArg)
|
||||||
JS_DECLARE_CALLINFO(js_CloneFunctionObject)
|
JS_DECLARE_CALLINFO(js_CloneFunctionObject)
|
||||||
JS_DECLARE_CALLINFO(js_CreateCallObjectOnTrace)
|
JS_DECLARE_CALLINFO(js_CreateCallObjectOnTrace)
|
||||||
JS_DECLARE_CALLINFO(js_Arguments)
|
JS_DECLARE_CALLINFO(js_NewArgumentsOnTrace)
|
||||||
|
|
||||||
/* Defined in jsnum.cpp. */
|
/* Defined in jsnum.cpp. */
|
||||||
JS_DECLARE_CALLINFO(js_NumberToString)
|
JS_DECLARE_CALLINFO(js_NumberToString)
|
||||||
|
|
|
@ -76,6 +76,8 @@
|
||||||
#include "jstracer.h"
|
#include "jstracer.h"
|
||||||
|
|
||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
# include "jswin.h"
|
# include "jswin.h"
|
||||||
|
@ -112,13 +114,13 @@ StackSegment::contains(const JSStackFrame *fp) const
|
||||||
if (isActive()) {
|
if (isActive()) {
|
||||||
JS_ASSERT(cx->hasfp());
|
JS_ASSERT(cx->hasfp());
|
||||||
start = cx->fp();
|
start = cx->fp();
|
||||||
stop = cx->activeSegment()->initialFrame->down;
|
stop = cx->activeSegment()->initialFrame->prev();
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(suspendedRegs && suspendedRegs->fp);
|
JS_ASSERT(suspendedRegs && suspendedRegs->fp);
|
||||||
start = suspendedRegs->fp;
|
start = suspendedRegs->fp;
|
||||||
stop = initialFrame->down;
|
stop = initialFrame->prev();
|
||||||
}
|
}
|
||||||
for (JSStackFrame *f = start; f != stop; f = f->down) {
|
for (JSStackFrame *f = start; f != stop; f = f->prev()) {
|
||||||
if (f == fp)
|
if (f == fp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -199,7 +201,7 @@ StackSpace::bumpCommit(Value *from, ptrdiff_t nvals) const
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JS_REQUIRES_STACK void
|
void
|
||||||
StackSpace::mark(JSTracer *trc)
|
StackSpace::mark(JSTracer *trc)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -215,33 +217,33 @@ StackSpace::mark(JSTracer *trc)
|
||||||
for (StackSegment *seg = currentSegment; seg; seg = seg->getPreviousInMemory()) {
|
for (StackSegment *seg = currentSegment; seg; seg = seg->getPreviousInMemory()) {
|
||||||
if (seg->inContext()) {
|
if (seg->inContext()) {
|
||||||
/* This may be the only pointer to the initialVarObj. */
|
/* This may be the only pointer to the initialVarObj. */
|
||||||
if (JSObject *varobj = seg->getInitialVarObj())
|
if (seg->hasInitialVarObj())
|
||||||
JS_CALL_OBJECT_TRACER(trc, varobj, "varobj");
|
MarkObject(trc, seg->getInitialVarObj(), "varobj");
|
||||||
|
|
||||||
/* Mark slots/args trailing off of the last stack frame. */
|
/* Mark slots/args trailing off of the last stack frame. */
|
||||||
JSStackFrame *fp = seg->getCurrentFrame();
|
JSStackFrame *fp = seg->getCurrentFrame();
|
||||||
MarkStackRangeConservatively(trc, fp->slots(), end);
|
MarkStackRangeConservatively(trc, fp->slots(), end);
|
||||||
|
|
||||||
/* Mark stack frames and slots/args between stack frames. */
|
/* Mark stack frames and slots/args between stack frames. */
|
||||||
JSStackFrame *initialFrame = seg->getInitialFrame();
|
JSStackFrame *initial = seg->getInitialFrame();
|
||||||
for (JSStackFrame *f = fp; f != initialFrame; f = f->down) {
|
for (JSStackFrame *f = fp; f != initial; f = f->prev()) {
|
||||||
js_TraceStackFrame(trc, f);
|
js_TraceStackFrame(trc, f);
|
||||||
MarkStackRangeConservatively(trc, f->down->slots(), f->argEnd());
|
MarkStackRangeConservatively(trc, f->prev()->slots(), (Value *)f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark initialFrame stack frame and leading args. */
|
/* Mark initial stack frame and leading args. */
|
||||||
js_TraceStackFrame(trc, initialFrame);
|
js_TraceStackFrame(trc, initial);
|
||||||
MarkValueRange(trc, seg->getInitialArgBegin(), initialFrame->argEnd(), "stack");
|
MarkStackRangeConservatively(trc, seg->valueRangeBegin(), (Value *)initial);
|
||||||
} else {
|
} else {
|
||||||
/* Mark slots/args trailing off segment. */
|
/* Mark slots/args trailing off segment. */
|
||||||
MarkValueRange(trc, seg->getInitialArgBegin(), end, "stack");
|
MarkValueRange(trc, seg->valueRangeBegin(), end, "stack");
|
||||||
}
|
}
|
||||||
end = seg->previousSegmentEnd();
|
end = (Value *)seg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
bool
|
||||||
StackSpace::pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard &ag)
|
StackSpace::pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard *ag)
|
||||||
{
|
{
|
||||||
Value *start = firstUnused();
|
Value *start = firstUnused();
|
||||||
ptrdiff_t nvals = VALUES_PER_STACK_SEGMENT + 2 + argc;
|
ptrdiff_t nvals = VALUES_PER_STACK_SEGMENT + 2 + argc;
|
||||||
|
@ -252,24 +254,24 @@ StackSpace::pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard &ag)
|
||||||
seg->setPreviousInMemory(currentSegment);
|
seg->setPreviousInMemory(currentSegment);
|
||||||
currentSegment = seg;
|
currentSegment = seg;
|
||||||
|
|
||||||
ag.cx = cx;
|
ag->cx = cx;
|
||||||
ag.seg = seg;
|
ag->seg = seg;
|
||||||
ag.argv_ = seg->getInitialArgBegin() + 2;
|
ag->argv_ = seg->valueRangeBegin() + 2;
|
||||||
ag.argc_ = argc;
|
ag->argc_ = argc;
|
||||||
|
|
||||||
/* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */
|
/* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
ag.prevInvokeSegment = invokeSegment;
|
ag->prevInvokeSegment = invokeSegment;
|
||||||
invokeSegment = seg;
|
invokeSegment = seg;
|
||||||
ag.prevInvokeFrame = invokeFrame;
|
ag->prevInvokeFrame = invokeFrame;
|
||||||
invokeFrame = NULL;
|
invokeFrame = NULL;
|
||||||
#endif
|
#endif
|
||||||
ag.prevInvokeArgEnd = invokeArgEnd;
|
ag->prevInvokeArgEnd = invokeArgEnd;
|
||||||
invokeArgEnd = ag.argv() + ag.argc();
|
invokeArgEnd = ag->argv() + ag->argc();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK void
|
void
|
||||||
StackSpace::popSegmentForInvoke(const InvokeArgsGuard &ag)
|
StackSpace::popSegmentForInvoke(const InvokeArgsGuard &ag)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!currentSegment->inContext());
|
JS_ASSERT(!currentSegment->inContext());
|
||||||
|
@ -286,44 +288,41 @@ StackSpace::popSegmentForInvoke(const InvokeArgsGuard &ag)
|
||||||
invokeArgEnd = ag.prevInvokeArgEnd;
|
invokeArgEnd = ag.prevInvokeArgEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
bool
|
||||||
* Always push a segment when starting a new execute frame since segments
|
StackSpace::getSegmentAndFrame(JSContext *cx, uintN vplen, uintN nfixed,
|
||||||
* provide initialVarObj, which may change.
|
FrameGuard *fg) const
|
||||||
*/
|
|
||||||
JS_REQUIRES_STACK bool
|
|
||||||
StackSpace::getExecuteFrame(JSContext *cx, JSStackFrame *down,
|
|
||||||
uintN vplen, uintN nfixed,
|
|
||||||
FrameGuard &fg) const
|
|
||||||
{
|
{
|
||||||
Value *start = firstUnused();
|
Value *start = firstUnused();
|
||||||
ptrdiff_t nvals = VALUES_PER_STACK_SEGMENT + vplen + VALUES_PER_STACK_FRAME + nfixed;
|
uintN nvals = VALUES_PER_STACK_SEGMENT + vplen + VALUES_PER_STACK_FRAME + nfixed;
|
||||||
if (!ensureSpace(cx, start, nvals))
|
if (!ensureSpace(cx, start, nvals))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fg.seg = new(start) StackSegment;
|
fg->seg_ = new(start) StackSegment;
|
||||||
fg.vp = start + VALUES_PER_STACK_SEGMENT;
|
fg->vp_ = start + VALUES_PER_STACK_SEGMENT;
|
||||||
fg.fp = reinterpret_cast<JSStackFrame *>(fg.vp + vplen);
|
fg->fp_ = reinterpret_cast<JSStackFrame *>(fg->vp() + vplen);
|
||||||
fg.down = down;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK void
|
void
|
||||||
StackSpace::pushExecuteFrame(JSContext *cx, FrameGuard &fg,
|
StackSpace::pushSegmentAndFrame(JSContext *cx, JSObject *initialVarObj,
|
||||||
JSFrameRegs ®s, JSObject *initialVarObj)
|
JSFrameRegs *regs, FrameGuard *fg)
|
||||||
{
|
{
|
||||||
fg.fp->down = fg.down;
|
/* Caller should have already initialized regs. */
|
||||||
StackSegment *seg = fg.seg;
|
JS_ASSERT(regs->fp == fg->fp());
|
||||||
|
|
||||||
|
/* Push segment. */
|
||||||
|
StackSegment *seg = fg->segment();
|
||||||
seg->setPreviousInMemory(currentSegment);
|
seg->setPreviousInMemory(currentSegment);
|
||||||
currentSegment = seg;
|
currentSegment = seg;
|
||||||
|
|
||||||
regs.fp = fg.fp;
|
/* Push frame. */
|
||||||
cx->pushSegmentAndFrame(seg, regs);
|
cx->pushSegmentAndFrame(seg, *regs);
|
||||||
seg->setInitialVarObj(initialVarObj);
|
seg->setInitialVarObj(initialVarObj);
|
||||||
fg.cx = cx;
|
fg->cx_ = cx;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK void
|
void
|
||||||
StackSpace::popFrame(JSContext *cx)
|
StackSpace::popSegmentAndFrame(JSContext *cx)
|
||||||
{
|
{
|
||||||
JS_ASSERT(isCurrentAndActive(cx));
|
JS_ASSERT(isCurrentAndActive(cx));
|
||||||
JS_ASSERT(cx->hasActiveSegment());
|
JS_ASSERT(cx->hasActiveSegment());
|
||||||
|
@ -331,34 +330,78 @@ StackSpace::popFrame(JSContext *cx)
|
||||||
currentSegment = currentSegment->getPreviousInMemory();
|
currentSegment = currentSegment->getPreviousInMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK
|
|
||||||
FrameGuard::~FrameGuard()
|
FrameGuard::~FrameGuard()
|
||||||
{
|
{
|
||||||
if (!pushed())
|
if (!pushed())
|
||||||
return;
|
return;
|
||||||
JS_ASSERT(cx->activeSegment() == seg);
|
JS_ASSERT(cx_->activeSegment() == segment());
|
||||||
JS_ASSERT(cx->maybefp() == fp);
|
JS_ASSERT(cx_->maybefp() == fp());
|
||||||
cx->stack().popFrame(cx);
|
cx_->stack().popSegmentAndFrame(cx_);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
bool
|
||||||
StackSpace::pushDummyFrame(JSContext *cx, FrameGuard &fg, JSFrameRegs ®s, JSObject *scopeChain)
|
StackSpace::getExecuteFrame(JSContext *cx, JSScript *script, ExecuteFrameGuard *fg) const
|
||||||
{
|
{
|
||||||
if (!getExecuteFrame(cx, cx->maybefp(), 0, 0, fg))
|
return getSegmentAndFrame(cx, 2, script->nfixed, fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StackSpace::pushExecuteFrame(JSContext *cx, JSObject *initialVarObj, ExecuteFrameGuard *fg)
|
||||||
|
{
|
||||||
|
JSStackFrame *fp = fg->fp();
|
||||||
|
JSScript *script = fp->script();
|
||||||
|
fg->regs_.pc = script->code;
|
||||||
|
fg->regs_.fp = fp;
|
||||||
|
fg->regs_.sp = fp->base();
|
||||||
|
pushSegmentAndFrame(cx, initialVarObj, &fg->regs_, fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
StackSpace::pushDummyFrame(JSContext *cx, JSObject &scopeChain, DummyFrameGuard *fg)
|
||||||
|
{
|
||||||
|
if (!getSegmentAndFrame(cx, 0 /*vplen*/, 0 /*nfixed*/, fg))
|
||||||
return false;
|
return false;
|
||||||
|
fg->fp()->initDummyFrame(cx, scopeChain);
|
||||||
JSStackFrame *fp = fg.getFrame();
|
fg->regs_.fp = fg->fp();
|
||||||
PodZero(fp);
|
fg->regs_.pc = NULL;
|
||||||
fp->setScopeChain(scopeChain);
|
fg->regs_.sp = fg->fp()->slots();
|
||||||
fp->flags = JSFRAME_DUMMY;
|
pushSegmentAndFrame(cx, NULL /*varobj*/, &fg->regs_, fg);
|
||||||
|
|
||||||
regs.pc = NULL;
|
|
||||||
regs.sp = fp->slots();
|
|
||||||
|
|
||||||
pushExecuteFrame(cx, fg, regs, NULL);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
StackSpace::getGeneratorFrame(JSContext *cx, uintN vplen, uintN nfixed, GeneratorFrameGuard *fg)
|
||||||
|
{
|
||||||
|
return getSegmentAndFrame(cx, vplen, nfixed, fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StackSpace::pushGeneratorFrame(JSContext *cx, JSFrameRegs *regs, GeneratorFrameGuard *fg)
|
||||||
|
{
|
||||||
|
JS_ASSERT(regs->fp == fg->fp());
|
||||||
|
JS_ASSERT(regs->fp->prev() == cx->maybefp());
|
||||||
|
pushSegmentAndFrame(cx, NULL /*varobj*/, regs, fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
StackSpace::bumpCommitAndLimit(JSStackFrame *base, Value *sp, uintN nvals, Value **limit) const
|
||||||
|
{
|
||||||
|
JS_ASSERT(sp == firstUnused());
|
||||||
|
JS_ASSERT(sp + nvals >= *limit);
|
||||||
|
#ifdef XP_WIN
|
||||||
|
if (commitEnd <= *limit) {
|
||||||
|
Value *quotaEnd = (Value *)base + STACK_QUOTA;
|
||||||
|
if (sp + nvals < quotaEnd) {
|
||||||
|
if (!ensureSpace(NULL, sp, nvals))
|
||||||
|
return false;
|
||||||
|
*limit = Min(quotaEnd, commitEnd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FrameRegsIter::initSlow()
|
FrameRegsIter::initSlow()
|
||||||
{
|
{
|
||||||
|
@ -377,35 +420,35 @@ FrameRegsIter::initSlow()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Using the invariant described in the js::StackSegment comment, we know that,
|
* Using the invariant described in the js::StackSegment comment, we know that,
|
||||||
* when a pair of down-linked stack frames are in the same segment, the
|
* when a pair of prev-linked stack frames are in the same segment, the
|
||||||
* up-frame's address is the top of the down-frame's stack, modulo missing
|
* first frame's address is the top of the prev-frame's stack, modulo missing
|
||||||
* arguments.
|
* arguments.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
FrameRegsIter::incSlow(JSStackFrame *up, JSStackFrame *down)
|
FrameRegsIter::incSlow(JSStackFrame *fp, JSStackFrame *prev)
|
||||||
{
|
{
|
||||||
JS_ASSERT(down);
|
JS_ASSERT(prev);
|
||||||
JS_ASSERT(curpc == down->savedPC);
|
JS_ASSERT(curpc == prev->savedpc_);
|
||||||
JS_ASSERT(up == curseg->getInitialFrame());
|
JS_ASSERT(fp == curseg->getInitialFrame());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the up-frame is in csup and the down-frame is in csdown, it is not
|
* If fp is in cs and the prev-frame is in csprev, it is not necessarily
|
||||||
* necessarily the case that |csup->getPreviousInContext == csdown| or that
|
* the case that |cs->getPreviousInContext == csprev| or that
|
||||||
* |csdown->getSuspendedFrame == down| (because of indirect eval and
|
* |csprev->getSuspendedFrame == prev| (because of indirect eval and
|
||||||
* JS_EvaluateInStackFrame). To compute down's sp, we need to do a linear
|
* JS_EvaluateInStackFrame). To compute prev's sp, we need to do a linear
|
||||||
* scan, keeping track of what is immediately after down in memory.
|
* scan, keeping track of what is immediately after prev in memory.
|
||||||
*/
|
*/
|
||||||
curseg = curseg->getPreviousInContext();
|
curseg = curseg->getPreviousInContext();
|
||||||
cursp = curseg->getSuspendedRegs()->sp;
|
cursp = curseg->getSuspendedRegs()->sp;
|
||||||
JSStackFrame *f = curseg->getSuspendedFrame();
|
JSStackFrame *f = curseg->getSuspendedFrame();
|
||||||
while (f != down) {
|
while (f != prev) {
|
||||||
if (f == curseg->getInitialFrame()) {
|
if (f == curseg->getInitialFrame()) {
|
||||||
curseg = curseg->getPreviousInContext();
|
curseg = curseg->getPreviousInContext();
|
||||||
cursp = curseg->getSuspendedRegs()->sp;
|
cursp = curseg->getSuspendedRegs()->sp;
|
||||||
f = curseg->getSuspendedFrame();
|
f = curseg->getSuspendedFrame();
|
||||||
} else {
|
} else {
|
||||||
cursp = contiguousDownFrameSP(f);
|
cursp = f->formalArgsEnd();
|
||||||
f = f->down;
|
f = f->prev();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -424,7 +467,7 @@ AllFramesIter::operator++()
|
||||||
curcs = curcs->getPreviousInMemory();
|
curcs = curcs->getPreviousInMemory();
|
||||||
curfp = curcs ? curcs->getCurrentFrame() : NULL;
|
curfp = curcs ? curcs->getCurrentFrame() : NULL;
|
||||||
} else {
|
} else {
|
||||||
curfp = curfp->down;
|
curfp = curfp->prev();
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -1346,9 +1389,9 @@ PopulateReportBlame(JSContext *cx, JSErrorReport *report)
|
||||||
* Walk stack until we find a frame that is associated with some script
|
* Walk stack until we find a frame that is associated with some script
|
||||||
* rather than a native frame.
|
* rather than a native frame.
|
||||||
*/
|
*/
|
||||||
for (JSStackFrame *fp = js_GetTopStackFrame(cx); fp; fp = fp->down) {
|
for (JSStackFrame *fp = js_GetTopStackFrame(cx); fp; fp = fp->prev()) {
|
||||||
if (fp->pc(cx)) {
|
if (fp->pc(cx)) {
|
||||||
report->filename = fp->getScript()->filename;
|
report->filename = fp->script()->filename;
|
||||||
report->lineno = js_FramePCToLineNumber(cx, fp);
|
report->lineno = js_FramePCToLineNumber(cx, fp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1442,7 +1485,7 @@ checkReportFlags(JSContext *cx, uintN *flags)
|
||||||
* the nearest scripted frame is strict, see bug 536306.
|
* the nearest scripted frame is strict, see bug 536306.
|
||||||
*/
|
*/
|
||||||
JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
|
JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
|
||||||
if (fp && fp->getScript()->strictModeCode)
|
if (fp && fp->script()->strictModeCode)
|
||||||
*flags &= ~JSREPORT_WARNING;
|
*flags &= ~JSREPORT_WARNING;
|
||||||
else if (JS_HAS_STRICT_OPTION(cx))
|
else if (JS_HAS_STRICT_OPTION(cx))
|
||||||
*flags |= JSREPORT_WARNING;
|
*flags |= JSREPORT_WARNING;
|
||||||
|
@ -1917,8 +1960,8 @@ js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
|
||||||
if (!fp)
|
if (!fp)
|
||||||
fp = js_GetTopStackFrame(cx);
|
fp = js_GetTopStackFrame(cx);
|
||||||
while (fp && fp->isDummyFrame())
|
while (fp && fp->isDummyFrame())
|
||||||
fp = fp->down;
|
fp = fp->prev();
|
||||||
JS_ASSERT_IF(fp, fp->hasScript());
|
JS_ASSERT_IF(fp, fp->isScriptFrame());
|
||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1938,7 +1981,7 @@ js_GetCurrentBytecodePC(JSContext* cx)
|
||||||
pc = cx->regs ? cx->regs->pc : NULL;
|
pc = cx->regs ? cx->regs->pc : NULL;
|
||||||
if (!pc)
|
if (!pc)
|
||||||
return NULL;
|
return NULL;
|
||||||
imacpc = cx->fp()->maybeIMacroPC();
|
imacpc = cx->fp()->maybeImacropc();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1956,7 +1999,7 @@ js_CurrentPCIsInImacro(JSContext *cx)
|
||||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||||
if (JS_ON_TRACE(cx))
|
if (JS_ON_TRACE(cx))
|
||||||
return cx->bailExit->imacpc != NULL;
|
return cx->bailExit->imacpc != NULL;
|
||||||
return cx->fp()->hasIMacroPC();
|
return cx->fp()->hasImacropc();
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
@ -2009,15 +2052,16 @@ JSContext::JSContext(JSRuntime *rt)
|
||||||
void
|
void
|
||||||
JSContext::pushSegmentAndFrame(js::StackSegment *newseg, JSFrameRegs &newregs)
|
JSContext::pushSegmentAndFrame(js::StackSegment *newseg, JSFrameRegs &newregs)
|
||||||
{
|
{
|
||||||
|
JS_ASSERT(regs != &newregs);
|
||||||
if (hasActiveSegment()) {
|
if (hasActiveSegment()) {
|
||||||
JS_ASSERT(regs->fp->savedPC == JSStackFrame::sInvalidPC);
|
JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
|
||||||
regs->fp->savedPC = regs->pc;
|
regs->fp->savedpc_ = regs->pc;
|
||||||
currentSegment->suspend(regs);
|
currentSegment->suspend(regs);
|
||||||
}
|
}
|
||||||
newseg->setPreviousInContext(currentSegment);
|
newseg->setPreviousInContext(currentSegment);
|
||||||
currentSegment = newseg;
|
currentSegment = newseg;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
newregs.fp->savedPC = JSStackFrame::sInvalidPC;
|
newregs.fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||||
#endif
|
#endif
|
||||||
setCurrentRegs(&newregs);
|
setCurrentRegs(&newregs);
|
||||||
newseg->joinContext(this, newregs.fp);
|
newseg->joinContext(this, newregs.fp);
|
||||||
|
@ -2028,7 +2072,7 @@ JSContext::popSegmentAndFrame()
|
||||||
{
|
{
|
||||||
JS_ASSERT(currentSegment->maybeContext() == this);
|
JS_ASSERT(currentSegment->maybeContext() == this);
|
||||||
JS_ASSERT(currentSegment->getInitialFrame() == regs->fp);
|
JS_ASSERT(currentSegment->getInitialFrame() == regs->fp);
|
||||||
JS_ASSERT(regs->fp->savedPC == JSStackFrame::sInvalidPC);
|
JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
|
||||||
currentSegment->leaveContext();
|
currentSegment->leaveContext();
|
||||||
currentSegment = currentSegment->getPreviousInContext();
|
currentSegment = currentSegment->getPreviousInContext();
|
||||||
if (currentSegment) {
|
if (currentSegment) {
|
||||||
|
@ -2038,11 +2082,11 @@ JSContext::popSegmentAndFrame()
|
||||||
setCurrentRegs(currentSegment->getSuspendedRegs());
|
setCurrentRegs(currentSegment->getSuspendedRegs());
|
||||||
currentSegment->resume();
|
currentSegment->resume();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
regs->fp->savedPC = JSStackFrame::sInvalidPC;
|
regs->fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(regs->fp->down == NULL);
|
JS_ASSERT(regs->fp->prev() == NULL);
|
||||||
setCurrentRegs(NULL);
|
setCurrentRegs(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2052,8 +2096,8 @@ JSContext::saveActiveSegment()
|
||||||
{
|
{
|
||||||
JS_ASSERT(hasActiveSegment());
|
JS_ASSERT(hasActiveSegment());
|
||||||
currentSegment->save(regs);
|
currentSegment->save(regs);
|
||||||
JS_ASSERT(regs->fp->savedPC == JSStackFrame::sInvalidPC);
|
JS_ASSERT(regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
|
||||||
regs->fp->savedPC = regs->pc;
|
regs->fp->savedpc_ = regs->pc;
|
||||||
setCurrentRegs(NULL);
|
setCurrentRegs(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2064,23 +2108,23 @@ JSContext::restoreSegment()
|
||||||
setCurrentRegs(ccs->getSuspendedRegs());
|
setCurrentRegs(ccs->getSuspendedRegs());
|
||||||
ccs->restore();
|
ccs->restore();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
regs->fp->savedPC = JSStackFrame::sInvalidPC;
|
regs->fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
JSGenerator *
|
JSGenerator *
|
||||||
JSContext::generatorFor(JSStackFrame *fp) const
|
JSContext::generatorFor(JSStackFrame *fp) const
|
||||||
{
|
{
|
||||||
JS_ASSERT(stack().contains(fp) && fp->isGenerator());
|
JS_ASSERT(stack().contains(fp) && fp->isGeneratorFrame());
|
||||||
JS_ASSERT(!fp->isFloatingGenerator());
|
JS_ASSERT(!fp->isFloatingGenerator());
|
||||||
JS_ASSERT(!genStack.empty());
|
JS_ASSERT(!genStack.empty());
|
||||||
|
|
||||||
if (JS_LIKELY(fp == genStack.back()->liveFrame))
|
if (JS_LIKELY(fp == genStack.back()->liveFrame()))
|
||||||
return genStack.back();
|
return genStack.back();
|
||||||
|
|
||||||
/* General case; should only be needed for debug APIs. */
|
/* General case; should only be needed for debug APIs. */
|
||||||
for (size_t i = 0; i < genStack.length(); ++i) {
|
for (size_t i = 0; i < genStack.length(); ++i) {
|
||||||
if (genStack[i]->liveFrame == fp)
|
if (genStack[i]->liveFrame() == fp)
|
||||||
return genStack[i];
|
return genStack[i];
|
||||||
}
|
}
|
||||||
JS_NOT_REACHED("no matching generator");
|
JS_NOT_REACHED("no matching generator");
|
||||||
|
@ -2100,8 +2144,8 @@ JSContext::containingSegment(const JSStackFrame *target)
|
||||||
JS_ASSERT(regs->fp);
|
JS_ASSERT(regs->fp);
|
||||||
JS_ASSERT(activeSegment() == seg);
|
JS_ASSERT(activeSegment() == seg);
|
||||||
JSStackFrame *f = regs->fp;
|
JSStackFrame *f = regs->fp;
|
||||||
JSStackFrame *stop = seg->getInitialFrame()->down;
|
JSStackFrame *stop = seg->getInitialFrame()->prev();
|
||||||
for (; f != stop; f = f->down) {
|
for (; f != stop; f = f->prev()) {
|
||||||
if (f == target)
|
if (f == target)
|
||||||
return seg;
|
return seg;
|
||||||
}
|
}
|
||||||
|
@ -2111,8 +2155,8 @@ JSContext::containingSegment(const JSStackFrame *target)
|
||||||
/* A suspended segment's top frame is its suspended frame. */
|
/* A suspended segment's top frame is its suspended frame. */
|
||||||
for (; seg; seg = seg->getPreviousInContext()) {
|
for (; seg; seg = seg->getPreviousInContext()) {
|
||||||
JSStackFrame *f = seg->getSuspendedFrame();
|
JSStackFrame *f = seg->getSuspendedFrame();
|
||||||
JSStackFrame *stop = seg->getInitialFrame()->down;
|
JSStackFrame *stop = seg->getInitialFrame()->prev();
|
||||||
for (; f != stop; f = f->down) {
|
for (; f != stop; f = f->prev()) {
|
||||||
if (f == target)
|
if (f == target)
|
||||||
return seg;
|
return seg;
|
||||||
}
|
}
|
||||||
|
|
257
js/src/jscntxt.h
257
js/src/jscntxt.h
|
@ -280,19 +280,18 @@ struct GlobalState {
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A StackSegment (referred to as just a 'segment') contains a down-linked set
|
* A StackSegment (referred to as just a 'segment') contains a prev-linked set
|
||||||
* of stack frames and the slots associated with each frame. A segment and its
|
* of stack frames and the slots associated with each frame. A segment and its
|
||||||
* contained frames/slots also have a precise memory layout that is described
|
* contained frames/slots also have a precise memory layout that is described
|
||||||
* in the js::StackSpace comment. A key layout invariant for segments is that
|
* in the js::StackSpace comment. A key layout invariant for segments is that
|
||||||
* down-linked frames are adjacent in memory, separated only by the values that
|
* prev-linked frames are adjacent in memory, separated only by the values that
|
||||||
* constitute the locals and expression stack of the down-frame and arguments
|
* constitute the locals and expression stack of the prev-frame.
|
||||||
* of the up-frame.
|
|
||||||
*
|
*
|
||||||
* The set of stack frames in a non-empty segment start at the segment's
|
* The set of stack frames in a non-empty segment start at the segment's
|
||||||
* "current frame", which is the most recently pushed frame, and ends at the
|
* "current frame", which is the most recently pushed frame, and ends at the
|
||||||
* segment's "initial frame". Note that, while all stack frames in a segment
|
* segment's "initial frame". Note that, while all stack frames in a segment
|
||||||
* are down-linked, not all down-linked frames are in the same segment. Hence,
|
* are prev-linked, not all prev-linked frames are in the same segment. Hence,
|
||||||
* for a segment |ss|, |ss->getInitialFrame()->down| may be non-null and in a
|
* for a segment |ss|, |ss->getInitialFrame()->prev| may be non-null and in a
|
||||||
* different segment. This occurs when the VM reenters itself (via Invoke or
|
* different segment. This occurs when the VM reenters itself (via Invoke or
|
||||||
* Execute). In full generality, a single context may contain a forest of trees
|
* Execute). In full generality, a single context may contain a forest of trees
|
||||||
* of stack frames. With respect to this forest, a segment contains a linear
|
* of stack frames. With respect to this forest, a segment contains a linear
|
||||||
|
@ -372,11 +371,7 @@ class StackSegment
|
||||||
|
|
||||||
/* Safe casts guaranteed by the contiguous-stack layout. */
|
/* Safe casts guaranteed by the contiguous-stack layout. */
|
||||||
|
|
||||||
Value *previousSegmentEnd() const {
|
Value *valueRangeBegin() const {
|
||||||
return (Value *)this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *getInitialArgBegin() const {
|
|
||||||
return (Value *)(this + 1);
|
return (Value *)(this + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,9 +510,14 @@ class StackSegment
|
||||||
initialVarObj = obj;
|
initialVarObj = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *getInitialVarObj() const {
|
bool hasInitialVarObj() {
|
||||||
JS_ASSERT(inContext());
|
JS_ASSERT(inContext());
|
||||||
return initialVarObj;
|
return initialVarObj != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSObject &getInitialVarObj() const {
|
||||||
|
JS_ASSERT(inContext() && initialVarObj);
|
||||||
|
return *initialVarObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -559,33 +559,51 @@ struct InvokeArgsAlreadyOnTheStack : CallArgs
|
||||||
class InvokeFrameGuard
|
class InvokeFrameGuard
|
||||||
{
|
{
|
||||||
friend class StackSpace;
|
friend class StackSpace;
|
||||||
JSContext *cx; /* null implies nothing pushed */
|
JSContext *cx_; /* null implies nothing pushed */
|
||||||
JSFrameRegs regs;
|
JSFrameRegs regs_;
|
||||||
JSFrameRegs *prevRegs;
|
JSFrameRegs *prevRegs_;
|
||||||
public:
|
public:
|
||||||
InvokeFrameGuard() : cx(NULL) {}
|
InvokeFrameGuard() : cx_(NULL) {}
|
||||||
JS_REQUIRES_STACK ~InvokeFrameGuard();
|
JS_REQUIRES_STACK ~InvokeFrameGuard();
|
||||||
bool pushed() const { return cx != NULL; }
|
bool pushed() const { return cx_ != NULL; }
|
||||||
JSFrameRegs &getRegs() { return regs; }
|
JSStackFrame *fp() const { return regs_.fp; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* See StackSpace::pushExecuteFrame. */
|
/* Reusable base; not for direct use. */
|
||||||
class FrameGuard
|
class FrameGuard
|
||||||
{
|
{
|
||||||
friend class StackSpace;
|
friend class StackSpace;
|
||||||
JSContext *cx; /* null implies nothing pushed */
|
JSContext *cx_; /* null implies nothing pushed */
|
||||||
StackSegment *seg;
|
StackSegment *seg_;
|
||||||
Value *vp;
|
Value *vp_;
|
||||||
JSStackFrame *fp;
|
JSStackFrame *fp_;
|
||||||
JSStackFrame *down;
|
|
||||||
public:
|
public:
|
||||||
FrameGuard() : cx(NULL), vp(NULL), fp(NULL) {}
|
FrameGuard() : cx_(NULL), vp_(NULL), fp_(NULL) {}
|
||||||
JS_REQUIRES_STACK ~FrameGuard();
|
JS_REQUIRES_STACK ~FrameGuard();
|
||||||
bool pushed() const { return cx != NULL; }
|
bool pushed() const { return cx_ != NULL; }
|
||||||
Value *getvp() const { return vp; }
|
StackSegment *segment() const { return seg_; }
|
||||||
JSStackFrame *getFrame() const { return fp; }
|
Value *vp() const { return vp_; }
|
||||||
|
JSStackFrame *fp() const { return fp_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* See StackSpace::pushExecuteFrame. */
|
||||||
|
class ExecuteFrameGuard : public FrameGuard
|
||||||
|
{
|
||||||
|
friend class StackSpace;
|
||||||
|
JSFrameRegs regs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* See StackSpace::pushDummyFrame. */
|
||||||
|
class DummyFrameGuard : public FrameGuard
|
||||||
|
{
|
||||||
|
friend class StackSpace;
|
||||||
|
JSFrameRegs regs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* See StackSpace::pushGeneratorFrame. */
|
||||||
|
class GeneratorFrameGuard : public FrameGuard
|
||||||
|
{};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stack layout
|
* Stack layout
|
||||||
*
|
*
|
||||||
|
@ -610,7 +628,7 @@ class FrameGuard
|
||||||
* |segment| slots |frame| slots |frame| slots |frame| slots |
|
* |segment| slots |frame| slots |frame| slots |frame| slots |
|
||||||
* | ^ | ^ |
|
* | ^ | ^ |
|
||||||
* ? <----------' `----------' `----------'
|
* ? <----------' `----------' `----------'
|
||||||
* down down down
|
* prev prev prev
|
||||||
*
|
*
|
||||||
* Moreover, the bytes in the following ranges form a contiguous array of
|
* Moreover, the bytes in the following ranges form a contiguous array of
|
||||||
* Values that are marked during GC:
|
* Values that are marked during GC:
|
||||||
|
@ -653,7 +671,7 @@ class FrameGuard
|
||||||
* preserves order (in terms of previousInContext and previousInMemory,
|
* preserves order (in terms of previousInContext and previousInMemory,
|
||||||
* respectively).
|
* respectively).
|
||||||
* 2. the mapping from stack frames to their containing segment preserves
|
* 2. the mapping from stack frames to their containing segment preserves
|
||||||
* order (in terms of down and previousInContext, respectively).
|
* order (in terms of prev and previousInContext, respectively).
|
||||||
*/
|
*/
|
||||||
class StackSpace
|
class StackSpace
|
||||||
{
|
{
|
||||||
|
@ -674,23 +692,42 @@ class StackSpace
|
||||||
#endif
|
#endif
|
||||||
Value *invokeArgEnd;
|
Value *invokeArgEnd;
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool pushSegmentForInvoke(JSContext *cx, uintN argc,
|
|
||||||
InvokeArgsGuard &ag);
|
|
||||||
JS_REQUIRES_STACK bool pushInvokeFrameSlow(JSContext *cx, const InvokeArgsGuard &ag,
|
|
||||||
InvokeFrameGuard &fg);
|
|
||||||
JS_REQUIRES_STACK void popInvokeFrameSlow(const CallArgs &args);
|
|
||||||
JS_REQUIRES_STACK void popSegmentForInvoke(const InvokeArgsGuard &ag);
|
|
||||||
|
|
||||||
/* Although guards are friends, XGuard should only call popX(). */
|
|
||||||
friend class InvokeArgsGuard;
|
friend class InvokeArgsGuard;
|
||||||
JS_REQUIRES_STACK inline void popInvokeArgs(const InvokeArgsGuard &args);
|
|
||||||
friend class InvokeFrameGuard;
|
friend class InvokeFrameGuard;
|
||||||
JS_REQUIRES_STACK void popInvokeFrame(const InvokeFrameGuard &ag);
|
|
||||||
friend class FrameGuard;
|
friend class FrameGuard;
|
||||||
JS_REQUIRES_STACK void popFrame(JSContext *cx);
|
|
||||||
|
|
||||||
/* Return a pointer to the first unused slot. */
|
bool pushSegmentForInvoke(JSContext *cx, uintN argc, InvokeArgsGuard *ag);
|
||||||
JS_REQUIRES_STACK
|
void popSegmentForInvoke(const InvokeArgsGuard &ag);
|
||||||
|
|
||||||
|
bool pushInvokeFrameSlow(JSContext *cx, const InvokeArgsGuard &ag,
|
||||||
|
InvokeFrameGuard *fg);
|
||||||
|
void popInvokeFrameSlow(const CallArgs &args);
|
||||||
|
|
||||||
|
bool getSegmentAndFrame(JSContext *cx, uintN vplen, uintN nfixed,
|
||||||
|
FrameGuard *fg) const;
|
||||||
|
void pushSegmentAndFrame(JSContext *cx, JSObject *initialVarObj,
|
||||||
|
JSFrameRegs *regs, FrameGuard *fg);
|
||||||
|
void popSegmentAndFrame(JSContext *cx);
|
||||||
|
|
||||||
|
struct EnsureSpaceCheck {
|
||||||
|
inline bool operator()(const StackSpace &, JSContext *, Value *, uintN);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LimitCheck {
|
||||||
|
JSStackFrame *base;
|
||||||
|
Value **limit;
|
||||||
|
LimitCheck(JSStackFrame *base, Value **limit) : base(base), limit(limit) {}
|
||||||
|
inline bool operator()(const StackSpace &, JSContext *, Value *, uintN);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Check>
|
||||||
|
inline JSStackFrame *getCallFrame(JSContext *cx, Value *sp, uintN nactual,
|
||||||
|
JSFunction *fun, JSScript *script,
|
||||||
|
uint32 *pflags, Check check) const;
|
||||||
|
|
||||||
|
inline void popInvokeArgs(const InvokeArgsGuard &args);
|
||||||
|
inline void popInvokeFrame(const InvokeFrameGuard &ag);
|
||||||
|
|
||||||
inline Value *firstUnused() const;
|
inline Value *firstUnused() const;
|
||||||
|
|
||||||
inline bool isCurrentAndActive(JSContext *cx) const;
|
inline bool isCurrentAndActive(JSContext *cx) const;
|
||||||
|
@ -714,6 +751,19 @@ class StackSpace
|
||||||
static const size_t COMMIT_VALS = 16 * 1024;
|
static const size_t COMMIT_VALS = 16 * 1024;
|
||||||
static const size_t COMMIT_BYTES = COMMIT_VALS * sizeof(Value);
|
static const size_t COMMIT_BYTES = COMMIT_VALS * sizeof(Value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SunSpider and v8bench have roughly an average of 9 slots per script.
|
||||||
|
* Our heuristic for a quick over-recursion check uses a generous slot
|
||||||
|
* count based on this estimate. We take this frame size and multiply it
|
||||||
|
* by the old recursion limit from the interpreter.
|
||||||
|
*
|
||||||
|
* Worst case, if an average size script (<=9 slots) over recurses, it'll
|
||||||
|
* effectively be the same as having increased the old inline call count
|
||||||
|
* to <= 5,000.
|
||||||
|
*/
|
||||||
|
static const size_t STACK_QUOTA = (VALUES_PER_STACK_FRAME + 18) *
|
||||||
|
JS_MAX_INLINE_CALL_COUNT;
|
||||||
|
|
||||||
/* Kept as a member of JSThreadData; cannot use constructor/destructor. */
|
/* Kept as a member of JSThreadData; cannot use constructor/destructor. */
|
||||||
bool init();
|
bool init();
|
||||||
void finish();
|
void finish();
|
||||||
|
@ -735,6 +785,9 @@ class StackSpace
|
||||||
*/
|
*/
|
||||||
inline bool ensureEnoughSpaceToEnterTrace();
|
inline bool ensureEnoughSpaceToEnterTrace();
|
||||||
|
|
||||||
|
/* See stubs::HitStackQuota. */
|
||||||
|
inline bool bumpCommitEnd(Value *from, uintN nslots);
|
||||||
|
|
||||||
/* +1 for slow native's stack frame. */
|
/* +1 for slow native's stack frame. */
|
||||||
static const ptrdiff_t MAX_TRACE_SPACE_VALS =
|
static const ptrdiff_t MAX_TRACE_SPACE_VALS =
|
||||||
MAX_NATIVE_STACK_SLOTS + MAX_CALL_STACK_ENTRIES * VALUES_PER_STACK_FRAME +
|
MAX_NATIVE_STACK_SLOTS + MAX_CALL_STACK_ENTRIES * VALUES_PER_STACK_FRAME +
|
||||||
|
@ -744,14 +797,14 @@ class StackSpace
|
||||||
JS_REQUIRES_STACK void mark(JSTracer *trc);
|
JS_REQUIRES_STACK void mark(JSTracer *trc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For all four use cases below:
|
* For all five use cases below:
|
||||||
* - The boolean-valued functions call js_ReportOutOfScriptQuota on OOM.
|
* - The boolean-valued functions call js_ReportOutOfScriptQuota on OOM.
|
||||||
* - The "get*Frame" functions do not change any global state, they just
|
* - The "get*Frame" functions do not change any global state, they just
|
||||||
* check OOM and return pointers to an uninitialized frame with the
|
* check OOM and return pointers to an uninitialized frame with the
|
||||||
* requested missing arguments/slots. Only once the "push*Frame"
|
* requested missing arguments/slots. Only once the "push*Frame"
|
||||||
* function has been called is global state updated. Thus, between
|
* function has been called is global state updated. Thus, between
|
||||||
* "get*Frame" and "push*Frame", the frame and slots are unrooted.
|
* "get*Frame" and "push*Frame", the frame and slots are unrooted.
|
||||||
* - The "push*Frame" functions will set fp->down; the caller needn't.
|
* - The "push*Frame" functions will set fp->prev; the caller needn't.
|
||||||
* - Functions taking "*Guard" arguments will use the guard's destructor
|
* - Functions taking "*Guard" arguments will use the guard's destructor
|
||||||
* to pop the allocation. The caller must ensure the guard has the
|
* to pop the allocation. The caller must ensure the guard has the
|
||||||
* appropriate lifetime.
|
* appropriate lifetime.
|
||||||
|
@ -765,66 +818,54 @@ class StackSpace
|
||||||
* Invoke calls. The InvokeArgumentsGuard passed to Invoke must come from
|
* Invoke calls. The InvokeArgumentsGuard passed to Invoke must come from
|
||||||
* an immediately-enclosing (stack-wise) call to pushInvokeArgs.
|
* an immediately-enclosing (stack-wise) call to pushInvokeArgs.
|
||||||
*/
|
*/
|
||||||
JS_REQUIRES_STACK
|
bool pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard *ag);
|
||||||
bool pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard &ag);
|
|
||||||
|
|
||||||
/* These functions are called inside Invoke, not Invoke clients. */
|
/* These functions are called inside Invoke, not Invoke clients. */
|
||||||
bool getInvokeFrame(JSContext *cx, const CallArgs &args,
|
bool getInvokeFrame(JSContext *cx, const CallArgs &args, JSFunction *fun,
|
||||||
uintN nmissing, uintN nfixed,
|
JSScript *script, uint32 *flags, InvokeFrameGuard *fg) const;
|
||||||
InvokeFrameGuard &fg) const;
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK
|
void pushInvokeFrame(JSContext *cx, const CallArgs &args, InvokeFrameGuard *fg);
|
||||||
void pushInvokeFrame(JSContext *cx, const CallArgs &args, InvokeFrameGuard &fg);
|
|
||||||
|
|
||||||
/*
|
/* These functions are called inside Execute, not Execute clients. */
|
||||||
* For the simpler case when arguments are allocated at the same time as
|
bool getExecuteFrame(JSContext *cx, JSScript *script, ExecuteFrameGuard *fg) const;
|
||||||
* the frame and it is not necessary to have rooted argument values before
|
void pushExecuteFrame(JSContext *cx, JSObject *initialVarObj, ExecuteFrameGuard *fg);
|
||||||
* pushing the frame.
|
|
||||||
*/
|
|
||||||
JS_REQUIRES_STACK
|
|
||||||
bool getExecuteFrame(JSContext *cx, JSStackFrame *down,
|
|
||||||
uintN vplen, uintN nfixed,
|
|
||||||
FrameGuard &fg) const;
|
|
||||||
JS_REQUIRES_STACK
|
|
||||||
void pushExecuteFrame(JSContext *cx, FrameGuard &fg,
|
|
||||||
JSFrameRegs ®s, JSObject *initialVarObj);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since RAII cannot be used for inline frames, callers must manually
|
* Since RAII cannot be used for inline frames, callers must manually
|
||||||
* call pushInlineFrame/popInlineFrame.
|
* call pushInlineFrame/popInlineFrame.
|
||||||
*/
|
*/
|
||||||
JS_REQUIRES_STACK
|
inline JSStackFrame *getInlineFrame(JSContext *cx, Value *sp, uintN nactual,
|
||||||
inline JSStackFrame *getInlineFrame(JSContext *cx, Value *sp,
|
JSFunction *fun, JSScript *script,
|
||||||
uintN nmissing, uintN nfixed) const;
|
uint32 *flags) const;
|
||||||
|
inline void pushInlineFrame(JSContext *cx, JSScript *script, JSStackFrame *fp,
|
||||||
|
JSFrameRegs *regs);
|
||||||
|
inline void popInlineFrame(JSContext *cx, JSStackFrame *prev, js::Value *newsp);
|
||||||
|
|
||||||
JS_REQUIRES_STACK
|
/* These functions are called inside SendToGenerator. */
|
||||||
inline JSStackFrame *getInlineFrameUnchecked(JSContext *cx, Value *sp,
|
bool getGeneratorFrame(JSContext *cx, uintN vplen, uintN nfixed,
|
||||||
uintN nmissing) const;
|
GeneratorFrameGuard *fg);
|
||||||
|
void pushGeneratorFrame(JSContext *cx, JSFrameRegs *regs, GeneratorFrameGuard *fg);
|
||||||
|
|
||||||
JS_REQUIRES_STACK
|
/* Pushes a JSStackFrame::isDummyFrame. */
|
||||||
inline void pushInlineFrame(JSContext *cx, JSStackFrame *fp, jsbytecode *pc,
|
bool pushDummyFrame(JSContext *cx, JSObject &scopeChain, DummyFrameGuard *fg);
|
||||||
JSStackFrame *newfp);
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK
|
/* Check and bump the given stack limit. */
|
||||||
inline void popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down);
|
inline JSStackFrame *getInlineFrameWithinLimit(JSContext *cx, Value *sp, uintN nactual,
|
||||||
|
JSFunction *fun, JSScript *script, uint32 *flags,
|
||||||
|
JSStackFrame *base, Value **limit) const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For pushing a bookkeeping frame.
|
* Compute a stack limit for entering method jit code which allows the
|
||||||
|
* method jit to check for end-of-stack and over-recursion with a single
|
||||||
|
* comparison. See STACK_QUOTA above.
|
||||||
*/
|
*/
|
||||||
JS_REQUIRES_STACK
|
inline Value *getStackLimit(JSContext *cx);
|
||||||
bool pushDummyFrame(JSContext *cx, FrameGuard &fg, JSFrameRegs ®s, JSObject *scopeChain);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure space based on an over-recursion limit.
|
* Try to bump the given 'limit' by bumping the commit limit. Return false
|
||||||
|
* if fully committed or if 'limit' exceeds 'base' + STACK_QUOTA.
|
||||||
*/
|
*/
|
||||||
inline bool ensureSpace(JSContext *maybecx, Value *start, Value *from,
|
bool bumpCommitAndLimit(JSStackFrame *base, Value *from, uintN nvals, Value **limit) const;
|
||||||
Value *& limit, uint32 nslots) const;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a stack limit for quickly detecting over-recursion and whether
|
|
||||||
* a commit bump is needed.
|
|
||||||
*/
|
|
||||||
inline Value *makeStackLimit(Value *start) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
JS_STATIC_ASSERT(StackSpace::CAPACITY_VALS % StackSpace::COMMIT_VALS == 0);
|
JS_STATIC_ASSERT(StackSpace::CAPACITY_VALS % StackSpace::COMMIT_VALS == 0);
|
||||||
|
@ -832,7 +873,7 @@ JS_STATIC_ASSERT(StackSpace::CAPACITY_VALS % StackSpace::COMMIT_VALS == 0);
|
||||||
/*
|
/*
|
||||||
* While |cx->fp|'s pc/sp are available in |cx->regs|, to compute the saved
|
* While |cx->fp|'s pc/sp are available in |cx->regs|, to compute the saved
|
||||||
* value of pc/sp for any other frame, it is necessary to know about that
|
* value of pc/sp for any other frame, it is necessary to know about that
|
||||||
* frame's up-frame. This iterator maintains this information when walking down
|
* frame's next-frame. This iterator maintains this information when walking
|
||||||
* a chain of stack frames starting at |cx->fp|.
|
* a chain of stack frames starting at |cx->fp|.
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
|
@ -847,8 +888,7 @@ class FrameRegsIter
|
||||||
jsbytecode *curpc;
|
jsbytecode *curpc;
|
||||||
|
|
||||||
void initSlow();
|
void initSlow();
|
||||||
void incSlow(JSStackFrame *up, JSStackFrame *down);
|
void incSlow(JSStackFrame *fp, JSStackFrame *prev);
|
||||||
static inline Value *contiguousDownFrameSP(JSStackFrame *up);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JS_REQUIRES_STACK inline FrameRegsIter(JSContext *cx);
|
JS_REQUIRES_STACK inline FrameRegsIter(JSContext *cx);
|
||||||
|
@ -2155,10 +2195,10 @@ struct JSContext
|
||||||
JSStackFrame *findFrameAtLevel(uintN targetLevel) {
|
JSStackFrame *findFrameAtLevel(uintN targetLevel) {
|
||||||
JSStackFrame *fp = this->regs->fp;
|
JSStackFrame *fp = this->regs->fp;
|
||||||
while (true) {
|
while (true) {
|
||||||
JS_ASSERT(fp && fp->hasScript());
|
JS_ASSERT(fp && fp->isScriptFrame());
|
||||||
if (fp->getScript()->staticLevel == targetLevel)
|
if (fp->script()->staticLevel == targetLevel)
|
||||||
break;
|
break;
|
||||||
fp = fp->down;
|
fp = fp->prev();
|
||||||
}
|
}
|
||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
|
@ -2373,27 +2413,6 @@ js_TraceRegExpStatics(JSTracer *trc, JSContext *acx)
|
||||||
acx->regExpStatics.mark(trc);
|
acx->regExpStatics.mark(trc);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ALWAYS_INLINE JSObject *
|
|
||||||
JSStackFrame::varobj(js::StackSegment *seg) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(seg->contains(this));
|
|
||||||
return hasFunction() ? maybeCallObj() : seg->getInitialVarObj();
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE JSObject *
|
|
||||||
JSStackFrame::varobj(JSContext *cx) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(cx->activeSegment()->contains(this));
|
|
||||||
return hasFunction() ? maybeCallObj() : cx->activeSegment()->getInitialVarObj();
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE jsbytecode *
|
|
||||||
JSStackFrame::pc(JSContext *cx) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(cx->regs && cx->containingSegment(this) != NULL);
|
|
||||||
return (cx->regs->fp == this) ? cx->regs->pc : savedPC;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
# define JS_THREAD_ID(cx) ((cx)->thread ? (cx)->thread->id : 0)
|
# define JS_THREAD_ID(cx) ((cx)->thread ? (cx)->thread->id : 0)
|
||||||
#endif
|
#endif
|
||||||
|
@ -2428,16 +2447,16 @@ class AutoCheckRequestDepth {
|
||||||
static inline uintN
|
static inline uintN
|
||||||
FramePCOffset(JSContext *cx, JSStackFrame* fp)
|
FramePCOffset(JSContext *cx, JSStackFrame* fp)
|
||||||
{
|
{
|
||||||
jsbytecode *pc = fp->hasIMacroPC() ? fp->getIMacroPC() : fp->pc(cx);
|
jsbytecode *pc = fp->hasImacropc() ? fp->imacropc() : fp->pc(cx);
|
||||||
return uintN(pc - fp->getScript()->code);
|
return uintN(pc - fp->script()->code);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline JSAtom **
|
static inline JSAtom **
|
||||||
FrameAtomBase(JSContext *cx, JSStackFrame *fp)
|
FrameAtomBase(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return fp->hasIMacroPC()
|
return fp->hasImacropc()
|
||||||
? COMMON_ATOMS_START(&cx->runtime->atomState)
|
? COMMON_ATOMS_START(&cx->runtime->atomState)
|
||||||
: fp->getScript()->atomMap.vector;
|
: fp->script()->atomMap.vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
|
@ -108,63 +108,14 @@ StackSpace::isCurrentAndActive(JSContext *cx) const
|
||||||
currentSegment == cx->getCurrentSegment();
|
currentSegment == cx->getCurrentSegment();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* SunSpider and v8bench have roughly an average of 9 slots per script.
|
|
||||||
* Our heuristic for a quick over-recursion check uses a generous slot
|
|
||||||
* count based on this estimate. We take this frame size and multiply it
|
|
||||||
* by the old recursion limit from the interpreter.
|
|
||||||
*
|
|
||||||
* Worst case, if an average size script (<=9 slots) over recurses, it'll
|
|
||||||
* effectively be the same as having increased the old inline call count
|
|
||||||
* to <= 5,000.
|
|
||||||
*/
|
|
||||||
static const uint32 MAX_STACK_USAGE = (VALUES_PER_STACK_FRAME + 18) * JS_MAX_INLINE_CALL_COUNT;
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE Value *
|
|
||||||
StackSpace::makeStackLimit(Value *start) const
|
|
||||||
{
|
|
||||||
Value *limit = JS_MIN(start + MAX_STACK_USAGE, end);
|
|
||||||
#ifdef XP_WIN
|
|
||||||
limit = JS_MIN(limit, commitEnd);
|
|
||||||
#endif
|
|
||||||
return limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE bool
|
|
||||||
StackSpace::ensureSpace(JSContext *maybecx, Value *start, Value *from,
|
|
||||||
Value *& limit, uint32 nslots) const
|
|
||||||
{
|
|
||||||
JS_ASSERT(from == firstUnused());
|
|
||||||
#ifdef XP_WIN
|
|
||||||
/*
|
|
||||||
* If commitEnd < limit, we're guaranteed that we reached the end of the
|
|
||||||
* commit depth, because stackLimit is MIN(commitEnd, limit). If we did
|
|
||||||
* reach this soft limit, check if we can bump the commit end without
|
|
||||||
* over-recursing.
|
|
||||||
*/
|
|
||||||
ptrdiff_t nvals = VALUES_PER_STACK_FRAME + nslots;
|
|
||||||
if (commitEnd <= limit && from + nvals < (start + MAX_STACK_USAGE)) {
|
|
||||||
if (!ensureSpace(maybecx, from, nvals))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Compute a new limit. */
|
|
||||||
limit = makeStackLimit(start);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
js_ReportOverRecursed(maybecx);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ALWAYS_INLINE bool
|
JS_ALWAYS_INLINE bool
|
||||||
StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
|
StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
|
||||||
{
|
{
|
||||||
JS_ASSERT(from == firstUnused());
|
JS_ASSERT(from == firstUnused());
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
JS_ASSERT(from <= commitEnd);
|
JS_ASSERT(from <= commitEnd);
|
||||||
if (commitEnd - from >= nvals)
|
if (JS_LIKELY(commitEnd - from >= nvals))
|
||||||
return true;
|
goto success;
|
||||||
if (end - from < nvals) {
|
if (end - from < nvals) {
|
||||||
if (maybecx)
|
if (maybecx)
|
||||||
js_ReportOutOfScriptQuota(maybecx);
|
js_ReportOutOfScriptQuota(maybecx);
|
||||||
|
@ -175,15 +126,20 @@ StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const
|
||||||
js_ReportOutOfScriptQuota(maybecx);
|
js_ReportOutOfScriptQuota(maybecx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
goto success;
|
||||||
#else
|
#else
|
||||||
if (end - from < nvals) {
|
if (JS_LIKELY(end - from < nvals)) {
|
||||||
if (maybecx)
|
if (maybecx)
|
||||||
js_ReportOutOfScriptQuota(maybecx);
|
js_ReportOutOfScriptQuota(maybecx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
goto success;
|
||||||
#endif
|
#endif
|
||||||
|
success:
|
||||||
|
#ifdef DEBUG
|
||||||
|
memset(from, 0xde, nvals * sizeof(js::Value));
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_ALWAYS_INLINE bool
|
JS_ALWAYS_INLINE bool
|
||||||
|
@ -195,8 +151,29 @@ StackSpace::ensureEnoughSpaceToEnterTrace()
|
||||||
return end - firstUnused() > MAX_TRACE_SPACE_VALS;
|
return end - firstUnused() > MAX_TRACE_SPACE_VALS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_ALWAYS_INLINE bool
|
||||||
|
StackSpace::EnsureSpaceCheck::operator()(const StackSpace &stack, JSContext *cx,
|
||||||
|
Value *from, uintN nvals)
|
||||||
|
{
|
||||||
|
return stack.ensureSpace(cx, from, nvals);
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_ALWAYS_INLINE bool
|
||||||
|
StackSpace::LimitCheck::operator()(const StackSpace &stack, JSContext *cx,
|
||||||
|
Value *from, uintN nvals)
|
||||||
|
{
|
||||||
|
JS_ASSERT(from == stack.firstUnused());
|
||||||
|
JS_ASSERT(from < *limit);
|
||||||
|
if (*limit - from >= ptrdiff_t(nvals))
|
||||||
|
return true;
|
||||||
|
if (stack.bumpCommitAndLimit(base, from, nvals, limit))
|
||||||
|
return true;
|
||||||
|
js_ReportOverRecursed(cx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE bool
|
JS_REQUIRES_STACK JS_ALWAYS_INLINE bool
|
||||||
StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard &ag)
|
StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard *ag)
|
||||||
{
|
{
|
||||||
if (JS_UNLIKELY(!isCurrentAndActive(cx)))
|
if (JS_UNLIKELY(!isCurrentAndActive(cx)))
|
||||||
return pushSegmentForInvoke(cx, argc, ag);
|
return pushSegmentForInvoke(cx, argc, ag);
|
||||||
|
@ -213,18 +190,18 @@ StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard &ag)
|
||||||
MakeValueRangeGCSafe(vp, vpend);
|
MakeValueRangeGCSafe(vp, vpend);
|
||||||
|
|
||||||
/* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */
|
/* Use invokeArgEnd to root [vp, vpend) until the frame is pushed. */
|
||||||
ag.prevInvokeArgEnd = invokeArgEnd;
|
ag->prevInvokeArgEnd = invokeArgEnd;
|
||||||
invokeArgEnd = vpend;
|
invokeArgEnd = vpend;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
ag.prevInvokeSegment = invokeSegment;
|
ag->prevInvokeSegment = invokeSegment;
|
||||||
invokeSegment = currentSegment;
|
invokeSegment = currentSegment;
|
||||||
ag.prevInvokeFrame = invokeFrame;
|
ag->prevInvokeFrame = invokeFrame;
|
||||||
invokeFrame = cx->maybefp();
|
invokeFrame = cx->maybefp();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ag.cx = cx;
|
ag->cx = cx;
|
||||||
ag.argv_ = vp + 2;
|
ag->argv_ = vp + 2;
|
||||||
ag.argc_ = argc;
|
ag->argc_ = argc;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,61 +233,99 @@ InvokeArgsGuard::~InvokeArgsGuard()
|
||||||
cx->stack().popInvokeArgs(*this);
|
cx->stack().popInvokeArgs(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Check>
|
||||||
|
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
|
||||||
|
StackSpace::getCallFrame(JSContext *cx, Value *firstUnused, uintN nactual,
|
||||||
|
JSFunction *fun, JSScript *script, uint32 *flags,
|
||||||
|
Check check) const
|
||||||
|
{
|
||||||
|
JS_ASSERT(fun->script() == script);
|
||||||
|
|
||||||
|
/* Include an extra sizeof(JSStackFrame) for the method-jit. */
|
||||||
|
uintN nvals = VALUES_PER_STACK_FRAME + script->nslots;
|
||||||
|
uintN nformal = fun->nargs;
|
||||||
|
|
||||||
|
/* Maintain layout invariant: &formalArgs[0] == ((Value *)fp) - nformal. */
|
||||||
|
|
||||||
|
if (nactual == nformal) {
|
||||||
|
if (JS_UNLIKELY(!check(*this, cx, firstUnused, nvals)))
|
||||||
|
return NULL;
|
||||||
|
return reinterpret_cast<JSStackFrame *>(firstUnused);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nactual < nformal) {
|
||||||
|
*flags |= JSFRAME_UNDERFLOW_ARGS;
|
||||||
|
uintN nmissing = nformal - nactual;
|
||||||
|
if (JS_UNLIKELY(!check(*this, cx, firstUnused, nmissing + nvals)))
|
||||||
|
return NULL;
|
||||||
|
SetValueRangeToUndefined(firstUnused, nmissing);
|
||||||
|
return reinterpret_cast<JSStackFrame *>(firstUnused + nmissing);
|
||||||
|
}
|
||||||
|
|
||||||
|
*flags |= JSFRAME_OVERFLOW_ARGS;
|
||||||
|
uintN ncopy = 2 + nformal;
|
||||||
|
if (JS_UNLIKELY(!check(*this, cx, firstUnused, ncopy + nvals)))
|
||||||
|
return NULL;
|
||||||
|
memcpy(firstUnused, firstUnused - (2 + nactual), ncopy * sizeof(Value));
|
||||||
|
return reinterpret_cast<JSStackFrame *>(firstUnused + ncopy);
|
||||||
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE bool
|
JS_REQUIRES_STACK JS_ALWAYS_INLINE bool
|
||||||
StackSpace::getInvokeFrame(JSContext *cx, const CallArgs &args,
|
StackSpace::getInvokeFrame(JSContext *cx, const CallArgs &args,
|
||||||
uintN nmissing, uintN nfixed,
|
JSFunction *fun, JSScript *script,
|
||||||
InvokeFrameGuard &fg) const
|
uint32 *flags, InvokeFrameGuard *fg) const
|
||||||
{
|
{
|
||||||
JS_ASSERT(firstUnused() == args.argv() + args.argc());
|
JS_ASSERT(firstUnused() == args.argv() + args.argc());
|
||||||
|
|
||||||
Value *start = args.argv() + args.argc();
|
Value *firstUnused = args.argv() + args.argc();
|
||||||
ptrdiff_t nvals = nmissing + VALUES_PER_STACK_FRAME + nfixed;
|
fg->regs_.fp = getCallFrame(cx, firstUnused, args.argc(), fun, script, flags,
|
||||||
if (!ensureSpace(cx, start, nvals))
|
EnsureSpaceCheck());
|
||||||
return false;
|
fg->regs_.sp = fg->regs_.fp->slots() + script->nfixed;
|
||||||
fg.regs.fp = reinterpret_cast<JSStackFrame *>(start + nmissing);
|
fg->regs_.pc = script->code;
|
||||||
return true;
|
|
||||||
|
return fg->regs_.fp != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
||||||
StackSpace::pushInvokeFrame(JSContext *cx, const CallArgs &args,
|
StackSpace::pushInvokeFrame(JSContext *cx, const CallArgs &args,
|
||||||
InvokeFrameGuard &fg)
|
InvokeFrameGuard *fg)
|
||||||
{
|
{
|
||||||
JS_ASSERT(firstUnused() == args.argv() + args.argc());
|
JS_ASSERT(firstUnused() == args.argv() + args.argc());
|
||||||
|
|
||||||
JSStackFrame *fp = fg.regs.fp;
|
JSStackFrame *fp = fg->regs_.fp;
|
||||||
JSStackFrame *down = cx->maybefp();
|
JSStackFrame *prev = cx->maybefp();
|
||||||
fp->down = down;
|
fp->prev_ = prev;
|
||||||
if (JS_UNLIKELY(!currentSegment->inContext())) {
|
if (JS_UNLIKELY(!currentSegment->inContext())) {
|
||||||
cx->pushSegmentAndFrame(currentSegment, fg.regs);
|
cx->pushSegmentAndFrame(currentSegment, fg->regs_);
|
||||||
} else {
|
} else {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fp->savedPC = JSStackFrame::sInvalidPC;
|
fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||||
JS_ASSERT(down->savedPC == JSStackFrame::sInvalidPC);
|
JS_ASSERT(prev->savedpc_ == JSStackFrame::sInvalidpc);
|
||||||
#endif
|
#endif
|
||||||
down->savedPC = cx->regs->pc;
|
prev->savedpc_ = cx->regs->pc;
|
||||||
fg.prevRegs = cx->regs;
|
fg->prevRegs_ = cx->regs;
|
||||||
cx->setCurrentRegs(&fg.regs);
|
cx->setCurrentRegs(&fg->regs_);
|
||||||
}
|
}
|
||||||
fg.cx = cx;
|
|
||||||
|
|
||||||
|
fg->cx_ = cx;
|
||||||
JS_ASSERT(isCurrentAndActive(cx));
|
JS_ASSERT(isCurrentAndActive(cx));
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
||||||
StackSpace::popInvokeFrame(const InvokeFrameGuard &fg)
|
StackSpace::popInvokeFrame(const InvokeFrameGuard &fg)
|
||||||
{
|
{
|
||||||
JSContext *cx = fg.cx;
|
JSContext *cx = fg.cx_;
|
||||||
JSStackFrame *fp = fg.regs.fp;
|
JSStackFrame *fp = fg.regs_.fp;
|
||||||
|
|
||||||
JS_ASSERT(isCurrentAndActive(cx));
|
JS_ASSERT(isCurrentAndActive(cx));
|
||||||
if (JS_UNLIKELY(currentSegment->getInitialFrame() == fp)) {
|
if (JS_UNLIKELY(currentSegment->getInitialFrame() == fp)) {
|
||||||
cx->popSegmentAndFrame();
|
cx->popSegmentAndFrame();
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(&fg.regs == cx->regs);
|
JS_ASSERT(&fg.regs_ == cx->regs);
|
||||||
JS_ASSERT(fp->down == fg.prevRegs->fp);
|
JS_ASSERT(fp->prev_ == fg.prevRegs_->fp);
|
||||||
cx->setCurrentRegs(fg.prevRegs);
|
cx->setCurrentRegs(fg.prevRegs_);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
cx->fp()->savedPC = JSStackFrame::sInvalidPC;
|
cx->fp()->savedpc_ = JSStackFrame::sInvalidpc;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,60 +335,92 @@ InvokeFrameGuard::~InvokeFrameGuard()
|
||||||
{
|
{
|
||||||
if (JS_UNLIKELY(!pushed()))
|
if (JS_UNLIKELY(!pushed()))
|
||||||
return;
|
return;
|
||||||
cx->stack().popInvokeFrame(*this);
|
cx_->stack().popInvokeFrame(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
|
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
|
||||||
StackSpace::getInlineFrameUnchecked(JSContext *cx, Value *sp,
|
StackSpace::getInlineFrame(JSContext *cx, Value *sp, uintN nactual,
|
||||||
uintN nmissing) const
|
JSFunction *fun, JSScript *script, uint32 *flags) const
|
||||||
{
|
{
|
||||||
JS_ASSERT(isCurrentAndActive(cx));
|
JS_ASSERT(isCurrentAndActive(cx));
|
||||||
JS_ASSERT(cx->hasActiveSegment());
|
JS_ASSERT(cx->hasActiveSegment());
|
||||||
JS_ASSERT(cx->regs->sp == sp);
|
JS_ASSERT(cx->regs->sp == sp);
|
||||||
|
|
||||||
JSStackFrame *fp = reinterpret_cast<JSStackFrame *>(sp + nmissing);
|
return getCallFrame(cx, sp, nactual, fun, script, flags, EnsureSpaceCheck());
|
||||||
return fp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
|
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
|
||||||
StackSpace::getInlineFrame(JSContext *cx, Value *sp,
|
StackSpace::getInlineFrameWithinLimit(JSContext *cx, Value *sp, uintN nactual,
|
||||||
uintN nmissing, uintN nfixed) const
|
JSFunction *fun, JSScript *script, uint32 *flags,
|
||||||
{
|
JSStackFrame *base, Value **limit) const
|
||||||
ptrdiff_t nvals = nmissing + VALUES_PER_STACK_FRAME + nfixed;
|
|
||||||
if (!ensureSpace(cx, sp, nvals))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return getInlineFrameUnchecked(cx, sp, nmissing);
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
|
||||||
StackSpace::pushInlineFrame(JSContext *cx, JSStackFrame *fp, jsbytecode *pc,
|
|
||||||
JSStackFrame *newfp)
|
|
||||||
{
|
|
||||||
JS_ASSERT(isCurrentAndActive(cx));
|
|
||||||
JS_ASSERT(cx->regs->fp == fp && cx->regs->pc == pc);
|
|
||||||
|
|
||||||
fp->savedPC = pc;
|
|
||||||
newfp->down = fp;
|
|
||||||
#ifdef DEBUG
|
|
||||||
newfp->savedPC = JSStackFrame::sInvalidPC;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
|
||||||
StackSpace::popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down)
|
|
||||||
{
|
{
|
||||||
JS_ASSERT(isCurrentAndActive(cx));
|
JS_ASSERT(isCurrentAndActive(cx));
|
||||||
JS_ASSERT(cx->hasActiveSegment());
|
JS_ASSERT(cx->hasActiveSegment());
|
||||||
JS_ASSERT(cx->regs->fp == up && up->down == down);
|
JS_ASSERT(cx->regs->sp == sp);
|
||||||
JS_ASSERT(up->savedPC == JSStackFrame::sInvalidPC);
|
|
||||||
JS_ASSERT(!up->hasIMacroPC());
|
return getCallFrame(cx, sp, nactual, fun, script, flags, LimitCheck(base, limit));
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
||||||
|
StackSpace::pushInlineFrame(JSContext *cx, JSScript *script, JSStackFrame *fp,
|
||||||
|
JSFrameRegs *regs)
|
||||||
|
{
|
||||||
|
JS_ASSERT(isCurrentAndActive(cx));
|
||||||
|
JS_ASSERT(cx->regs == regs && script == fp->script());
|
||||||
|
|
||||||
|
regs->fp->savedpc_ = regs->pc;
|
||||||
|
fp->prev_ = regs->fp;
|
||||||
|
#ifdef DEBUG
|
||||||
|
fp->savedpc_ = JSStackFrame::sInvalidpc;
|
||||||
|
#endif
|
||||||
|
regs->fp = fp;
|
||||||
|
regs->pc = script->code;
|
||||||
|
regs->sp = fp->slots() + script->nfixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_REQUIRES_STACK JS_ALWAYS_INLINE void
|
||||||
|
StackSpace::popInlineFrame(JSContext *cx, JSStackFrame *prev, Value *newsp)
|
||||||
|
{
|
||||||
|
JS_ASSERT(isCurrentAndActive(cx));
|
||||||
|
JS_ASSERT(cx->hasActiveSegment());
|
||||||
|
JS_ASSERT(cx->regs->fp->prev_ == prev);
|
||||||
|
JS_ASSERT(cx->regs->fp->savedpc_ == JSStackFrame::sInvalidpc);
|
||||||
|
JS_ASSERT(!cx->regs->fp->hasImacropc());
|
||||||
|
JS_ASSERT(prev->base() <= newsp && newsp <= cx->regs->fp->formalArgsEnd());
|
||||||
|
|
||||||
JSFrameRegs *regs = cx->regs;
|
JSFrameRegs *regs = cx->regs;
|
||||||
regs->fp = down;
|
regs->fp = prev;
|
||||||
regs->pc = down->savedPC;
|
regs->pc = prev->savedpc_;
|
||||||
|
regs->sp = newsp;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
down->savedPC = JSStackFrame::sInvalidPC;
|
prev->savedpc_ = JSStackFrame::sInvalidpc;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_ALWAYS_INLINE Value *
|
||||||
|
StackSpace::getStackLimit(JSContext *cx)
|
||||||
|
{
|
||||||
|
Value *sp = cx->regs->sp;
|
||||||
|
JS_ASSERT(sp == firstUnused());
|
||||||
|
Value *limit = sp + STACK_QUOTA;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to reserve the whole STACK_QUOTA. If that fails, though, just
|
||||||
|
* reserve the minimum required space: enough for the nslots + an
|
||||||
|
* additional stack frame.
|
||||||
|
*/
|
||||||
|
#ifdef XP_WIN
|
||||||
|
if (JS_LIKELY(limit <= commitEnd))
|
||||||
|
return limit;
|
||||||
|
if (ensureSpace(NULL /* don't report error */, sp, STACK_QUOTA))
|
||||||
|
return limit;
|
||||||
|
uintN minimum = cx->fp()->numSlots() + VALUES_PER_STACK_FRAME;
|
||||||
|
return ensureSpace(cx, sp, minimum) ? sp + minimum : NULL;
|
||||||
|
#else
|
||||||
|
if (JS_LIKELY(limit <= end))
|
||||||
|
return limit;
|
||||||
|
uintN minimum = cx->fp()->numSlots() + VALUES_PER_STACK_FRAME;
|
||||||
|
return ensureSpace(cx, sp, minimum) ? sp + minimum : NULL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,42 +439,22 @@ FrameRegsIter::FrameRegsIter(JSContext *cx)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value *
|
|
||||||
FrameRegsIter::contiguousDownFrameSP(JSStackFrame *up)
|
|
||||||
{
|
|
||||||
JS_ASSERT(up->argv);
|
|
||||||
Value *sp = up->argv + up->numActualArgs();
|
|
||||||
#ifdef DEBUG
|
|
||||||
JS_ASSERT(sp <= up->argEnd());
|
|
||||||
JS_ASSERT(sp >= (up->down->hasScript() ? up->down->base() : up->down->slots()));
|
|
||||||
if (up->hasFunction()) {
|
|
||||||
uint16 nargs = up->getFunction()->nargs;
|
|
||||||
uintN argc = up->numActualArgs();
|
|
||||||
uintN missing = argc < nargs ? nargs - argc : 0;
|
|
||||||
JS_ASSERT(sp == up->argEnd() - missing);
|
|
||||||
} else {
|
|
||||||
JS_ASSERT(sp == up->argEnd());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return sp;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline FrameRegsIter &
|
inline FrameRegsIter &
|
||||||
FrameRegsIter::operator++()
|
FrameRegsIter::operator++()
|
||||||
{
|
{
|
||||||
JSStackFrame *up = curfp;
|
JSStackFrame *fp = curfp;
|
||||||
JSStackFrame *down = curfp = curfp->down;
|
JSStackFrame *prev = curfp = curfp->prev();
|
||||||
if (!down)
|
if (!prev)
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
curpc = down->savedPC;
|
curpc = prev->savedpc_;
|
||||||
|
|
||||||
if (JS_UNLIKELY(up == curseg->getInitialFrame())) {
|
if (JS_UNLIKELY(fp == curseg->getInitialFrame())) {
|
||||||
incSlow(up, down);
|
incSlow(fp, prev);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursp = contiguousDownFrameSP(up);
|
cursp = fp->formalArgsEnd();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2056,7 +2056,7 @@ date_toJSON(JSContext *cx, uintN argc, Value *vp)
|
||||||
/* Step 6. */
|
/* Step 6. */
|
||||||
LeaveTrace(cx);
|
LeaveTrace(cx);
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, 0, args))
|
if (!cx->stack().pushInvokeArgs(cx, 0, &args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
args.callee() = toISO;
|
args.callee() = toISO;
|
||||||
|
|
|
@ -64,6 +64,7 @@
|
||||||
#include "jsstr.h"
|
#include "jsstr.h"
|
||||||
|
|
||||||
#include "jsatominlines.h"
|
#include "jsatominlines.h"
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsscopeinlines.h"
|
#include "jsscopeinlines.h"
|
||||||
|
|
||||||
|
@ -1077,7 +1078,7 @@ JS_GetScriptPrincipals(JSContext *cx, JSScript *script)
|
||||||
JS_PUBLIC_API(JSStackFrame *)
|
JS_PUBLIC_API(JSStackFrame *)
|
||||||
JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
|
JS_FrameIterator(JSContext *cx, JSStackFrame **iteratorp)
|
||||||
{
|
{
|
||||||
*iteratorp = (*iteratorp == NULL) ? js_GetTopStackFrame(cx) : (*iteratorp)->down;
|
*iteratorp = (*iteratorp == NULL) ? js_GetTopStackFrame(cx) : (*iteratorp)->prev();
|
||||||
return *iteratorp;
|
return *iteratorp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1104,16 +1105,16 @@ js_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
JSSecurityCallbacks *callbacks;
|
JSSecurityCallbacks *callbacks;
|
||||||
|
|
||||||
if (fp->hasFunction()) {
|
if (fp->isFunctionFrame()) {
|
||||||
callbacks = JS_GetSecurityCallbacks(cx);
|
callbacks = JS_GetSecurityCallbacks(cx);
|
||||||
if (callbacks && callbacks->findObjectPrincipals) {
|
if (callbacks && callbacks->findObjectPrincipals) {
|
||||||
if (FUN_OBJECT(fp->getFunction()) != fp->callee())
|
if (&fp->fun()->compiledFunObj() != &fp->callee())
|
||||||
return callbacks->findObjectPrincipals(cx, fp->callee());
|
return callbacks->findObjectPrincipals(cx, &fp->callee());
|
||||||
/* FALL THROUGH */
|
/* FALL THROUGH */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fp->hasScript())
|
if (fp->isScriptFrame())
|
||||||
return fp->getScript()->principals;
|
return fp->script()->principals;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1140,7 +1141,7 @@ js_EvalFramePrincipals(JSContext *cx, JSObject *callee, JSStackFrame *caller)
|
||||||
JS_PUBLIC_API(void *)
|
JS_PUBLIC_API(void *)
|
||||||
JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
if (fp->hasAnnotation() && fp->hasScript()) {
|
if (fp->annotation() && fp->isScriptFrame()) {
|
||||||
JSPrincipals *principals = js_StackFramePrincipals(cx, fp);
|
JSPrincipals *principals = js_StackFramePrincipals(cx, fp);
|
||||||
|
|
||||||
if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
|
if (principals && principals->globalPrivilegesEnabled(cx, principals)) {
|
||||||
|
@ -1148,7 +1149,7 @@ JS_GetFrameAnnotation(JSContext *cx, JSStackFrame *fp)
|
||||||
* Give out an annotation only if privileges have not been revoked
|
* Give out an annotation only if privileges have not been revoked
|
||||||
* or disabled globally.
|
* or disabled globally.
|
||||||
*/
|
*/
|
||||||
return fp->getAnnotation();
|
return fp->annotation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1182,7 +1183,7 @@ JS_IsScriptFrame(JSContext *cx, JSStackFrame *fp)
|
||||||
JS_PUBLIC_API(JSObject *)
|
JS_PUBLIC_API(JSObject *)
|
||||||
JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameObject(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return fp->maybeScopeChain();
|
return &fp->scopeChain();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSObject *)
|
JS_PUBLIC_API(JSObject *)
|
||||||
|
@ -1200,7 +1201,7 @@ JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
JS_ASSERT(cx->stack().contains(fp));
|
JS_ASSERT(cx->stack().contains(fp));
|
||||||
|
|
||||||
if (!fp->hasFunction())
|
if (!fp->isFunctionFrame())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Force creation of argument object if not yet created */
|
/* Force creation of argument object if not yet created */
|
||||||
|
@ -1218,37 +1219,36 @@ JS_GetFrameThis(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
if (fp->isDummyFrame())
|
if (fp->isDummyFrame())
|
||||||
return NULL;
|
return NULL;
|
||||||
else
|
return fp->computeThisObject(cx);
|
||||||
return fp->getThisObject(cx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSFunction *)
|
JS_PUBLIC_API(JSFunction *)
|
||||||
JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return fp->maybeFunction();
|
return fp->maybeFun();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSObject *)
|
JS_PUBLIC_API(JSObject *)
|
||||||
JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
if (!fp->hasFunction())
|
if (!fp->isFunctionFrame())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
JS_ASSERT(fp->callee()->isFunction());
|
JS_ASSERT(fp->callee().isFunction());
|
||||||
JS_ASSERT(fp->callee()->getPrivate() == fp->getFunction());
|
JS_ASSERT(fp->callee().getPrivate() == fp->fun());
|
||||||
return fp->callee();
|
return &fp->callee();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
|
JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return (fp->flags & JSFRAME_CONSTRUCTING) != 0;
|
return fp->isConstructing();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSObject *)
|
JS_PUBLIC_API(JSObject *)
|
||||||
JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return fp->callee();
|
return fp->maybeCallee();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
|
@ -1265,13 +1265,13 @@ JS_GetValidFrameCalleeObject(JSContext *cx, JSStackFrame *fp, jsval *vp)
|
||||||
JS_PUBLIC_API(JSBool)
|
JS_PUBLIC_API(JSBool)
|
||||||
JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
|
JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return (fp->flags & JSFRAME_DEBUGGER) != 0;
|
return fp->isDebuggerFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(jsval)
|
JS_PUBLIC_API(jsval)
|
||||||
JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
|
JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return Jsvalify(fp->getReturnValue());
|
return Jsvalify(fp->returnValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(void)
|
JS_PUBLIC_API(void)
|
||||||
|
@ -1354,7 +1354,7 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp,
|
||||||
if (!script)
|
if (!script)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool ok = !!Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL, Valueify(rval));
|
bool ok = Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL, Valueify(rval));
|
||||||
|
|
||||||
js_DestroyScript(cx, script);
|
js_DestroyScript(cx, script);
|
||||||
return ok;
|
return ok;
|
||||||
|
@ -1534,13 +1534,14 @@ js_GetPropertyByIdWithFakeFrame(JSContext *cx, JSObject *obj, JSObject *scopeobj
|
||||||
{
|
{
|
||||||
JS_ASSERT(scopeobj->isGlobal());
|
JS_ASSERT(scopeobj->isGlobal());
|
||||||
|
|
||||||
JSFrameRegs regs;
|
DummyFrameGuard frame;
|
||||||
FrameGuard frame;
|
if (!cx->stack().pushDummyFrame(cx, *scopeobj, &frame))
|
||||||
if (!cx->stack().pushDummyFrame(cx, frame, regs, scopeobj))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool ok = JS_GetPropertyById(cx, obj, id, vp);
|
bool ok = JS_GetPropertyById(cx, obj, id, vp);
|
||||||
frame.getFrame()->putActivationObjects(cx);
|
|
||||||
|
JS_ASSERT(!frame.fp()->hasCallObj());
|
||||||
|
JS_ASSERT(!frame.fp()->hasArgsObj());
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1550,13 +1551,14 @@ js_SetPropertyByIdWithFakeFrame(JSContext *cx, JSObject *obj, JSObject *scopeobj
|
||||||
{
|
{
|
||||||
JS_ASSERT(scopeobj->isGlobal());
|
JS_ASSERT(scopeobj->isGlobal());
|
||||||
|
|
||||||
JSFrameRegs regs;
|
DummyFrameGuard frame;
|
||||||
FrameGuard frame;
|
if (!cx->stack().pushDummyFrame(cx, *scopeobj, &frame))
|
||||||
if (!cx->stack().pushDummyFrame(cx, frame, regs, scopeobj))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool ok = JS_SetPropertyById(cx, obj, id, vp);
|
bool ok = JS_SetPropertyById(cx, obj, id, vp);
|
||||||
frame.getFrame()->putActivationObjects(cx);
|
|
||||||
|
JS_ASSERT(!frame.fp()->hasCallObj());
|
||||||
|
JS_ASSERT(!frame.fp()->hasArgsObj());
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1566,13 +1568,14 @@ js_CallFunctionValueWithFakeFrame(JSContext *cx, JSObject *obj, JSObject *scopeo
|
||||||
{
|
{
|
||||||
JS_ASSERT(scopeobj->isGlobal());
|
JS_ASSERT(scopeobj->isGlobal());
|
||||||
|
|
||||||
JSFrameRegs regs;
|
DummyFrameGuard frame;
|
||||||
FrameGuard frame;
|
if (!cx->stack().pushDummyFrame(cx, *scopeobj, &frame))
|
||||||
if (!cx->stack().pushDummyFrame(cx, frame, regs, scopeobj))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool ok = JS_CallFunctionValue(cx, obj, funval, argc, argv, rval);
|
bool ok = JS_CallFunctionValue(cx, obj, funval, argc, argv, rval);
|
||||||
frame.getFrame()->putActivationObjects(cx);
|
|
||||||
|
JS_ASSERT(!frame.fp()->hasCallObj());
|
||||||
|
JS_ASSERT(!frame.fp()->hasArgsObj());
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1747,9 +1750,9 @@ JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
|
||||||
if (!fp)
|
if (!fp)
|
||||||
fp = js_GetTopStackFrame(cx);
|
fp = js_GetTopStackFrame(cx);
|
||||||
while (fp) {
|
while (fp) {
|
||||||
if (fp->hasScript())
|
if (fp->isScriptFrame())
|
||||||
return JS_GetScriptFilenameFlags(fp->getScript());
|
return JS_GetScriptFilenameFlags(fp->script());
|
||||||
fp = fp->down;
|
fp = fp->prev();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2254,7 +2257,7 @@ inline char *
|
||||||
jstv_Filename(JSStackFrame *fp)
|
jstv_Filename(JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
while (fp && fp->script == NULL)
|
while (fp && fp->script == NULL)
|
||||||
fp = fp->down;
|
fp = fp->prev;
|
||||||
return (fp && fp->script && fp->script->filename)
|
return (fp && fp->script && fp->script->filename)
|
||||||
? (char *)fp->script->filename
|
? (char *)fp->script->filename
|
||||||
: jstv_empty;
|
: jstv_empty;
|
||||||
|
@ -2263,7 +2266,7 @@ inline uintN
|
||||||
jstv_Lineno(JSContext *cx, JSStackFrame *fp)
|
jstv_Lineno(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
while (fp && fp->pc(cx) == NULL)
|
while (fp && fp->pc(cx) == NULL)
|
||||||
fp = fp->down;
|
fp = fp->prev;
|
||||||
return (fp && fp->pc(cx)) ? js_FramePCToLineNumber(cx, fp) : 0;
|
return (fp && fp->pc(cx)) ? js_FramePCToLineNumber(cx, fp) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1894,7 +1894,7 @@ static bool
|
||||||
MakeUpvarForEval(JSParseNode *pn, JSCodeGenerator *cg)
|
MakeUpvarForEval(JSParseNode *pn, JSCodeGenerator *cg)
|
||||||
{
|
{
|
||||||
JSContext *cx = cg->parser->context;
|
JSContext *cx = cg->parser->context;
|
||||||
JSFunction *fun = cg->parser->callerFrame->getFunction();
|
JSFunction *fun = cg->parser->callerFrame->fun();
|
||||||
uintN upvarLevel = fun->u.i.script->staticLevel;
|
uintN upvarLevel = fun->u.i.script->staticLevel;
|
||||||
|
|
||||||
JSFunctionBox *funbox = cg->funbox;
|
JSFunctionBox *funbox = cg->funbox;
|
||||||
|
@ -2077,8 +2077,8 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
if (cg->flags & TCF_IN_FOR_INIT)
|
if (cg->flags & TCF_IN_FOR_INIT)
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
JS_ASSERT(caller->hasScript());
|
JS_ASSERT(caller->isScriptFrame());
|
||||||
if (!caller->hasFunction())
|
if (!caller->isFunctionFrame())
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2107,7 +2107,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
* defeats the display optimization to static link searching used
|
* defeats the display optimization to static link searching used
|
||||||
* by JSOP_{GET,CALL}UPVAR.
|
* by JSOP_{GET,CALL}UPVAR.
|
||||||
*/
|
*/
|
||||||
JSFunction *fun = cg->parser->callerFrame->getFunction();
|
JSFunction *fun = cg->parser->callerFrame->fun();
|
||||||
JS_ASSERT(cg->staticLevel >= fun->u.i.script->staticLevel);
|
JS_ASSERT(cg->staticLevel >= fun->u.i.script->staticLevel);
|
||||||
unsigned skip = cg->staticLevel - fun->u.i.script->staticLevel;
|
unsigned skip = cg->staticLevel - fun->u.i.script->staticLevel;
|
||||||
if (cg->skipSpansGenerator(skip))
|
if (cg->skipSpansGenerator(skip))
|
||||||
|
@ -2202,8 +2202,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JSStackFrame *caller = cg->parser->callerFrame;
|
JSStackFrame *caller = cg->parser->callerFrame;
|
||||||
#endif
|
#endif
|
||||||
JS_ASSERT(caller);
|
JS_ASSERT(caller->isScriptFrame());
|
||||||
JS_ASSERT(caller->hasScript());
|
|
||||||
|
|
||||||
JSTreeContext *tc = cg;
|
JSTreeContext *tc = cg;
|
||||||
while (tc->staticLevel != level)
|
while (tc->staticLevel != level)
|
||||||
|
@ -2212,7 +2211,7 @@ BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||||
|
|
||||||
JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
|
JSCodeGenerator *evalcg = (JSCodeGenerator *) tc;
|
||||||
JS_ASSERT(evalcg->compileAndGo());
|
JS_ASSERT(evalcg->compileAndGo());
|
||||||
JS_ASSERT(caller->hasFunction() && cg->parser->callerVarObj == evalcg->scopeChain);
|
JS_ASSERT(caller->isFunctionFrame() && cg->parser->callerVarObj == evalcg->scopeChain);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't generate upvars on the left side of a for loop. See
|
* Don't generate upvars on the left side of a for loop. See
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
#include "jsstaticcheck.h"
|
#include "jsstaticcheck.h"
|
||||||
|
|
||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
|
@ -257,6 +258,19 @@ GetStackTraceValueBuffer(JSExnPrivate *priv)
|
||||||
return (jsval *)(priv->stackElems + priv->stackDepth);
|
return (jsval *)(priv->stackElems + priv->stackDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct CopyTo
|
||||||
|
{
|
||||||
|
Value *dst;
|
||||||
|
CopyTo(jsval *dst) : dst(Valueify(dst)) {}
|
||||||
|
void operator()(uintN, Value *src) {
|
||||||
|
*dst++ = *src;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
||||||
JSString *filename, uintN lineno, JSErrorReport *report)
|
JSString *filename, uintN lineno, JSErrorReport *report)
|
||||||
|
@ -292,11 +306,11 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
||||||
callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom);
|
callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom);
|
||||||
stackDepth = 0;
|
stackDepth = 0;
|
||||||
valueCount = 0;
|
valueCount = 0;
|
||||||
for (fp = js_GetTopStackFrame(cx); fp; fp = fp->down) {
|
for (fp = js_GetTopStackFrame(cx); fp; fp = fp->prev()) {
|
||||||
if (fp->hasFunction() && fp->argv && !fp->isEvalFrame()) {
|
if (fp->isFunctionFrame() && !fp->isEvalFrame()) {
|
||||||
Value v = NullValue();
|
Value v = NullValue();
|
||||||
if (checkAccess &&
|
if (checkAccess &&
|
||||||
!checkAccess(cx, fp->callee(), callerid, JSACC_READ, &v)) {
|
!checkAccess(cx, &fp->callee(), callerid, JSACC_READ, &v)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
valueCount += fp->numActualArgs();
|
valueCount += fp->numActualArgs();
|
||||||
|
@ -333,22 +347,22 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
|
||||||
|
|
||||||
values = GetStackTraceValueBuffer(priv);
|
values = GetStackTraceValueBuffer(priv);
|
||||||
elem = priv->stackElems;
|
elem = priv->stackElems;
|
||||||
for (fp = js_GetTopStackFrame(cx); fp != fpstop; fp = fp->down) {
|
for (fp = js_GetTopStackFrame(cx); fp != fpstop; fp = fp->prev()) {
|
||||||
if (!fp->hasFunction() || fp->isEvalFrame()) {
|
if (!fp->isFunctionFrame() || fp->isEvalFrame()) {
|
||||||
elem->funName = NULL;
|
elem->funName = NULL;
|
||||||
elem->argc = 0;
|
elem->argc = 0;
|
||||||
} else {
|
} else {
|
||||||
elem->funName = fp->getFunction()->atom
|
elem->funName = fp->fun()->atom
|
||||||
? ATOM_TO_STRING(fp->getFunction()->atom)
|
? ATOM_TO_STRING(fp->fun()->atom)
|
||||||
: cx->runtime->emptyString;
|
: cx->runtime->emptyString;
|
||||||
elem->argc = fp->numActualArgs();
|
elem->argc = fp->numActualArgs();
|
||||||
memcpy(values, fp->argv, elem->argc * sizeof(jsval));
|
fp->forEachCanonicalActualArg(CopyTo(values));
|
||||||
values += elem->argc;
|
values += elem->argc;
|
||||||
}
|
}
|
||||||
elem->ulineno = 0;
|
elem->ulineno = 0;
|
||||||
elem->filename = NULL;
|
elem->filename = NULL;
|
||||||
if (fp->hasScript()) {
|
if (fp->isScriptFrame()) {
|
||||||
elem->filename = fp->getScript()->filename;
|
elem->filename = fp->script()->filename;
|
||||||
if (fp->pc(cx))
|
if (fp->pc(cx))
|
||||||
elem->ulineno = js_FramePCToLineNumber(cx, fp);
|
elem->ulineno = js_FramePCToLineNumber(cx, fp);
|
||||||
}
|
}
|
||||||
|
@ -746,7 +760,7 @@ Exception(JSContext *cx, uintN argc, Value *vp)
|
||||||
} else {
|
} else {
|
||||||
fp = js_GetScriptedCaller(cx, NULL);
|
fp = js_GetScriptedCaller(cx, NULL);
|
||||||
if (fp) {
|
if (fp) {
|
||||||
filename = FilenameToString(cx, fp->getScript()->filename);
|
filename = FilenameToString(cx, fp->script()->filename);
|
||||||
if (!filename)
|
if (!filename)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
} else {
|
} else {
|
||||||
|
|
332
js/src/jsfun.cpp
332
js/src/jsfun.cpp
|
@ -88,6 +88,7 @@
|
||||||
#include "jsatominlines.h"
|
#include "jsatominlines.h"
|
||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
#include "jsfuninlines.h"
|
#include "jsfuninlines.h"
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
|
@ -103,10 +104,10 @@ js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp)
|
||||||
{
|
{
|
||||||
JSObject *argsobj;
|
JSObject *argsobj;
|
||||||
|
|
||||||
if (fp->flags & JSFRAME_OVERRIDE_ARGS) {
|
if (fp->hasOverriddenArgs()) {
|
||||||
JS_ASSERT(fp->hasCallObj());
|
JS_ASSERT(fp->hasCallObj());
|
||||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
|
jsid id = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
|
||||||
return fp->getCallObj()->getProperty(cx, id, vp);
|
return fp->callObj().getProperty(cx, id, vp);
|
||||||
}
|
}
|
||||||
argsobj = js_GetArgsObject(cx, fp);
|
argsobj = js_GetArgsObject(cx, fp);
|
||||||
if (!argsobj)
|
if (!argsobj)
|
||||||
|
@ -118,12 +119,14 @@ js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp)
|
||||||
JSBool
|
JSBool
|
||||||
js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp)
|
js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp)
|
||||||
{
|
{
|
||||||
if (fp->flags & JSFRAME_OVERRIDE_ARGS) {
|
JS_ASSERT(fp->isFunctionFrame());
|
||||||
|
|
||||||
|
if (fp->hasOverriddenArgs()) {
|
||||||
JS_ASSERT(fp->hasCallObj());
|
JS_ASSERT(fp->hasCallObj());
|
||||||
|
|
||||||
jsid argumentsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
|
jsid argumentsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
|
||||||
Value v;
|
Value v;
|
||||||
if (!fp->getCallObj()->getProperty(cx, argumentsid, &v))
|
if (!fp->callObj().getProperty(cx, argumentsid, &v))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JSObject *obj;
|
JSObject *obj;
|
||||||
|
@ -146,7 +149,7 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp)
|
||||||
if (argsobj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
|
if (argsobj->getArgsElement(arg).isMagic(JS_ARGS_HOLE))
|
||||||
return argsobj->getProperty(cx, id, vp);
|
return argsobj->getProperty(cx, id, vp);
|
||||||
}
|
}
|
||||||
*vp = fp->argv[arg];
|
*vp = fp->canonicalActualArg(arg);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share
|
* Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share
|
||||||
|
@ -173,7 +176,7 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSObject *
|
static JSObject *
|
||||||
NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
|
NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
|
||||||
{
|
{
|
||||||
JSObject *proto;
|
JSObject *proto;
|
||||||
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
|
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
|
||||||
|
@ -190,7 +193,7 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
|
||||||
SetValueRangeToUndefined(data->slots, argc);
|
SetValueRangeToUndefined(data->slots, argc);
|
||||||
|
|
||||||
/* Can't fail from here on, so initialize everything in argsobj. */
|
/* Can't fail from here on, so initialize everything in argsobj. */
|
||||||
argsobj->init(callee->getFunctionPrivate()->inStrictMode()
|
argsobj->init(callee.getFunctionPrivate()->inStrictMode()
|
||||||
? &StrictArgumentsClass
|
? &StrictArgumentsClass
|
||||||
: &js_ArgumentsClass,
|
: &js_ArgumentsClass,
|
||||||
proto, parent, NULL, cx);
|
proto, parent, NULL, cx);
|
||||||
|
@ -199,21 +202,24 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
|
||||||
|
|
||||||
argsobj->setArgsLength(argc);
|
argsobj->setArgsLength(argc);
|
||||||
argsobj->setArgsData(data);
|
argsobj->setArgsData(data);
|
||||||
data->callee = ObjectValue(*callee);
|
data->callee.setObject(callee);
|
||||||
|
|
||||||
return argsobj;
|
return argsobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
namespace {
|
||||||
PutArguments(JSContext *cx, JSObject *argsobj, Value *args)
|
|
||||||
|
struct PutArg
|
||||||
{
|
{
|
||||||
JS_ASSERT(argsobj->isNormalArguments());
|
PutArg(Value *dst) : dst(dst) {}
|
||||||
uint32 argc = argsobj->getArgsInitialLength();
|
Value *dst;
|
||||||
ArgumentsData *data = argsobj->getArgsData();
|
void operator()(uintN, Value *src) {
|
||||||
for (uint32 i = 0; i != argc; ++i) {
|
if (!dst->isMagic(JS_ARGS_HOLE))
|
||||||
if (!data->slots[i].isMagic(JS_ARGS_HOLE))
|
*dst = *src;
|
||||||
data->slots[i] = args[i];
|
++dst;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *
|
JSObject *
|
||||||
|
@ -223,21 +229,18 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
|
||||||
* We must be in a function activation; the function must be lightweight
|
* We must be in a function activation; the function must be lightweight
|
||||||
* or else fp must have a variable object.
|
* or else fp must have a variable object.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(fp->hasFunction());
|
JS_ASSERT_IF(fp->fun()->isHeavyweight(), fp->hasCallObj());
|
||||||
JS_ASSERT_IF(fp->getFunction()->flags & JSFUN_HEAVYWEIGHT,
|
|
||||||
fp->varobj(cx->containingSegment(fp)));
|
|
||||||
|
|
||||||
/* Skip eval and debugger frames. */
|
while (fp->isEvalOrDebuggerFrame())
|
||||||
while (fp->flags & JSFRAME_SPECIAL)
|
fp = fp->prev();
|
||||||
fp = fp->down;
|
|
||||||
|
|
||||||
/* Create an arguments object for fp only if it lacks one. */
|
/* Create an arguments object for fp only if it lacks one. */
|
||||||
if (fp->hasArgsObj())
|
if (fp->hasArgsObj())
|
||||||
return fp->getArgsObj();
|
return &fp->argsObj();
|
||||||
|
|
||||||
/* Compute the arguments object's parent slot from fp's scope chain. */
|
/* Compute the arguments object's parent slot from fp's scope chain. */
|
||||||
JSObject *global = fp->getScopeChain()->getGlobal();
|
JSObject *global = fp->scopeChain().getGlobal();
|
||||||
JSObject *argsobj = NewArguments(cx, global, fp->numActualArgs(), &fp->argv[-2].toObject());
|
JSObject *argsobj = NewArguments(cx, global, fp->numActualArgs(), fp->callee());
|
||||||
if (!argsobj)
|
if (!argsobj)
|
||||||
return argsobj;
|
return argsobj;
|
||||||
|
|
||||||
|
@ -251,26 +254,25 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
|
||||||
* retrieve up-to-date parameter values.
|
* retrieve up-to-date parameter values.
|
||||||
*/
|
*/
|
||||||
if (argsobj->isStrictArguments())
|
if (argsobj->isStrictArguments())
|
||||||
memcpy(argsobj->getArgsData()->slots, fp->argv, fp->numActualArgs() * sizeof(Value));
|
fp->forEachCanonicalActualArg(PutArg(argsobj->getArgsData()->slots));
|
||||||
else
|
else
|
||||||
argsobj->setPrivate(fp);
|
argsobj->setPrivate(fp);
|
||||||
|
|
||||||
fp->setArgsObj(argsobj);
|
fp->setArgsObj(*argsobj);
|
||||||
return argsobj;
|
return argsobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
|
js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
JSObject *argsobj = fp->getArgsObj();
|
JSObject &argsobj = fp->argsObj();
|
||||||
if (argsobj->isNormalArguments()) {
|
if (argsobj.isNormalArguments()) {
|
||||||
JS_ASSERT(argsobj->getPrivate() == fp);
|
JS_ASSERT(argsobj.getPrivate() == fp);
|
||||||
PutArguments(cx, argsobj, fp->argv);
|
fp->forEachCanonicalActualArg(PutArg(argsobj.getArgsData()->slots));
|
||||||
argsobj->setPrivate(NULL);
|
argsobj.setPrivate(NULL);
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(!argsobj->getPrivate());
|
JS_ASSERT(!argsobj.getPrivate());
|
||||||
}
|
}
|
||||||
fp->setArgsObj(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
|
@ -279,9 +281,9 @@ js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
|
||||||
* Traced versions of js_GetArgsObject and js_PutArgsObject.
|
* Traced versions of js_GetArgsObject and js_PutArgsObject.
|
||||||
*/
|
*/
|
||||||
JSObject * JS_FASTCALL
|
JSObject * JS_FASTCALL
|
||||||
js_Arguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
|
js_NewArgumentsOnTrace(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
|
||||||
{
|
{
|
||||||
JSObject *argsobj = NewArguments(cx, parent, argc, callee);
|
JSObject *argsobj = NewArguments(cx, parent, argc, *callee);
|
||||||
if (!argsobj)
|
if (!argsobj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -297,20 +299,32 @@ js_Arguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee)
|
||||||
|
|
||||||
return argsobj;
|
return argsobj;
|
||||||
}
|
}
|
||||||
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_Arguments, CONTEXT, OBJECT, UINT32, OBJECT,
|
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewArgumentsOnTrace, CONTEXT, OBJECT, UINT32, OBJECT,
|
||||||
0, nanojit::ACCSET_STORE_ANY)
|
0, nanojit::ACCSET_STORE_ANY)
|
||||||
|
|
||||||
/* FIXME change the return type to void. */
|
/* FIXME change the return type to void. */
|
||||||
JSBool JS_FASTCALL
|
JSBool JS_FASTCALL
|
||||||
js_PutArguments(JSContext *cx, JSObject *argsobj, Value *args)
|
js_PutArgumentsOnTrace(JSContext *cx, JSObject *argsobj, Value *args)
|
||||||
{
|
{
|
||||||
JS_ASSERT(argsobj->isNormalArguments());
|
JS_ASSERT(argsobj->isNormalArguments());
|
||||||
JS_ASSERT(argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE);
|
JS_ASSERT(argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE);
|
||||||
PutArguments(cx, argsobj, args);
|
|
||||||
|
/*
|
||||||
|
* TraceRecorder::putActivationObjects builds a single, contiguous array of
|
||||||
|
* the arguments, regardless of whether #actuals > #formals so there is no
|
||||||
|
* need to worry about actual vs. formal arguments.
|
||||||
|
*/
|
||||||
|
Value *srcend = args + argsobj->getArgsInitialLength();
|
||||||
|
Value *dst = argsobj->getArgsData()->slots;
|
||||||
|
for (Value *src = args; src != srcend; ++src, ++dst) {
|
||||||
|
if (!dst->isMagic(JS_ARGS_HOLE))
|
||||||
|
*dst = *src;
|
||||||
|
}
|
||||||
|
|
||||||
argsobj->setPrivate(NULL);
|
argsobj->setPrivate(NULL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArguments, CONTEXT, OBJECT, VALUEPTR, 0,
|
JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArgumentsOnTrace, CONTEXT, OBJECT, VALUEPTR, 0,
|
||||||
nanojit::ACCSET_STORE_ANY)
|
nanojit::ACCSET_STORE_ANY)
|
||||||
|
|
||||||
#endif /* JS_TRACER */
|
#endif /* JS_TRACER */
|
||||||
|
@ -496,7 +510,8 @@ ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
if (arg < obj->getArgsInitialLength()) {
|
if (arg < obj->getArgsInitialLength()) {
|
||||||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
||||||
if (fp) {
|
if (fp) {
|
||||||
*vp = fp->argv[arg];
|
JS_ASSERT(fp->numActualArgs() == obj->getArgsInitialLength());
|
||||||
|
*vp = fp->canonicalActualArg(arg);
|
||||||
} else {
|
} else {
|
||||||
const Value &v = obj->getArgsElement(arg);
|
const Value &v = obj->getArgsElement(arg);
|
||||||
if (!v.isMagic(JS_ARGS_HOLE))
|
if (!v.isMagic(JS_ARGS_HOLE))
|
||||||
|
@ -551,7 +566,7 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
if (arg < obj->getArgsInitialLength()) {
|
if (arg < obj->getArgsInitialLength()) {
|
||||||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
||||||
if (fp) {
|
if (fp) {
|
||||||
fp->argv[arg] = *vp;
|
fp->canonicalActualArg(arg) = *vp;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -800,7 +815,7 @@ MaybeMarkGenerator(JSTracer *trc, JSObject *obj)
|
||||||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
||||||
if (fp && fp->isFloatingGenerator()) {
|
if (fp && fp->isFloatingGenerator()) {
|
||||||
JSObject *genobj = js_FloatingFrameToGenerator(fp)->obj;
|
JSObject *genobj = js_FloatingFrameToGenerator(fp)->obj;
|
||||||
MarkObject(trc, genobj, "generator object");
|
MarkObject(trc, *genobj, "generator object");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -816,7 +831,7 @@ args_trace(JSTracer *trc, JSObject *obj)
|
||||||
|
|
||||||
ArgumentsData *data = obj->getArgsData();
|
ArgumentsData *data = obj->getArgsData();
|
||||||
if (data->callee.isObject())
|
if (data->callee.isObject())
|
||||||
MarkObject(trc, &data->callee.toObject(), js_callee_str);
|
MarkObject(trc, data->callee.toObject(), js_callee_str);
|
||||||
MarkValueRange(trc, obj->getArgsInitialLength(), data->slots, js_arguments_str);
|
MarkValueRange(trc, obj->getArgsInitialLength(), data->slots, js_arguments_str);
|
||||||
|
|
||||||
MaybeMarkGenerator(trc, obj);
|
MaybeMarkGenerator(trc, obj);
|
||||||
|
@ -887,10 +902,6 @@ Class StrictArgumentsClass = {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32 JSSLOT_CALLEE = JSSLOT_PRIVATE + 1;
|
|
||||||
const uint32 JSSLOT_CALL_ARGUMENTS = JSSLOT_PRIVATE + 2;
|
|
||||||
const uint32 CALL_CLASS_RESERVED_SLOTS = 2;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A Declarative Environment object stores its active JSStackFrame pointer in
|
* A Declarative Environment object stores its active JSStackFrame pointer in
|
||||||
* its private slot, just as Call and Arguments objects do.
|
* its private slot, just as Call and Arguments objects do.
|
||||||
|
@ -951,13 +962,13 @@ CalleeGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSObject *
|
static JSObject *
|
||||||
NewCallObject(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
|
NewCallObject(JSContext *cx, JSFunction *fun, JSObject &scopeChain, JSObject &callee)
|
||||||
{
|
{
|
||||||
JSObject *callobj = js_NewGCObject(cx);
|
JSObject *callobj = js_NewGCObject(cx);
|
||||||
if (!callobj)
|
if (!callobj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
callobj->init(&js_CallClass, NULL, scopeChain, NULL, cx);
|
callobj->init(&js_CallClass, NULL, &scopeChain, NULL, cx);
|
||||||
callobj->setMap(fun->u.i.names);
|
callobj->setMap(fun->u.i.names);
|
||||||
|
|
||||||
/* This must come after callobj->lastProp has been set. */
|
/* This must come after callobj->lastProp has been set. */
|
||||||
|
@ -973,6 +984,8 @@ NewCallObject(JSContext *cx, JSFunction *fun, JSObject *scopeChain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
callobj->setCallObjCallee(callee);
|
||||||
return callobj;
|
return callobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -983,7 +996,7 @@ NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
|
||||||
if (!envobj)
|
if (!envobj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
envobj->init(&js_DeclEnvClass, NULL, fp->maybeScopeChain(), fp, cx);
|
envobj->init(&js_DeclEnvClass, NULL, &fp->scopeChain(), fp, cx);
|
||||||
envobj->setMap(cx->runtime->emptyDeclEnvShape);
|
envobj->setMap(cx->runtime->emptyDeclEnvShape);
|
||||||
return envobj;
|
return envobj;
|
||||||
}
|
}
|
||||||
|
@ -992,17 +1005,17 @@ JSObject *
|
||||||
js_GetCallObject(JSContext *cx, JSStackFrame *fp)
|
js_GetCallObject(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
/* Create a call object for fp only if it lacks one. */
|
/* Create a call object for fp only if it lacks one. */
|
||||||
JS_ASSERT(fp->hasFunction());
|
JS_ASSERT(fp->isFunctionFrame());
|
||||||
if (fp->hasCallObj())
|
if (fp->hasCallObj())
|
||||||
return fp->getCallObj();
|
return &fp->callObj();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
/* A call object should be a frame's outermost scope chain element. */
|
/* A call object should be a frame's outermost scope chain element. */
|
||||||
Class *clasp = fp->getScopeChain()->getClass();
|
Class *clasp = fp->scopeChain().getClass();
|
||||||
if (clasp == &js_WithClass || clasp == &js_BlockClass)
|
if (clasp == &js_WithClass || clasp == &js_BlockClass)
|
||||||
JS_ASSERT(fp->getScopeChain()->getPrivate() != js_FloatingFrameIfGenerator(cx, fp));
|
JS_ASSERT(fp->scopeChain().getPrivate() != js_FloatingFrameIfGenerator(cx, fp));
|
||||||
else if (clasp == &js_CallClass)
|
else if (clasp == &js_CallClass)
|
||||||
JS_ASSERT(fp->getScopeChain()->getPrivate() != fp);
|
JS_ASSERT(fp->scopeChain().getPrivate() != fp);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1012,17 +1025,16 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
|
||||||
* function's name.
|
* function's name.
|
||||||
*/
|
*/
|
||||||
JSAtom *lambdaName =
|
JSAtom *lambdaName =
|
||||||
(fp->getFunction()->flags & JSFUN_LAMBDA) ? fp->getFunction()->atom : NULL;
|
(fp->fun()->flags & JSFUN_LAMBDA) ? fp->fun()->atom : NULL;
|
||||||
if (lambdaName) {
|
if (lambdaName) {
|
||||||
JSObject *envobj = NewDeclEnvObject(cx, fp);
|
JSObject *envobj = NewDeclEnvObject(cx, fp);
|
||||||
if (!envobj)
|
if (!envobj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */
|
/* Root envobj before js_DefineNativeProperty (-> JSClass.addProperty). */
|
||||||
fp->setScopeChain(envobj);
|
fp->setScopeChainNoCallObj(*envobj);
|
||||||
JS_ASSERT(fp->argv);
|
if (!js_DefineNativeProperty(cx, &fp->scopeChain(), ATOM_TO_JSID(lambdaName),
|
||||||
if (!js_DefineNativeProperty(cx, fp->getScopeChain(), ATOM_TO_JSID(lambdaName),
|
ObjectValue(fp->callee()),
|
||||||
fp->calleeValue(),
|
|
||||||
CalleeGetter, NULL,
|
CalleeGetter, NULL,
|
||||||
JSPROP_PERMANENT | JSPROP_READONLY,
|
JSPROP_PERMANENT | JSPROP_READONLY,
|
||||||
0, 0, NULL)) {
|
0, 0, NULL)) {
|
||||||
|
@ -1030,21 +1042,18 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *callobj = NewCallObject(cx, fp->getFunction(), fp->getScopeChain());
|
JSObject *callobj = NewCallObject(cx, fp->fun(), fp->scopeChain(), fp->callee());
|
||||||
if (!callobj)
|
if (!callobj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
callobj->setPrivate(fp);
|
callobj->setPrivate(fp);
|
||||||
JS_ASSERT(fp->argv);
|
JS_ASSERT(fp->fun() == fp->callee().getFunctionPrivate());
|
||||||
JS_ASSERT(fp->getFunction() == GET_FUNCTION_PRIVATE(cx, fp->callee()));
|
|
||||||
callobj->setSlot(JSSLOT_CALLEE, fp->calleeValue());
|
|
||||||
fp->setCallObj(callobj);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Push callobj on the top of the scope chain, and make it the
|
* Push callobj on the top of the scope chain, and make it the
|
||||||
* variables object.
|
* variables object.
|
||||||
*/
|
*/
|
||||||
fp->setScopeChain(callobj);
|
fp->setScopeChainAndCallObj(*callobj);
|
||||||
return callobj;
|
return callobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1052,38 +1061,22 @@ JSObject * JS_FASTCALL
|
||||||
js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain)
|
js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSObject *scopeChain)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!js_IsNamedLambda(fun));
|
JS_ASSERT(!js_IsNamedLambda(fun));
|
||||||
JSObject *callobj = NewCallObject(cx, fun, scopeChain);
|
JS_ASSERT(scopeChain);
|
||||||
if (!callobj)
|
return NewCallObject(cx, fun, *scopeChain, *callee);
|
||||||
return NULL;
|
|
||||||
callobj->setSlot(JSSLOT_CALLEE, ObjectValue(*callee));
|
|
||||||
return callobj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTION, OBJECT, OBJECT,
|
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTION, OBJECT, OBJECT,
|
||||||
0, nanojit::ACCSET_STORE_ANY)
|
0, nanojit::ACCSET_STORE_ANY)
|
||||||
|
|
||||||
JSFunction *
|
|
||||||
js_GetCallObjectFunction(JSObject *obj)
|
|
||||||
{
|
|
||||||
JS_ASSERT(obj->isCall());
|
|
||||||
const Value &v = obj->getSlot(JSSLOT_CALLEE);
|
|
||||||
if (v.isUndefined()) {
|
|
||||||
/* Newborn or prototype object. */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
JS_ASSERT(v.isObject());
|
|
||||||
return GET_FUNCTION_PRIVATE(cx, &v.toObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static void
|
inline static void
|
||||||
CopyValuesToCallObject(JSObject *callobj, uintN nargs, Value *argv, uintN nvars, Value *slots)
|
CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars, Value *slots)
|
||||||
{
|
{
|
||||||
/* Copy however many args fit into fslots. */
|
/* Copy however many args fit into fslots. */
|
||||||
uintN first = JSSLOT_PRIVATE + CALL_CLASS_RESERVED_SLOTS + 1;
|
uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
|
||||||
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
|
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
|
||||||
|
|
||||||
Value *vp = &callobj->fslots[first];
|
Value *vp = &callobj.fslots[first];
|
||||||
uintN len = JS_MIN(nargs, JS_INITIAL_NSLOTS - first);
|
uintN len = Min(nargs, uintN(JS_INITIAL_NSLOTS) - first);
|
||||||
|
|
||||||
memcpy(vp, argv, len * sizeof(Value));
|
memcpy(vp, argv, len * sizeof(Value));
|
||||||
vp += len;
|
vp += len;
|
||||||
|
@ -1091,7 +1084,7 @@ CopyValuesToCallObject(JSObject *callobj, uintN nargs, Value *argv, uintN nvars,
|
||||||
nargs -= len;
|
nargs -= len;
|
||||||
if (nargs != 0) {
|
if (nargs != 0) {
|
||||||
/* Copy any remaining args into dslots. */
|
/* Copy any remaining args into dslots. */
|
||||||
vp = callobj->dslots;
|
vp = callobj.dslots;
|
||||||
memcpy(vp, argv + len, nargs * sizeof(Value));
|
memcpy(vp, argv + len, nargs * sizeof(Value));
|
||||||
vp += nargs;
|
vp += nargs;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1101,7 +1094,7 @@ CopyValuesToCallObject(JSObject *callobj, uintN nargs, Value *argv, uintN nvars,
|
||||||
memcpy(vp, slots, len * sizeof(Value));
|
memcpy(vp, slots, len * sizeof(Value));
|
||||||
slots += len;
|
slots += len;
|
||||||
nvars -= len;
|
nvars -= len;
|
||||||
vp = callobj->dslots;
|
vp = callobj.dslots;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy any remaining vars into dslots. */
|
/* Copy any remaining vars into dslots. */
|
||||||
|
@ -1111,17 +1104,17 @@ CopyValuesToCallObject(JSObject *callobj, uintN nargs, Value *argv, uintN nvars,
|
||||||
void
|
void
|
||||||
js_PutCallObject(JSContext *cx, JSStackFrame *fp)
|
js_PutCallObject(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
JSObject *callobj = fp->getCallObj();
|
JSObject &callobj = fp->callObj();
|
||||||
|
|
||||||
/* Get the arguments object to snapshot fp's actual argument values. */
|
/* Get the arguments object to snapshot fp's actual argument values. */
|
||||||
if (fp->hasArgsObj()) {
|
if (fp->hasArgsObj()) {
|
||||||
if (!(fp->flags & JSFRAME_OVERRIDE_ARGS))
|
if (!fp->hasOverriddenArgs())
|
||||||
callobj->setSlot(JSSLOT_CALL_ARGUMENTS, ObjectOrNullValue(fp->getArgsObj()));
|
callobj.setCallObjArguments(ObjectValue(fp->argsObj()));
|
||||||
js_PutArgsObject(cx, fp);
|
js_PutArgsObject(cx, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSFunction *fun = fp->getFunction();
|
JSFunction *fun = fp->fun();
|
||||||
JS_ASSERT(fun == js_GetCallObjectFunction(callobj));
|
JS_ASSERT(fun == callobj.getCallObjCalleeFunction());
|
||||||
uintN n = fun->countArgsAndVars();
|
uintN n = fun->countArgsAndVars();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1129,52 +1122,52 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
|
||||||
* arguments and variables straight into JSObject.dslots.
|
* arguments and variables straight into JSObject.dslots.
|
||||||
*/
|
*/
|
||||||
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS - JSSLOT_PRIVATE ==
|
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS - JSSLOT_PRIVATE ==
|
||||||
1 + CALL_CLASS_RESERVED_SLOTS);
|
1 + JSObject::CALL_RESERVED_SLOTS);
|
||||||
if (n != 0) {
|
if (n != 0) {
|
||||||
JS_ASSERT(JSFunction::FIRST_FREE_SLOT + n <= callobj->numSlots());
|
JS_ASSERT(JSFunction::FIRST_FREE_SLOT + n <= callobj.numSlots());
|
||||||
|
|
||||||
JSScript *script = fun->u.i.script;
|
|
||||||
uint32 nargs = fun->nargs;
|
uint32 nargs = fun->nargs;
|
||||||
uint32 nvars = fun->u.i.nvars;
|
uint32 nvars = fun->u.i.nvars;
|
||||||
|
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
memcpy(callobj->dslots, fp->argv, nargs * sizeof(Value));
|
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1);
|
||||||
|
JSScript *script = fun->u.i.script;
|
||||||
|
memcpy(callobj.dslots, fp->formalArgs(), nargs * sizeof(Value));
|
||||||
if (!script->jit || script->usesEval) {
|
if (!script->jit || script->usesEval) {
|
||||||
memcpy(callobj->dslots + nargs, fp->slots(), nvars * sizeof(Value));
|
memcpy(callobj.dslots + nargs, fp->slots(), nvars * sizeof(Value));
|
||||||
} else if (script->jit) {
|
} else if (script->jit) {
|
||||||
for (uint32 i = 0; i < script->jit->nescaping; i++) {
|
for (uint32 i = 0; i < script->jit->nescaping; i++) {
|
||||||
uint32 e = script->jit->escaping[i];
|
uint32 e = script->jit->escaping[i];
|
||||||
callobj->dslots[nargs + e] = fp->slots()[e];
|
callobj.dslots[nargs + e] = fp->slots()[e];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
CopyValuesToCallObject(callobj, nargs, fp->argv, nvars, fp->slots());
|
CopyValuesToCallObject(callobj, nargs, fp->formalArgs(), nvars, fp->slots());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear private pointers to fp, which is about to go away (js_Invoke). */
|
/* Clear private pointers to fp, which is about to go away (js_Invoke). */
|
||||||
if (js_IsNamedLambda(fun)) {
|
if (js_IsNamedLambda(fun)) {
|
||||||
JSObject *env = callobj->getParent();
|
JSObject *env = callobj.getParent();
|
||||||
|
|
||||||
JS_ASSERT(env->getClass() == &js_DeclEnvClass);
|
JS_ASSERT(env->getClass() == &js_DeclEnvClass);
|
||||||
JS_ASSERT(env->getPrivate() == fp);
|
JS_ASSERT(env->getPrivate() == fp);
|
||||||
env->setPrivate(NULL);
|
env->setPrivate(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
callobj->setPrivate(NULL);
|
callobj.setPrivate(NULL);
|
||||||
fp->setCallObj(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool JS_FASTCALL
|
JSBool JS_FASTCALL
|
||||||
js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs, Value *argv,
|
js_PutCallObjectOnTrace(JSContext *cx, JSObject *callobj, uint32 nargs, Value *argv,
|
||||||
uint32 nvars, Value *slots)
|
uint32 nvars, Value *slots)
|
||||||
{
|
{
|
||||||
JS_ASSERT(scopeChain->hasClass(&js_CallClass));
|
JS_ASSERT(callobj->isCall());
|
||||||
JS_ASSERT(!scopeChain->getPrivate());
|
JS_ASSERT(!callobj->getPrivate());
|
||||||
|
|
||||||
uintN n = nargs + nvars;
|
uintN n = nargs + nvars;
|
||||||
if (n != 0)
|
if (n != 0)
|
||||||
CopyValuesToCallObject(scopeChain, nargs, argv, nvars, slots);
|
CopyValuesToCallObject(*callobj, nargs, argv, nvars, slots);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1203,17 +1196,17 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
|
||||||
|
|
||||||
Value *array;
|
Value *array;
|
||||||
if (kind == JSCPK_UPVAR) {
|
if (kind == JSCPK_UPVAR) {
|
||||||
JSObject *callee = &obj->getSlot(JSSLOT_CALLEE).toObject();
|
JSObject &callee = obj->getCallObjCallee();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JSFunction *callee_fun = (JSFunction *) callee->getPrivate();
|
JSFunction *callee_fun = (JSFunction *) callee.getPrivate();
|
||||||
JS_ASSERT(FUN_FLAT_CLOSURE(callee_fun));
|
JS_ASSERT(FUN_FLAT_CLOSURE(callee_fun));
|
||||||
JS_ASSERT(i < callee_fun->u.i.nupvars);
|
JS_ASSERT(i < callee_fun->u.i.nupvars);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
array = callee->getFlatClosureUpvars();
|
array = callee.getFlatClosureUpvars();
|
||||||
} else {
|
} else {
|
||||||
JSFunction *fun = js_GetCallObjectFunction(obj);
|
JSFunction *fun = obj->getCallObjCalleeFunction();
|
||||||
JS_ASSERT_IF(kind == JSCPK_ARG, i < fun->nargs);
|
JS_ASSERT_IF(kind == JSCPK_ARG, i < fun->nargs);
|
||||||
JS_ASSERT_IF(kind == JSCPK_VAR, i < fun->u.i.nvars);
|
JS_ASSERT_IF(kind == JSCPK_VAR, i < fun->u.i.nvars);
|
||||||
|
|
||||||
|
@ -1222,10 +1215,10 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
|
||||||
if (kind == JSCPK_ARGUMENTS) {
|
if (kind == JSCPK_ARGUMENTS) {
|
||||||
if (setter) {
|
if (setter) {
|
||||||
if (fp)
|
if (fp)
|
||||||
fp->flags |= JSFRAME_OVERRIDE_ARGS;
|
fp->setOverriddenArgs();
|
||||||
obj->setSlot(JSSLOT_CALL_ARGUMENTS, *vp);
|
obj->setCallObjArguments(*vp);
|
||||||
} else {
|
} else {
|
||||||
if (fp && !(fp->flags & JSFRAME_OVERRIDE_ARGS)) {
|
if (fp && !fp->hasOverriddenArgs()) {
|
||||||
JSObject *argsobj;
|
JSObject *argsobj;
|
||||||
|
|
||||||
argsobj = js_GetArgsObject(cx, fp);
|
argsobj = js_GetArgsObject(cx, fp);
|
||||||
|
@ -1233,7 +1226,7 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
|
||||||
return false;
|
return false;
|
||||||
vp->setObject(*argsobj);
|
vp->setObject(*argsobj);
|
||||||
} else {
|
} else {
|
||||||
*vp = obj->getSlot(JSSLOT_CALL_ARGUMENTS);
|
*vp = obj->getCallObjArguments();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1245,13 +1238,13 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
|
||||||
else
|
else
|
||||||
JS_ASSERT(kind == JSCPK_ARG);
|
JS_ASSERT(kind == JSCPK_ARG);
|
||||||
|
|
||||||
const uintN first = JSSLOT_PRIVATE + CALL_CLASS_RESERVED_SLOTS + 1;
|
const uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
|
||||||
JS_ASSERT(first == JSSLOT_FREE(&js_CallClass));
|
JS_ASSERT(first == JSSLOT_FREE(&js_CallClass));
|
||||||
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
|
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
|
||||||
|
|
||||||
array = (i < JS_INITIAL_NSLOTS - first) ? obj->fslots : obj->dslots;
|
array = (i < JS_INITIAL_NSLOTS - first) ? obj->fslots : obj->dslots;
|
||||||
} else if (kind == JSCPK_ARG) {
|
} else if (kind == JSCPK_ARG) {
|
||||||
array = fp->argv;
|
array = fp->formalArgs();
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(kind == JSCPK_VAR);
|
JS_ASSERT(kind == JSCPK_VAR);
|
||||||
array = fp->slots();
|
array = fp->slots();
|
||||||
|
@ -1354,13 +1347,8 @@ call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||||
if (!JSID_IS_ATOM(id))
|
if (!JSID_IS_ATOM(id))
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
|
||||||
const Value &callee = obj->getSlot(JSSLOT_CALLEE);
|
|
||||||
if (callee.isUndefined())
|
|
||||||
return JS_TRUE;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JSFunction *fun;
|
JSFunction *fun = obj->getCallObjCalleeFunction();
|
||||||
fun = GET_FUNCTION_PRIVATE(cx, &callee.toObject());
|
|
||||||
JS_ASSERT(fun->lookupLocal(cx, JSID_TO_ATOM(id), NULL) == JSLOCAL_NONE);
|
JS_ASSERT(fun->lookupLocal(cx, JSID_TO_ATOM(id), NULL) == JSLOCAL_NONE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1396,10 +1384,10 @@ call_trace(JSTracer *trc, JSObject *obj)
|
||||||
* cycles involving Call objects whose frames are active without this
|
* cycles involving Call objects whose frames are active without this
|
||||||
* hiding hack.
|
* hiding hack.
|
||||||
*/
|
*/
|
||||||
uintN first = JSSLOT_PRIVATE + CALL_CLASS_RESERVED_SLOTS + 1;
|
uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
|
||||||
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
|
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
|
||||||
|
|
||||||
uintN count = fp->getFunction()->countArgsAndVars();
|
uintN count = fp->fun()->countArgsAndVars();
|
||||||
uintN fixed = JS_MIN(count, JS_INITIAL_NSLOTS - first);
|
uintN fixed = JS_MIN(count, JS_INITIAL_NSLOTS - first);
|
||||||
|
|
||||||
SetValueRangeToUndefined(&obj->fslots[first], fixed);
|
SetValueRangeToUndefined(&obj->fslots[first], fixed);
|
||||||
|
@ -1412,7 +1400,7 @@ call_trace(JSTracer *trc, JSObject *obj)
|
||||||
JS_PUBLIC_DATA(Class) js_CallClass = {
|
JS_PUBLIC_DATA(Class) js_CallClass = {
|
||||||
"Call",
|
"Call",
|
||||||
JSCLASS_HAS_PRIVATE |
|
JSCLASS_HAS_PRIVATE |
|
||||||
JSCLASS_HAS_RESERVED_SLOTS(CALL_CLASS_RESERVED_SLOTS) |
|
JSCLASS_HAS_RESERVED_SLOTS(JSObject::CALL_RESERVED_SLOTS) |
|
||||||
JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE,
|
JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE,
|
||||||
PropertyStub, /* addProperty */
|
PropertyStub, /* addProperty */
|
||||||
PropertyStub, /* delProperty */
|
PropertyStub, /* delProperty */
|
||||||
|
@ -1434,12 +1422,12 @@ JS_PUBLIC_DATA(Class) js_CallClass = {
|
||||||
bool
|
bool
|
||||||
JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
|
JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
|
||||||
{
|
{
|
||||||
if (!hasFunction()) {
|
if (!isFunctionFrame()) {
|
||||||
*vp = argv ? argv[-2] : UndefinedValue();
|
vp->setUndefined();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSFunction *fun = getFunction();
|
JSFunction *fun = this->fun();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See the equivalent condition in ArgGetter for the 'callee' id case, but
|
* See the equivalent condition in ArgGetter for the 'callee' id case, but
|
||||||
|
@ -1455,19 +1443,20 @@ JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject *funobj = &calleeObject();
|
JSObject &funobj = callee();
|
||||||
vp->setObject(*funobj);
|
vp->setObject(funobj);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for an escape attempt by a joined function object, which must go
|
* Check for an escape attempt by a joined function object, which must go
|
||||||
* through the frame's |this| object's method read barrier for the method
|
* through the frame's |this| object's method read barrier for the method
|
||||||
* atom by which it was uniquely associated with a property.
|
* atom by which it was uniquely associated with a property.
|
||||||
*/
|
*/
|
||||||
if (getThisValue().isObject()) {
|
const Value &thisv = functionThis();
|
||||||
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
|
if (thisv.isObject()) {
|
||||||
|
JS_ASSERT(funobj.getFunctionPrivate() == fun);
|
||||||
|
|
||||||
if (fun == funobj && fun->methodAtom()) {
|
if (&fun->compiledFunObj() == &funobj && fun->methodAtom()) {
|
||||||
JSObject *thisp = &getThisValue().toObject();
|
JSObject *thisp = &thisv.toObject();
|
||||||
JS_ASSERT(thisp->canHaveMethodBarrier());
|
JS_ASSERT(thisp->canHaveMethodBarrier());
|
||||||
|
|
||||||
if (thisp->hasMethodBarrier()) {
|
if (thisp->hasMethodBarrier()) {
|
||||||
|
@ -1486,10 +1475,10 @@ JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
|
||||||
* been replaced, or its value to have been overwritten.
|
* been replaced, or its value to have been overwritten.
|
||||||
*/
|
*/
|
||||||
if (shape) {
|
if (shape) {
|
||||||
if (shape->isMethod() && &shape->methodObject() == funobj) {
|
if (shape->isMethod() && &shape->methodObject() == &funobj) {
|
||||||
if (!thisp->methodReadBarrier(cx, *shape, vp))
|
if (!thisp->methodReadBarrier(cx, *shape, vp))
|
||||||
return false;
|
return false;
|
||||||
setCalleeObject(vp->toObject());
|
calleeValue().setObject(vp->toObject());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (shape->hasSlot()) {
|
if (shape->hasSlot()) {
|
||||||
|
@ -1499,9 +1488,9 @@ JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
|
||||||
if (IsFunctionObject(v, &clone) &&
|
if (IsFunctionObject(v, &clone) &&
|
||||||
GET_FUNCTION_PRIVATE(cx, clone) == fun &&
|
GET_FUNCTION_PRIVATE(cx, clone) == fun &&
|
||||||
clone->hasMethodObj(*thisp)) {
|
clone->hasMethodObj(*thisp)) {
|
||||||
JS_ASSERT(clone != funobj);
|
JS_ASSERT(clone != &funobj);
|
||||||
*vp = v;
|
*vp = v;
|
||||||
setCalleeObject(*clone);
|
calleeValue().setObject(*clone);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1515,11 +1504,11 @@ JSStackFrame::getValidCalleeObject(JSContext *cx, Value *vp)
|
||||||
* access. It seems that there are no longer any properties
|
* access. It seems that there are no longer any properties
|
||||||
* referring to fun.
|
* referring to fun.
|
||||||
*/
|
*/
|
||||||
funobj = CloneFunctionObject(cx, fun, fun->getParent());
|
JSObject *newfunobj = CloneFunctionObject(cx, fun, fun->getParent());
|
||||||
if (!funobj)
|
if (!newfunobj)
|
||||||
return false;
|
return false;
|
||||||
funobj->setMethodObj(*thisp);
|
newfunobj->setMethodObj(*thisp);
|
||||||
setCalleeObject(*funobj);
|
calleeValue().setObject(*newfunobj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1579,8 +1568,8 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
/* Find fun's top-most activation record. */
|
/* Find fun's top-most activation record. */
|
||||||
JSStackFrame *fp;
|
JSStackFrame *fp;
|
||||||
for (fp = js_GetTopStackFrame(cx);
|
for (fp = js_GetTopStackFrame(cx);
|
||||||
fp && (fp->maybeFunction() != fun || (fp->flags & JSFRAME_SPECIAL));
|
fp && (fp->maybeFun() != fun || fp->isEvalOrDebuggerFrame());
|
||||||
fp = fp->down) {
|
fp = fp->prev()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1614,7 +1603,7 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
|
|
||||||
case FUN_CALLER:
|
case FUN_CALLER:
|
||||||
vp->setNull();
|
vp->setNull();
|
||||||
if (fp && fp->down && !fp->down->getValidCalleeObject(cx, vp))
|
if (fp && fp->prev() && !fp->prev()->getValidCalleeObject(cx, vp))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (vp->isObject()) {
|
if (vp->isObject()) {
|
||||||
|
@ -1633,8 +1622,8 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* XXX fun[0] and fun.arguments[0] are equivalent. */
|
/* XXX fun[0] and fun.arguments[0] are equivalent. */
|
||||||
if (fp && fp->hasFunction() && uint16(slot) < fp->getFunction()->nargs)
|
if (fp && fp->isFunctionFrame() && uint16(slot) < fp->numFormalArgs())
|
||||||
*vp = fp->argv[slot];
|
*vp = fp->formalArg(slot);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2067,7 +2056,7 @@ fun_trace(JSTracer *trc, JSObject *obj)
|
||||||
|
|
||||||
if (fun != obj) {
|
if (fun != obj) {
|
||||||
/* obj is a cloned function object, trace the clone-parent, fun. */
|
/* obj is a cloned function object, trace the clone-parent, fun. */
|
||||||
MarkObject(trc, fun, "private");
|
MarkObject(trc, *fun, "private");
|
||||||
|
|
||||||
/* The function could be a flat closure with upvar copies in the clone. */
|
/* The function could be a flat closure with upvar copies in the clone. */
|
||||||
if (FUN_FLAT_CLOSURE(fun) && fun->u.i.nupvars)
|
if (FUN_FLAT_CLOSURE(fun) && fun->u.i.nupvars)
|
||||||
|
@ -2262,7 +2251,7 @@ js_fun_call(JSContext *cx, uintN argc, Value *vp)
|
||||||
|
|
||||||
/* Allocate stack space for fval, obj, and the args. */
|
/* Allocate stack space for fval, obj, and the args. */
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, argc, args))
|
if (!cx->stack().pushInvokeArgs(cx, argc, &args))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
/* Push fval, obj, and the args. */
|
/* Push fval, obj, and the args. */
|
||||||
|
@ -2275,6 +2264,24 @@ js_fun_call(JSContext *cx, uintN argc, Value *vp)
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct CopyNonHoleArgs
|
||||||
|
{
|
||||||
|
CopyNonHoleArgs(JSObject *aobj, Value *dst) : aobj(aobj), dst(dst) {}
|
||||||
|
JSObject *aobj;
|
||||||
|
Value *dst;
|
||||||
|
void operator()(uintN argi, Value *src) {
|
||||||
|
if (aobj->getArgsElement(argi).isMagic(JS_ARGS_HOLE))
|
||||||
|
dst->setUndefined();
|
||||||
|
else
|
||||||
|
*dst = *src;
|
||||||
|
++dst;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* ES5 15.3.4.3 */
|
/* ES5 15.3.4.3 */
|
||||||
JSBool
|
JSBool
|
||||||
js_fun_apply(JSContext *cx, uintN argc, Value *vp)
|
js_fun_apply(JSContext *cx, uintN argc, Value *vp)
|
||||||
|
@ -2343,7 +2350,7 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp)
|
||||||
uintN n = uintN(JS_MIN(length, JS_ARGS_LENGTH_MAX));
|
uintN n = uintN(JS_MIN(length, JS_ARGS_LENGTH_MAX));
|
||||||
|
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, n, args))
|
if (!cx->stack().pushInvokeArgs(cx, n, &args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Push fval, obj, and aobj's elements as args. */
|
/* Push fval, obj, and aobj's elements as args. */
|
||||||
|
@ -2361,11 +2368,8 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp)
|
||||||
JSStackFrame *fp = (JSStackFrame *) aobj->getPrivate();
|
JSStackFrame *fp = (JSStackFrame *) aobj->getPrivate();
|
||||||
Value *argv = args.argv();
|
Value *argv = args.argv();
|
||||||
if (fp) {
|
if (fp) {
|
||||||
memcpy(argv, fp->argv, n * sizeof(Value));
|
JS_ASSERT(fp->numActualArgs() <= JS_ARGS_LENGTH_MAX);
|
||||||
for (uintN i = 0; i < n; i++) {
|
fp->forEachCanonicalActualArg(CopyNonHoleArgs(aobj, argv));
|
||||||
if (aobj->getArgsElement(i).isMagic(JS_ARGS_HOLE)) // suppress deleted element
|
|
||||||
argv[i].setUndefined();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for (uintN i = 0; i < n; i++) {
|
for (uintN i = 0; i < n; i++) {
|
||||||
argv[i] = aobj->getArgsElement(i);
|
argv[i] = aobj->getArgsElement(i);
|
||||||
|
@ -2489,7 +2493,7 @@ CallOrConstructBoundFunction(JSContext *cx, uintN argc, Value *vp)
|
||||||
const Value &boundThis = obj->getBoundFunctionThis();
|
const Value &boundThis = obj->getBoundFunctionThis();
|
||||||
|
|
||||||
InvokeArgsGuard args;
|
InvokeArgsGuard args;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, argc + argslen, args))
|
if (!cx->stack().pushInvokeArgs(cx, argc + argslen, &args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* 15.3.4.5.1, 15.3.4.5.2 step 4. */
|
/* 15.3.4.5.1, 15.3.4.5.2 step 4. */
|
||||||
|
@ -2991,8 +2995,8 @@ js_NewFlatClosure(JSContext *cx, JSFunction *fun)
|
||||||
JSObject *
|
JSObject *
|
||||||
js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun)
|
js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun)
|
||||||
{
|
{
|
||||||
JS_ASSERT(cx->fp()->getFunction()->flags & JSFUN_HEAVYWEIGHT);
|
JS_ASSERT(cx->fp()->fun()->flags & JSFUN_HEAVYWEIGHT);
|
||||||
JS_ASSERT(!cx->fp()->getFunction()->optimizedClosure());
|
JS_ASSERT(!cx->fp()->fun()->optimizedClosure());
|
||||||
JS_ASSERT(FUN_FLAT_CLOSURE(fun));
|
JS_ASSERT(FUN_FLAT_CLOSURE(fun));
|
||||||
|
|
||||||
return WrapEscapingClosure(cx, cx->fp(), fun);
|
return WrapEscapingClosure(cx, cx->fp(), fun);
|
||||||
|
@ -3094,7 +3098,7 @@ js_ReportIsNotFunction(JSContext *cx, const Value *vp, uintN flags)
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
if (!i.done()) {
|
if (!i.done()) {
|
||||||
uintN depth = js_ReconstructStackDepth(cx, i.fp()->getScript(), i.pc());
|
uintN depth = js_ReconstructStackDepth(cx, i.fp()->script(), i.pc());
|
||||||
Value *simsp = i.fp()->base() + depth;
|
Value *simsp = i.fp()->base() + depth;
|
||||||
JS_ASSERT(simsp <= i.sp());
|
JS_ASSERT(simsp <= i.sp());
|
||||||
if (i.fp()->base() <= vp && vp < simsp)
|
if (i.fp()->base() <= vp && vp < simsp)
|
||||||
|
@ -3143,7 +3147,7 @@ JSFunction::addLocal(JSContext *cx, JSAtom *atom, JSLocalKind kind)
|
||||||
uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED;
|
uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED;
|
||||||
uint16 *indexp;
|
uint16 *indexp;
|
||||||
PropertyOp getter, setter;
|
PropertyOp getter, setter;
|
||||||
uint32 slot = JSSLOT_START(&js_CallClass) + CALL_CLASS_RESERVED_SLOTS;
|
uint32 slot = JSSLOT_START(&js_CallClass) + JSObject::CALL_RESERVED_SLOTS;
|
||||||
|
|
||||||
if (kind == JSLOCAL_ARG) {
|
if (kind == JSLOCAL_ARG) {
|
||||||
JS_ASSERT(u.i.nupvars == 0);
|
JS_ASSERT(u.i.nupvars == 0);
|
||||||
|
|
|
@ -169,7 +169,6 @@ struct JSFunction : public JSObject
|
||||||
bool isNative() const { return !FUN_INTERPRETED(this); }
|
bool isNative() const { return !FUN_INTERPRETED(this); }
|
||||||
bool isConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
|
bool isConstructor() const { return flags & JSFUN_CONSTRUCTOR; }
|
||||||
bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
|
bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); }
|
||||||
unsigned minArgs() const { return isInterpreted() ? nargs : 0; }
|
|
||||||
|
|
||||||
inline bool inStrictMode() const;
|
inline bool inStrictMode() const;
|
||||||
|
|
||||||
|
@ -254,6 +253,10 @@ struct JSFunction : public JSObject
|
||||||
return flags & JSFUN_JOINABLE;
|
return flags & JSFUN_JOINABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSObject &compiledFunObj() {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
* js_FunctionClass reserves two slots, which are free in JSObject::fslots
|
* js_FunctionClass reserves two slots, which are free in JSObject::fslots
|
||||||
|
@ -292,6 +295,11 @@ struct JSFunction : public JSObject
|
||||||
return isInterpreted() ? NULL : u.n.native;
|
return isInterpreted() ? NULL : u.n.native;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSScript *script() const {
|
||||||
|
JS_ASSERT(isInterpreted());
|
||||||
|
return u.i.script;
|
||||||
|
}
|
||||||
|
|
||||||
/* Number of extra fixed function object slots besides JSSLOT_PRIVATE. */
|
/* Number of extra fixed function object slots besides JSSLOT_PRIVATE. */
|
||||||
static const uint32 CLASS_RESERVED_SLOTS = JSObject::FUN_CLASS_RESERVED_SLOTS;
|
static const uint32 CLASS_RESERVED_SLOTS = JSObject::FUN_CLASS_RESERVED_SLOTS;
|
||||||
static const uint32 FIRST_FREE_SLOT = JSSLOT_PRIVATE + CLASS_RESERVED_SLOTS + 1;
|
static const uint32 FIRST_FREE_SLOT = JSSLOT_PRIVATE + CLASS_RESERVED_SLOTS + 1;
|
||||||
|
@ -364,7 +372,6 @@ JSObject::isArguments() const
|
||||||
extern JS_PUBLIC_DATA(js::Class) js_CallClass;
|
extern JS_PUBLIC_DATA(js::Class) js_CallClass;
|
||||||
extern JS_PUBLIC_DATA(js::Class) js_FunctionClass;
|
extern JS_PUBLIC_DATA(js::Class) js_FunctionClass;
|
||||||
extern js::Class js_DeclEnvClass;
|
extern js::Class js_DeclEnvClass;
|
||||||
extern const uint32 CALL_CLASS_RESERVED_SLOTS;
|
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
JSObject::isCall() const
|
JSObject::isCall() const
|
||||||
|
@ -551,9 +558,6 @@ extern JSBool JS_FASTCALL
|
||||||
js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs,
|
js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs,
|
||||||
js::Value *argv, uint32 nvars, js::Value *slots);
|
js::Value *argv, uint32 nvars, js::Value *slots);
|
||||||
|
|
||||||
extern JSFunction *
|
|
||||||
js_GetCallObjectFunction(JSObject *obj);
|
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
|
js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,7 @@
|
||||||
|
|
||||||
#include "jsprobes.h"
|
#include "jsprobes.h"
|
||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jshashtable.h"
|
#include "jshashtable.h"
|
||||||
|
|
||||||
|
@ -2032,18 +2033,19 @@ gc_lock_traversal(const GCLocks::Entry &entry, JSTracer *trc)
|
||||||
void
|
void
|
||||||
js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
|
js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
if (fp->hasCallObj())
|
MarkObject(trc, fp->scopeChain(), "scope chain");
|
||||||
JS_CALL_OBJECT_TRACER(trc, fp->getCallObj(), "call");
|
if (fp->isDummyFrame())
|
||||||
if (fp->hasArgsObj())
|
return;
|
||||||
JS_CALL_OBJECT_TRACER(trc, fp->getArgsObj(), "arguments");
|
|
||||||
if (fp->hasScript())
|
|
||||||
js_TraceScript(trc, fp->getScript());
|
|
||||||
|
|
||||||
/* Allow for primitive this parameter due to JSFUN_THISP_* flags. */
|
if (fp->hasCallObj())
|
||||||
MarkValue(trc, fp->getThisValue(), "this");
|
MarkObject(trc, fp->callObj(), "call");
|
||||||
MarkValue(trc, fp->getReturnValue(), "rval");
|
if (fp->hasArgsObj())
|
||||||
if (fp->hasScopeChain())
|
MarkObject(trc, fp->argsObj(), "arguments");
|
||||||
JS_CALL_OBJECT_TRACER(trc, fp->getScopeChain(), "scope chain");
|
if (fp->isScriptFrame())
|
||||||
|
js_TraceScript(trc, fp->script());
|
||||||
|
|
||||||
|
MarkValue(trc, fp->thisValue(), "this");
|
||||||
|
MarkValue(trc, fp->returnValue(), "rval");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
|
@ -2094,12 +2096,12 @@ AutoGCRooter::trace(JSTracer *trc)
|
||||||
case DESCRIPTOR : {
|
case DESCRIPTOR : {
|
||||||
PropertyDescriptor &desc = *static_cast<AutoPropertyDescriptorRooter *>(this);
|
PropertyDescriptor &desc = *static_cast<AutoPropertyDescriptorRooter *>(this);
|
||||||
if (desc.obj)
|
if (desc.obj)
|
||||||
MarkObject(trc, desc.obj, "Descriptor::obj");
|
MarkObject(trc, *desc.obj, "Descriptor::obj");
|
||||||
MarkValue(trc, desc.value, "Descriptor::value");
|
MarkValue(trc, desc.value, "Descriptor::value");
|
||||||
if ((desc.attrs & JSPROP_GETTER) && desc.getter)
|
if ((desc.attrs & JSPROP_GETTER) && desc.getter)
|
||||||
MarkObject(trc, CastAsObject(desc.getter), "Descriptor::get");
|
MarkObject(trc, *CastAsObject(desc.getter), "Descriptor::get");
|
||||||
if (desc.attrs & JSPROP_SETTER && desc.setter)
|
if (desc.attrs & JSPROP_SETTER && desc.setter)
|
||||||
MarkObject(trc, CastAsObject(desc.setter), "Descriptor::set");
|
MarkObject(trc, *CastAsObject(desc.setter), "Descriptor::set");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2117,7 +2119,7 @@ AutoGCRooter::trace(JSTracer *trc)
|
||||||
|
|
||||||
case OBJECT:
|
case OBJECT:
|
||||||
if (JSObject *obj = static_cast<AutoObjectRooter *>(this)->obj)
|
if (JSObject *obj = static_cast<AutoObjectRooter *>(this)->obj)
|
||||||
MarkObject(trc, obj, "js::AutoObjectRooter.obj");
|
MarkObject(trc, *obj, "js::AutoObjectRooter.obj");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case ID:
|
case ID:
|
||||||
|
|
|
@ -599,11 +599,10 @@ MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
MarkObject(JSTracer *trc, JSObject *obj, const char *name)
|
MarkObject(JSTracer *trc, JSObject &obj, const char *name)
|
||||||
{
|
{
|
||||||
JS_ASSERT(obj);
|
|
||||||
JS_SET_TRACING_NAME(trc, name);
|
JS_SET_TRACING_NAME(trc, name);
|
||||||
Mark(trc, obj, JSTRACE_OBJECT);
|
Mark(trc, &obj, JSTRACE_OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
1120
js/src/jsinterp.h
1120
js/src/jsinterp.h
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,399 @@
|
||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||||
|
*
|
||||||
|
* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is SpiderMonkey code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Mozilla Corporation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Luke Wagner <lw@mozilla.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#ifndef jsinterpinlines_h__
|
||||||
|
#define jsinterpinlines_h__
|
||||||
|
|
||||||
|
inline void
|
||||||
|
JSStackFrame::initCallFrame(JSContext *cx, JSObject &callee, JSFunction *fun,
|
||||||
|
uint32 nactual, uint32 flagsArg)
|
||||||
|
{
|
||||||
|
JS_ASSERT((flagsArg & ~(JSFRAME_CONSTRUCTING |
|
||||||
|
JSFRAME_OVERFLOW_ARGS |
|
||||||
|
JSFRAME_UNDERFLOW_ARGS)) == 0);
|
||||||
|
JS_ASSERT(fun == callee.getFunctionPrivate());
|
||||||
|
|
||||||
|
/* Initialize stack frame members. */
|
||||||
|
flags_ = JSFRAME_FUNCTION | flagsArg;
|
||||||
|
exec.fun = fun;
|
||||||
|
args.nactual = nactual; /* only need to write if over/under-flow */
|
||||||
|
scopeChain_ = callee.getParent();
|
||||||
|
/* savedpc_, prev_ initialized by push*Frame */
|
||||||
|
JS_ASSERT(!hasImacropc());
|
||||||
|
JS_ASSERT(!hasHookData());
|
||||||
|
rval_.setUndefined();
|
||||||
|
blockChain_ = NULL;
|
||||||
|
JS_ASSERT(annotation() == NULL);
|
||||||
|
|
||||||
|
JS_ASSERT(!hasCallObj());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
JSStackFrame::initCallFrameCallerHalf(JSContext *cx, JSObject &scopeChain,
|
||||||
|
uint32 nactual, uint32 flagsArg)
|
||||||
|
{
|
||||||
|
JS_ASSERT((flagsArg & ~(JSFRAME_CONSTRUCTING |
|
||||||
|
JSFRAME_FUNCTION |
|
||||||
|
JSFRAME_OVERFLOW_ARGS |
|
||||||
|
JSFRAME_UNDERFLOW_ARGS)) == 0);
|
||||||
|
JSFrameRegs *regs = cx->regs;
|
||||||
|
|
||||||
|
/* Save caller pc. */
|
||||||
|
regs->fp->savedpc_ = regs->pc;
|
||||||
|
|
||||||
|
/* Initialize the caller half of the stack frame members. */
|
||||||
|
flags_ = JSFRAME_FUNCTION | flagsArg;
|
||||||
|
args.nactual = nactual; /* only need to write if over/under-flow */
|
||||||
|
scopeChain_ = &scopeChain;
|
||||||
|
prev_ = regs->fp;
|
||||||
|
JS_ASSERT(!hasImacropc());
|
||||||
|
JS_ASSERT(!hasHookData());
|
||||||
|
JS_ASSERT(annotation() == NULL);
|
||||||
|
|
||||||
|
JS_ASSERT(!hasCallObj());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The "early prologue" refers to the members that are stored for the benefit
|
||||||
|
* of slow paths before initializing the rest of the members.
|
||||||
|
*/
|
||||||
|
inline void
|
||||||
|
JSStackFrame::initCallFrameEarlyPrologue(JSFunction *fun, void *ncode)
|
||||||
|
{
|
||||||
|
/* Initialize state that gets set early in a jitted function's prologue. */
|
||||||
|
exec.fun = fun;
|
||||||
|
ncode_ = ncode;
|
||||||
|
#ifdef DEBUG
|
||||||
|
savedpc_ = JSStackFrame::sInvalidpc;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The "late prologue" refers to the members that are stored after having
|
||||||
|
* checked for stack overflow and formal/actual arg mismatch.
|
||||||
|
*/
|
||||||
|
inline void
|
||||||
|
JSStackFrame::initCallFrameLatePrologue()
|
||||||
|
{
|
||||||
|
rval_.setUndefined();
|
||||||
|
blockChain_ = NULL;
|
||||||
|
callerVersion_ = prev_->callerVersion_; // WRONG
|
||||||
|
|
||||||
|
SetValueRangeToUndefined(slots(), script()->nfixed);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
JSStackFrame::initEvalFrame(JSScript *script, JSStackFrame *downFrame, uint32 flagsArg)
|
||||||
|
{
|
||||||
|
JS_ASSERT(flagsArg & JSFRAME_EVAL);
|
||||||
|
JS_ASSERT((flagsArg & ~(JSFRAME_EVAL | JSFRAME_DEBUGGER)) == 0);
|
||||||
|
JS_ASSERT(downFrame->flags_ & (JSFRAME_FUNCTION | JSFRAME_GLOBAL));
|
||||||
|
|
||||||
|
/* Copy (callee, thisv). */
|
||||||
|
js::Value *dstvp = (js::Value *)this - 2;
|
||||||
|
js::Value *srcvp = downFrame->flags_ & (JSFRAME_GLOBAL | JSFRAME_EVAL)
|
||||||
|
? (js::Value *)downFrame - 2
|
||||||
|
: downFrame->formalArgs() - 2;
|
||||||
|
dstvp[0] = srcvp[0];
|
||||||
|
dstvp[1] = srcvp[1];
|
||||||
|
JS_ASSERT_IF(downFrame->flags_ & JSFRAME_FUNCTION,
|
||||||
|
dstvp[0].toObject().isFunction());
|
||||||
|
|
||||||
|
/* Initialize stack frame members. */
|
||||||
|
flags_ = flagsArg | (downFrame->flags_ & (JSFRAME_FUNCTION |
|
||||||
|
JSFRAME_GLOBAL |
|
||||||
|
JSFRAME_HAS_CALL_OBJ));
|
||||||
|
if (isFunctionFrame()) {
|
||||||
|
exec = downFrame->exec;
|
||||||
|
args.script = script;
|
||||||
|
} else {
|
||||||
|
exec.script = script;
|
||||||
|
}
|
||||||
|
scopeChain_ = &downFrame->scopeChain();
|
||||||
|
JS_ASSERT_IF(isFunctionFrame(), &callObj() == &downFrame->callObj());
|
||||||
|
/* savedpc initialized by pushExecuteFrame */
|
||||||
|
prev_ = downFrame;
|
||||||
|
JS_ASSERT(!hasImacropc());
|
||||||
|
JS_ASSERT(!hasHookData());
|
||||||
|
rval_.setUndefined();
|
||||||
|
blockChain_ = NULL;
|
||||||
|
setAnnotation(downFrame->annotation());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
JSStackFrame::initGlobalFrame(JSScript *script, JSObject &chain, uint32 flagsArg)
|
||||||
|
{
|
||||||
|
JS_ASSERT((flagsArg & ~(JSFRAME_EVAL | JSFRAME_DEBUGGER)) == 0);
|
||||||
|
|
||||||
|
/* Initialize (callee, thisv). */
|
||||||
|
js::Value *vp = (js::Value *)this - 2;
|
||||||
|
vp[0].setUndefined();
|
||||||
|
vp[1].setUndefined(); /* Set after frame pushed using thisObject */
|
||||||
|
|
||||||
|
/* Initialize stack frame members. */
|
||||||
|
flags_ = flagsArg | JSFRAME_GLOBAL;
|
||||||
|
exec.script = script;
|
||||||
|
args.script = (JSScript *)0xbad;
|
||||||
|
scopeChain_ = &chain;
|
||||||
|
/* savedpc initialized by pushExecuteFrame */
|
||||||
|
prev_ = NULL;
|
||||||
|
JS_ASSERT(!hasImacropc());
|
||||||
|
JS_ASSERT(!hasHookData());
|
||||||
|
rval_.setUndefined();
|
||||||
|
blockChain_ = NULL;
|
||||||
|
JS_ASSERT(annotation() == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
JSStackFrame::initDummyFrame(JSContext *cx, JSObject &chain)
|
||||||
|
{
|
||||||
|
js::PodZero(this);
|
||||||
|
flags_ = JSFRAME_DUMMY;
|
||||||
|
prev_ = cx->maybefp();
|
||||||
|
chain.isGlobal();
|
||||||
|
setScopeChainNoCallObj(chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
JSStackFrame::stealFrameAndSlots(js::Value *vp, JSStackFrame *otherfp,
|
||||||
|
js::Value *othervp, js::Value *othersp)
|
||||||
|
{
|
||||||
|
JS_ASSERT(vp == (js::Value *)this - (otherfp->formalArgsEnd() - othervp));
|
||||||
|
JS_ASSERT(othervp == otherfp->actualArgs() - 2);
|
||||||
|
JS_ASSERT(othersp >= otherfp->slots());
|
||||||
|
JS_ASSERT(othersp <= otherfp->base() + otherfp->numSlots());
|
||||||
|
|
||||||
|
size_t nbytes = (othersp - othervp) * sizeof(js::Value);
|
||||||
|
memcpy(vp, othervp, nbytes);
|
||||||
|
JS_ASSERT(vp == actualArgs() - 2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Repoint Call, Arguments, Block and With objects to the new live frame.
|
||||||
|
* Call and Arguments are done directly because we have pointers to them.
|
||||||
|
* Block and With objects are done indirectly through 'liveFrame'. See
|
||||||
|
* js_LiveFrameToFloating comment in jsiter.h.
|
||||||
|
*/
|
||||||
|
if (hasCallObj()) {
|
||||||
|
callObj().setPrivate(this);
|
||||||
|
otherfp->flags_ &= ~JSFRAME_HAS_CALL_OBJ;
|
||||||
|
}
|
||||||
|
if (hasArgsObj()) {
|
||||||
|
argsObj().setPrivate(this);
|
||||||
|
otherfp->flags_ &= ~JSFRAME_HAS_ARGS_OBJ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline js::Value &
|
||||||
|
JSStackFrame::canonicalActualArg(uintN i) const
|
||||||
|
{
|
||||||
|
if (i < numFormalArgs())
|
||||||
|
return formalArg(i);
|
||||||
|
JS_ASSERT(i < numActualArgs());
|
||||||
|
return actualArgs()[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Op>
|
||||||
|
inline void
|
||||||
|
JSStackFrame::forEachCanonicalActualArg(Op op)
|
||||||
|
{
|
||||||
|
uintN nformal = fun()->nargs;
|
||||||
|
js::Value *formals = formalArgsEnd() - nformal;
|
||||||
|
uintN nactual = numActualArgs();
|
||||||
|
if (nactual <= nformal) {
|
||||||
|
uintN i = 0;
|
||||||
|
js::Value *actualsEnd = formals + nactual;
|
||||||
|
for (js::Value *p = formals; p != actualsEnd; ++p, ++i)
|
||||||
|
op(i, p);
|
||||||
|
} else {
|
||||||
|
uintN i = 0;
|
||||||
|
js::Value *formalsEnd = formalArgsEnd();
|
||||||
|
for (js::Value *p = formals; p != formalsEnd; ++p, ++i)
|
||||||
|
op(i, p);
|
||||||
|
js::Value *actuals = formalsEnd - (nactual + 2);
|
||||||
|
js::Value *actualsEnd = formals - 2;
|
||||||
|
for (js::Value *p = actuals; p != actualsEnd; ++p, ++i)
|
||||||
|
op(i, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Op>
|
||||||
|
inline void
|
||||||
|
JSStackFrame::forEachFormalArg(Op op)
|
||||||
|
{
|
||||||
|
js::Value *formals = formalArgsEnd() - fun()->nargs;
|
||||||
|
js::Value *formalsEnd = formalArgsEnd();
|
||||||
|
uintN i = 0;
|
||||||
|
for (js::Value *p = formals; p != formalsEnd; ++p, ++i)
|
||||||
|
op(i, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline JSObject *
|
||||||
|
JSStackFrame::computeThisObject(JSContext *cx)
|
||||||
|
{
|
||||||
|
js::Value &thisv = thisValue();
|
||||||
|
if (JS_LIKELY(!thisv.isPrimitive()))
|
||||||
|
return &thisv.toObject();
|
||||||
|
if (!js::ComputeThisFromArgv(cx, &thisv + 1))
|
||||||
|
return NULL;
|
||||||
|
JS_ASSERT(IsSaneThisObject(thisv.toObject()));
|
||||||
|
return &thisv.toObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline JSObject &
|
||||||
|
JSStackFrame::varobj(js::StackSegment *seg) const
|
||||||
|
{
|
||||||
|
JS_ASSERT(seg->contains(this));
|
||||||
|
return isFunctionFrame() ? callObj() : seg->getInitialVarObj();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline JSObject &
|
||||||
|
JSStackFrame::varobj(JSContext *cx) const
|
||||||
|
{
|
||||||
|
JS_ASSERT(cx->activeSegment()->contains(this));
|
||||||
|
return isFunctionFrame() ? callObj() : cx->activeSegment()->getInitialVarObj();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline jsbytecode *
|
||||||
|
JSStackFrame::pc(JSContext *cx) const
|
||||||
|
{
|
||||||
|
JS_ASSERT(cx->regs && cx->containingSegment(this) != NULL);
|
||||||
|
return (cx->regs->fp == this) ? cx->regs->pc : savedpc_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uintN
|
||||||
|
JSStackFrame::numActualArgs() const
|
||||||
|
{
|
||||||
|
JS_ASSERT(isFunctionFrame() && !isEvalFrame());
|
||||||
|
if (JS_UNLIKELY(flags_ & (JSFRAME_OVERFLOW_ARGS | JSFRAME_UNDERFLOW_ARGS)))
|
||||||
|
return hasArgsObj() ? argsObj().getArgsInitialLength() : args.nactual;
|
||||||
|
return numFormalArgs();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline js::Value *
|
||||||
|
JSStackFrame::actualArgs() const
|
||||||
|
{
|
||||||
|
JS_ASSERT(isFunctionFrame() && !isEvalFrame());
|
||||||
|
js::Value *argv = formalArgsEnd() - numFormalArgs();
|
||||||
|
if (JS_UNLIKELY(flags_ & JSFRAME_OVERFLOW_ARGS)) {
|
||||||
|
uintN nactual = hasArgsObj() ? argsObj().getArgsInitialLength() : args.nactual;
|
||||||
|
return argv - (2 + nactual);
|
||||||
|
}
|
||||||
|
return argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline js::Value *
|
||||||
|
JSStackFrame::actualArgsEnd() const
|
||||||
|
{
|
||||||
|
JS_ASSERT(isFunctionFrame() && !isEvalFrame());
|
||||||
|
if (JS_UNLIKELY(flags_ & JSFRAME_OVERFLOW_ARGS))
|
||||||
|
return formalArgsEnd() - (2 + numFormalArgs());
|
||||||
|
uintN argc = numActualArgs();
|
||||||
|
uintN nmissing = numFormalArgs() - argc;
|
||||||
|
return formalArgsEnd() - nmissing;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
JSStackFrame::setArgsObj(JSObject &obj)
|
||||||
|
{
|
||||||
|
JS_ASSERT_IF(hasArgsObj(), &obj == args.obj);
|
||||||
|
JS_ASSERT_IF(!hasArgsObj(), numActualArgs() == obj.getArgsInitialLength());
|
||||||
|
args.obj = &obj;
|
||||||
|
flags_ |= JSFRAME_HAS_ARGS_OBJ;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
JSStackFrame::setScopeChainNoCallObj(JSObject &obj)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
JS_ASSERT(&obj != NULL);
|
||||||
|
JSObject *callObjBefore = maybeCallObj();
|
||||||
|
if (!hasCallObj() && scopeChain_ != sInvalidScopeChain) {
|
||||||
|
for (JSObject *pobj = scopeChain_; pobj; pobj = pobj->getParent())
|
||||||
|
JS_ASSERT_IF(pobj->isCall(), pobj->getPrivate() != this);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
scopeChain_ = &obj;
|
||||||
|
JS_ASSERT(callObjBefore == maybeCallObj());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
JSStackFrame::setScopeChainAndCallObj(JSObject &obj)
|
||||||
|
{
|
||||||
|
JS_ASSERT(&obj != NULL);
|
||||||
|
JS_ASSERT(!hasCallObj() && obj.isCall() && obj.getPrivate() == this);
|
||||||
|
scopeChain_ = &obj;
|
||||||
|
flags_ |= JSFRAME_HAS_CALL_OBJ;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline JSObject &
|
||||||
|
JSStackFrame::callObj() const
|
||||||
|
{
|
||||||
|
JS_ASSERT(hasCallObj());
|
||||||
|
JSObject *pobj = &scopeChain();
|
||||||
|
while (JS_UNLIKELY(pobj->getClass() != &js_CallClass)) {
|
||||||
|
JS_ASSERT(js_IsCacheableNonGlobalScope(pobj) || pobj->isWith());
|
||||||
|
pobj = pobj->getParent();
|
||||||
|
}
|
||||||
|
return *pobj;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline JSObject *
|
||||||
|
JSStackFrame::maybeCallObj() const
|
||||||
|
{
|
||||||
|
return hasCallObj() ? &callObj() : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace js {
|
||||||
|
|
||||||
|
inline void
|
||||||
|
PutActivationObjects(JSContext *cx, JSStackFrame *fp)
|
||||||
|
{
|
||||||
|
JS_ASSERT(fp->isFunctionFrame() && !fp->isEvalFrame());
|
||||||
|
|
||||||
|
/* The order is important as js_PutCallObject needs to access argsObj. */
|
||||||
|
if (fp->hasCallObj()) {
|
||||||
|
js_PutCallObject(cx, fp);
|
||||||
|
} else if (fp->hasArgsObj()) {
|
||||||
|
js_PutArgsObject(cx, fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* jsinterpinlines_h__ */
|
|
@ -76,6 +76,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsstrinlines.h"
|
#include "jsstrinlines.h"
|
||||||
|
|
||||||
|
@ -121,7 +122,7 @@ NativeIterator::mark(JSTracer *trc)
|
||||||
else
|
else
|
||||||
MarkValueRange(trc, beginValue(), endValue(), "props");
|
MarkValueRange(trc, beginValue(), endValue(), "props");
|
||||||
if (obj)
|
if (obj)
|
||||||
MarkObject(trc, obj, "obj");
|
MarkObject(trc, *obj, "obj");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1088,11 +1089,11 @@ generator_trace(JSTracer *trc, JSObject *obj)
|
||||||
if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING)
|
if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JSStackFrame *fp = gen->getFloatingFrame();
|
JSStackFrame *fp = gen->floatingFrame();
|
||||||
JS_ASSERT(gen->getLiveFrame() == fp);
|
JS_ASSERT(gen->liveFrame() == fp);
|
||||||
MarkValueRange(trc, gen->floatingStack, fp->argEnd(), "generator slots");
|
MarkValueRange(trc, gen->floatingStack, fp->formalArgsEnd(), "generator slots");
|
||||||
js_TraceStackFrame(trc, fp);
|
js_TraceStackFrame(trc, fp);
|
||||||
MarkValueRange(trc, fp->slots(), gen->savedRegs.sp, "generator slots");
|
MarkValueRange(trc, fp->slots(), gen->regs.sp, "generator slots");
|
||||||
}
|
}
|
||||||
|
|
||||||
Class js_GeneratorClass = {
|
Class js_GeneratorClass = {
|
||||||
|
@ -1123,6 +1124,13 @@ Class js_GeneratorClass = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
RebaseRegsFromTo(JSFrameRegs *regs, JSStackFrame *from, JSStackFrame *to)
|
||||||
|
{
|
||||||
|
regs->fp = to;
|
||||||
|
regs->sp = to->slots() + (regs->sp - from->slots());
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called from the JSOP_GENERATOR case in the interpreter, with fp referring
|
* Called from the JSOP_GENERATOR case in the interpreter, with fp referring
|
||||||
* to the frame by which the generator function was activated. Create a new
|
* to the frame by which the generator function was activated. Create a new
|
||||||
|
@ -1138,65 +1146,42 @@ js_NewGenerator(JSContext *cx)
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
JSStackFrame *stackfp = cx->fp();
|
||||||
|
JS_ASSERT(stackfp->base() == cx->regs->sp);
|
||||||
|
JS_ASSERT(stackfp->actualArgs() <= stackfp->formalArgs());
|
||||||
|
|
||||||
/* Load and compute stack slot counts. */
|
/* Load and compute stack slot counts. */
|
||||||
JSStackFrame *fp = cx->fp();
|
Value *stackvp = stackfp->actualArgs() - 2;
|
||||||
uintN argc = fp->numActualArgs();
|
uintN vplen = stackfp->formalArgsEnd() - stackvp;
|
||||||
uintN nargs = JS_MAX(argc, fp->numFormalArgs());
|
|
||||||
uintN vplen = 2 + nargs;
|
|
||||||
|
|
||||||
/* Compute JSGenerator size. */
|
/* Compute JSGenerator size. */
|
||||||
uintN nbytes = sizeof(JSGenerator) +
|
uintN nbytes = sizeof(JSGenerator) +
|
||||||
(-1 + /* one Value included in JSGenerator */
|
(-1 + /* one Value included in JSGenerator */
|
||||||
vplen +
|
vplen +
|
||||||
VALUES_PER_STACK_FRAME +
|
VALUES_PER_STACK_FRAME +
|
||||||
fp->getSlotCount()) * sizeof(Value);
|
stackfp->numSlots()) * sizeof(Value);
|
||||||
|
|
||||||
JSGenerator *gen = (JSGenerator *) cx->malloc(nbytes);
|
JSGenerator *gen = (JSGenerator *) cx->malloc(nbytes);
|
||||||
if (!gen)
|
if (!gen)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Cut up floatingStack space. */
|
/* Cut up floatingStack space. */
|
||||||
Value *vp = gen->floatingStack;
|
Value *genvp = gen->floatingStack;
|
||||||
JSStackFrame *newfp = reinterpret_cast<JSStackFrame *>(vp + vplen);
|
JSStackFrame *genfp = reinterpret_cast<JSStackFrame *>(genvp + vplen);
|
||||||
Value *slots = newfp->slots();
|
|
||||||
|
|
||||||
/* Initialize JSGenerator. */
|
/* Initialize JSGenerator. */
|
||||||
gen->obj = obj;
|
gen->obj = obj;
|
||||||
gen->state = JSGEN_NEWBORN;
|
gen->state = JSGEN_NEWBORN;
|
||||||
gen->savedRegs.pc = cx->regs->pc;
|
|
||||||
JS_ASSERT(cx->regs->sp == fp->slots() + fp->getFixedCount());
|
|
||||||
gen->savedRegs.sp = slots + fp->getFixedCount();
|
|
||||||
gen->vplen = vplen;
|
|
||||||
gen->enumerators = NULL;
|
gen->enumerators = NULL;
|
||||||
gen->liveFrame = newfp;
|
gen->floating = genfp;
|
||||||
|
|
||||||
/* Copy generator's stack frame copy in from |cx->fp|. */
|
/* Initialize regs stored in generator. */
|
||||||
newfp->setCallObj(fp->maybeCallObj());
|
gen->regs = *cx->regs;
|
||||||
if (fp->hasCallObj()) { /* Steal call object. */
|
RebaseRegsFromTo(&gen->regs, stackfp, genfp);
|
||||||
fp->getCallObj()->setPrivate(newfp);
|
|
||||||
fp->setCallObj(NULL);
|
|
||||||
}
|
|
||||||
newfp->setArgsObj(fp->maybeArgsObj());
|
|
||||||
if (fp->hasArgsObj()) { /* Steal args object. */
|
|
||||||
fp->getArgsObj()->setPrivate(newfp);
|
|
||||||
fp->setArgsObj(NULL);
|
|
||||||
}
|
|
||||||
newfp->setScript(fp->getScript());
|
|
||||||
newfp->setFunction(fp->getFunction());
|
|
||||||
newfp->setThisValue(fp->getThisValue());
|
|
||||||
newfp->setNumActualArgs(fp->numActualArgs());
|
|
||||||
newfp->argv = vp + 2;
|
|
||||||
newfp->setReturnValue(fp->getReturnValue());
|
|
||||||
newfp->setAnnotation(NULL);
|
|
||||||
newfp->setScopeChain(fp->maybeScopeChain());
|
|
||||||
JS_ASSERT(!fp->hasBlockChain());
|
|
||||||
newfp->setBlockChain(NULL);
|
|
||||||
newfp->flags = fp->flags | JSFRAME_GENERATOR | JSFRAME_FLOATING_GENERATOR;
|
|
||||||
JS_ASSERT(!newfp->hasIMacroPC());
|
|
||||||
|
|
||||||
/* Copy in arguments and slots. */
|
/* Copy frame off the stack. */
|
||||||
memcpy(vp, fp->argv - 2, vplen * sizeof(Value));
|
genfp->stealFrameAndSlots(genvp, stackfp, stackvp, cx->regs->sp);
|
||||||
memcpy(slots, fp->slots(), fp->getFixedCount() * sizeof(Value));
|
genfp->initFloatingGenerator();
|
||||||
|
|
||||||
obj->setPrivate(gen);
|
obj->setPrivate(gen);
|
||||||
return obj;
|
return obj;
|
||||||
|
@ -1205,8 +1190,8 @@ js_NewGenerator(JSContext *cx)
|
||||||
JSGenerator *
|
JSGenerator *
|
||||||
js_FloatingFrameToGenerator(JSStackFrame *fp)
|
js_FloatingFrameToGenerator(JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
JS_ASSERT(fp->isGenerator() && fp->isFloatingGenerator());
|
JS_ASSERT(fp->isGeneratorFrame() && fp->isFloatingGenerator());
|
||||||
char *floatingStackp = (char *)(fp->argv - 2);
|
char *floatingStackp = (char *)(fp->actualArgs() - 2);
|
||||||
char *p = floatingStackp - offsetof(JSGenerator, floatingStack);
|
char *p = floatingStackp - offsetof(JSGenerator, floatingStack);
|
||||||
return reinterpret_cast<JSGenerator *>(p);
|
return reinterpret_cast<JSGenerator *>(p);
|
||||||
}
|
}
|
||||||
|
@ -1229,7 +1214,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
||||||
if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) {
|
if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) {
|
||||||
js_ReportValueError(cx, JSMSG_NESTING_GENERATOR,
|
js_ReportValueError(cx, JSMSG_NESTING_GENERATOR,
|
||||||
JSDVG_SEARCH_STACK, ObjectOrNullValue(obj),
|
JSDVG_SEARCH_STACK, ObjectOrNullValue(obj),
|
||||||
JS_GetFunctionId(gen->getFloatingFrame()->getFunction()));
|
JS_GetFunctionId(gen->floatingFrame()->fun()));
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1246,7 +1231,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
||||||
* Store the argument to send as the result of the yield
|
* Store the argument to send as the result of the yield
|
||||||
* expression.
|
* expression.
|
||||||
*/
|
*/
|
||||||
gen->savedRegs.sp[-1] = arg;
|
gen->regs.sp[-1] = arg;
|
||||||
}
|
}
|
||||||
gen->state = JSGEN_RUNNING;
|
gen->state = JSGEN_RUNNING;
|
||||||
break;
|
break;
|
||||||
|
@ -1263,96 +1248,63 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSStackFrame *genfp = gen->getFloatingFrame();
|
JSStackFrame *genfp = gen->floatingFrame();
|
||||||
|
Value *genvp = gen->floatingStack;
|
||||||
|
uintN vplen = genfp->formalArgsEnd() - genvp;
|
||||||
|
|
||||||
|
JSStackFrame *stackfp;
|
||||||
|
Value *stackvp;
|
||||||
JSBool ok;
|
JSBool ok;
|
||||||
{
|
{
|
||||||
Value *genVp = gen->floatingStack;
|
|
||||||
uintN vplen = gen->vplen;
|
|
||||||
uintN nfixed = genfp->getSlotCount();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a pointer to new frame/slots. This memory is not "claimed", so
|
* Get a pointer to new frame/slots. This memory is not "claimed", so
|
||||||
* the code before pushExecuteFrame must not reenter the interpreter.
|
* the code before pushExecuteFrame must not reenter the interpreter.
|
||||||
*/
|
*/
|
||||||
FrameGuard frame;
|
GeneratorFrameGuard frame;
|
||||||
if (!cx->stack().getExecuteFrame(cx, cx->maybefp(), vplen, nfixed, frame)) {
|
if (!cx->stack().getGeneratorFrame(cx, vplen, genfp->numSlots(), &frame)) {
|
||||||
gen->state = JSGEN_CLOSED;
|
gen->state = JSGEN_CLOSED;
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
stackfp = frame.fp();
|
||||||
|
stackvp = frame.vp();
|
||||||
|
|
||||||
Value *vp = frame.getvp();
|
/* Copy frame onto the stack. */
|
||||||
JSStackFrame *fp = frame.getFrame();
|
stackfp->stealFrameAndSlots(stackvp, genfp, genvp, gen->regs.sp);
|
||||||
|
stackfp->repointGeneratorFrameDown(cx->maybefp());
|
||||||
|
stackfp->unsetFloatingGenerator();
|
||||||
|
RebaseRegsFromTo(&gen->regs, genfp, stackfp);
|
||||||
|
MUST_FLOW_THROUGH("restore");
|
||||||
|
|
||||||
/*
|
/* Officially push frame. frame's destructor pops. */
|
||||||
* Copy and rebase stack frame/args/slots. The "floating" flag must
|
cx->stack().pushGeneratorFrame(cx, &gen->regs, &frame);
|
||||||
* only be set on the generator's frame. See args_or_call_trace.
|
|
||||||
*/
|
|
||||||
uintN usedBefore = gen->savedRegs.sp - genVp;
|
|
||||||
memcpy(vp, genVp, usedBefore * sizeof(Value));
|
|
||||||
fp->flags &= ~JSFRAME_FLOATING_GENERATOR;
|
|
||||||
fp->argv = vp + 2;
|
|
||||||
gen->savedRegs.sp = fp->slots() + (gen->savedRegs.sp - genfp->slots());
|
|
||||||
JS_ASSERT(uintN(gen->savedRegs.sp - fp->slots()) <= fp->getSlotCount());
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
cx->enterGenerator(gen); /* OOM check above. */
|
||||||
JSObject *callobjBefore = fp->maybeCallObj();
|
|
||||||
JSObject *argsobjBefore = fp->maybeArgsObj();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Repoint Call, Arguments, Block and With objects to the new live
|
|
||||||
* frame. Call and Arguments are done directly because we have
|
|
||||||
* pointers to them. Block and With objects are done indirectly through
|
|
||||||
* 'liveFrame'. See js_LiveFrameToFloating comment in jsiter.h.
|
|
||||||
*/
|
|
||||||
if (genfp->hasCallObj())
|
|
||||||
fp->getCallObj()->setPrivate(fp);
|
|
||||||
if (genfp->hasArgsObj())
|
|
||||||
fp->getArgsObj()->setPrivate(fp);
|
|
||||||
gen->liveFrame = fp;
|
|
||||||
(void)cx->enterGenerator(gen); /* OOM check above. */
|
|
||||||
|
|
||||||
/* Officially push |fp|. |frame|'s destructor pops. */
|
|
||||||
cx->stack().pushExecuteFrame(cx, frame, gen->savedRegs, NULL);
|
|
||||||
|
|
||||||
/* Swap the enumerators stack for the generator's stack. */
|
|
||||||
JSObject *enumerators = cx->enumerators;
|
JSObject *enumerators = cx->enumerators;
|
||||||
cx->enumerators = gen->enumerators;
|
cx->enumerators = gen->enumerators;
|
||||||
|
|
||||||
ok = RunScript(cx, fp->maybeScript(), fp->maybeFunction(), fp->getScopeChain());
|
ok = RunScript(cx, stackfp->script(), stackfp->fun(), stackfp->scopeChain());
|
||||||
|
|
||||||
/* Restore the original enumerators stack. */
|
|
||||||
gen->enumerators = cx->enumerators;
|
gen->enumerators = cx->enumerators;
|
||||||
cx->enumerators = enumerators;
|
cx->enumerators = enumerators;
|
||||||
|
|
||||||
/* Restore call/args/block objects. */
|
|
||||||
cx->leaveGenerator(gen);
|
cx->leaveGenerator(gen);
|
||||||
gen->liveFrame = genfp;
|
|
||||||
if (fp->hasArgsObj())
|
|
||||||
fp->getArgsObj()->setPrivate(genfp);
|
|
||||||
if (fp->hasCallObj())
|
|
||||||
fp->getCallObj()->setPrivate(genfp);
|
|
||||||
|
|
||||||
JS_ASSERT_IF(argsobjBefore, argsobjBefore == fp->maybeArgsObj());
|
/*
|
||||||
JS_ASSERT_IF(callobjBefore, callobjBefore == fp->maybeCallObj());
|
* Copy the stack frame and rebase the regs, but not before popping
|
||||||
|
* the stack, since cx->regs == &gen->regs.
|
||||||
/* Copy and rebase stack frame/args/slots. Restore "floating" flag. */
|
*/
|
||||||
JS_ASSERT(uintN(gen->savedRegs.sp - fp->slots()) <= fp->getSlotCount());
|
genfp->stealFrameAndSlots(genvp, stackfp, stackvp, gen->regs.sp);
|
||||||
uintN usedAfter = gen->savedRegs.sp - vp;
|
genfp->setFloatingGenerator();
|
||||||
memcpy(genVp, vp, usedAfter * sizeof(Value));
|
|
||||||
genfp->flags |= JSFRAME_FLOATING_GENERATOR;
|
|
||||||
genfp->argv = genVp + 2;
|
|
||||||
gen->savedRegs.sp = genfp->slots() + (gen->savedRegs.sp - fp->slots());
|
|
||||||
JS_ASSERT(uintN(gen->savedRegs.sp - genfp->slots()) <= genfp->getSlotCount());
|
|
||||||
}
|
}
|
||||||
|
MUST_FLOW_LABEL(restore)
|
||||||
|
RebaseRegsFromTo(&gen->regs, stackfp, genfp);
|
||||||
|
|
||||||
if (gen->getFloatingFrame()->flags & JSFRAME_YIELDING) {
|
if (gen->floatingFrame()->isYielding()) {
|
||||||
/* Yield cannot fail, throw or be called on closing. */
|
/* Yield cannot fail, throw or be called on closing. */
|
||||||
JS_ASSERT(ok);
|
JS_ASSERT(ok);
|
||||||
JS_ASSERT(!cx->throwing);
|
JS_ASSERT(!cx->throwing);
|
||||||
JS_ASSERT(gen->state == JSGEN_RUNNING);
|
JS_ASSERT(gen->state == JSGEN_RUNNING);
|
||||||
JS_ASSERT(op != JSGENOP_CLOSE);
|
JS_ASSERT(op != JSGENOP_CLOSE);
|
||||||
genfp->flags &= ~JSFRAME_YIELDING;
|
genfp->clearYielding();
|
||||||
gen->state = JSGEN_OPEN;
|
gen->state = JSGEN_OPEN;
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1446,7 +1398,7 @@ generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc)
|
||||||
bool undef = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && argc != 0);
|
bool undef = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && argc != 0);
|
||||||
if (!SendToGenerator(cx, op, obj, gen, undef ? vp[2] : UndefinedValue()))
|
if (!SendToGenerator(cx, op, obj, gen, undef ? vp[2] : UndefinedValue()))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
*vp = gen->getFloatingFrame()->getReturnValue();
|
*vp = gen->floatingFrame()->returnValue();
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,20 +201,19 @@ typedef enum JSGeneratorState {
|
||||||
struct JSGenerator {
|
struct JSGenerator {
|
||||||
JSObject *obj;
|
JSObject *obj;
|
||||||
JSGeneratorState state;
|
JSGeneratorState state;
|
||||||
JSFrameRegs savedRegs;
|
JSFrameRegs regs;
|
||||||
uintN vplen;
|
|
||||||
JSStackFrame *liveFrame;
|
|
||||||
JSObject *enumerators;
|
JSObject *enumerators;
|
||||||
|
JSStackFrame *floating;
|
||||||
js::Value floatingStack[1];
|
js::Value floatingStack[1];
|
||||||
|
|
||||||
JSStackFrame *getFloatingFrame() {
|
JSStackFrame *floatingFrame() {
|
||||||
return reinterpret_cast<JSStackFrame *>(floatingStack + vplen);
|
return floating;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSStackFrame *getLiveFrame() {
|
JSStackFrame *liveFrame() {
|
||||||
JS_ASSERT((state == JSGEN_RUNNING || state == JSGEN_CLOSING) ==
|
JS_ASSERT((state == JSGEN_RUNNING || state == JSGEN_CLOSING) ==
|
||||||
(liveFrame != getFloatingFrame()));
|
(regs.fp != floatingFrame()));
|
||||||
return liveFrame;
|
return regs.fp;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -236,8 +235,8 @@ inline JSStackFrame *
|
||||||
js_FloatingFrameIfGenerator(JSContext *cx, JSStackFrame *fp)
|
js_FloatingFrameIfGenerator(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
JS_ASSERT(cx->stack().contains(fp));
|
JS_ASSERT(cx->stack().contains(fp));
|
||||||
if (JS_UNLIKELY(fp->isGenerator()))
|
if (JS_UNLIKELY(fp->isGeneratorFrame()))
|
||||||
return cx->generatorFor(fp)->getFloatingFrame();
|
return cx->generatorFor(fp)->floatingFrame();
|
||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,9 +247,7 @@ js_FloatingFrameToGenerator(JSStackFrame *fp);
|
||||||
inline JSStackFrame *
|
inline JSStackFrame *
|
||||||
js_LiveFrameIfGenerator(JSStackFrame *fp)
|
js_LiveFrameIfGenerator(JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
if (fp->flags & JSFRAME_GENERATOR)
|
return fp->isGeneratorFrame() ? js_FloatingFrameToGenerator(fp)->liveFrame() : fp;
|
||||||
return js_FloatingFrameToGenerator(fp)->getLiveFrame();
|
|
||||||
return fp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
124
js/src/jsobj.cpp
124
js/src/jsobj.cpp
|
@ -78,6 +78,7 @@
|
||||||
#include "jsdbgapi.h"
|
#include "jsdbgapi.h"
|
||||||
#include "json.h"
|
#include "json.h"
|
||||||
|
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jsscopeinlines.h"
|
#include "jsscopeinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
@ -951,7 +952,7 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JS_ASSERT(principals || !(callbacks && callbacks->findObjectPrincipals));
|
JS_ASSERT(principals || !(callbacks && callbacks->findObjectPrincipals));
|
||||||
flags = JS_GetScriptFilenameFlags(caller->getScript());
|
flags = JS_GetScriptFilenameFlags(caller->script());
|
||||||
if ((flags & JSFILENAME_PROTECTED) &&
|
if ((flags & JSFILENAME_PROTECTED) &&
|
||||||
principals &&
|
principals &&
|
||||||
strcmp(principals->codebase, "[System Principal]")) {
|
strcmp(principals->codebase, "[System Principal]")) {
|
||||||
|
@ -960,13 +961,13 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
|
||||||
}
|
}
|
||||||
|
|
||||||
jsbytecode *pc = caller->pc(cx);
|
jsbytecode *pc = caller->pc(cx);
|
||||||
if (pc && js_GetOpcode(cx, caller->getScript(), pc) == JSOP_EVAL) {
|
if (pc && js_GetOpcode(cx, caller->script(), pc) == JSOP_EVAL) {
|
||||||
JS_ASSERT(js_GetOpcode(cx, caller->getScript(), pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
|
JS_ASSERT(js_GetOpcode(cx, caller->script(), pc + JSOP_EVAL_LENGTH) == JSOP_LINENO);
|
||||||
*linenop = GET_UINT16(pc + JSOP_EVAL_LENGTH);
|
*linenop = GET_UINT16(pc + JSOP_EVAL_LENGTH);
|
||||||
} else {
|
} else {
|
||||||
*linenop = js_FramePCToLineNumber(cx, caller);
|
*linenop = js_FramePCToLineNumber(cx, caller);
|
||||||
}
|
}
|
||||||
return caller->getScript()->filename;
|
return caller->script()->filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef EVAL_CACHE_CHAIN_LIMIT
|
#ifndef EVAL_CACHE_CHAIN_LIMIT
|
||||||
|
@ -1056,18 +1057,18 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
|
||||||
* when evaluating the code string. Warn when such uses are seen so that
|
* when evaluating the code string. Warn when such uses are seen so that
|
||||||
* authors will know that support for eval(s, o) has been removed.
|
* authors will know that support for eval(s, o) has been removed.
|
||||||
*/
|
*/
|
||||||
if (argc > 1 && !caller->getScript()->warnedAboutTwoArgumentEval) {
|
if (argc > 1 && !caller->script()->warnedAboutTwoArgumentEval) {
|
||||||
static const char TWO_ARGUMENT_WARNING[] =
|
static const char TWO_ARGUMENT_WARNING[] =
|
||||||
"Support for eval(code, scopeObject) has been removed. "
|
"Support for eval(code, scopeObject) has been removed. "
|
||||||
"Use |with (scopeObject) eval(code);| instead.";
|
"Use |with (scopeObject) eval(code);| instead.";
|
||||||
if (!JS_ReportWarning(cx, TWO_ARGUMENT_WARNING))
|
if (!JS_ReportWarning(cx, TWO_ARGUMENT_WARNING))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
caller->getScript()->warnedAboutTwoArgumentEval = true;
|
caller->script()->warnedAboutTwoArgumentEval = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* From here on, control must exit through label out with ok set. */
|
/* From here on, control must exit through label out with ok set. */
|
||||||
MUST_FLOW_THROUGH("out");
|
MUST_FLOW_THROUGH("out");
|
||||||
uintN staticLevel = caller->getScript()->staticLevel + 1;
|
uintN staticLevel = caller->script()->staticLevel + 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bring fp->scopeChain up to date. We're either going to use
|
* Bring fp->scopeChain up to date. We're either going to use
|
||||||
|
@ -1104,7 +1105,7 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
|
||||||
*
|
*
|
||||||
* NB: This means that the C API must not be used to call eval.
|
* NB: This means that the C API must not be used to call eval.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT_IF(caller->argv, caller->hasCallObj());
|
JS_ASSERT_IF(caller->isFunctionFrame(), caller->hasCallObj());
|
||||||
scopeobj = callerScopeChain;
|
scopeobj = callerScopeChain;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1162,7 +1163,7 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
|
||||||
* calls to eval from global code are not cached.
|
* calls to eval from global code are not cached.
|
||||||
*/
|
*/
|
||||||
JSScript **bucket = EvalCacheHash(cx, str);
|
JSScript **bucket = EvalCacheHash(cx, str);
|
||||||
if (!indirectCall && caller->hasFunction()) {
|
if (!indirectCall && caller->isFunctionFrame()) {
|
||||||
uintN count = 0;
|
uintN count = 0;
|
||||||
JSScript **scriptp = bucket;
|
JSScript **scriptp = bucket;
|
||||||
|
|
||||||
|
@ -1180,7 +1181,7 @@ obj_eval(JSContext *cx, uintN argc, Value *vp)
|
||||||
*/
|
*/
|
||||||
JSFunction *fun = script->getFunction(0);
|
JSFunction *fun = script->getFunction(0);
|
||||||
|
|
||||||
if (fun == caller->getFunction()) {
|
if (fun == caller->fun()) {
|
||||||
/*
|
/*
|
||||||
* Get the source string passed for safekeeping in the
|
* Get the source string passed for safekeeping in the
|
||||||
* atom map by the prior eval to Compiler::compileScript.
|
* atom map by the prior eval to Compiler::compileScript.
|
||||||
|
@ -2727,10 +2728,10 @@ Detecting(JSContext *cx, jsbytecode *pc)
|
||||||
JSOp op;
|
JSOp op;
|
||||||
JSAtom *atom;
|
JSAtom *atom;
|
||||||
|
|
||||||
script = cx->fp()->getScript();
|
script = cx->fp()->script();
|
||||||
endpc = script->code + script->length;
|
endpc = script->code + script->length;
|
||||||
for (;; pc += js_CodeSpec[op].length) {
|
for (;; pc += js_CodeSpec[op].length) {
|
||||||
JS_ASSERT_IF(!cx->fp()->hasIMacroPC(), script->code <= pc && pc < endpc);
|
JS_ASSERT_IF(!cx->fp()->hasImacropc(), script->code <= pc && pc < endpc);
|
||||||
|
|
||||||
/* General case: a branch or equality op follows the access. */
|
/* General case: a branch or equality op follows the access. */
|
||||||
op = js_GetOpcode(cx, script, pc);
|
op = js_GetOpcode(cx, script, pc);
|
||||||
|
@ -2801,16 +2802,15 @@ js_InferFlags(JSContext *cx, uintN defaultFlags)
|
||||||
JSStackFrame *const fp = js_GetTopStackFrame(cx);
|
JSStackFrame *const fp = js_GetTopStackFrame(cx);
|
||||||
if (!fp || !(pc = cx->regs->pc))
|
if (!fp || !(pc = cx->regs->pc))
|
||||||
return defaultFlags;
|
return defaultFlags;
|
||||||
cs = &js_CodeSpec[js_GetOpcode(cx, fp->getScript(), pc)];
|
cs = &js_CodeSpec[js_GetOpcode(cx, fp->script(), pc)];
|
||||||
format = cs->format;
|
format = cs->format;
|
||||||
if (JOF_MODE(format) != JOF_NAME)
|
if (JOF_MODE(format) != JOF_NAME)
|
||||||
flags |= JSRESOLVE_QUALIFIED;
|
flags |= JSRESOLVE_QUALIFIED;
|
||||||
if ((format & (JOF_SET | JOF_FOR)) ||
|
if ((format & (JOF_SET | JOF_FOR)) || fp->isAssigning()) {
|
||||||
(fp->flags & JSFRAME_ASSIGNING)) {
|
|
||||||
flags |= JSRESOLVE_ASSIGNING;
|
flags |= JSRESOLVE_ASSIGNING;
|
||||||
} else if (cs->length >= 0) {
|
} else if (cs->length >= 0) {
|
||||||
pc += cs->length;
|
pc += cs->length;
|
||||||
JSScript *script = cx->fp()->getScript();
|
JSScript *script = cx->fp()->script();
|
||||||
if (pc < script->code + script->length && Detecting(cx, pc))
|
if (pc < script->code + script->length && Detecting(cx, pc))
|
||||||
flags |= JSRESOLVE_DETECTING;
|
flags |= JSRESOLVE_DETECTING;
|
||||||
}
|
}
|
||||||
|
@ -2987,7 +2987,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
||||||
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2);
|
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2);
|
||||||
|
|
||||||
JSStackFrame *const fp = cx->fp();
|
JSStackFrame *const fp = cx->fp();
|
||||||
JSObject *obj = fp->getScopeChain();
|
JSObject *obj = &fp->scopeChain();
|
||||||
JS_ASSERT(obj->isClonedBlock());
|
JS_ASSERT(obj->isClonedBlock());
|
||||||
JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()));
|
JS_ASSERT(obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()));
|
||||||
|
|
||||||
|
@ -3008,7 +3008,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
||||||
uintN flen = JS_MIN(count, JS_INITIAL_NSLOTS - slot);
|
uintN flen = JS_MIN(count, JS_INITIAL_NSLOTS - slot);
|
||||||
uintN stop = slot + flen;
|
uintN stop = slot + flen;
|
||||||
|
|
||||||
depth += fp->getFixedCount();
|
depth += fp->numFixed();
|
||||||
while (slot < stop)
|
while (slot < stop)
|
||||||
obj->fslots[slot++] = fp->slots()[depth++];
|
obj->fslots[slot++] = fp->slots()[depth++];
|
||||||
count -= flen;
|
count -= flen;
|
||||||
|
@ -3018,7 +3018,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
||||||
|
|
||||||
/* We must clear the private slot even with errors. */
|
/* We must clear the private slot even with errors. */
|
||||||
obj->setPrivate(NULL);
|
obj->setPrivate(NULL);
|
||||||
fp->setScopeChain(obj->getParent());
|
fp->setScopeChainNoCallObj(*obj->getParent());
|
||||||
return normalUnwind;
|
return normalUnwind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3037,8 +3037,8 @@ block_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
||||||
if (fp) {
|
if (fp) {
|
||||||
fp = js_LiveFrameIfGenerator(fp);
|
fp = js_LiveFrameIfGenerator(fp);
|
||||||
index += fp->getFixedCount() + OBJ_BLOCK_DEPTH(cx, obj);
|
index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj);
|
||||||
JS_ASSERT(index < fp->getSlotCount());
|
JS_ASSERT(index < fp->numSlots());
|
||||||
*vp = fp->slots()[index];
|
*vp = fp->slots()[index];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3058,8 +3058,8 @@ block_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||||
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
JSStackFrame *fp = (JSStackFrame *) obj->getPrivate();
|
||||||
if (fp) {
|
if (fp) {
|
||||||
fp = js_LiveFrameIfGenerator(fp);
|
fp = js_LiveFrameIfGenerator(fp);
|
||||||
index += fp->getFixedCount() + OBJ_BLOCK_DEPTH(cx, obj);
|
index += fp->numFixed() + OBJ_BLOCK_DEPTH(cx, obj);
|
||||||
JS_ASSERT(index < fp->getSlotCount());
|
JS_ASSERT(index < fp->numSlots());
|
||||||
fp->slots()[index] = *vp;
|
fp->slots()[index] = *vp;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3741,7 +3741,7 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey,
|
||||||
*/
|
*/
|
||||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||||
if (!start && (fp = cx->maybefp()) != NULL)
|
if (!start && (fp = cx->maybefp()) != NULL)
|
||||||
start = fp->maybeScopeChain();
|
start = &fp->scopeChain();
|
||||||
|
|
||||||
if (start) {
|
if (start) {
|
||||||
/* Find the topmost object in the scope chain. */
|
/* Find the topmost object in the scope chain. */
|
||||||
|
@ -4479,7 +4479,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult,
|
||||||
JSProperty *prop;
|
JSProperty *prop;
|
||||||
|
|
||||||
JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx));
|
JS_ASSERT_IF(cacheResult, !JS_ON_TRACE(cx));
|
||||||
scopeChain = js_GetTopStackFrame(cx)->getScopeChain();
|
scopeChain = &js_GetTopStackFrame(cx)->scopeChain();
|
||||||
|
|
||||||
/* Scan entries on the scope chain that we can cache across. */
|
/* Scan entries on the scope chain that we can cache across. */
|
||||||
entry = JS_NO_PROP_CACHE_FILL;
|
entry = JS_NO_PROP_CACHE_FILL;
|
||||||
|
@ -4796,7 +4796,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow,
|
||||||
op = (JSOp) *pc;
|
op = (JSOp) *pc;
|
||||||
if (op == JSOP_TRAP) {
|
if (op == JSOP_TRAP) {
|
||||||
JS_ASSERT_NOT_ON_TRACE(cx);
|
JS_ASSERT_NOT_ON_TRACE(cx);
|
||||||
op = JS_GetTrapOpcode(cx, cx->fp()->getScript(), pc);
|
op = JS_GetTrapOpcode(cx, cx->fp()->script(), pc);
|
||||||
}
|
}
|
||||||
if (op == JSOP_GETXPROP) {
|
if (op == JSOP_GETXPROP) {
|
||||||
flags = JSREPORT_ERROR;
|
flags = JSREPORT_ERROR;
|
||||||
|
@ -4888,7 +4888,7 @@ js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* If neither cx nor the code is strict, then no check is needed. */
|
/* If neither cx nor the code is strict, then no check is needed. */
|
||||||
if (!(fp->hasScript() && fp->getScript()->strictModeCode) &&
|
if (!(fp->isScriptFrame() && fp->script()->strictModeCode) &&
|
||||||
!JS_HAS_STRICT_OPTION(cx)) {
|
!JS_HAS_STRICT_OPTION(cx)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -5282,11 +5282,12 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval)
|
||||||
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
||||||
|
|
||||||
if (fun != funobj) {
|
if (fun != funobj) {
|
||||||
for (JSStackFrame *fp = cx->maybefp(); fp; fp = fp->down) {
|
for (JSStackFrame *fp = cx->maybefp(); fp; fp = fp->prev()) {
|
||||||
if (fp->callee() == fun &&
|
if (fp->isFunctionFrame() &&
|
||||||
fp->getThisValue().isObject() &&
|
&fp->callee() == &fun->compiledFunObj() &&
|
||||||
&fp->getThisValue().toObject() == obj) {
|
fp->thisValue().isObject() &&
|
||||||
fp->setCalleeObject(*funobj);
|
&fp->thisValue().toObject() == obj) {
|
||||||
|
fp->calleeValue().setObject(*funobj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5579,7 +5580,7 @@ js_GetClassPrototype(JSContext *cx, JSObject *scopeobj, JSProtoKey protoKey,
|
||||||
if (protoKey != JSProto_Null) {
|
if (protoKey != JSProto_Null) {
|
||||||
if (!scopeobj) {
|
if (!scopeobj) {
|
||||||
if (cx->hasfp())
|
if (cx->hasfp())
|
||||||
scopeobj = cx->fp()->maybeScopeChain();
|
scopeobj = &cx->fp()->scopeChain();
|
||||||
if (!scopeobj) {
|
if (!scopeobj) {
|
||||||
scopeobj = cx->globalObject;
|
scopeobj = cx->globalObject;
|
||||||
if (!scopeobj) {
|
if (!scopeobj) {
|
||||||
|
@ -6385,27 +6386,27 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
|
||||||
JSStackFrame *const fp = i.fp();
|
JSStackFrame *const fp = i.fp();
|
||||||
|
|
||||||
fprintf(stderr, "JSStackFrame at %p\n", (void *) fp);
|
fprintf(stderr, "JSStackFrame at %p\n", (void *) fp);
|
||||||
if (fp->argv) {
|
if (fp->isFunctionFrame()) {
|
||||||
fprintf(stderr, "callee: ");
|
fprintf(stderr, "callee fun: ");
|
||||||
dumpValue(fp->argv[-2]);
|
dumpValue(ObjectValue(fp->callee()));
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "global frame, no callee");
|
fprintf(stderr, "global frame, no callee");
|
||||||
}
|
}
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
|
|
||||||
if (fp->hasScript()) {
|
if (fp->isScriptFrame()) {
|
||||||
fprintf(stderr, "file %s line %u\n",
|
fprintf(stderr, "file %s line %u\n",
|
||||||
fp->getScript()->filename, (unsigned) fp->getScript()->lineno);
|
fp->script()->filename, (unsigned) fp->script()->lineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jsbytecode *pc = i.pc()) {
|
if (jsbytecode *pc = i.pc()) {
|
||||||
if (!fp->hasScript()) {
|
if (!fp->isScriptFrame()) {
|
||||||
fprintf(stderr, "*** pc && !script, skipping frame\n\n");
|
fprintf(stderr, "*** pc && !script, skipping frame\n\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (fp->hasIMacroPC()) {
|
if (fp->hasImacropc()) {
|
||||||
fprintf(stderr, " pc in imacro at %p\n called from ", pc);
|
fprintf(stderr, " pc in imacro at %p\n called from ", pc);
|
||||||
pc = fp->getIMacroPC();
|
pc = fp->imacropc();
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, " ");
|
fprintf(stderr, " ");
|
||||||
}
|
}
|
||||||
|
@ -6422,38 +6423,37 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start)
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(stderr, " argv: %p (argc: %u)\n",
|
if (fp->isFunctionFrame() && !fp->isEvalFrame()) {
|
||||||
(void *) fp->argv, (unsigned) fp->numActualArgs());
|
fprintf(stderr, " actuals: %p (%u) ", (void *) fp->actualArgs(), (unsigned) fp->numActualArgs());
|
||||||
|
fprintf(stderr, " formals: %p (%u)\n", (void *) fp->formalArgs(), (unsigned) fp->numFormalArgs());
|
||||||
|
}
|
||||||
MaybeDumpObject("callobj", fp->maybeCallObj());
|
MaybeDumpObject("callobj", fp->maybeCallObj());
|
||||||
MaybeDumpObject("argsobj", fp->maybeArgsObj());
|
MaybeDumpObject("argsobj", fp->maybeArgsObj());
|
||||||
MaybeDumpValue("this", fp->getThisValue());
|
MaybeDumpValue("this", fp->thisValue());
|
||||||
fprintf(stderr, " rval: ");
|
fprintf(stderr, " rval: ");
|
||||||
dumpValue(fp->getReturnValue());
|
dumpValue(fp->returnValue());
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
|
|
||||||
fprintf(stderr, " flags:");
|
fprintf(stderr, " flags:");
|
||||||
if (fp->flags == 0)
|
if (fp->isConstructing())
|
||||||
fprintf(stderr, " none");
|
|
||||||
if (fp->flags & JSFRAME_CONSTRUCTING)
|
|
||||||
fprintf(stderr, " constructing");
|
fprintf(stderr, " constructing");
|
||||||
if (fp->flags & JSFRAME_ASSIGNING)
|
if (fp->hasOverriddenArgs())
|
||||||
fprintf(stderr, " assigning");
|
|
||||||
if (fp->flags & JSFRAME_DEBUGGER)
|
|
||||||
fprintf(stderr, " debugger");
|
|
||||||
if (fp->flags & JSFRAME_EVAL)
|
|
||||||
fprintf(stderr, " eval");
|
|
||||||
if (fp->flags & JSFRAME_YIELDING)
|
|
||||||
fprintf(stderr, " yielding");
|
|
||||||
if (fp->flags & JSFRAME_GENERATOR)
|
|
||||||
fprintf(stderr, " generator");
|
|
||||||
if (fp->flags & JSFRAME_OVERRIDE_ARGS)
|
|
||||||
fprintf(stderr, " overridden_args");
|
fprintf(stderr, " overridden_args");
|
||||||
|
if (fp->isAssigning())
|
||||||
|
fprintf(stderr, " assigning");
|
||||||
|
if (fp->isDebuggerFrame())
|
||||||
|
fprintf(stderr, " debugger");
|
||||||
|
if (fp->isEvalFrame())
|
||||||
|
fprintf(stderr, " eval");
|
||||||
|
if (fp->isYielding())
|
||||||
|
fprintf(stderr, " yielding");
|
||||||
|
if (fp->isGeneratorFrame())
|
||||||
|
fprintf(stderr, " generator");
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
|
|
||||||
if (fp->hasScopeChain())
|
fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) &fp->scopeChain());
|
||||||
fprintf(stderr, " scopeChain: (JSObject *) %p\n", (void *) fp->getScopeChain());
|
|
||||||
if (fp->hasBlockChain())
|
if (fp->hasBlockChain())
|
||||||
fprintf(stderr, " blockChain: (JSObject *) %p\n", (void *) fp->getBlockChain());
|
fprintf(stderr, " blockChain: (JSObject *) %p\n", (void *) fp->blockChain());
|
||||||
|
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -780,6 +780,25 @@ struct JSObject {
|
||||||
inline js::Value *addressOfArgsElement(uint32 i) const;
|
inline js::Value *addressOfArgsElement(uint32 i) const;
|
||||||
inline void setArgsElement(uint32 i, const js::Value &v);
|
inline void setArgsElement(uint32 i, const js::Value &v);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*
|
||||||
|
* Reserved slot structure for Arguments objects:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static const uint32 JSSLOT_CALL_CALLEE = JSSLOT_PRIVATE + 1;
|
||||||
|
static const uint32 JSSLOT_CALL_ARGUMENTS = JSSLOT_PRIVATE + 2;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/* Number of extra fixed slots besides JSSLOT_PRIVATE. */
|
||||||
|
static const uint32 CALL_RESERVED_SLOTS = 2;
|
||||||
|
|
||||||
|
inline JSObject &getCallObjCallee() const;
|
||||||
|
inline JSFunction *getCallObjCalleeFunction() const;
|
||||||
|
inline void setCallObjCallee(JSObject &callee);
|
||||||
|
|
||||||
|
inline const js::Value &getCallObjArguments() const;
|
||||||
|
inline void setCallObjArguments(const js::Value &v);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Date-specific getters and setters.
|
* Date-specific getters and setters.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -439,6 +439,42 @@ JSObject::setArgsElement(uint32 i, const js::Value &v)
|
||||||
getArgsData()->slots[i] = v;
|
getArgsData()->slots[i] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
JSObject::setCallObjCallee(JSObject &callee)
|
||||||
|
{
|
||||||
|
JS_ASSERT(isCall());
|
||||||
|
JS_ASSERT(callee.isFunction());
|
||||||
|
return fslots[JSSLOT_CALL_CALLEE].setObject(callee);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline JSObject &
|
||||||
|
JSObject::getCallObjCallee() const
|
||||||
|
{
|
||||||
|
JS_ASSERT(isCall());
|
||||||
|
return fslots[JSSLOT_CALL_CALLEE].toObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline JSFunction *
|
||||||
|
JSObject::getCallObjCalleeFunction() const
|
||||||
|
{
|
||||||
|
JS_ASSERT(isCall());
|
||||||
|
return fslots[JSSLOT_CALL_CALLEE].toObject().getFunctionPrivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const js::Value &
|
||||||
|
JSObject::getCallObjArguments() const
|
||||||
|
{
|
||||||
|
JS_ASSERT(isCall());
|
||||||
|
return fslots[JSSLOT_CALL_ARGUMENTS];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
JSObject::setCallObjArguments(const js::Value &v)
|
||||||
|
{
|
||||||
|
JS_ASSERT(isCall());
|
||||||
|
fslots[JSSLOT_CALL_ARGUMENTS] = v;
|
||||||
|
}
|
||||||
|
|
||||||
inline const js::Value &
|
inline const js::Value &
|
||||||
JSObject::getDateUTCTime() const
|
JSObject::getDateUTCTime() const
|
||||||
{
|
{
|
||||||
|
@ -861,7 +897,7 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp)
|
||||||
if (!global)
|
if (!global)
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
global = cx->fp()->getScopeChain()->getGlobal();
|
global = cx->fp()->scopeChain().getGlobal();
|
||||||
}
|
}
|
||||||
JS_ASSERT(global->getClass()->flags & JSCLASS_IS_GLOBAL);
|
JS_ASSERT(global->getClass()->flags & JSCLASS_IS_GLOBAL);
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,8 @@
|
||||||
#include "jstracer.h"
|
#include "jstracer.h"
|
||||||
#include "jsvector.h"
|
#include "jsvector.h"
|
||||||
|
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
|
#include "jsobjinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
|
|
||||||
|
@ -279,7 +281,7 @@ js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp)
|
||||||
JS_FRIEND_API(JSBool)
|
JS_FRIEND_API(JSBool)
|
||||||
js_DumpPC(JSContext *cx)
|
js_DumpPC(JSContext *cx)
|
||||||
{
|
{
|
||||||
return js_DisassembleAtPC(cx, cx->fp()->getScript(), true, stdout, cx->regs->pc);
|
return js_DisassembleAtPC(cx, cx->fp()->script(), true, stdout, cx->regs->pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSBool
|
JSBool
|
||||||
|
@ -2880,10 +2882,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||||
*/
|
*/
|
||||||
JSStackFrame *fp = js_GetTopStackFrame(cx);
|
JSStackFrame *fp = js_GetTopStackFrame(cx);
|
||||||
if (fp) {
|
if (fp) {
|
||||||
while (!(fp->flags & JSFRAME_EVAL))
|
while (!fp->isEvalFrame())
|
||||||
fp = fp->down;
|
fp = fp->prev();
|
||||||
JS_ASSERT(fp->getScript() == jp->script);
|
JS_ASSERT(fp->script() == jp->script);
|
||||||
JS_ASSERT(fp->down->getFunction() == jp->fun);
|
JS_ASSERT(fp->prev()->fun() == jp->fun);
|
||||||
JS_ASSERT(FUN_INTERPRETED(jp->fun));
|
JS_ASSERT(FUN_INTERPRETED(jp->fun));
|
||||||
JS_ASSERT(jp->script != jp->fun->u.i.script);
|
JS_ASSERT(jp->script != jp->fun->u.i.script);
|
||||||
JS_ASSERT(jp->script->upvarsOffset != 0);
|
JS_ASSERT(jp->script->upvarsOffset != 0);
|
||||||
|
@ -5089,8 +5091,8 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
||||||
JSString *fallback)
|
JSString *fallback)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp;
|
JSStackFrame *fp;
|
||||||
jsbytecode *pc;
|
|
||||||
JSScript *script;
|
JSScript *script;
|
||||||
|
jsbytecode *pc;
|
||||||
|
|
||||||
Value v = Valueify(v_in);
|
Value v = Valueify(v_in);
|
||||||
|
|
||||||
|
@ -5100,17 +5102,12 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
||||||
|
|
||||||
LeaveTrace(cx);
|
LeaveTrace(cx);
|
||||||
|
|
||||||
/* Get scripted caller */
|
if (!cx->regs || !cx->regs->fp || !cx->regs->fp->isScriptFrame())
|
||||||
FrameRegsIter i(cx);
|
|
||||||
while (!i.done() && !i.fp()->hasScript())
|
|
||||||
++i;
|
|
||||||
|
|
||||||
if (i.done() || !i.pc() || i.fp()->getSlotCount() == 0)
|
|
||||||
goto do_fallback;
|
goto do_fallback;
|
||||||
|
|
||||||
fp = i.fp();
|
fp = cx->regs->fp;
|
||||||
script = fp->getScript();
|
script = fp->script();
|
||||||
pc = fp->hasIMacroPC() ? fp->getIMacroPC() : i.pc();
|
pc = fp->hasImacropc() ? fp->imacropc() : cx->regs->pc;
|
||||||
JS_ASSERT(pc >= script->main && pc < script->code + script->length);
|
JS_ASSERT(pc >= script->main && pc < script->code + script->length);
|
||||||
|
|
||||||
if (spindex != JSDVG_IGNORE_STACK) {
|
if (spindex != JSDVG_IGNORE_STACK) {
|
||||||
|
@ -5141,7 +5138,7 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
||||||
* it that caused exception, see bug 328664.
|
* it that caused exception, see bug 328664.
|
||||||
*/
|
*/
|
||||||
Value *stackBase = fp->base();
|
Value *stackBase = fp->base();
|
||||||
Value *sp = i.sp();
|
Value *sp = cx->regs->sp;
|
||||||
do {
|
do {
|
||||||
if (sp == stackBase) {
|
if (sp == stackBase) {
|
||||||
pcdepth = -1;
|
pcdepth = -1;
|
||||||
|
@ -5172,15 +5169,11 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
jsbytecode* savepc = i.pc();
|
jsbytecode* savedImacropc = fp->maybeImacropc();
|
||||||
jsbytecode* savedIMacroPC = fp->maybeIMacroPC();
|
if (savedImacropc) {
|
||||||
if (savedIMacroPC) {
|
|
||||||
JS_ASSERT(cx->hasfp());
|
JS_ASSERT(cx->hasfp());
|
||||||
if (fp == cx->fp())
|
cx->regs->pc = savedImacropc;
|
||||||
cx->regs->pc = savedIMacroPC;
|
fp->clearImacropc();
|
||||||
else
|
|
||||||
fp->savedPC = savedIMacroPC;
|
|
||||||
fp->clearIMacroPC();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5188,18 +5181,15 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
|
||||||
* value *inside* an imacro; this would confuse the decompiler.
|
* value *inside* an imacro; this would confuse the decompiler.
|
||||||
*/
|
*/
|
||||||
char *name;
|
char *name;
|
||||||
if (savedIMacroPC && size_t(pc - script->code) >= script->length)
|
if (savedImacropc && size_t(pc - script->code) >= script->length)
|
||||||
name = FAILED_EXPRESSION_DECOMPILER;
|
name = FAILED_EXPRESSION_DECOMPILER;
|
||||||
else
|
else
|
||||||
name = DecompileExpression(cx, script, fp->maybeFunction(), pc);
|
name = DecompileExpression(cx, script, fp->maybeFun(), pc);
|
||||||
|
|
||||||
if (savedIMacroPC) {
|
if (savedImacropc) {
|
||||||
JS_ASSERT(cx->hasfp());
|
JS_ASSERT(cx->hasfp());
|
||||||
if (fp == cx->fp())
|
cx->regs->pc = savedImacropc;
|
||||||
cx->regs->pc = savedIMacroPC;
|
fp->setImacropc(savedImacropc);
|
||||||
else
|
|
||||||
fp->savedPC = savepc;
|
|
||||||
fp->setIMacroPC(savedIMacroPC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name != FAILED_EXPRESSION_DECOMPILER)
|
if (name != FAILED_EXPRESSION_DECOMPILER)
|
||||||
|
@ -5492,8 +5482,8 @@ ReconstructImacroPCStack(JSContext *cx, JSScript *script,
|
||||||
* the state-of-the-world at the *start* of the imacro.
|
* the state-of-the-world at the *start* of the imacro.
|
||||||
*/
|
*/
|
||||||
JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
|
JSStackFrame *fp = js_GetScriptedCaller(cx, NULL);
|
||||||
JS_ASSERT(fp->hasIMacroPC());
|
JS_ASSERT(fp->hasImacropc());
|
||||||
intN pcdepth = ReconstructPCStack(cx, script, fp->getIMacroPC(), pcstack);
|
intN pcdepth = ReconstructPCStack(cx, script, fp->imacropc(), pcstack);
|
||||||
if (pcdepth < 0)
|
if (pcdepth < 0)
|
||||||
return pcdepth;
|
return pcdepth;
|
||||||
return SimulateImacroCFG(cx, script, pcdepth, imacstart, target, pcstack);
|
return SimulateImacroCFG(cx, script, pcdepth, imacstart, target, pcstack);
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "jsatominlines.h"
|
#include "jsatominlines.h"
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsregexpinlines.h"
|
#include "jsregexpinlines.h"
|
||||||
|
|
||||||
|
@ -168,6 +169,25 @@ JSParseNode::clear()
|
||||||
pn_parens = false;
|
pn_parens = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Parser::Parser(JSContext *cx, JSPrincipals *prin, JSStackFrame *cfp)
|
||||||
|
: js::AutoGCRooter(cx, PARSER),
|
||||||
|
context(cx),
|
||||||
|
aleFreeList(NULL),
|
||||||
|
tokenStream(cx),
|
||||||
|
principals(NULL),
|
||||||
|
callerFrame(cfp),
|
||||||
|
callerVarObj(cfp ? &cfp->varobj(cx->containingSegment(cfp)) : NULL),
|
||||||
|
nodeList(NULL),
|
||||||
|
functionCount(0),
|
||||||
|
traceListHead(NULL),
|
||||||
|
tc(NULL),
|
||||||
|
keepAtoms(cx->runtime)
|
||||||
|
{
|
||||||
|
js::PodArrayZero(tempFreeList);
|
||||||
|
setPrincipals(prin);
|
||||||
|
JS_ASSERT_IF(cfp, cfp->isScriptFrame());
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Parser::init(const jschar *base, size_t length,
|
Parser::init(const jschar *base, size_t length,
|
||||||
FILE *fp, const char *filename, uintN lineno)
|
FILE *fp, const char *filename, uintN lineno)
|
||||||
|
@ -717,6 +737,11 @@ SetStaticLevel(JSTreeContext *tc, uintN staticLevel)
|
||||||
/*
|
/*
|
||||||
* Compile a top-level script.
|
* Compile a top-level script.
|
||||||
*/
|
*/
|
||||||
|
Compiler::Compiler(JSContext *cx, JSPrincipals *prin, JSStackFrame *cfp)
|
||||||
|
: parser(cx, prin, cfp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
JSScript *
|
JSScript *
|
||||||
Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,
|
Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *callerFrame,
|
||||||
JSPrincipals *principals, uint32 tcflags,
|
JSPrincipals *principals, uint32 tcflags,
|
||||||
|
@ -792,8 +817,8 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
|
||||||
|
|
||||||
/* If this is a direct call to eval, inherit the caller's strictness. */
|
/* If this is a direct call to eval, inherit the caller's strictness. */
|
||||||
if (callerFrame &&
|
if (callerFrame &&
|
||||||
callerFrame->hasScript() &&
|
callerFrame->isScriptFrame() &&
|
||||||
callerFrame->getScript()->strictModeCode) {
|
callerFrame->script()->strictModeCode) {
|
||||||
cg.flags |= TCF_STRICT_MODE_CODE;
|
cg.flags |= TCF_STRICT_MODE_CODE;
|
||||||
tokenStream.setStrictMode();
|
tokenStream.setStrictMode();
|
||||||
}
|
}
|
||||||
|
@ -816,13 +841,13 @@ Compiler::compileScript(JSContext *cx, JSObject *scopeChain, JSStackFrame *calle
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callerFrame && callerFrame->hasFunction()) {
|
if (callerFrame && callerFrame->isFunctionFrame()) {
|
||||||
/*
|
/*
|
||||||
* An eval script in a caller frame needs to have its enclosing
|
* An eval script in a caller frame needs to have its enclosing
|
||||||
* function captured in case it refers to an upvar, and someone
|
* function captured in case it refers to an upvar, and someone
|
||||||
* wishes to decompile it while it's running.
|
* wishes to decompile it while it's running.
|
||||||
*/
|
*/
|
||||||
funbox = parser.newObjectBox(FUN_OBJECT(callerFrame->getFunction()));
|
funbox = parser.newObjectBox(FUN_OBJECT(callerFrame->fun()));
|
||||||
if (!funbox)
|
if (!funbox)
|
||||||
goto out;
|
goto out;
|
||||||
funbox->emitLink = cg.objectList.lastbox;
|
funbox->emitLink = cg.objectList.lastbox;
|
||||||
|
|
|
@ -998,18 +998,7 @@ struct Parser : private js::AutoGCRooter
|
||||||
/* Root atoms and objects allocated for the parsed tree. */
|
/* Root atoms and objects allocated for the parsed tree. */
|
||||||
js::AutoKeepAtoms keepAtoms;
|
js::AutoKeepAtoms keepAtoms;
|
||||||
|
|
||||||
Parser(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL)
|
Parser(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL);
|
||||||
: js::AutoGCRooter(cx, PARSER), context(cx),
|
|
||||||
aleFreeList(NULL), tokenStream(cx), principals(NULL), callerFrame(cfp),
|
|
||||||
callerVarObj(cfp ? cfp->varobj(cx->containingSegment(cfp)) : NULL),
|
|
||||||
nodeList(NULL), functionCount(0), traceListHead(NULL), tc(NULL),
|
|
||||||
keepAtoms(cx->runtime)
|
|
||||||
{
|
|
||||||
js::PodArrayZero(tempFreeList);
|
|
||||||
setPrincipals(prin);
|
|
||||||
JS_ASSERT_IF(cfp, cfp->hasScript());
|
|
||||||
}
|
|
||||||
|
|
||||||
~Parser();
|
~Parser();
|
||||||
|
|
||||||
friend void js::AutoGCRooter::trace(JSTracer *trc);
|
friend void js::AutoGCRooter::trace(JSTracer *trc);
|
||||||
|
@ -1155,10 +1144,7 @@ struct Compiler
|
||||||
Parser parser;
|
Parser parser;
|
||||||
GlobalScope *globalScope;
|
GlobalScope *globalScope;
|
||||||
|
|
||||||
Compiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL)
|
Compiler(JSContext *cx, JSPrincipals *prin = NULL, JSStackFrame *cfp = NULL);
|
||||||
: parser(cx, prin, cfp)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize a compiler. Parameters are passed on to init parser.
|
* Initialize a compiler. Parameters are passed on to init parser.
|
||||||
|
|
|
@ -127,7 +127,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI
|
||||||
* opcode format flags.
|
* opcode format flags.
|
||||||
*/
|
*/
|
||||||
pc = cx->regs->pc;
|
pc = cx->regs->pc;
|
||||||
op = js_GetOpcode(cx, cx->fp()->getScript(), pc);
|
op = js_GetOpcode(cx, cx->fp()->script(), pc);
|
||||||
cs = &js_CodeSpec[op];
|
cs = &js_CodeSpec[op];
|
||||||
kshape = 0;
|
kshape = 0;
|
||||||
|
|
||||||
|
@ -304,7 +304,7 @@ GetAtomFromBytecode(JSContext *cx, jsbytecode *pc, JSOp op, const JSCodeSpec &cs
|
||||||
|
|
||||||
ptrdiff_t pcoff = (JOF_TYPE(cs.format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0;
|
ptrdiff_t pcoff = (JOF_TYPE(cs.format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0;
|
||||||
JSAtom *atom;
|
JSAtom *atom;
|
||||||
GET_ATOM_FROM_BYTECODE(cx->fp()->getScript(), pc, pcoff, atom);
|
GET_ATOM_FROM_BYTECODE(cx->fp()->script(), pc, pcoff, atom);
|
||||||
return atom;
|
return atom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,10 +318,10 @@ PropertyCache::fullTest(JSContext *cx, jsbytecode *pc, JSObject **objp, JSObject
|
||||||
JSStackFrame *fp = cx->fp();
|
JSStackFrame *fp = cx->fp();
|
||||||
|
|
||||||
JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
|
JS_ASSERT(this == &JS_PROPERTY_CACHE(cx));
|
||||||
JS_ASSERT(uintN((fp->hasIMacroPC() ? fp->getIMacroPC() : pc) - fp->getScript()->code)
|
JS_ASSERT(uintN((fp->hasImacropc() ? fp->imacropc() : pc) - fp->script()->code)
|
||||||
< fp->getScript()->length);
|
< fp->script()->length);
|
||||||
|
|
||||||
JSOp op = js_GetOpcode(cx, fp->getScript(), pc);
|
JSOp op = js_GetOpcode(cx, fp->script(), pc);
|
||||||
const JSCodeSpec &cs = js_CodeSpec[op];
|
const JSCodeSpec &cs = js_CodeSpec[op];
|
||||||
|
|
||||||
obj = *objp;
|
obj = *objp;
|
||||||
|
|
|
@ -131,6 +131,7 @@ class TraceRecorder;
|
||||||
struct TraceMonitor;
|
struct TraceMonitor;
|
||||||
class StackSpace;
|
class StackSpace;
|
||||||
class StackSegment;
|
class StackSegment;
|
||||||
|
class FrameRegsIter;
|
||||||
|
|
||||||
struct Compiler;
|
struct Compiler;
|
||||||
struct Parser;
|
struct Parser;
|
||||||
|
|
|
@ -2494,7 +2494,7 @@ ASTSerializer::literal(JSParseNode *pn, Value *dst)
|
||||||
LOCAL_ASSERT(re1 && re1->isRegExp());
|
LOCAL_ASSERT(re1 && re1->isRegExp());
|
||||||
|
|
||||||
JSObject *proto;
|
JSObject *proto;
|
||||||
if (!js_GetClassPrototype(cx, cx->fp()->getScopeChain(), JSProto_RegExp, &proto))
|
if (!js_GetClassPrototype(cx, &cx->fp()->scopeChain(), JSProto_RegExp, &proto))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JSObject *re2 = js_CloneRegExpObject(cx, re1, proto);
|
JSObject *re2 = js_CloneRegExpObject(cx, re1, proto);
|
||||||
|
|
|
@ -66,6 +66,7 @@
|
||||||
#endif
|
#endif
|
||||||
#include "methodjit/MethodJIT.h"
|
#include "methodjit/MethodJIT.h"
|
||||||
|
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
|
|
||||||
|
@ -1249,7 +1250,7 @@ js_DestroyScript(JSContext *cx, JSScript *script)
|
||||||
if (!cx->runtime->gcRunning) {
|
if (!cx->runtime->gcRunning) {
|
||||||
JSStackFrame *fp = js_GetTopStackFrame(cx);
|
JSStackFrame *fp = js_GetTopStackFrame(cx);
|
||||||
|
|
||||||
if (!(fp && (fp->flags & JSFRAME_EVAL))) {
|
if (!(fp && fp->isEvalFrame())) {
|
||||||
JS_PROPERTY_CACHE(cx).purgeForScript(script);
|
JS_PROPERTY_CACHE(cx).purgeForScript(script);
|
||||||
|
|
||||||
#ifdef CHECK_SCRIPT_OWNER
|
#ifdef CHECK_SCRIPT_OWNER
|
||||||
|
@ -1434,8 +1435,8 @@ js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc)
|
||||||
uintN
|
uintN
|
||||||
js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp)
|
js_FramePCToLineNumber(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
return js_PCToLineNumber(cx, fp->getScript(),
|
return js_PCToLineNumber(cx, fp->script(),
|
||||||
fp->hasIMacroPC() ? fp->getIMacroPC() : fp->pc(cx));
|
fp->hasImacropc() ? fp->imacropc() : fp->pc(cx));
|
||||||
}
|
}
|
||||||
|
|
||||||
uintN
|
uintN
|
||||||
|
|
|
@ -2069,7 +2069,7 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep)
|
||||||
uintN p = statics.getParenCount();
|
uintN p = statics.getParenCount();
|
||||||
uintN argc = 1 + p + 2;
|
uintN argc = 1 + p + 2;
|
||||||
|
|
||||||
if (!rdata.args.pushed() && !cx->stack().pushInvokeArgs(cx, argc, rdata.args))
|
if (!rdata.args.pushed() && !cx->stack().pushInvokeArgs(cx, argc, &rdata.args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PreserveRegExpStatics save(cx);
|
PreserveRegExpStatics save(cx);
|
||||||
|
@ -2382,7 +2382,7 @@ str_replace_flat_lambda(JSContext *cx, uintN argc, Value *vp, ReplaceData &rdata
|
||||||
|
|
||||||
/* lambda(matchStr, matchStart, textstr) */
|
/* lambda(matchStr, matchStart, textstr) */
|
||||||
static const uint32 lambdaArgc = 3;
|
static const uint32 lambdaArgc = 3;
|
||||||
if (!cx->stack().pushInvokeArgs(cx, lambdaArgc, rdata.args))
|
if (!cx->stack().pushInvokeArgs(cx, lambdaArgc, &rdata.args))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CallArgs &args = rdata.args;
|
CallArgs &args = rdata.args;
|
||||||
|
|
|
@ -441,6 +441,20 @@ ForEach(InputIterT begin, InputIterT end, CallableT f)
|
||||||
f(*begin);
|
f(*begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static inline T
|
||||||
|
Min(T t1, T t2)
|
||||||
|
{
|
||||||
|
return t1 < t2 ? t1 : t2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static inline T
|
||||||
|
Max(T t1, T t2)
|
||||||
|
{
|
||||||
|
return t1 > t2 ? t1 : t2;
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace js */
|
} /* namespace js */
|
||||||
|
|
||||||
#endif /* jstl_h_ */
|
#endif /* jstl_h_ */
|
||||||
|
|
1371
js/src/jstracer.cpp
1371
js/src/jstracer.cpp
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -553,7 +553,7 @@ struct FrameInfo {
|
||||||
* Number of stack slots in the caller, not counting slots pushed when
|
* Number of stack slots in the caller, not counting slots pushed when
|
||||||
* invoking the callee. That is, slots after JSOP_CALL completes but
|
* invoking the callee. That is, slots after JSOP_CALL completes but
|
||||||
* without the return value. This is also equal to the number of slots
|
* without the return value. This is also equal to the number of slots
|
||||||
* between fp->down->argv[-2] (calleR fp->callee) and fp->argv[-2]
|
* between fp->prev->argv[-2] (calleR fp->callee) and fp->argv[-2]
|
||||||
* (calleE fp->callee).
|
* (calleE fp->callee).
|
||||||
*/
|
*/
|
||||||
uint32 callerHeight;
|
uint32 callerHeight;
|
||||||
|
@ -1041,17 +1041,17 @@ class TraceRecorder
|
||||||
bool demote);
|
bool demote);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
bool isValidFrameObjPtr(JSObject **obj);
|
bool isValidFrameObjPtr(void *obj);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JS_REQUIRES_STACK void setImpl(void* p, nanojit::LIns* l, bool demote = true);
|
JS_REQUIRES_STACK void setImpl(void* p, nanojit::LIns* l, bool demote = true);
|
||||||
JS_REQUIRES_STACK void set(Value* p, nanojit::LIns* l, bool demote = true);
|
JS_REQUIRES_STACK void set(Value* p, nanojit::LIns* l, bool demote = true);
|
||||||
JS_REQUIRES_STACK void setFrameObjPtr(JSObject** p, nanojit::LIns* l, bool demote = true);
|
JS_REQUIRES_STACK void setFrameObjPtr(void* p, nanojit::LIns* l, bool demote = true);
|
||||||
nanojit::LIns* getFromTrackerImpl(const void *p);
|
nanojit::LIns* getFromTrackerImpl(const void *p);
|
||||||
nanojit::LIns* getFromTracker(const Value* p);
|
nanojit::LIns* getFromTracker(const Value* p);
|
||||||
JS_REQUIRES_STACK nanojit::LIns* getImpl(const void* p);
|
JS_REQUIRES_STACK nanojit::LIns* getImpl(const void* p);
|
||||||
JS_REQUIRES_STACK nanojit::LIns* get(const Value* p);
|
JS_REQUIRES_STACK nanojit::LIns* get(const Value* p);
|
||||||
JS_REQUIRES_STACK nanojit::LIns* getFrameObjPtr(JSObject** p);
|
JS_REQUIRES_STACK nanojit::LIns* getFrameObjPtr(void* p);
|
||||||
JS_REQUIRES_STACK nanojit::LIns* attemptImport(const Value* p);
|
JS_REQUIRES_STACK nanojit::LIns* attemptImport(const Value* p);
|
||||||
JS_REQUIRES_STACK nanojit::LIns* addr(Value* p);
|
JS_REQUIRES_STACK nanojit::LIns* addr(Value* p);
|
||||||
|
|
||||||
|
@ -1179,7 +1179,6 @@ class TraceRecorder
|
||||||
nanojit::LIns* stobj_get_fslot_uint32(nanojit::LIns* obj_ins, unsigned slot);
|
nanojit::LIns* stobj_get_fslot_uint32(nanojit::LIns* obj_ins, unsigned slot);
|
||||||
nanojit::LIns* stobj_set_fslot_uint32(nanojit::LIns* value_ins, nanojit::LIns* obj_ins,
|
nanojit::LIns* stobj_set_fslot_uint32(nanojit::LIns* value_ins, nanojit::LIns* obj_ins,
|
||||||
unsigned slot);
|
unsigned slot);
|
||||||
nanojit::LIns* stobj_get_fslot_ptr(nanojit::LIns* obj_ins, unsigned slot);
|
|
||||||
nanojit::LIns* unbox_slot(JSObject *obj, nanojit::LIns *obj_ins, uint32 slot,
|
nanojit::LIns* unbox_slot(JSObject *obj, nanojit::LIns *obj_ins, uint32 slot,
|
||||||
VMSideExit *exit);
|
VMSideExit *exit);
|
||||||
nanojit::LIns* stobj_get_parent(nanojit::LIns* obj_ins);
|
nanojit::LIns* stobj_get_parent(nanojit::LIns* obj_ins);
|
||||||
|
@ -1317,10 +1316,7 @@ class TraceRecorder
|
||||||
nanojit::LIns* obj_ins,
|
nanojit::LIns* obj_ins,
|
||||||
VMSideExit *exit);
|
VMSideExit *exit);
|
||||||
JS_REQUIRES_STACK RecordingStatus guardNativeConversion(Value& v);
|
JS_REQUIRES_STACK RecordingStatus guardNativeConversion(Value& v);
|
||||||
JS_REQUIRES_STACK JSStackFrame* entryFrame() const;
|
|
||||||
JS_REQUIRES_STACK void clearEntryFrameSlotsFromTracker(Tracker& which);
|
|
||||||
JS_REQUIRES_STACK void clearCurrentFrameSlotsFromTracker(Tracker& which);
|
JS_REQUIRES_STACK void clearCurrentFrameSlotsFromTracker(Tracker& which);
|
||||||
JS_REQUIRES_STACK void clearFrameSlotsFromTracker(Tracker& which, JSStackFrame* fp, unsigned nslots);
|
|
||||||
JS_REQUIRES_STACK void putActivationObjects();
|
JS_REQUIRES_STACK void putActivationObjects();
|
||||||
JS_REQUIRES_STACK RecordingStatus guardCallee(Value& callee);
|
JS_REQUIRES_STACK RecordingStatus guardCallee(Value& callee);
|
||||||
JS_REQUIRES_STACK JSStackFrame *guardArguments(JSObject *obj, nanojit::LIns* obj_ins,
|
JS_REQUIRES_STACK JSStackFrame *guardArguments(JSObject *obj, nanojit::LIns* obj_ins,
|
||||||
|
@ -1424,6 +1420,7 @@ class TraceRecorder
|
||||||
friend TracePointAction MonitorTracePoint(JSContext*, uintN &inlineCallCount,
|
friend TracePointAction MonitorTracePoint(JSContext*, uintN &inlineCallCount,
|
||||||
bool &blacklist);
|
bool &blacklist);
|
||||||
friend void AbortRecording(JSContext*, const char*);
|
friend void AbortRecording(JSContext*, const char*);
|
||||||
|
friend class BoxArg;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool JS_REQUIRES_STACK
|
static bool JS_REQUIRES_STACK
|
||||||
|
|
|
@ -261,6 +261,7 @@ typedef enum JSWhyMagic
|
||||||
JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */
|
JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */
|
||||||
JS_NO_CONSTANT, /* compiler sentinel value */
|
JS_NO_CONSTANT, /* compiler sentinel value */
|
||||||
JS_THIS_POISON, /* used in debug builds to catch tracing errors */
|
JS_THIS_POISON, /* used in debug builds to catch tracing errors */
|
||||||
|
JS_ARG_POISON, /* used in debug builds to catch tracing errors */
|
||||||
JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */
|
JS_SERIALIZE_NO_NODE, /* an empty subnode in the AST serializer */
|
||||||
JS_GENERIC_MAGIC /* for local use */
|
JS_GENERIC_MAGIC /* for local use */
|
||||||
} JSWhyMagic;
|
} JSWhyMagic;
|
||||||
|
|
|
@ -388,7 +388,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
|
||||||
* This loses us some transparency, and is generally very cheesy.
|
* This loses us some transparency, and is generally very cheesy.
|
||||||
*/
|
*/
|
||||||
JSObject *global =
|
JSObject *global =
|
||||||
cx->hasfp() ? cx->fp()->getScopeChain()->getGlobal() : cx->globalObject;
|
cx->hasfp() ? cx->fp()->scopeChain().getGlobal() : cx->globalObject;
|
||||||
wrapper->setParent(global);
|
wrapper->setParent(global);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -535,7 +535,7 @@ AutoCompartment::enter()
|
||||||
context->compartment = destination;
|
context->compartment = destination;
|
||||||
JSObject *scopeChain = target->getGlobal();
|
JSObject *scopeChain = target->getGlobal();
|
||||||
frame.construct();
|
frame.construct();
|
||||||
if (!context->stack().pushDummyFrame(context, frame.ref(), regs, scopeChain)) {
|
if (!context->stack().pushDummyFrame(context, *scopeChain, &frame.ref())) {
|
||||||
frame.destroy();
|
frame.destroy();
|
||||||
context->compartment = origin;
|
context->compartment = origin;
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -152,7 +152,7 @@ class AutoCompartment
|
||||||
JSObject * const target;
|
JSObject * const target;
|
||||||
JSCompartment * const destination;
|
JSCompartment * const destination;
|
||||||
private:
|
private:
|
||||||
LazilyConstructed<FrameGuard> frame;
|
LazilyConstructed<DummyFrameGuard> frame;
|
||||||
JSFrameRegs regs;
|
JSFrameRegs regs;
|
||||||
RegExpStatics statics;
|
RegExpStatics statics;
|
||||||
AutoStringRooter input;
|
AutoStringRooter input;
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
|
|
||||||
#include "jsatominlines.h"
|
#include "jsatominlines.h"
|
||||||
#include "jscntxtinlines.h"
|
#include "jscntxtinlines.h"
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -1715,14 +1716,14 @@ ParseXMLSource(JSContext *cx, JSString *src)
|
||||||
xml = NULL;
|
xml = NULL;
|
||||||
FrameRegsIter i(cx);
|
FrameRegsIter i(cx);
|
||||||
for (; !i.done() && !i.pc(); ++i)
|
for (; !i.done() && !i.pc(); ++i)
|
||||||
JS_ASSERT(!i.fp()->hasScript());
|
JS_ASSERT(!i.fp()->isScriptFrame());
|
||||||
filename = NULL;
|
filename = NULL;
|
||||||
lineno = 1;
|
lineno = 1;
|
||||||
if (!i.done()) {
|
if (!i.done()) {
|
||||||
JSStackFrame *fp = i.fp();
|
JSStackFrame *fp = i.fp();
|
||||||
op = (JSOp) *i.pc();
|
op = (JSOp) *i.pc();
|
||||||
if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) {
|
if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) {
|
||||||
filename = fp->getScript()->filename;
|
filename = fp->script()->filename;
|
||||||
lineno = js_FramePCToLineNumber(cx, fp);
|
lineno = js_FramePCToLineNumber(cx, fp);
|
||||||
for (endp = srcp + srclen; srcp < endp; srcp++) {
|
for (endp = srcp + srclen; srcp < endp; srcp++) {
|
||||||
if (*srcp == '\n')
|
if (*srcp == '\n')
|
||||||
|
@ -1734,7 +1735,7 @@ ParseXMLSource(JSContext *cx, JSString *src)
|
||||||
{
|
{
|
||||||
Parser parser(cx);
|
Parser parser(cx);
|
||||||
if (parser.init(chars, length, NULL, filename, lineno)) {
|
if (parser.init(chars, length, NULL, filename, lineno)) {
|
||||||
JSObject *scopeChain = js_GetTopStackFrame(cx)->getScopeChain();
|
JSObject *scopeChain = &js_GetTopStackFrame(cx)->scopeChain();
|
||||||
JSParseNode *pn = parser.parseXMLText(scopeChain, false);
|
JSParseNode *pn = parser.parseXMLText(scopeChain, false);
|
||||||
uintN flags;
|
uintN flags;
|
||||||
if (pn && GetXMLSettingFlags(cx, &flags)) {
|
if (pn && GetXMLSettingFlags(cx, &flags)) {
|
||||||
|
@ -7253,19 +7254,16 @@ JSBool
|
||||||
js_SetDefaultXMLNamespace(JSContext *cx, const Value &v)
|
js_SetDefaultXMLNamespace(JSContext *cx, const Value &v)
|
||||||
{
|
{
|
||||||
Value argv[2];
|
Value argv[2];
|
||||||
JSObject *ns, *varobj;
|
|
||||||
JSStackFrame *fp;
|
|
||||||
|
|
||||||
argv[0].setString(cx->runtime->emptyString);
|
argv[0].setString(cx->runtime->emptyString);
|
||||||
argv[1] = v;
|
argv[1] = v;
|
||||||
ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, 2, argv);
|
JSObject *ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, 2, argv);
|
||||||
if (!ns)
|
if (!ns)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
fp = js_GetTopStackFrame(cx);
|
JSStackFrame *fp = js_GetTopStackFrame(cx);
|
||||||
varobj = fp->varobj(cx);
|
JSObject &varobj = fp->varobj(cx);
|
||||||
if (!varobj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns),
|
if (!varobj.defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns),
|
||||||
PropertyStub, PropertyStub, JSPROP_PERMANENT)) {
|
PropertyStub, PropertyStub, JSPROP_PERMANENT)) {
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
|
@ -7436,7 +7434,7 @@ js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *i
|
||||||
if (!IsFunctionQName(cx, qn, &funid))
|
if (!IsFunctionQName(cx, qn, &funid))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
obj = js_GetTopStackFrame(cx)->getScopeChain();
|
obj = &js_GetTopStackFrame(cx)->scopeChain();
|
||||||
do {
|
do {
|
||||||
/* Skip any With object that can wrap XML. */
|
/* Skip any With object that can wrap XML. */
|
||||||
target = obj;
|
target = obj;
|
||||||
|
|
|
@ -323,17 +323,17 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::ARMRegiste
|
||||||
{
|
{
|
||||||
#ifndef JS_CPU_ARM
|
#ifndef JS_CPU_ARM
|
||||||
/* X86 and X64's "ret" instruction expects a return address on the stack. */
|
/* X86 and X64's "ret" instruction expects a return address on the stack. */
|
||||||
push(Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
|
push(Address(JSFrameReg, JSStackFrame::offsetOfncode()));
|
||||||
#else
|
#else
|
||||||
/* ARM returns either using its link register (LR) or directly from the stack, but masm.ret()
|
/* ARM returns either using its link register (LR) or directly from the stack, but masm.ret()
|
||||||
* always emits a return to LR. */
|
* always emits a return to LR. */
|
||||||
load32(Address(JSFrameReg, offsetof(JSStackFrame, ncode)), JSC::ARMRegisters::lr);
|
load32(Address(JSFrameReg, JSStackFrame::offsetOfncode()), JSC::ARMRegisters::lr);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveReturnAddress(RegisterID reg)
|
void saveReturnAddress(RegisterID reg)
|
||||||
{
|
{
|
||||||
storePtr(reg, Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
|
storePtr(reg, Address(JSFrameReg, JSStackFrame::offsetOfncode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void finalize(uint8 *ncode) {
|
void finalize(uint8 *ncode) {
|
||||||
|
|
|
@ -212,11 +212,14 @@ mjit::Compiler::generatePrologue()
|
||||||
invokeLabel = masm.label();
|
invokeLabel = masm.label();
|
||||||
RegisterID retAddr = takeHWReturnAddress(masm);
|
RegisterID retAddr = takeHWReturnAddress(masm);
|
||||||
masm.saveReturnAddress(retAddr);
|
masm.saveReturnAddress(retAddr);
|
||||||
|
#ifdef DEBUG
|
||||||
|
masm.storePtr(ImmPtr(JSStackFrame::sInvalidpc), Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
|
||||||
|
#endif
|
||||||
|
|
||||||
Label fastPath = masm.label();
|
Label fastPath = masm.label();
|
||||||
|
|
||||||
/* Store these early on so slow paths can access them. */
|
/* Store these early on so slow paths can access them. */
|
||||||
masm.storePtr(ImmPtr(script), Address(JSFrameReg, JSStackFrame::offsetScript()));
|
masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetOfExec()));
|
||||||
masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -229,14 +232,20 @@ mjit::Compiler::generatePrologue()
|
||||||
arityLabel = stubcc.masm.label();
|
arityLabel = stubcc.masm.label();
|
||||||
RegisterID retAddr = takeHWReturnAddress(stubcc.masm);
|
RegisterID retAddr = takeHWReturnAddress(stubcc.masm);
|
||||||
stubcc.masm.saveReturnAddress(retAddr);
|
stubcc.masm.saveReturnAddress(retAddr);
|
||||||
Jump argMatch = stubcc.masm.branch32(Assembler::AboveOrEqual, JSParamReg_Argc,
|
#ifdef DEBUG
|
||||||
|
stubcc.masm.storePtr(ImmPtr(JSStackFrame::sInvalidpc), Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
|
||||||
|
#endif
|
||||||
|
Jump argMatch = stubcc.masm.branch32(Assembler::Equal, JSParamReg_Argc,
|
||||||
Imm32(fun->nargs));
|
Imm32(fun->nargs));
|
||||||
stubcc.crossJump(argMatch, fastPath);
|
stubcc.crossJump(argMatch, fastPath);
|
||||||
|
|
||||||
|
if (JSParamReg_Argc != Registers::ArgReg1)
|
||||||
|
stubcc.masm.move(JSParamReg_Argc, Registers::ArgReg1);
|
||||||
|
|
||||||
/* Slow path - call the arity check function. Returns new fp. */
|
/* Slow path - call the arity check function. Returns new fp. */
|
||||||
stubcc.masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetFunction()));
|
stubcc.masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetOfExec()));
|
||||||
stubcc.masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
stubcc.masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
||||||
stubcc.call(stubs::CheckArity);
|
stubcc.call(stubs::FixupArity);
|
||||||
stubcc.masm.move(Registers::ReturnReg, JSFrameReg);
|
stubcc.masm.move(Registers::ReturnReg, JSFrameReg);
|
||||||
stubcc.crossJump(stubcc.masm.jump(), fastPath);
|
stubcc.crossJump(stubcc.masm.jump(), fastPath);
|
||||||
}
|
}
|
||||||
|
@ -254,28 +263,16 @@ mjit::Compiler::generatePrologue()
|
||||||
/* If the stack check fails... */
|
/* If the stack check fails... */
|
||||||
{
|
{
|
||||||
stubcc.linkExitDirect(stackCheck, stubcc.masm.label());
|
stubcc.linkExitDirect(stackCheck, stubcc.masm.label());
|
||||||
stubcc.masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetFunction()));
|
stubcc.call(stubs::HitStackQuota);
|
||||||
stubcc.call(stubs::CheckStackQuota);
|
|
||||||
stubcc.crossJump(stubcc.masm.jump(), masm.label());
|
stubcc.crossJump(stubcc.masm.jump(), masm.label());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Easy frame members. Hard ones are in caller. */
|
/* Fill in the members that initCallFrameLatePrologue does. */
|
||||||
masm.storePtr(ImmPtr(fun), Address(JSFrameReg, JSStackFrame::offsetFunction()));
|
masm.storeValue(UndefinedValue(), Address(JSFrameReg, JSStackFrame::offsetOfReturnValue()));
|
||||||
masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetCallObj()));
|
masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetOfBlockChain()));
|
||||||
masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetArgsObj()));
|
|
||||||
masm.storeValue(UndefinedValue(), Address(JSFrameReg, JSStackFrame::offsetReturnValue()));
|
|
||||||
masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetAnnotation()));
|
|
||||||
masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetBlockChain()));
|
|
||||||
if (script->debugMode)
|
|
||||||
masm.storePtr(ImmPtr(NULL), Address(JSFrameReg, JSStackFrame::offsetHookData()));
|
|
||||||
#ifdef DEBUG
|
|
||||||
masm.storePtr(ImmPtr(JSStackFrame::sInvalidPC),
|
|
||||||
Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* :TODO: This is entirely wrong. */
|
/* :TODO: This is entirely wrong. */
|
||||||
masm.store32(Imm32(cx->version),
|
masm.store32(Imm32(cx->version), Address(JSFrameReg, JSStackFrame::offsetOfCallerVersion()));
|
||||||
Address(JSFrameReg, JSStackFrame::offsetCallerVersion()));
|
|
||||||
|
|
||||||
/* Set cx->fp */
|
/* Set cx->fp */
|
||||||
masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), Registers::ReturnReg);
|
masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), Registers::ReturnReg);
|
||||||
|
@ -481,8 +478,6 @@ mjit::Compiler::finishThisUp()
|
||||||
script->callICs[i].funObjReg = callICs[i].funObjReg;
|
script->callICs[i].funObjReg = callICs[i].funObjReg;
|
||||||
script->callICs[i].funPtrReg = callICs[i].funPtrReg;
|
script->callICs[i].funPtrReg = callICs[i].funPtrReg;
|
||||||
script->callICs[i].frameDepth = callICs[i].frameDepth;
|
script->callICs[i].frameDepth = callICs[i].frameDepth;
|
||||||
script->callICs[i].isConstantThis = callICs[i].isConstantThis;
|
|
||||||
script->callICs[i].constantThis = callICs[i].constantThis;
|
|
||||||
}
|
}
|
||||||
#endif /* JS_MONOIC */
|
#endif /* JS_MONOIC */
|
||||||
|
|
||||||
|
@ -670,7 +665,7 @@ mjit::Compiler::generateMethod()
|
||||||
BEGIN_CASE(JSOP_SETRVAL)
|
BEGIN_CASE(JSOP_SETRVAL)
|
||||||
{
|
{
|
||||||
FrameEntry *fe = frame.peek(-1);
|
FrameEntry *fe = frame.peek(-1);
|
||||||
frame.storeTo(fe, Address(JSFrameReg, JSStackFrame::offsetReturnValue()), true);
|
frame.storeTo(fe, Address(JSFrameReg, JSStackFrame::offsetOfReturnValue()), true);
|
||||||
frame.pop();
|
frame.pop();
|
||||||
}
|
}
|
||||||
END_CASE(JSOP_POPV)
|
END_CASE(JSOP_POPV)
|
||||||
|
@ -678,7 +673,7 @@ mjit::Compiler::generateMethod()
|
||||||
BEGIN_CASE(JSOP_RETURN)
|
BEGIN_CASE(JSOP_RETURN)
|
||||||
{
|
{
|
||||||
FrameEntry *fe = frame.peek(-1);
|
FrameEntry *fe = frame.peek(-1);
|
||||||
frame.storeTo(fe, Address(JSFrameReg, JSStackFrame::offsetReturnValue()), true);
|
frame.storeTo(fe, Address(JSFrameReg, JSStackFrame::offsetOfReturnValue()), true);
|
||||||
frame.pop();
|
frame.pop();
|
||||||
emitReturn();
|
emitReturn();
|
||||||
}
|
}
|
||||||
|
@ -1171,8 +1166,7 @@ mjit::Compiler::generateMethod()
|
||||||
bool popped = PC[JSOP_SETARG_LENGTH] == JSOP_POP;
|
bool popped = PC[JSOP_SETARG_LENGTH] == JSOP_POP;
|
||||||
|
|
||||||
RegisterID reg = frame.allocReg();
|
RegisterID reg = frame.allocReg();
|
||||||
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, argv)), reg);
|
Address address = Address(JSFrameReg, JSStackFrame::offsetOfFormalArg(fun, slot));
|
||||||
Address address = Address(reg, slot * sizeof(Value));
|
|
||||||
frame.storeTo(top, address, popped);
|
frame.storeTo(top, address, popped);
|
||||||
frame.freeReg(reg);
|
frame.freeReg(reg);
|
||||||
}
|
}
|
||||||
|
@ -1386,8 +1380,7 @@ mjit::Compiler::generateMethod()
|
||||||
uintN index = GET_UINT16(PC);
|
uintN index = GET_UINT16(PC);
|
||||||
// JSObject *obj = &fp->argv[-2].toObject();
|
// JSObject *obj = &fp->argv[-2].toObject();
|
||||||
RegisterID reg = frame.allocReg();
|
RegisterID reg = frame.allocReg();
|
||||||
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, argv)), reg);
|
masm.loadPayload(Address(JSFrameReg, JSStackFrame::offsetOfCallee(fun)), reg);
|
||||||
masm.loadPayload(Address(reg, int32(sizeof(Value)) * -2), reg);
|
|
||||||
// obj->getFlatClosureUpvars()
|
// obj->getFlatClosureUpvars()
|
||||||
Address upvarAddress(reg, offsetof(JSObject, fslots) +
|
Address upvarAddress(reg, offsetof(JSObject, fslots) +
|
||||||
JSObject::JSSLOT_FLAT_CLOSURE_UPVARS * sizeof(Value));
|
JSObject::JSSLOT_FLAT_CLOSURE_UPVARS * sizeof(Value));
|
||||||
|
@ -1770,47 +1763,37 @@ mjit::Compiler::emitReturn()
|
||||||
stubCall(stubs::PutCallObject);
|
stubCall(stubs::PutCallObject);
|
||||||
frame.throwaway();
|
frame.throwaway();
|
||||||
} else {
|
} else {
|
||||||
/* if (callobj) ... */
|
/* if (hasCallObj() || hasArgsObj()) stubs::PutActivationObjects() */
|
||||||
Jump callObj = masm.branchPtr(Assembler::NotEqual,
|
Jump putObjs = masm.branchTest32(Assembler::NonZero,
|
||||||
Address(JSFrameReg, JSStackFrame::offsetCallObj()),
|
Address(JSFrameReg, JSStackFrame::offsetOfFlags()),
|
||||||
ImmPtr(0));
|
Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ));
|
||||||
stubcc.linkExit(callObj, Uses(frame.frameDepth()));
|
stubcc.linkExit(putObjs, Uses(frame.frameDepth()));
|
||||||
|
|
||||||
frame.throwaway();
|
frame.throwaway();
|
||||||
|
|
||||||
stubcc.leave();
|
stubcc.leave();
|
||||||
stubcc.call(stubs::PutCallObject);
|
stubcc.call(stubs::PutActivationObjects);
|
||||||
Jump j = stubcc.masm.jump();
|
|
||||||
|
|
||||||
/* if (arguments) ... */
|
|
||||||
Jump argsObj = masm.branchPtr(Assembler::NotEqual,
|
|
||||||
Address(JSFrameReg, JSStackFrame::offsetArgsObj()),
|
|
||||||
ImmIntPtr(0));
|
|
||||||
stubcc.linkExit(argsObj, Uses(0));
|
|
||||||
stubcc.call(stubs::PutArgsObject);
|
|
||||||
stubcc.rejoin(Changes(0));
|
stubcc.rejoin(Changes(0));
|
||||||
stubcc.crossJump(j, masm.label());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* r = fp->down
|
* r = fp->prev
|
||||||
* f.fp = r
|
* f.fp = r
|
||||||
*/
|
*/
|
||||||
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, down)), Registers::ReturnReg);
|
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), Registers::ReturnReg);
|
||||||
masm.storePtr(Registers::ReturnReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
masm.storePtr(Registers::ReturnReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
||||||
|
|
||||||
JS_STATIC_ASSERT(Registers::ReturnReg != JSReturnReg_Data);
|
JS_STATIC_ASSERT(Registers::ReturnReg != JSReturnReg_Data);
|
||||||
JS_STATIC_ASSERT(Registers::ReturnReg != JSReturnReg_Type);
|
JS_STATIC_ASSERT(Registers::ReturnReg != JSReturnReg_Type);
|
||||||
|
|
||||||
Address rval(JSFrameReg, JSStackFrame::offsetReturnValue());
|
Address rval(JSFrameReg, JSStackFrame::offsetOfReturnValue());
|
||||||
masm.loadPayload(rval, JSReturnReg_Data);
|
masm.loadPayload(rval, JSReturnReg_Data);
|
||||||
masm.loadTypeTag(rval, JSReturnReg_Type);
|
masm.loadTypeTag(rval, JSReturnReg_Type);
|
||||||
masm.restoreReturnAddress();
|
masm.restoreReturnAddress();
|
||||||
masm.move(Registers::ReturnReg, JSFrameReg);
|
masm.move(Registers::ReturnReg, JSFrameReg);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
masm.storePtr(ImmPtr(JSStackFrame::sInvalidPC),
|
masm.storePtr(ImmPtr(JSStackFrame::sInvalidpc),
|
||||||
Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
|
Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
|
||||||
#endif
|
#endif
|
||||||
masm.ret();
|
masm.ret();
|
||||||
}
|
}
|
||||||
|
@ -1925,11 +1908,6 @@ mjit::Compiler::inlineCallHelper(uint32 argc, bool callingNew)
|
||||||
* Save constant |this| to optimize thisv stores for common call cases
|
* Save constant |this| to optimize thisv stores for common call cases
|
||||||
* like CALL[LOCAL, GLOBAL, ARG] which push NULL.
|
* like CALL[LOCAL, GLOBAL, ARG] which push NULL.
|
||||||
*/
|
*/
|
||||||
callIC.isConstantThis = false;
|
|
||||||
if (thisvFe->isConstant()) {
|
|
||||||
callIC.isConstantThis = true;
|
|
||||||
callIC.constantThis = thisvFe->getValue();
|
|
||||||
}
|
|
||||||
callIC.frameDepth = frame.frameDepth();
|
callIC.frameDepth = frame.frameDepth();
|
||||||
|
|
||||||
/* Grab type and data registers up-front. */
|
/* Grab type and data registers up-front. */
|
||||||
|
@ -3066,7 +3044,7 @@ mjit::Compiler::jsop_bindname(uint32 index)
|
||||||
pic.fastPathStart = masm.label();
|
pic.fastPathStart = masm.label();
|
||||||
|
|
||||||
Address parent(pic.objReg, offsetof(JSObject, parent));
|
Address parent(pic.objReg, offsetof(JSObject, parent));
|
||||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetScopeChain()), pic.objReg);
|
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
|
||||||
|
|
||||||
pic.shapeGuard = masm.label();
|
pic.shapeGuard = masm.label();
|
||||||
#if defined JS_NUNBOX32
|
#if defined JS_NUNBOX32
|
||||||
|
@ -3132,7 +3110,7 @@ void
|
||||||
mjit::Compiler::jsop_bindname(uint32 index)
|
mjit::Compiler::jsop_bindname(uint32 index)
|
||||||
{
|
{
|
||||||
RegisterID reg = frame.allocReg();
|
RegisterID reg = frame.allocReg();
|
||||||
Address scopeChain(JSFrameReg, JSStackFrame::offsetScopeChain());
|
Address scopeChain(JSFrameReg, JSStackFrame::offsetOfScopeChain());
|
||||||
masm.loadPtr(scopeChain, reg);
|
masm.loadPtr(scopeChain, reg);
|
||||||
|
|
||||||
Address address(reg, offsetof(JSObject, parent));
|
Address address(reg, offsetof(JSObject, parent));
|
||||||
|
@ -3152,16 +3130,13 @@ mjit::Compiler::jsop_bindname(uint32 index)
|
||||||
void
|
void
|
||||||
mjit::Compiler::jsop_getarg(uint32 index)
|
mjit::Compiler::jsop_getarg(uint32 index)
|
||||||
{
|
{
|
||||||
RegisterID reg = frame.allocReg();
|
frame.push(Address(JSFrameReg, JSStackFrame::offsetOfFormalArg(fun, index)));
|
||||||
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, argv)), reg);
|
|
||||||
frame.freeReg(reg);
|
|
||||||
frame.push(Address(reg, index * sizeof(Value)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mjit::Compiler::jsop_this()
|
mjit::Compiler::jsop_this()
|
||||||
{
|
{
|
||||||
Address thisvAddr(JSFrameReg, JSStackFrame::offsetThisValue());
|
Address thisvAddr(JSFrameReg, JSStackFrame::offsetOfThis(fun));
|
||||||
if (0 && !script->strictModeCode) {
|
if (0 && !script->strictModeCode) {
|
||||||
Jump null = masm.testNull(Assembler::Equal, thisvAddr);
|
Jump null = masm.testNull(Assembler::Equal, thisvAddr);
|
||||||
stubcc.linkExit(null, Uses(1));
|
stubcc.linkExit(null, Uses(1));
|
||||||
|
|
|
@ -107,7 +107,7 @@ class Compiler
|
||||||
public:
|
public:
|
||||||
struct CallGenInfo {
|
struct CallGenInfo {
|
||||||
CallGenInfo(uint32 argc)
|
CallGenInfo(uint32 argc)
|
||||||
: argc(argc), constantThis(UndefinedValue())
|
: argc(argc)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -127,8 +127,6 @@ class Compiler
|
||||||
RegisterID funObjReg;
|
RegisterID funObjReg;
|
||||||
RegisterID funPtrReg;
|
RegisterID funPtrReg;
|
||||||
uint32 frameDepth;
|
uint32 frameDepth;
|
||||||
bool isConstantThis;
|
|
||||||
Value constantThis;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1132,21 +1132,16 @@ mjit::Compiler::jsop_arginc(JSOp op, uint32 slot, bool popped)
|
||||||
ovf = masm.branchSub32(Assembler::Overflow, Imm32(1), reg);
|
ovf = masm.branchSub32(Assembler::Overflow, Imm32(1), reg);
|
||||||
stubcc.linkExit(ovf, Uses(0));
|
stubcc.linkExit(ovf, Uses(0));
|
||||||
|
|
||||||
Address argv(JSFrameReg, offsetof(JSStackFrame, argv));
|
|
||||||
|
|
||||||
stubcc.leave();
|
stubcc.leave();
|
||||||
stubcc.masm.loadPtr(argv, Registers::ArgReg1);
|
stubcc.masm.addPtr(Imm32(JSStackFrame::offsetOfFormalArg(fun, slot)),
|
||||||
stubcc.masm.addPtr(Imm32(sizeof(Value) * slot), Registers::ArgReg1, Registers::ArgReg1);
|
JSFrameReg, Registers::ArgReg1);
|
||||||
stubcc.vpInc(op, depth);
|
stubcc.vpInc(op, depth);
|
||||||
|
|
||||||
frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
|
frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
|
||||||
fe = frame.peek(-1);
|
fe = frame.peek(-1);
|
||||||
|
|
||||||
reg = frame.allocReg();
|
Address address = Address(JSFrameReg, JSStackFrame::offsetOfFormalArg(fun, slot));
|
||||||
masm.loadPtr(argv, reg);
|
|
||||||
Address address = Address(reg, slot * sizeof(Value));
|
|
||||||
frame.storeTo(fe, address, popped);
|
frame.storeTo(fe, address, popped);
|
||||||
frame.freeReg(reg);
|
|
||||||
|
|
||||||
if (post || popped)
|
if (post || popped)
|
||||||
frame.pop();
|
frame.pop();
|
||||||
|
|
|
@ -61,16 +61,8 @@ struct AdjustedFrame {
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is used for emitting code to inline callee-side frame creation.
|
* This is used for emitting code to inline callee-side frame creation and
|
||||||
* Specifically, it initializes the following members:
|
* should jit code equivalent to JSStackFrame::initCallFrameCallerHalf.
|
||||||
*
|
|
||||||
* savedPC
|
|
||||||
* argc
|
|
||||||
* flags
|
|
||||||
* scopeChain
|
|
||||||
* argv
|
|
||||||
* thisv
|
|
||||||
* down
|
|
||||||
*
|
*
|
||||||
* Once finished, JSFrameReg is advanced to be the new fp.
|
* Once finished, JSFrameReg is advanced to be the new fp.
|
||||||
*/
|
*/
|
||||||
|
@ -81,8 +73,6 @@ class InlineFrameAssembler {
|
||||||
typedef JSC::MacroAssembler::ImmPtr ImmPtr;
|
typedef JSC::MacroAssembler::ImmPtr ImmPtr;
|
||||||
|
|
||||||
Assembler &masm;
|
Assembler &masm;
|
||||||
bool isConstantThis; // Is |thisv| constant?
|
|
||||||
Value constantThis; // If so, this is the value.
|
|
||||||
uint32 frameDepth; // script->nfixed + stack depth at caller call site
|
uint32 frameDepth; // script->nfixed + stack depth at caller call site
|
||||||
uint32 argc; // number of args being passed to the function
|
uint32 argc; // number of args being passed to the function
|
||||||
RegisterID funObjReg; // register containing the function object (callee)
|
RegisterID funObjReg; // register containing the function object (callee)
|
||||||
|
@ -99,8 +89,6 @@ class InlineFrameAssembler {
|
||||||
InlineFrameAssembler(Assembler &masm, JSContext *cx, ic::CallICInfo &ic, uint32 flags)
|
InlineFrameAssembler(Assembler &masm, JSContext *cx, ic::CallICInfo &ic, uint32 flags)
|
||||||
: masm(masm), flags(flags)
|
: masm(masm), flags(flags)
|
||||||
{
|
{
|
||||||
isConstantThis = ic.isConstantThis;
|
|
||||||
constantThis = ic.constantThis;
|
|
||||||
frameDepth = ic.frameDepth;
|
frameDepth = ic.frameDepth;
|
||||||
argc = ic.argc;
|
argc = ic.argc;
|
||||||
funObjReg = ic.funObjReg;
|
funObjReg = ic.funObjReg;
|
||||||
|
@ -112,8 +100,6 @@ class InlineFrameAssembler {
|
||||||
InlineFrameAssembler(Assembler &masm, Compiler::CallGenInfo &gen, jsbytecode *pc, uint32 flags)
|
InlineFrameAssembler(Assembler &masm, Compiler::CallGenInfo &gen, jsbytecode *pc, uint32 flags)
|
||||||
: masm(masm), pc(pc), flags(flags)
|
: masm(masm), pc(pc), flags(flags)
|
||||||
{
|
{
|
||||||
isConstantThis = gen.isConstantThis;
|
|
||||||
constantThis = gen.constantThis;
|
|
||||||
frameDepth = gen.frameDepth;
|
frameDepth = gen.frameDepth;
|
||||||
argc = gen.argc;
|
argc = gen.argc;
|
||||||
funObjReg = gen.funObjReg;
|
funObjReg = gen.funObjReg;
|
||||||
|
@ -122,38 +108,17 @@ class InlineFrameAssembler {
|
||||||
|
|
||||||
inline void assemble()
|
inline void assemble()
|
||||||
{
|
{
|
||||||
|
JS_ASSERT((flags & ~JSFRAME_CONSTRUCTING) == 0);
|
||||||
|
|
||||||
RegisterID t0 = tempRegs.takeAnyReg();
|
RegisterID t0 = tempRegs.takeAnyReg();
|
||||||
|
|
||||||
/* Note: savedPC goes into the down frame. */
|
masm.storePtr(ImmPtr(pc), Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
|
||||||
masm.storePtr(ImmPtr(pc), Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
|
|
||||||
|
|
||||||
AdjustedFrame adj(sizeof(JSStackFrame) + frameDepth * sizeof(Value));
|
AdjustedFrame adj(sizeof(JSStackFrame) + frameDepth * sizeof(Value));
|
||||||
masm.store32(Imm32(argc), adj.addrOf(offsetof(JSStackFrame, argc)));
|
masm.store32(Imm32(JSFRAME_FUNCTION | flags), adj.addrOf(JSStackFrame::offsetOfFlags()));
|
||||||
masm.store32(Imm32(flags), adj.addrOf(offsetof(JSStackFrame, flags)));
|
|
||||||
masm.loadPtr(Address(funObjReg, offsetof(JSObject, parent)), t0);
|
masm.loadPtr(Address(funObjReg, offsetof(JSObject, parent)), t0);
|
||||||
masm.storePtr(t0, adj.addrOf(JSStackFrame::offsetScopeChain()));
|
masm.storePtr(t0, adj.addrOf(JSStackFrame::offsetOfScopeChain()));
|
||||||
masm.addPtr(Imm32(adj.baseOffset - (argc * sizeof(Value))), JSFrameReg, t0);
|
masm.storePtr(JSFrameReg, adj.addrOf(JSStackFrame::offsetOfPrev()));
|
||||||
masm.storePtr(t0, adj.addrOf(offsetof(JSStackFrame, argv)));
|
|
||||||
|
|
||||||
Address targetThis = adj.addrOf(JSStackFrame::offsetThisValue());
|
|
||||||
if (isConstantThis) {
|
|
||||||
masm.storeValue(constantThis, targetThis);
|
|
||||||
} else {
|
|
||||||
Address thisvAddr = Address(t0, -int32(sizeof(Value) * 1));
|
|
||||||
#ifdef JS_NUNBOX32
|
|
||||||
RegisterID t1 = tempRegs.takeAnyReg();
|
|
||||||
masm.loadPayload(thisvAddr, t1);
|
|
||||||
masm.storePayload(t1, targetThis);
|
|
||||||
masm.loadTypeTag(thisvAddr, t1);
|
|
||||||
masm.storeTypeTag(t1, targetThis);
|
|
||||||
tempRegs.putReg(t1);
|
|
||||||
#elif JS_PUNBOX64
|
|
||||||
masm.loadPtr(thisvAddr, t0);
|
|
||||||
masm.storePtr(t0, targetThis);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
masm.storePtr(JSFrameReg, adj.addrOf(offsetof(JSStackFrame, down)));
|
|
||||||
|
|
||||||
/* Adjust JSFrameReg. Callee fills in the rest. */
|
/* Adjust JSFrameReg. Callee fills in the rest. */
|
||||||
masm.addPtr(Imm32(sizeof(JSStackFrame) + sizeof(Value) * frameDepth), JSFrameReg);
|
masm.addPtr(Imm32(sizeof(JSStackFrame) + sizeof(Value) * frameDepth), JSFrameReg);
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
#include "jspropertycache.h"
|
#include "jspropertycache.h"
|
||||||
#include "methodjit/MonoIC.h"
|
#include "methodjit/MonoIC.h"
|
||||||
|
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jspropertycacheinlines.h"
|
#include "jspropertycacheinlines.h"
|
||||||
#include "jsscopeinlines.h"
|
#include "jsscopeinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
|
@ -92,7 +93,7 @@ static jsbytecode *
|
||||||
FindExceptionHandler(JSContext *cx)
|
FindExceptionHandler(JSContext *cx)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp = cx->fp();
|
JSStackFrame *fp = cx->fp();
|
||||||
JSScript *script = fp->getScript();
|
JSScript *script = fp->script();
|
||||||
|
|
||||||
top:
|
top:
|
||||||
if (cx->throwing && script->trynotesOffset) {
|
if (cx->throwing && script->trynotesOffset) {
|
||||||
|
@ -129,7 +130,7 @@ top:
|
||||||
|
|
||||||
switch (tn->kind) {
|
switch (tn->kind) {
|
||||||
case JSTRY_CATCH:
|
case JSTRY_CATCH:
|
||||||
JS_ASSERT(js_GetOpcode(cx, fp->getScript(), pc) == JSOP_ENTERBLOCK);
|
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENTERBLOCK);
|
||||||
|
|
||||||
#if JS_HAS_GENERATORS
|
#if JS_HAS_GENERATORS
|
||||||
/* Catch cannot intercept the closing of a generator. */
|
/* Catch cannot intercept the closing of a generator. */
|
||||||
|
@ -165,7 +166,7 @@ top:
|
||||||
* pending exception.
|
* pending exception.
|
||||||
*/
|
*/
|
||||||
AutoValueRooter tvr(cx, cx->exception);
|
AutoValueRooter tvr(cx, cx->exception);
|
||||||
JS_ASSERT(js_GetOpcode(cx, fp->getScript(), pc) == JSOP_ENDITER);
|
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENDITER);
|
||||||
cx->throwing = JS_FALSE;
|
cx->throwing = JS_FALSE;
|
||||||
ok = !!js_CloseIterator(cx, &cx->regs->sp[-1].toObject());
|
ok = !!js_CloseIterator(cx, &cx->regs->sp[-1].toObject());
|
||||||
cx->regs->sp -= 1;
|
cx->regs->sp -= 1;
|
||||||
|
@ -190,7 +191,7 @@ InlineReturn(VMFrame &f, JSBool ok)
|
||||||
JS_ASSERT(f.fp() != f.entryFp);
|
JS_ASSERT(f.fp() != f.entryFp);
|
||||||
|
|
||||||
JS_ASSERT(!fp->hasBlockChain());
|
JS_ASSERT(!fp->hasBlockChain());
|
||||||
JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->getScopeChain(), 0));
|
JS_ASSERT(!js_IsActiveWithOrBlock(cx, &fp->scopeChain(), 0));
|
||||||
|
|
||||||
// Marker for debug support.
|
// Marker for debug support.
|
||||||
if (JS_UNLIKELY(fp->hasHookData())) {
|
if (JS_UNLIKELY(fp->hasHookData())) {
|
||||||
|
@ -204,27 +205,22 @@ InlineReturn(VMFrame &f, JSBool ok)
|
||||||
* optimizations and uninitialised warnings.
|
* optimizations and uninitialised warnings.
|
||||||
*/
|
*/
|
||||||
status = ok;
|
status = ok;
|
||||||
hook(cx, fp, JS_FALSE, &status, fp->getHookData());
|
hook(cx, fp, JS_FALSE, &status, fp->hookData());
|
||||||
ok = (status == JS_TRUE);
|
ok = (status == JS_TRUE);
|
||||||
// CHECK_INTERRUPT_HANDLER();
|
// CHECK_INTERRUPT_HANDLER();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fp->putActivationObjects(cx);
|
PutActivationObjects(cx, fp);
|
||||||
|
|
||||||
/* :TODO: version stuff */
|
/* :TODO: version stuff */
|
||||||
|
|
||||||
if (fp->flags & JSFRAME_CONSTRUCTING && fp->getReturnValue().isPrimitive())
|
if (fp->isConstructing() && fp->returnValue().isPrimitive())
|
||||||
fp->setReturnValue(fp->getThisValue());
|
fp->setReturnValue(fp->thisValue());
|
||||||
|
|
||||||
Value *newsp = fp->argv - 1;
|
Value *newsp = fp->actualArgs() - 1;
|
||||||
|
newsp[-1] = fp->returnValue();
|
||||||
cx->stack().popInlineFrame(cx, fp, fp->down);
|
cx->stack().popInlineFrame(cx, fp->prev(), newsp);
|
||||||
|
|
||||||
cx->regs->sp = newsp;
|
|
||||||
cx->regs->sp[-1] = fp->getReturnValue();
|
|
||||||
|
|
||||||
JS_ASSERT(cx->regs->pc != JSStackFrame::sInvalidPC);
|
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
@ -271,84 +267,82 @@ stubs::SlowNew(VMFrame &f, uint32 argc)
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function must only be called after the early prologue, since it depends
|
||||||
|
* on fp->exec.fun.
|
||||||
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
RemovePartialFrame(VMFrame &f)
|
RemovePartialFrame(JSContext *cx, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
/* Unwind the half-pushed frame. */
|
JSStackFrame *prev = fp->prev();
|
||||||
f.regs.pc = f.fp()->down->savedPC;
|
Value *newsp = (Value *)fp;
|
||||||
f.regs.sp = f.fp()->argv + f.fp()->argc;
|
cx->stack().popInlineFrame(cx, prev, newsp);
|
||||||
#ifdef DEBUG
|
|
||||||
f.fp()->down->savedPC = JSStackFrame::sInvalidPC;
|
|
||||||
#endif
|
|
||||||
f.regs.fp = f.fp()->down;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HitStackQuota is called after the early prologue pushing the new frame would
|
||||||
|
* overflow f.stackLimit.
|
||||||
|
*/
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::CheckStackQuota(VMFrame &f)
|
stubs::HitStackQuota(VMFrame &f)
|
||||||
{
|
{
|
||||||
if (JS_LIKELY(f.ensureSpace(0, f.fp()->getScript()->nslots)))
|
/* Include space to push another frame. */
|
||||||
|
uintN nvals = f.fp()->script()->nslots + VALUES_PER_STACK_FRAME;
|
||||||
|
JS_ASSERT(f.regs.sp == f.fp()->base());
|
||||||
|
if (f.cx->stack().bumpCommitAndLimit(f.entryFp, f.regs.sp, nvals, &f.stackLimit))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RemovePartialFrame(f);
|
/* Remove the current partially-constructed frame before throwing. */
|
||||||
|
RemovePartialFrame(f.cx, f.fp());
|
||||||
js_ReportOverRecursed(f.cx);
|
js_ReportOverRecursed(f.cx);
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function must only be called after the early prologue, since it depends
|
||||||
|
* on fp->exec.fun.
|
||||||
|
*/
|
||||||
void * JS_FASTCALL
|
void * JS_FASTCALL
|
||||||
stubs::CheckArity(VMFrame &f)
|
stubs::FixupArity(VMFrame &f, uint32 nactual)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *fp = f.fp();
|
JSStackFrame *oldfp = f.fp();
|
||||||
uint32 argc = fp->argc;
|
|
||||||
JSFunction *fun = fp->getFunction();
|
|
||||||
|
|
||||||
JS_ASSERT(argc < fun->nargs);
|
JS_ASSERT(nactual != oldfp->numFormalArgs());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Grossssss! *move* the stack frame. If this ends up being perf-critical,
|
* Grossssss! *move* the stack frame. If this ends up being perf-critical,
|
||||||
* we can figure out how to spot-optimize it. As the frame shrinks it will
|
* we can figure out how to spot-optimize it. Be careful to touch only the
|
||||||
* matter less.
|
* members that have been initialized by initCallFrameCallerHalf and the
|
||||||
|
* early prologue.
|
||||||
*/
|
*/
|
||||||
uint32 flags = fp->flags;
|
uint32 flags = oldfp->isConstructingFlag();
|
||||||
JSObject *scopeChain = fp->getScopeChain();
|
JSObject &scopeChain = oldfp->scopeChain();
|
||||||
Value *argv = fp->argv;
|
JSFunction *fun = oldfp->fun();
|
||||||
JSStackFrame *down = fp->down;
|
void *ncode = oldfp->nativeReturnAddress();
|
||||||
void *ncode = fp->ncode;
|
|
||||||
|
|
||||||
/* Pop the inline frame. */
|
/* Pop the inline frame. */
|
||||||
RemovePartialFrame(f);
|
RemovePartialFrame(cx, oldfp);
|
||||||
|
|
||||||
uint32 missing = fun->nargs - argc;
|
/* Reserve enough space for a callee frame. */
|
||||||
|
JSStackFrame *newfp = cx->stack().getInlineFrameWithinLimit(cx, cx->regs->sp, nactual,
|
||||||
/* Include an extra stack frame for callees. */
|
fun, fun->script(), &flags,
|
||||||
if (!f.ensureSpace(missing, fun->u.i.script->nslots + VALUES_PER_STACK_FRAME)) {
|
f.entryFp, &f.stackLimit);
|
||||||
js_ReportOverRecursed(cx);
|
if (!newfp)
|
||||||
THROWV(NULL);
|
THROWV(NULL);
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
/* Reset the part of the stack frame set by the caller. */
|
||||||
down->savedPC = f.regs.pc;
|
newfp->initCallFrameCallerHalf(cx, scopeChain, nactual, flags);
|
||||||
#endif
|
|
||||||
|
|
||||||
SetValueRangeToUndefined(f.regs.sp, missing);
|
/* Reset the part of the stack frame set by the prologue up to now. */
|
||||||
f.regs.sp += missing;
|
newfp->initCallFrameEarlyPrologue(fun, ncode);
|
||||||
|
|
||||||
JSStackFrame *newfp = (JSStackFrame *)f.regs.sp;
|
|
||||||
newfp->argc = argc;
|
|
||||||
newfp->setFunction(fun);
|
|
||||||
newfp->flags = flags;
|
|
||||||
newfp->argv = argv;
|
|
||||||
newfp->setScopeChain(scopeChain);
|
|
||||||
newfp->down = down;
|
|
||||||
newfp->ncode = ncode;
|
|
||||||
newfp->setThisValue(argv[-1]);
|
|
||||||
|
|
||||||
|
/* The caller takes care of assigning fp to regs. */
|
||||||
return newfp;
|
return newfp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void * JS_FASTCALL
|
void * JS_FASTCALL
|
||||||
stubs::CompileFunction(VMFrame &f)
|
stubs::CompileFunction(VMFrame &f, uint32 nactual)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We have a partially constructed frame. That's not really good enough to
|
* We have a partially constructed frame. That's not really good enough to
|
||||||
|
@ -356,56 +350,53 @@ stubs::CompileFunction(VMFrame &f)
|
||||||
*/
|
*/
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *fp = f.fp();
|
JSStackFrame *fp = f.fp();
|
||||||
uint32 argc = fp->argc;
|
|
||||||
|
|
||||||
JSObject *obj = &fp->argv[-2].toObject();
|
/*
|
||||||
JSFunction *fun = obj->getFunctionPrivate();
|
* Since we can only use members set by initCallFrameCallerHalf,
|
||||||
JSScript *script = fun->u.i.script;
|
* we must carefully extract the callee from the nactual.
|
||||||
|
*/
|
||||||
|
JSObject &callee = fp->formalArgsEnd()[-(int(nactual) + 2)].toObject();
|
||||||
|
JSFunction *fun = callee.getFunctionPrivate();
|
||||||
|
JSScript *script = fun->script();
|
||||||
|
|
||||||
bool callingNew = !!(fp->flags & JSFRAME_CONSTRUCTING);
|
/*
|
||||||
|
* FixupArity/RemovePartialFrame expect to be called after the early
|
||||||
|
* prologue. Pass null for ncode: either we will jump into jit code, which
|
||||||
|
* will set ncode, or we will jump into js::Interpret, which does not care
|
||||||
|
* about ncode.
|
||||||
|
*/
|
||||||
|
fp->initCallFrameEarlyPrologue(fun, NULL);
|
||||||
|
|
||||||
/* Empty script does nothing. */
|
/* Empty script does nothing. */
|
||||||
if (script->isEmpty()) {
|
if (script->isEmpty()) {
|
||||||
RemovePartialFrame(f);
|
bool callingNew = fp->isConstructing();
|
||||||
Value *vp = f.regs.sp - argc;
|
RemovePartialFrame(cx, fp);
|
||||||
|
Value *vp = f.regs.sp - (nactual + 2);
|
||||||
if (callingNew)
|
if (callingNew)
|
||||||
vp[-2] = vp[-1];
|
vp[0] = vp[1];
|
||||||
else
|
else
|
||||||
vp[-2].setUndefined();
|
vp[0].setUndefined();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CheckArity expects fun to be set. */
|
if (nactual != fp->numFormalArgs()) {
|
||||||
fp->setFunction(fun);
|
fp = (JSStackFrame *)FixupArity(f, nactual);
|
||||||
|
|
||||||
if (argc < fun->nargs) {
|
|
||||||
fp = (JSStackFrame *)CheckArity(f);
|
|
||||||
if (!fp)
|
if (!fp)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp->setCallObj(NULL);
|
/* Finish frame initialization. */
|
||||||
fp->setArgsObj(NULL);
|
fp->initCallFrameLatePrologue();
|
||||||
fp->setBlockChain(NULL);
|
|
||||||
fp->setHookData(NULL);
|
|
||||||
fp->setAnnotation(NULL);
|
|
||||||
fp->setCallerVersion(fp->down->getCallerVersion());
|
|
||||||
fp->setScript(script);
|
|
||||||
fp->clearReturnValue();
|
|
||||||
#ifdef DEBUG
|
|
||||||
fp->savedPC = JSStackFrame::sInvalidPC;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
/* These would have been initialized by the prologue. */
|
||||||
f.regs.fp = fp;
|
f.regs.fp = fp;
|
||||||
f.regs.sp = fp->base();
|
f.regs.sp = fp->base();
|
||||||
f.regs.pc = script->code;
|
f.regs.pc = script->code;
|
||||||
|
|
||||||
SetValueRangeToUndefined(fp->slots(), script->nfixed);
|
|
||||||
|
|
||||||
if (fun->isHeavyweight() && !js_GetCallObject(cx, fp))
|
if (fun->isHeavyweight() && !js_GetCallObject(cx, fp))
|
||||||
THROWV(NULL);
|
THROWV(NULL);
|
||||||
|
|
||||||
CompileStatus status = CanMethodJIT(cx, script, fun, fp->getScopeChain());
|
CompileStatus status = CanMethodJIT(cx, script, fun, &fp->scopeChain());
|
||||||
if (status == Compile_Okay)
|
if (status == Compile_Okay)
|
||||||
return script->jit->invoke;
|
return script->jit->invoke;
|
||||||
|
|
||||||
|
@ -419,112 +410,63 @@ stubs::CompileFunction(VMFrame &f)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Preserved for when calls need to be slow (debug mode, no ICs) */
|
static inline bool
|
||||||
static bool
|
UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
|
||||||
CreateFrame(VMFrame &f, uint32 flags, uint32 argc)
|
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *fp = f.fp();
|
JSStackFrame *fp = f.fp();
|
||||||
Value *vp = f.regs.sp - (argc + 2);
|
Value *vp = f.regs.sp - (argc + 2);
|
||||||
JSObject *funobj = &vp->toObject();
|
JSObject &callee = vp->toObject();
|
||||||
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
|
JSFunction *newfun = callee.getFunctionPrivate();
|
||||||
|
JSScript *newscript = newfun->script();
|
||||||
|
|
||||||
JS_ASSERT(FUN_INTERPRETED(fun));
|
/* Get pointer to new frame/slots, prepare arguments. */
|
||||||
|
|
||||||
JSScript *newscript = fun->u.i.script;
|
|
||||||
|
|
||||||
/* Allocate the frame. */
|
|
||||||
StackSpace &stack = cx->stack();
|
StackSpace &stack = cx->stack();
|
||||||
uintN nslots = newscript->nslots;
|
JSStackFrame *newfp = stack.getInlineFrameWithinLimit(cx, f.regs.sp, argc,
|
||||||
uintN funargs = fun->nargs;
|
newfun, newscript, &flags,
|
||||||
Value *argv = vp + 2;
|
f.entryFp, &f.stackLimit);
|
||||||
JSStackFrame *newfp;
|
if (JS_UNLIKELY(!newfp))
|
||||||
if (argc < funargs) {
|
|
||||||
uintN missing = funargs - argc;
|
|
||||||
if (!f.ensureSpace(missing, nslots))
|
|
||||||
return false;
|
|
||||||
newfp = stack.getInlineFrameUnchecked(cx, f.regs.sp, missing);
|
|
||||||
if (!newfp)
|
|
||||||
return false;
|
|
||||||
for (Value *v = argv + argc, *end = v + missing; v != end; ++v)
|
|
||||||
v->setUndefined();
|
|
||||||
} else {
|
|
||||||
if (!f.ensureSpace(0, nslots))
|
|
||||||
return false;
|
|
||||||
newfp = stack.getInlineFrameUnchecked(cx, f.regs.sp, 0);
|
|
||||||
if (!newfp)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize the frame. */
|
|
||||||
newfp->ncode = NULL;
|
|
||||||
newfp->setCallObj(NULL);
|
|
||||||
newfp->setArgsObj(NULL);
|
|
||||||
newfp->setScript(newscript);
|
|
||||||
newfp->setFunction(fun);
|
|
||||||
newfp->argc = argc;
|
|
||||||
newfp->argv = vp + 2;
|
|
||||||
newfp->clearReturnValue();
|
|
||||||
newfp->setAnnotation(NULL);
|
|
||||||
newfp->setScopeChain(funobj->getParent());
|
|
||||||
newfp->flags = flags;
|
|
||||||
newfp->setBlockChain(NULL);
|
|
||||||
newfp->setThisValue(vp[1]);
|
|
||||||
JS_ASSERT(!fp->hasIMacroPC());
|
|
||||||
|
|
||||||
/* Push void to initialize local variables. */
|
|
||||||
Value *newslots = newfp->slots();
|
|
||||||
Value *newsp = newslots + fun->u.i.nvars;
|
|
||||||
for (Value *v = newslots; v != newsp; ++v)
|
|
||||||
v->setUndefined();
|
|
||||||
|
|
||||||
/* Scope with a call object parented by callee's parent. */
|
|
||||||
if (fun->isHeavyweight() && !js_GetCallObject(cx, newfp))
|
|
||||||
return false;
|
return false;
|
||||||
|
JS_ASSERT_IF(!vp[1].isPrimitive(), IsSaneThisObject(vp[1].toObject()));
|
||||||
|
|
||||||
|
/* Initialize frame, locals. */
|
||||||
|
newfp->initCallFrame(cx, callee, newfun, argc, flags);
|
||||||
|
SetValueRangeToUndefined(newfp->slots(), newscript->nfixed);
|
||||||
|
|
||||||
/* :TODO: Switch version if currentVersion wasn't overridden. */
|
/* :TODO: Switch version if currentVersion wasn't overridden. */
|
||||||
newfp->setCallerVersion((JSVersion)cx->version);
|
newfp->setCallerVersion((JSVersion)cx->version);
|
||||||
|
|
||||||
// Marker for debug support.
|
/* Officially push the frame. */
|
||||||
|
stack.pushInlineFrame(cx, newscript, newfp, &f.regs);
|
||||||
|
JS_ASSERT(newfp == f.regs.fp);
|
||||||
|
|
||||||
|
/* Scope with a call object parented by callee's parent. */
|
||||||
|
if (newfun->isHeavyweight() && !js_GetCallObject(cx, newfp))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Marker for debug support. */
|
||||||
if (JSInterpreterHook hook = cx->debugHooks->callHook) {
|
if (JSInterpreterHook hook = cx->debugHooks->callHook) {
|
||||||
newfp->setHookData(hook(cx, fp, JS_TRUE, 0,
|
newfp->setHookData(hook(cx, fp, JS_TRUE, 0,
|
||||||
cx->debugHooks->callHookData));
|
cx->debugHooks->callHookData));
|
||||||
} else {
|
|
||||||
newfp->setHookData(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stack.pushInlineFrame(cx, fp, cx->regs->pc, newfp);
|
/* Try to compile if not already compiled. */
|
||||||
f.regs.fp = newfp;
|
if (!newscript->ncode) {
|
||||||
|
if (mjit::TryCompile(cx, newscript, newfp->fun(), &newfp->scopeChain()) == Compile_Error) {
|
||||||
return true;
|
/* A runtime exception was thrown, get out. */
|
||||||
}
|
InlineReturn(f, JS_FALSE);
|
||||||
|
return false;
|
||||||
static inline bool
|
|
||||||
UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
|
|
||||||
{
|
|
||||||
if (!CreateFrame(f, flags, argc))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
JSContext *cx = f.cx;
|
|
||||||
JSStackFrame *fp = cx->fp();
|
|
||||||
JSScript *script = fp->getScript();
|
|
||||||
f.regs.pc = script->code;
|
|
||||||
f.regs.sp = fp->base();
|
|
||||||
|
|
||||||
if (cx->options & JSOPTION_METHODJIT) {
|
|
||||||
if (!script->ncode) {
|
|
||||||
if (mjit::TryCompile(cx, script, fp->getFunction(), fp->getScopeChain()) == Compile_Error) {
|
|
||||||
InlineReturn(f, JS_FALSE);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
JS_ASSERT(script->ncode);
|
|
||||||
if (script->ncode != JS_UNJITTABLE_METHOD) {
|
|
||||||
*pret = script->jit->invoke;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If newscript was successfully compiled, run it. */
|
||||||
|
JS_ASSERT(newscript->ncode);
|
||||||
|
if (newscript->ncode != JS_UNJITTABLE_METHOD) {
|
||||||
|
*pret = newscript->jit->invoke;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, run newscript in the interpreter. */
|
||||||
bool ok = !!Interpret(cx, cx->fp());
|
bool ok = !!Interpret(cx, cx->fp());
|
||||||
InlineReturn(f, JS_TRUE);
|
InlineReturn(f, JS_TRUE);
|
||||||
|
|
||||||
|
@ -536,43 +478,19 @@ void * JS_FASTCALL
|
||||||
stubs::UncachedNew(VMFrame &f, uint32 argc)
|
stubs::UncachedNew(VMFrame &f, uint32 argc)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
|
|
||||||
Value *vp = f.regs.sp - (argc + 2);
|
Value *vp = f.regs.sp - (argc + 2);
|
||||||
|
|
||||||
JSObject *obj;
|
/* Try to do a fast inline call before the general Invoke path. */
|
||||||
if (IsFunctionObject(*vp, &obj)) {
|
JSFunction *fun;
|
||||||
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj);
|
if (IsFunctionObject(*vp, &fun) && fun->isInterpreted() && !fun->script()->isEmpty()) {
|
||||||
|
void *ret;
|
||||||
if (fun->isInterpreted()) {
|
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ret, argc))
|
||||||
JSScript *script = fun->u.i.script;
|
THROWV(NULL);
|
||||||
if (!stubs::NewObject(f, argc))
|
return ret;
|
||||||
THROWV(NULL);
|
|
||||||
|
|
||||||
if (script->isEmpty()) {
|
|
||||||
vp[0] = vp[1];
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *ret;
|
|
||||||
if (!UncachedInlineCall(f, JSFRAME_CONSTRUCTING, &ret, argc))
|
|
||||||
THROWV(NULL);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fun->isConstructor()) {
|
|
||||||
vp[1].setMagicWithObjectOrNullPayload(NULL);
|
|
||||||
Native fn = fun->u.n.native;
|
|
||||||
if (!fn(cx, argc, vp))
|
|
||||||
THROWV(NULL);
|
|
||||||
JS_ASSERT(!vp->isPrimitive());
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
|
if (!InvokeConstructor(cx, InvokeArgsAlreadyOnTheStack(vp, argc)))
|
||||||
THROWV(NULL);
|
THROWV(NULL);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -620,13 +538,13 @@ stubs::PutCallObject(VMFrame &f)
|
||||||
{
|
{
|
||||||
JS_ASSERT(f.fp()->hasCallObj());
|
JS_ASSERT(f.fp()->hasCallObj());
|
||||||
js_PutCallObject(f.cx, f.fp());
|
js_PutCallObject(f.cx, f.fp());
|
||||||
JS_ASSERT(!f.fp()->hasArgsObj());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::PutArgsObject(VMFrame &f)
|
stubs::PutActivationObjects(VMFrame &f)
|
||||||
{
|
{
|
||||||
js_PutArgsObject(f.cx, f.fp());
|
JS_ASSERT(f.fp()->hasCallObj() || f.fp()->hasArgsObj());
|
||||||
|
js::PutActivationObjects(f.cx, f.fp());
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void *
|
extern "C" void *
|
||||||
|
@ -641,7 +559,7 @@ js_InternalThrow(VMFrame &f)
|
||||||
JSThrowHook handler = f.cx->debugHooks->throwHook;
|
JSThrowHook handler = f.cx->debugHooks->throwHook;
|
||||||
if (handler) {
|
if (handler) {
|
||||||
Value rval;
|
Value rval;
|
||||||
switch (handler(cx, cx->fp()->getScript(), cx->regs->pc, Jsvalify(&rval),
|
switch (handler(cx, cx->fp()->script(), cx->regs->pc, Jsvalify(&rval),
|
||||||
cx->debugHooks->throwHookData)) {
|
cx->debugHooks->throwHookData)) {
|
||||||
case JSTRAP_ERROR:
|
case JSTRAP_ERROR:
|
||||||
cx->throwing = JS_FALSE;
|
cx->throwing = JS_FALSE;
|
||||||
|
@ -686,13 +604,13 @@ js_InternalThrow(VMFrame &f)
|
||||||
if (!pc)
|
if (!pc)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return cx->fp()->getScript()->pcToNative(pc);
|
return cx->fp()->script()->pcToNative(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::GetCallObject(VMFrame &f)
|
stubs::GetCallObject(VMFrame &f)
|
||||||
{
|
{
|
||||||
JS_ASSERT(f.fp()->getFunction()->isHeavyweight());
|
JS_ASSERT(f.fp()->fun()->isHeavyweight());
|
||||||
if (!js_GetCallObject(f.cx, f.fp()))
|
if (!js_GetCallObject(f.cx, f.fp()))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
@ -721,13 +639,13 @@ SwallowErrors(VMFrame &f, JSStackFrame *stopFp)
|
||||||
JSStackFrame *fp = cx->fp();
|
JSStackFrame *fp = cx->fp();
|
||||||
|
|
||||||
/* Look for an imacro with hard-coded exception handlers. */
|
/* Look for an imacro with hard-coded exception handlers. */
|
||||||
if (fp->hasIMacroPC() && cx->throwing) {
|
if (fp->hasImacropc() && cx->throwing) {
|
||||||
cx->regs->pc = fp->getIMacroPC();
|
cx->regs->pc = fp->imacropc();
|
||||||
fp->clearIMacroPC();
|
fp->clearImacropc();
|
||||||
if (ok)
|
if (ok)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
JS_ASSERT(!fp->hasIMacroPC());
|
JS_ASSERT(!fp->hasImacropc());
|
||||||
|
|
||||||
/* If there's an exception and a handler, set the pc and leave. */
|
/* If there's an exception and a handler, set the pc and leave. */
|
||||||
jsbytecode *pc = FindExceptionHandler(cx);
|
jsbytecode *pc = FindExceptionHandler(cx);
|
||||||
|
@ -757,10 +675,10 @@ static inline bool
|
||||||
AtSafePoint(JSContext *cx)
|
AtSafePoint(JSContext *cx)
|
||||||
{
|
{
|
||||||
JSStackFrame *fp = cx->fp();
|
JSStackFrame *fp = cx->fp();
|
||||||
if (fp->hasIMacroPC())
|
if (fp->hasImacropc())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
JSScript *script = fp->getScript();
|
JSScript *script = fp->script();
|
||||||
if (!script->nmap)
|
if (!script->nmap)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -774,14 +692,12 @@ PartialInterpret(VMFrame &f)
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSStackFrame *fp = cx->fp();
|
JSStackFrame *fp = cx->fp();
|
||||||
|
|
||||||
JS_ASSERT(fp->hasIMacroPC() || !fp->getScript()->nmap ||
|
JS_ASSERT(fp->hasImacropc() || !fp->script()->nmap ||
|
||||||
!fp->getScript()->nmap[cx->regs->pc - fp->getScript()->code]);
|
!fp->script()->nmap[cx->regs->pc - fp->script()->code]);
|
||||||
|
|
||||||
JSBool ok = JS_TRUE;
|
JSBool ok = JS_TRUE;
|
||||||
ok = Interpret(cx, fp, 0, JSINTERP_SAFEPOINT);
|
ok = Interpret(cx, fp, 0, JSINTERP_SAFEPOINT);
|
||||||
|
|
||||||
f.fp() = cx->fp();
|
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -802,11 +718,11 @@ static bool
|
||||||
RemoveExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
|
RemoveExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
|
||||||
{
|
{
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
while (cx->fp() != entryFrame || entryFrame->hasIMacroPC()) {
|
while (cx->fp() != entryFrame || entryFrame->hasImacropc()) {
|
||||||
JSStackFrame *fp = cx->fp();
|
JSStackFrame *fp = cx->fp();
|
||||||
|
|
||||||
if (AtSafePoint(cx)) {
|
if (AtSafePoint(cx)) {
|
||||||
JSScript *script = fp->getScript();
|
JSScript *script = fp->script();
|
||||||
if (!JaegerShotAtSafePoint(cx, script->nmap[cx->regs->pc - script->code])) {
|
if (!JaegerShotAtSafePoint(cx, script->nmap[cx->regs->pc - script->code])) {
|
||||||
if (!SwallowErrors(f, entryFrame))
|
if (!SwallowErrors(f, entryFrame))
|
||||||
return false;
|
return false;
|
||||||
|
@ -825,10 +741,10 @@ RemoveExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
|
||||||
* Partial interpret could have dropped us anywhere. Deduce the
|
* Partial interpret could have dropped us anywhere. Deduce the
|
||||||
* edge case: at a RETURN, needing to pop a frame.
|
* edge case: at a RETURN, needing to pop a frame.
|
||||||
*/
|
*/
|
||||||
JS_ASSERT(!cx->fp()->hasIMacroPC());
|
JS_ASSERT(!cx->fp()->hasImacropc());
|
||||||
if (FrameIsFinished(cx)) {
|
if (FrameIsFinished(cx)) {
|
||||||
JSOp op = JSOp(*cx->regs->pc);
|
JSOp op = JSOp(*cx->regs->pc);
|
||||||
if (op == JSOP_RETURN && !(cx->fp()->flags & JSFRAME_BAILED_AT_RETURN))
|
if (op == JSOP_RETURN && !cx->fp()->isBailedAtReturn())
|
||||||
cx->fp()->setReturnValue(f.regs.sp[-1]);
|
cx->fp()->setReturnValue(f.regs.sp[-1]);
|
||||||
InlineReturn(f, JS_TRUE);
|
InlineReturn(f, JS_TRUE);
|
||||||
AdvanceReturnPC(cx);
|
AdvanceReturnPC(cx);
|
||||||
|
@ -909,7 +825,7 @@ RunTracer(VMFrame &f)
|
||||||
case TPA_Error:
|
case TPA_Error:
|
||||||
if (!SwallowErrors(f, entryFrame))
|
if (!SwallowErrors(f, entryFrame))
|
||||||
THROWV(NULL);
|
THROWV(NULL);
|
||||||
JS_ASSERT(!cx->fp()->hasIMacroPC());
|
JS_ASSERT(!cx->fp()->hasImacropc());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TPA_RanStuff:
|
case TPA_RanStuff:
|
||||||
|
@ -945,19 +861,19 @@ RunTracer(VMFrame &f)
|
||||||
THROWV(NULL);
|
THROWV(NULL);
|
||||||
|
|
||||||
/* IMacros are guaranteed to have been removed by now. */
|
/* IMacros are guaranteed to have been removed by now. */
|
||||||
JS_ASSERT(!entryFrame->hasIMacroPC());
|
JS_ASSERT(!entryFrame->hasImacropc());
|
||||||
|
|
||||||
/* Step 2. If entryFrame is at a safe point, just leave. */
|
/* Step 2. If entryFrame is at a safe point, just leave. */
|
||||||
if (AtSafePoint(cx)) {
|
if (AtSafePoint(cx)) {
|
||||||
uint32 offs = uint32(cx->regs->pc - entryFrame->getScript()->code);
|
uint32 offs = uint32(cx->regs->pc - entryFrame->script()->code);
|
||||||
JS_ASSERT(entryFrame->getScript()->nmap[offs]);
|
JS_ASSERT(entryFrame->script()->nmap[offs]);
|
||||||
return entryFrame->getScript()->nmap[offs];
|
return entryFrame->script()->nmap[offs];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 3. If entryFrame is at a RETURN, then leave slightly differently. */
|
/* Step 3. If entryFrame is at a RETURN, then leave slightly differently. */
|
||||||
if (JSOp op = FrameIsFinished(cx)) {
|
if (JSOp op = FrameIsFinished(cx)) {
|
||||||
/* We're not guaranteed that the RETURN was run. */
|
/* We're not guaranteed that the RETURN was run. */
|
||||||
if (op == JSOP_RETURN && !(entryFrame->flags & JSFRAME_BAILED_AT_RETURN))
|
if (op == JSOP_RETURN && !entryFrame->isBailedAtReturn())
|
||||||
entryFrame->setReturnValue(f.regs.sp[-1]);
|
entryFrame->setReturnValue(f.regs.sp[-1]);
|
||||||
|
|
||||||
/* Don't pop the frame if it's maybe owned by an Invoke. */
|
/* Don't pop the frame if it's maybe owned by an Invoke. */
|
||||||
|
@ -986,7 +902,7 @@ RunTracer(VMFrame &f)
|
||||||
void *JS_FASTCALL
|
void *JS_FASTCALL
|
||||||
stubs::InvokeTracer(VMFrame &f, uint32 index)
|
stubs::InvokeTracer(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSScript *script = f.fp()->getScript();
|
JSScript *script = f.fp()->script();
|
||||||
ic::MICInfo &mic = script->mics[index];
|
ic::MICInfo &mic = script->mics[index];
|
||||||
|
|
||||||
JS_ASSERT(mic.kind == ic::MICInfo::TRACER);
|
JS_ASSERT(mic.kind == ic::MICInfo::TRACER);
|
||||||
|
|
|
@ -49,6 +49,25 @@
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::mjit;
|
using namespace js::mjit;
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
JSStackFrame::methodjitStaticAsserts()
|
||||||
|
{
|
||||||
|
/* Static assert for x86 trampolines in MethodJIT.cpp. */
|
||||||
|
#if defined(JS_CPU_X86)
|
||||||
|
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 0x18);
|
||||||
|
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) + 4 == 0x1C);
|
||||||
|
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 0x2C);
|
||||||
|
/* ARM uses decimal literals. */
|
||||||
|
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 24);
|
||||||
|
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) + 4 == 28);
|
||||||
|
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 44);
|
||||||
|
#elif defined(JS_CPU_X64)
|
||||||
|
JS_STATIC_ASSERT(offsetof(JSStackFrame, rval_) == 0x30);
|
||||||
|
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode_) == 0x50);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Explanation of VMFrame activation and various helper thunks below.
|
* Explanation of VMFrame activation and various helper thunks below.
|
||||||
*
|
*
|
||||||
|
@ -254,7 +273,6 @@ SYMBOL_STRING(JaegerThrowpoline) ":" "\n"
|
||||||
"ret" "\n"
|
"ret" "\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode) == 0x60);
|
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38);
|
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38);
|
||||||
|
|
||||||
asm volatile (
|
asm volatile (
|
||||||
|
@ -262,7 +280,7 @@ asm volatile (
|
||||||
".globl " SYMBOL_STRING(SafePointTrampoline) "\n"
|
".globl " SYMBOL_STRING(SafePointTrampoline) "\n"
|
||||||
SYMBOL_STRING(SafePointTrampoline) ":" "\n"
|
SYMBOL_STRING(SafePointTrampoline) ":" "\n"
|
||||||
"popq %rax" "\n"
|
"popq %rax" "\n"
|
||||||
"movq %rax, 0x60(%rbx)" "\n"
|
"movq %rax, 0x50(%rbx)" "\n"
|
||||||
"jmp *8(%rsp)" "\n"
|
"jmp *8(%rsp)" "\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -270,8 +288,8 @@ asm volatile (
|
||||||
".text\n"
|
".text\n"
|
||||||
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
|
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
|
||||||
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
|
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
|
||||||
"movq 0x40(%rbx), %rcx" "\n" /* load Value into typeReg */
|
"movq 0x30(%rbx), %rcx" "\n" /* load fp->rval_ into typeReg */
|
||||||
"movq 0x60(%rbx), %rax" "\n" /* fp->ncode */
|
"movq 0x50(%rbx), %rax" "\n" /* fp->ncode_ */
|
||||||
|
|
||||||
/* Reimplementation of PunboxAssembler::loadValueAsComponents() */
|
/* Reimplementation of PunboxAssembler::loadValueAsComponents() */
|
||||||
"movq %r14, %rdx" "\n" /* payloadReg = payloadMaskReg */
|
"movq %r14, %rdx" "\n" /* payloadReg = payloadMaskReg */
|
||||||
|
@ -363,16 +381,15 @@ SYMBOL_STRING(JaegerThrowpoline) ":" "\n"
|
||||||
"ret" "\n"
|
"ret" "\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode) == 0x3C);
|
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x1C);
|
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x1C);
|
||||||
|
|
||||||
asm volatile (
|
asm volatile (
|
||||||
".text\n"
|
".text\n"
|
||||||
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
|
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
|
||||||
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
|
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
|
||||||
"movl 0x28(%ebx), %edx" "\n" /* fp->rval data */
|
"movl 0x18(%ebx), %edx" "\n" /* fp->rval_ data */
|
||||||
"movl 0x2C(%ebx), %ecx" "\n" /* fp->rval type */
|
"movl 0x1C(%ebx), %ecx" "\n" /* fp->rval_ type */
|
||||||
"movl 0x3C(%ebx), %eax" "\n" /* fp->ncode */
|
"movl 0x2C(%ebx), %eax" "\n" /* fp->ncode_ */
|
||||||
"movl 0x1C(%esp), %ebx" "\n" /* f.fp */
|
"movl 0x1C(%esp), %ebx" "\n" /* f.fp */
|
||||||
"pushl %eax" "\n"
|
"pushl %eax" "\n"
|
||||||
"ret" "\n"
|
"ret" "\n"
|
||||||
|
@ -387,7 +404,7 @@ asm volatile (
|
||||||
".globl " SYMBOL_STRING(SafePointTrampoline) "\n"
|
".globl " SYMBOL_STRING(SafePointTrampoline) "\n"
|
||||||
SYMBOL_STRING(SafePointTrampoline) ":" "\n"
|
SYMBOL_STRING(SafePointTrampoline) ":" "\n"
|
||||||
"popl %eax" "\n"
|
"popl %eax" "\n"
|
||||||
"movl %eax, 0x3C(%ebx)" "\n"
|
"movl %eax, 0x2C(%ebx)" "\n"
|
||||||
"jmp *24(%ebp)" "\n"
|
"jmp *24(%ebp)" "\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -401,7 +418,6 @@ JS_STATIC_ASSERT(offsetof(VMFrame, cx) == (4*8));
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == (4*7));
|
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == (4*7));
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, unused) == (4*4));
|
JS_STATIC_ASSERT(offsetof(VMFrame, unused) == (4*4));
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, previous) == (4*3));
|
JS_STATIC_ASSERT(offsetof(VMFrame, previous) == (4*3));
|
||||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode) == 60);
|
|
||||||
|
|
||||||
JS_STATIC_ASSERT(JSFrameReg == JSC::ARMRegisters::r11);
|
JS_STATIC_ASSERT(JSFrameReg == JSC::ARMRegisters::r11);
|
||||||
JS_STATIC_ASSERT(JSReturnReg_Data == JSC::ARMRegisters::r1);
|
JS_STATIC_ASSERT(JSReturnReg_Data == JSC::ARMRegisters::r1);
|
||||||
|
@ -412,9 +428,9 @@ asm volatile (
|
||||||
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
|
".globl " SYMBOL_STRING(InjectJaegerReturn) "\n"
|
||||||
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
|
SYMBOL_STRING(InjectJaegerReturn) ":" "\n"
|
||||||
/* Restore frame regs. */
|
/* Restore frame regs. */
|
||||||
"ldr lr, [r11, #60]" "\n" /* fp->ncode */
|
"ldr lr, [r11, #44]" "\n" /* fp->ncode */
|
||||||
"ldr r1, [r11, #40]" "\n" /* fp->rval data */
|
"ldr r1, [r11, #24]" "\n" /* fp->rval data */
|
||||||
"ldr r2, [r11, #44]" "\n" /* fp->rval type */
|
"ldr r2, [r11, #28]" "\n" /* fp->rval type */
|
||||||
"ldr r11, [sp, #28]" "\n" /* load f.fp */
|
"ldr r11, [sp, #28]" "\n" /* load f.fp */
|
||||||
"bx lr" "\n"
|
"bx lr" "\n"
|
||||||
);
|
);
|
||||||
|
@ -430,7 +446,7 @@ SYMBOL_STRING(SafePointTrampoline) ":"
|
||||||
*/
|
*/
|
||||||
"ldr ip, [sp, #80]" "\n"
|
"ldr ip, [sp, #80]" "\n"
|
||||||
/* Save the return address (in JaegerTrampoline) to fp->ncode. */
|
/* Save the return address (in JaegerTrampoline) to fp->ncode. */
|
||||||
"str lr, [r11, #60]" "\n"
|
"str lr, [r11, #44]" "\n"
|
||||||
/* Jump to 'safePoint' via 'ip' because a load into the PC from an address on
|
/* Jump to 'safePoint' via 'ip' because a load into the PC from an address on
|
||||||
* the stack looks like a return, and may upset return stack prediction. */
|
* the stack looks like a return, and may upset return stack prediction. */
|
||||||
"bx ip" "\n"
|
"bx ip" "\n"
|
||||||
|
@ -566,9 +582,9 @@ extern "C" {
|
||||||
__declspec(naked) void InjectJaegerReturn()
|
__declspec(naked) void InjectJaegerReturn()
|
||||||
{
|
{
|
||||||
__asm {
|
__asm {
|
||||||
mov edx, [ebx + 0x28];
|
mov edx, [ebx + 0x18];
|
||||||
mov ecx, [ebx + 0x2C];
|
mov ecx, [ebx + 0x1C];
|
||||||
mov eax, [ebx + 0x3C];
|
mov eax, [ebx + 0x2C];
|
||||||
mov ebx, [esp + 0x1C];
|
mov ebx, [esp + 0x1C];
|
||||||
push eax;
|
push eax;
|
||||||
ret;
|
ret;
|
||||||
|
@ -579,7 +595,7 @@ extern "C" {
|
||||||
{
|
{
|
||||||
__asm {
|
__asm {
|
||||||
pop eax;
|
pop eax;
|
||||||
mov [ebx + 0x3C], eax;
|
mov [ebx + 0x2C], eax;
|
||||||
jmp [ebp + 24];
|
jmp [ebp + 24];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -666,7 +682,6 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, savedRBX) == 0x58);
|
JS_STATIC_ASSERT(offsetof(VMFrame, savedRBX) == 0x58);
|
||||||
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38);
|
JS_STATIC_ASSERT(offsetof(VMFrame, regs.fp) == 0x38);
|
||||||
JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode) == 0x60);
|
|
||||||
JS_STATIC_ASSERT(JSVAL_TAG_MASK == 0xFFFF800000000000LL);
|
JS_STATIC_ASSERT(JSVAL_TAG_MASK == 0xFFFF800000000000LL);
|
||||||
JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL);
|
JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL);
|
||||||
|
|
||||||
|
@ -728,7 +743,7 @@ EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, void *safePoint)
|
||||||
|
|
||||||
#ifdef JS_METHODJIT_SPEW
|
#ifdef JS_METHODJIT_SPEW
|
||||||
Profiler prof;
|
Profiler prof;
|
||||||
JSScript *script = fp->getScript();
|
JSScript *script = fp->script();
|
||||||
|
|
||||||
JaegerSpew(JSpew_Prof, "%s jaeger script: %s, line %d\n",
|
JaegerSpew(JSpew_Prof, "%s jaeger script: %s, line %d\n",
|
||||||
safePoint ? "dropping" : "entering",
|
safePoint ? "dropping" : "entering",
|
||||||
|
@ -740,19 +755,9 @@ EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, void *safePoint)
|
||||||
JSStackFrame *checkFp = fp;
|
JSStackFrame *checkFp = fp;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Value *fpAsVp = reinterpret_cast<Value*>(fp);
|
Value *stackLimit = cx->stack().getStackLimit(cx);
|
||||||
StackSpace &stack = cx->stack();
|
if (!stackLimit)
|
||||||
Value *stackLimit = stack.makeStackLimit(fpAsVp);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We ensure that there is always enough space to speculatively create a
|
|
||||||
* stack frame. By passing nslots = 0, we ensure only sizeof(JSStackFrame).
|
|
||||||
*/
|
|
||||||
if (fpAsVp + VALUES_PER_STACK_FRAME >= stackLimit &&
|
|
||||||
!stack.ensureSpace(cx, fpAsVp, cx->regs->sp, stackLimit, 0)) {
|
|
||||||
js_ReportOutOfScriptQuota(cx);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
JSFrameRegs *oldRegs = cx->regs;
|
JSFrameRegs *oldRegs = cx->regs;
|
||||||
|
|
||||||
|
@ -774,7 +779,7 @@ EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, void *safePoint)
|
||||||
JSBool
|
JSBool
|
||||||
mjit::JaegerShot(JSContext *cx)
|
mjit::JaegerShot(JSContext *cx)
|
||||||
{
|
{
|
||||||
JSScript *script = cx->fp()->getScript();
|
JSScript *script = cx->fp()->script();
|
||||||
|
|
||||||
JS_ASSERT(script->ncode && script->ncode != JS_UNJITTABLE_METHOD);
|
JS_ASSERT(script->ncode && script->ncode != JS_UNJITTABLE_METHOD);
|
||||||
|
|
||||||
|
@ -867,10 +872,3 @@ mjit::ProfileStubCall(VMFrame &f)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool
|
|
||||||
VMFrame::slowEnsureSpace(uint32 nslots)
|
|
||||||
{
|
|
||||||
return cx->stack().ensureSpace(cx, reinterpret_cast<Value*>(entryFp), regs.sp,
|
|
||||||
stackLimit, nslots + VALUES_PER_STACK_FRAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -132,17 +132,6 @@ struct VMFrame
|
||||||
JSRuntime *runtime() { return cx->runtime; }
|
JSRuntime *runtime() { return cx->runtime; }
|
||||||
|
|
||||||
JSStackFrame *&fp() { return regs.fp; }
|
JSStackFrame *&fp() { return regs.fp; }
|
||||||
|
|
||||||
bool slowEnsureSpace(uint32 nslots);
|
|
||||||
|
|
||||||
bool ensureSpace(uint32 nmissing, uint32 nslots) {
|
|
||||||
/* Fast check - if it's below the limit, it's safe to just get a frame. */
|
|
||||||
if (JS_LIKELY(regs.sp + VALUES_PER_STACK_FRAME + nmissing + nslots < stackLimit))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* Slower check that might have to commit memory or throw an error. */
|
|
||||||
return slowEnsureSpace(nmissing + nslots);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef JS_CPU_ARM
|
#ifdef JS_CPU_ARM
|
||||||
|
|
|
@ -50,6 +50,8 @@
|
||||||
#include "methodjit/Compiler.h"
|
#include "methodjit/Compiler.h"
|
||||||
#include "InlineFrameAssembler.h"
|
#include "InlineFrameAssembler.h"
|
||||||
#include "jsobj.h"
|
#include "jsobj.h"
|
||||||
|
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsscopeinlines.h"
|
#include "jsscopeinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
|
@ -78,9 +80,9 @@ PatchGetFallback(VMFrame &f, ic::MICInfo &mic)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
ic::GetGlobalName(VMFrame &f, uint32 index)
|
ic::GetGlobalName(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSObject *obj = f.fp()->getScopeChain()->getGlobal();
|
JSObject *obj = f.fp()->scopeChain().getGlobal();
|
||||||
ic::MICInfo &mic = f.fp()->getScript()->mics[index];
|
ic::MICInfo &mic = f.fp()->script()->mics[index];
|
||||||
JSAtom *atom = f.fp()->getScript()->getAtom(GET_INDEX(f.regs.pc));
|
JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc));
|
||||||
jsid id = ATOM_TO_JSID(atom);
|
jsid id = ATOM_TO_JSID(atom);
|
||||||
|
|
||||||
JS_ASSERT(mic.kind == ic::MICInfo::GET);
|
JS_ASSERT(mic.kind == ic::MICInfo::GET);
|
||||||
|
@ -129,7 +131,7 @@ ic::GetGlobalName(VMFrame &f, uint32 index)
|
||||||
static void JS_FASTCALL
|
static void JS_FASTCALL
|
||||||
SetGlobalNameSlow(VMFrame &f, uint32 index)
|
SetGlobalNameSlow(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSAtom *atom = f.fp()->getScript()->getAtom(GET_INDEX(f.regs.pc));
|
JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc));
|
||||||
stubs::SetGlobalName(f, atom);
|
stubs::SetGlobalName(f, atom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,9 +156,9 @@ GetStubForSetGlobalName(VMFrame &f)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
ic::SetGlobalName(VMFrame &f, uint32 index)
|
ic::SetGlobalName(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSObject *obj = f.fp()->getScopeChain()->getGlobal();
|
JSObject *obj = f.fp()->scopeChain().getGlobal();
|
||||||
ic::MICInfo &mic = f.fp()->getScript()->mics[index];
|
ic::MICInfo &mic = f.fp()->script()->mics[index];
|
||||||
JSAtom *atom = f.fp()->getScript()->getAtom(GET_INDEX(f.regs.pc));
|
JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc));
|
||||||
jsid id = ATOM_TO_JSID(atom);
|
jsid id = ATOM_TO_JSID(atom);
|
||||||
|
|
||||||
JS_ASSERT(mic.kind == ic::MICInfo::SET);
|
JS_ASSERT(mic.kind == ic::MICInfo::SET);
|
||||||
|
@ -213,7 +215,7 @@ ic::SetGlobalName(VMFrame &f, uint32 index)
|
||||||
static void * JS_FASTCALL
|
static void * JS_FASTCALL
|
||||||
SlowCallFromIC(VMFrame &f, uint32 index)
|
SlowCallFromIC(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSScript *oldscript = f.fp()->getScript();
|
JSScript *oldscript = f.fp()->script();
|
||||||
CallICInfo &ic= oldscript->callICs[index];
|
CallICInfo &ic= oldscript->callICs[index];
|
||||||
|
|
||||||
stubs::SlowCall(f, ic.argc);
|
stubs::SlowCall(f, ic.argc);
|
||||||
|
@ -224,7 +226,7 @@ SlowCallFromIC(VMFrame &f, uint32 index)
|
||||||
static void * JS_FASTCALL
|
static void * JS_FASTCALL
|
||||||
SlowNewFromIC(VMFrame &f, uint32 index)
|
SlowNewFromIC(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSScript *oldscript = f.fp()->getScript();
|
JSScript *oldscript = f.fp()->script();
|
||||||
CallICInfo &ic = oldscript->callICs[index];
|
CallICInfo &ic = oldscript->callICs[index];
|
||||||
|
|
||||||
stubs::SlowNew(f, ic.argc);
|
stubs::SlowNew(f, ic.argc);
|
||||||
|
@ -297,23 +299,6 @@ class CallCompiler
|
||||||
return ep;
|
return ep;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void pushFrameFromCaller(JSObject *scopeChain, uint32 flags)
|
|
||||||
{
|
|
||||||
JSStackFrame *fp = (JSStackFrame *)f.regs.sp;
|
|
||||||
fp->argc = ic.argc;
|
|
||||||
fp->argv = vp + 2;
|
|
||||||
fp->flags = flags;
|
|
||||||
fp->setScopeChain(scopeChain);
|
|
||||||
fp->setThisValue(vp[1]);
|
|
||||||
fp->down = f.fp();
|
|
||||||
fp->savedPC = f.regs.pc;
|
|
||||||
fp->down->savedPC = f.regs.pc;
|
|
||||||
#ifdef DEBUG
|
|
||||||
fp->savedPC = JSStackFrame::sInvalidPC;
|
|
||||||
#endif
|
|
||||||
f.regs.fp = fp;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool generateFullCallStub(JSScript *script, uint32 flags)
|
bool generateFullCallStub(JSScript *script, uint32 flags)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -344,6 +329,7 @@ class CallCompiler
|
||||||
|
|
||||||
/* Try and compile. On success we get back the nmap pointer. */
|
/* Try and compile. On success we get back the nmap pointer. */
|
||||||
masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
masm.storePtr(JSFrameReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
||||||
|
masm.move(Imm32(ic.argc), Registers::ArgReg1);
|
||||||
JSC::MacroAssembler::Call tryCompile =
|
JSC::MacroAssembler::Call tryCompile =
|
||||||
masm.stubCall(JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction),
|
masm.stubCall(JS_FUNC_TO_DATA_PTR(void *, stubs::CompileFunction),
|
||||||
script->code, ic.frameDepth);
|
script->code, ic.frameDepth);
|
||||||
|
@ -648,7 +634,7 @@ class CallCompiler
|
||||||
stubs::NewObject(f, ic.argc);
|
stubs::NewObject(f, ic.argc);
|
||||||
|
|
||||||
if (!ic.hit) {
|
if (!ic.hit) {
|
||||||
if (ic.argc < fun->nargs) {
|
if (ic.argc != fun->nargs) {
|
||||||
if (!generateFullCallStub(script, flags))
|
if (!generateFullCallStub(script, flags))
|
||||||
THROWV(NULL);
|
THROWV(NULL);
|
||||||
} else {
|
} else {
|
||||||
|
@ -672,9 +658,18 @@ class CallCompiler
|
||||||
ic.hit = true;
|
ic.hit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We'll still return to the OOL path, so make sure a frame exists. */
|
/*
|
||||||
pushFrameFromCaller(scopeChain, flags);
|
* We are about to jump into the callee's prologue, so push the frame as
|
||||||
if (ic.argc >= fun->nargs)
|
* if we had been executing in the caller's inline call path. In theory,
|
||||||
|
* we could actually jump to the inline call path, but doing it from
|
||||||
|
* C++ allows JSStackFrame::initCallFrameCallerHalf to serve as a
|
||||||
|
* reference for what the jitted path should be doing.
|
||||||
|
*/
|
||||||
|
JSStackFrame *fp = (JSStackFrame *)f.regs.sp;
|
||||||
|
fp->initCallFrameCallerHalf(cx, *scopeChain, ic.argc, flags);
|
||||||
|
f.regs.fp = fp;
|
||||||
|
|
||||||
|
if (ic.argc == fun->nargs)
|
||||||
return script->ncode;
|
return script->ncode;
|
||||||
return script->jit->arityCheck;
|
return script->jit->arityCheck;
|
||||||
}
|
}
|
||||||
|
@ -683,7 +678,7 @@ class CallCompiler
|
||||||
void * JS_FASTCALL
|
void * JS_FASTCALL
|
||||||
ic::Call(VMFrame &f, uint32 index)
|
ic::Call(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSScript *oldscript = f.fp()->getScript();
|
JSScript *oldscript = f.fp()->script();
|
||||||
CallICInfo &ic = oldscript->callICs[index];
|
CallICInfo &ic = oldscript->callICs[index];
|
||||||
CallCompiler cc(f, ic, false);
|
CallCompiler cc(f, ic, false);
|
||||||
return cc.update();
|
return cc.update();
|
||||||
|
@ -692,7 +687,7 @@ ic::Call(VMFrame &f, uint32 index)
|
||||||
void * JS_FASTCALL
|
void * JS_FASTCALL
|
||||||
ic::New(VMFrame &f, uint32 index)
|
ic::New(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSScript *oldscript = f.fp()->getScript();
|
JSScript *oldscript = f.fp()->script();
|
||||||
CallICInfo &ic = oldscript->callICs[index];
|
CallICInfo &ic = oldscript->callICs[index];
|
||||||
CallCompiler cc(f, ic, true);
|
CallCompiler cc(f, ic, true);
|
||||||
return cc.update();
|
return cc.update();
|
||||||
|
@ -701,7 +696,7 @@ ic::New(VMFrame &f, uint32 index)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
ic::NativeCall(VMFrame &f, uint32 index)
|
ic::NativeCall(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSScript *oldscript = f.fp()->getScript();
|
JSScript *oldscript = f.fp()->script();
|
||||||
CallICInfo &ic = oldscript->callICs[index];
|
CallICInfo &ic = oldscript->callICs[index];
|
||||||
CallCompiler cc(f, ic, false);
|
CallCompiler cc(f, ic, false);
|
||||||
if (!cc.generateNativeStub())
|
if (!cc.generateNativeStub())
|
||||||
|
@ -711,7 +706,7 @@ ic::NativeCall(VMFrame &f, uint32 index)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
ic::NativeNew(VMFrame &f, uint32 index)
|
ic::NativeNew(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSScript *oldscript = f.fp()->getScript();
|
JSScript *oldscript = f.fp()->script();
|
||||||
CallICInfo &ic = oldscript->callICs[index];
|
CallICInfo &ic = oldscript->callICs[index];
|
||||||
CallCompiler cc(f, ic, true);
|
CallCompiler cc(f, ic, true);
|
||||||
if (!cc.generateNativeStub())
|
if (!cc.generateNativeStub())
|
||||||
|
|
|
@ -124,7 +124,6 @@ struct CallICInfo {
|
||||||
/* Used for rooting and reification. */
|
/* Used for rooting and reification. */
|
||||||
JSObject *fastGuardedObject;
|
JSObject *fastGuardedObject;
|
||||||
JSObject *fastGuardedNative;
|
JSObject *fastGuardedNative;
|
||||||
Value constantThis;
|
|
||||||
|
|
||||||
uint32 argc : 16;
|
uint32 argc : 16;
|
||||||
uint32 frameDepth : 16;
|
uint32 frameDepth : 16;
|
||||||
|
@ -156,7 +155,6 @@ struct CallICInfo {
|
||||||
|
|
||||||
RegisterID funObjReg : 5;
|
RegisterID funObjReg : 5;
|
||||||
RegisterID funPtrReg : 5;
|
RegisterID funPtrReg : 5;
|
||||||
bool isConstantThis : 1;
|
|
||||||
bool hit : 1;
|
bool hit : 1;
|
||||||
bool hasJsFunCheck : 1;
|
bool hasJsFunCheck : 1;
|
||||||
|
|
||||||
|
|
|
@ -467,6 +467,14 @@ class SetPropCompiler : public PICStubCompiler
|
||||||
|
|
||||||
emitStore(masm, address);
|
emitStore(masm, address);
|
||||||
} else {
|
} else {
|
||||||
|
// \ / In general, two function objects with different JSFunctions
|
||||||
|
// # can have the same shape, thus we must not rely on the identity
|
||||||
|
// >--+--< of 'fun' remaining the same. However, since:
|
||||||
|
// ||| 1. the shape includes all arguments and locals and their setters
|
||||||
|
// \\ V and getters, and
|
||||||
|
// \===/ 2. arguments and locals have different getters
|
||||||
|
// then we can rely on fun->nargs remaining invariant.
|
||||||
|
JSFunction *fun = obj->getCallObjCalleeFunction();
|
||||||
uint16 slot = uint16(shape->shortid);
|
uint16 slot = uint16(shape->shortid);
|
||||||
|
|
||||||
/* Guard that the call object has a frame. */
|
/* Guard that the call object has a frame. */
|
||||||
|
@ -474,22 +482,17 @@ class SetPropCompiler : public PICStubCompiler
|
||||||
Jump escapedFrame = masm.branchTestPtr(Assembler::Zero, pic.shapeReg, pic.shapeReg);
|
Jump escapedFrame = masm.branchTestPtr(Assembler::Zero, pic.shapeReg, pic.shapeReg);
|
||||||
|
|
||||||
{
|
{
|
||||||
uint32 bias = 0;
|
Address addr(pic.shapeReg, shape->setterOp() == SetCallArg
|
||||||
if (shape->setterOp() == SetCallArg)
|
? JSStackFrame::offsetOfFormalArg(fun, slot)
|
||||||
masm.loadPtr(Address(pic.shapeReg, offsetof(JSStackFrame, argv)), pic.shapeReg);
|
: JSStackFrame::offsetOfFixed(slot));
|
||||||
else
|
emitStore(masm, addr);
|
||||||
bias = sizeof(JSStackFrame);
|
|
||||||
Address address(pic.shapeReg, bias + slot * sizeof(Value));
|
|
||||||
emitStore(masm, address);
|
|
||||||
skipOver = masm.jump();
|
skipOver = masm.jump();
|
||||||
}
|
}
|
||||||
|
|
||||||
escapedFrame.linkTo(masm.label(), &masm);
|
escapedFrame.linkTo(masm.label(), &masm);
|
||||||
{
|
{
|
||||||
if (shape->setterOp() == SetCallVar) {
|
if (shape->setterOp() == SetCallVar)
|
||||||
JSFunction *fun = js_GetCallObjectFunction(obj);
|
|
||||||
slot += fun->nargs;
|
slot += fun->nargs;
|
||||||
}
|
|
||||||
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
|
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
|
||||||
|
|
||||||
Address dslot(pic.objReg, slot * sizeof(Value));
|
Address dslot(pic.objReg, slot * sizeof(Value));
|
||||||
|
@ -874,7 +877,7 @@ class GetPropCompiler : public PICStubCompiler
|
||||||
JS_ASSERT(pic.hasTypeCheck());
|
JS_ASSERT(pic.hasTypeCheck());
|
||||||
JS_ASSERT(pic.kind == ic::PICInfo::CALL);
|
JS_ASSERT(pic.kind == ic::PICInfo::CALL);
|
||||||
|
|
||||||
if (!f.fp()->getScript()->compileAndGo)
|
if (!f.fp()->script()->compileAndGo)
|
||||||
return disable("String.prototype without compile-and-go");
|
return disable("String.prototype without compile-and-go");
|
||||||
|
|
||||||
JSObject *holder;
|
JSObject *holder;
|
||||||
|
@ -1656,7 +1659,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||||
Assembler masm;
|
Assembler masm;
|
||||||
JumpList fails(f.cx);
|
JumpList fails(f.cx);
|
||||||
|
|
||||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetScopeChain()), pic.objReg);
|
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
|
||||||
|
|
||||||
JS_ASSERT(obj == holder);
|
JS_ASSERT(obj == holder);
|
||||||
JS_ASSERT(holder == scopeChain->getGlobal());
|
JS_ASSERT(holder == scopeChain->getGlobal());
|
||||||
|
@ -1729,7 +1732,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||||
Assembler masm;
|
Assembler masm;
|
||||||
Vector<Jump, 8, ContextAllocPolicy> fails(f.cx);
|
Vector<Jump, 8, ContextAllocPolicy> fails(f.cx);
|
||||||
|
|
||||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetScopeChain()), pic.objReg);
|
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
|
||||||
|
|
||||||
JS_ASSERT(obj == holder);
|
JS_ASSERT(obj == holder);
|
||||||
JS_ASSERT(holder != scopeChain->getGlobal());
|
JS_ASSERT(holder != scopeChain->getGlobal());
|
||||||
|
@ -1756,6 +1759,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||||
/* Get callobj's stack frame. */
|
/* Get callobj's stack frame. */
|
||||||
masm.loadFunctionPrivate(pic.objReg, pic.shapeReg);
|
masm.loadFunctionPrivate(pic.objReg, pic.shapeReg);
|
||||||
|
|
||||||
|
JSFunction *fun = holder->getCallObjCalleeFunction();
|
||||||
uint16 slot = uint16(shape->shortid);
|
uint16 slot = uint16(shape->shortid);
|
||||||
|
|
||||||
Jump skipOver;
|
Jump skipOver;
|
||||||
|
@ -1763,12 +1767,8 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||||
|
|
||||||
/* Not-escaped case. */
|
/* Not-escaped case. */
|
||||||
{
|
{
|
||||||
uint32 bias = 0;
|
Address addr(pic.shapeReg, kind == ARG ? JSStackFrame::offsetOfFormalArg(fun, slot)
|
||||||
if (kind == ARG)
|
: JSStackFrame::offsetOfFixed(slot));
|
||||||
masm.loadPtr(Address(pic.shapeReg, offsetof(JSStackFrame, argv)), pic.shapeReg);
|
|
||||||
else
|
|
||||||
bias = sizeof(JSStackFrame);
|
|
||||||
Address addr(pic.shapeReg, bias + slot * sizeof(Value));
|
|
||||||
masm.loadPayload(addr, pic.objReg);
|
masm.loadPayload(addr, pic.objReg);
|
||||||
masm.loadTypeTag(addr, pic.shapeReg);
|
masm.loadTypeTag(addr, pic.shapeReg);
|
||||||
skipOver = masm.jump();
|
skipOver = masm.jump();
|
||||||
|
@ -1779,7 +1779,6 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||||
{
|
{
|
||||||
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
|
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
|
||||||
|
|
||||||
JSFunction *fun = js_GetCallObjectFunction(holder);
|
|
||||||
if (kind == VAR)
|
if (kind == VAR)
|
||||||
slot += fun->nargs;
|
slot += fun->nargs;
|
||||||
Address dslot(pic.objReg, slot * sizeof(Value));
|
Address dslot(pic.objReg, slot * sizeof(Value));
|
||||||
|
@ -1914,7 +1913,7 @@ class BindNameCompiler : public PICStubCompiler
|
||||||
js::Vector<Jump, 8, ContextAllocPolicy> fails(f.cx);
|
js::Vector<Jump, 8, ContextAllocPolicy> fails(f.cx);
|
||||||
|
|
||||||
/* Guard on the shape of the scope chain. */
|
/* Guard on the shape of the scope chain. */
|
||||||
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetScopeChain()), pic.objReg);
|
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
|
||||||
masm.loadShape(pic.objReg, pic.shapeReg);
|
masm.loadShape(pic.objReg, pic.shapeReg);
|
||||||
Jump firstShape = masm.branch32(Assembler::NotEqual, pic.shapeReg,
|
Jump firstShape = masm.branch32(Assembler::NotEqual, pic.shapeReg,
|
||||||
Imm32(scopeChain->shape()));
|
Imm32(scopeChain->shape()));
|
||||||
|
@ -2008,7 +2007,7 @@ class BindNameCompiler : public PICStubCompiler
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
ic::GetProp(VMFrame &f, uint32 index)
|
ic::GetProp(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSScript *script = f.fp()->getScript();
|
JSScript *script = f.fp()->script();
|
||||||
PICInfo &pic = script->pics[index];
|
PICInfo &pic = script->pics[index];
|
||||||
|
|
||||||
JSAtom *atom = pic.atom;
|
JSAtom *atom = pic.atom;
|
||||||
|
@ -2066,7 +2065,7 @@ ic::GetProp(VMFrame &f, uint32 index)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
ic::GetElem(VMFrame &f, uint32 picIndex)
|
ic::GetElem(VMFrame &f, uint32 picIndex)
|
||||||
{
|
{
|
||||||
JSScript *script = f.fp()->getScript();
|
JSScript *script = f.fp()->script();
|
||||||
PICInfo &pic = script->pics[picIndex];
|
PICInfo &pic = script->pics[picIndex];
|
||||||
|
|
||||||
JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
|
JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
|
||||||
|
@ -2096,7 +2095,7 @@ ic::GetElem(VMFrame &f, uint32 picIndex)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
ic::SetPropDumb(VMFrame &f, uint32 index)
|
ic::SetPropDumb(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSScript *script = f.fp()->getScript();
|
JSScript *script = f.fp()->script();
|
||||||
ic::PICInfo &pic = script->pics[index];
|
ic::PICInfo &pic = script->pics[index];
|
||||||
JS_ASSERT(pic.isSet());
|
JS_ASSERT(pic.isSet());
|
||||||
JSAtom *atom = pic.atom;
|
JSAtom *atom = pic.atom;
|
||||||
|
@ -2113,7 +2112,7 @@ ic::SetPropDumb(VMFrame &f, uint32 index)
|
||||||
static void JS_FASTCALL
|
static void JS_FASTCALL
|
||||||
SetPropSlow(VMFrame &f, uint32 index)
|
SetPropSlow(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSScript *script = f.fp()->getScript();
|
JSScript *script = f.fp()->script();
|
||||||
ic::PICInfo &pic = script->pics[index];
|
ic::PICInfo &pic = script->pics[index];
|
||||||
JS_ASSERT(pic.isSet());
|
JS_ASSERT(pic.isSet());
|
||||||
|
|
||||||
|
@ -2128,7 +2127,7 @@ ic::SetProp(VMFrame &f, uint32 index)
|
||||||
if (!obj)
|
if (!obj)
|
||||||
THROW();
|
THROW();
|
||||||
|
|
||||||
JSScript *script = f.fp()->getScript();
|
JSScript *script = f.fp()->script();
|
||||||
ic::PICInfo &pic = script->pics[index];
|
ic::PICInfo &pic = script->pics[index];
|
||||||
JSAtom *atom = pic.atom;
|
JSAtom *atom = pic.atom;
|
||||||
JS_ASSERT(pic.isSet());
|
JS_ASSERT(pic.isSet());
|
||||||
|
@ -2172,7 +2171,7 @@ ic::SetProp(VMFrame &f, uint32 index)
|
||||||
static void JS_FASTCALL
|
static void JS_FASTCALL
|
||||||
CallPropSlow(VMFrame &f, uint32 index)
|
CallPropSlow(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSScript *script = f.fp()->getScript();
|
JSScript *script = f.fp()->script();
|
||||||
ic::PICInfo &pic = script->pics[index];
|
ic::PICInfo &pic = script->pics[index];
|
||||||
stubs::CallProp(f, pic.atom);
|
stubs::CallProp(f, pic.atom);
|
||||||
}
|
}
|
||||||
|
@ -2183,7 +2182,7 @@ ic::CallProp(VMFrame &f, uint32 index)
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSFrameRegs ®s = f.regs;
|
JSFrameRegs ®s = f.regs;
|
||||||
|
|
||||||
JSScript *script = f.fp()->getScript();
|
JSScript *script = f.fp()->script();
|
||||||
ic::PICInfo &pic = script->pics[index];
|
ic::PICInfo &pic = script->pics[index];
|
||||||
JSAtom *origAtom = pic.atom;
|
JSAtom *origAtom = pic.atom;
|
||||||
|
|
||||||
|
@ -2320,11 +2319,11 @@ SlowName(VMFrame &f, uint32 index)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
ic::Name(VMFrame &f, uint32 index)
|
ic::Name(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSScript *script = f.fp()->getScript();
|
JSScript *script = f.fp()->script();
|
||||||
ic::PICInfo &pic = script->pics[index];
|
ic::PICInfo &pic = script->pics[index];
|
||||||
JSAtom *atom = pic.atom;
|
JSAtom *atom = pic.atom;
|
||||||
|
|
||||||
ScopeNameCompiler cc(f, script, f.fp()->getScopeChain(), pic, atom, SlowName);
|
ScopeNameCompiler cc(f, script, &f.fp()->scopeChain(), pic, atom, SlowName);
|
||||||
|
|
||||||
if (!cc.update()) {
|
if (!cc.update()) {
|
||||||
cc.disable("error");
|
cc.disable("error");
|
||||||
|
@ -2340,7 +2339,7 @@ ic::Name(VMFrame &f, uint32 index)
|
||||||
if (!cc.prop) {
|
if (!cc.prop) {
|
||||||
/* Kludge to allow (typeof foo == "undefined") tests. */
|
/* Kludge to allow (typeof foo == "undefined") tests. */
|
||||||
cc.disable("property not found");
|
cc.disable("property not found");
|
||||||
JSOp op2 = js_GetOpcode(f.cx, f.fp()->getScript(), f.regs.pc + JSOP_NAME_LENGTH);
|
JSOp op2 = js_GetOpcode(f.cx, f.fp()->script(), f.regs.pc + JSOP_NAME_LENGTH);
|
||||||
if (op2 == JSOP_TYPEOF) {
|
if (op2 == JSOP_TYPEOF) {
|
||||||
f.regs.sp[0].setUndefined();
|
f.regs.sp[0].setUndefined();
|
||||||
return;
|
return;
|
||||||
|
@ -2369,11 +2368,11 @@ SlowBindName(VMFrame &f, uint32 index)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
ic::BindName(VMFrame &f, uint32 index)
|
ic::BindName(VMFrame &f, uint32 index)
|
||||||
{
|
{
|
||||||
JSScript *script = f.fp()->getScript();
|
JSScript *script = f.fp()->script();
|
||||||
ic::PICInfo &pic = script->pics[index];
|
ic::PICInfo &pic = script->pics[index];
|
||||||
JSAtom *atom = pic.atom;
|
JSAtom *atom = pic.atom;
|
||||||
|
|
||||||
BindNameCompiler cc(f, script, f.fp()->getScopeChain(), pic, atom, SlowBindName);
|
BindNameCompiler cc(f, script, &f.fp()->scopeChain(), pic, atom, SlowBindName);
|
||||||
|
|
||||||
JSObject *obj = cc.update();
|
JSObject *obj = cc.update();
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
|
|
|
@ -125,8 +125,8 @@ Recompiler::recompile()
|
||||||
for (AllFramesIter i(cx); !i.done(); ++i) {
|
for (AllFramesIter i(cx); !i.done(); ++i) {
|
||||||
if (!firstFrame && i.fp()->maybeScript() == script)
|
if (!firstFrame && i.fp()->maybeScript() == script)
|
||||||
firstFrame = i.fp();
|
firstFrame = i.fp();
|
||||||
if (script->isValidJitCode(i.fp()->ncode)) {
|
if (script->isValidJitCode(i.fp()->nativeReturnAddress())) {
|
||||||
if (!toPatch.append(findPatch(&i.fp()->ncode)))
|
if (!toPatch.append(findPatch(i.fp()->addressOfNativeReturnAddress())))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ Recompiler::recompile()
|
||||||
/* If we get this far, the script is live, and we better be safe to re-jit. */
|
/* If we get this far, the script is live, and we better be safe to re-jit. */
|
||||||
JS_ASSERT(cx->compartment->debugMode);
|
JS_ASSERT(cx->compartment->debugMode);
|
||||||
|
|
||||||
Compiler c(cx, script, firstFrame->getFunction(), firstFrame->getScopeChain());
|
Compiler c(cx, script, firstFrame->fun(), &firstFrame->scopeChain());
|
||||||
if (c.Compile() != Compile_Okay)
|
if (c.Compile() != Compile_Okay)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,8 @@
|
||||||
#include "methodjit/Compiler.h"
|
#include "methodjit/Compiler.h"
|
||||||
#include "methodjit/StubCalls.h"
|
#include "methodjit/StubCalls.h"
|
||||||
#include "jstracer.h"
|
#include "jstracer.h"
|
||||||
|
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jspropertycache.h"
|
#include "jspropertycache.h"
|
||||||
#include "jspropertycacheinlines.h"
|
#include "jspropertycacheinlines.h"
|
||||||
#include "jsscopeinlines.h"
|
#include "jsscopeinlines.h"
|
||||||
|
@ -78,16 +80,16 @@ stubs::BindName(VMFrame &f)
|
||||||
PropertyCacheEntry *entry;
|
PropertyCacheEntry *entry;
|
||||||
|
|
||||||
/* Fast-path should have caught this. See comment in interpreter. */
|
/* Fast-path should have caught this. See comment in interpreter. */
|
||||||
JS_ASSERT(f.fp()->getScopeChain()->getParent());
|
JS_ASSERT(f.fp()->scopeChain().getParent());
|
||||||
|
|
||||||
JSAtom *atom;
|
JSAtom *atom;
|
||||||
JSObject *obj2;
|
JSObject *obj2;
|
||||||
JSContext *cx = f.cx;
|
JSContext *cx = f.cx;
|
||||||
JSObject *obj = f.fp()->getScopeChain();
|
JSObject *obj = &f.fp()->scopeChain();
|
||||||
JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom);
|
JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom);
|
||||||
if (atom) {
|
if (atom) {
|
||||||
jsid id = ATOM_TO_JSID(atom);
|
jsid id = ATOM_TO_JSID(atom);
|
||||||
obj = js_FindIdentifierBase(cx, f.fp()->getScopeChain(), id);
|
obj = js_FindIdentifierBase(cx, &f.fp()->scopeChain(), id);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
@ -98,7 +100,7 @@ stubs::BindName(VMFrame &f)
|
||||||
JSObject * JS_FASTCALL
|
JSObject * JS_FASTCALL
|
||||||
stubs::BindGlobalName(VMFrame &f)
|
stubs::BindGlobalName(VMFrame &f)
|
||||||
{
|
{
|
||||||
return f.fp()->getScopeChain()->getGlobal();
|
return f.fp()->scopeChain().getGlobal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
|
@ -353,7 +355,7 @@ NameOp(VMFrame &f, JSObject *obj, bool callname = false)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!prop) {
|
if (!prop) {
|
||||||
/* Kludge to allow (typeof foo == "undefined") tests. */
|
/* Kludge to allow (typeof foo == "undefined") tests. */
|
||||||
JSOp op2 = js_GetOpcode(cx, f.fp()->getScript(), f.regs.pc + JSOP_NAME_LENGTH);
|
JSOp op2 = js_GetOpcode(cx, f.fp()->script(), f.regs.pc + JSOP_NAME_LENGTH);
|
||||||
if (op2 == JSOP_TYPEOF) {
|
if (op2 == JSOP_TYPEOF) {
|
||||||
f.regs.sp++;
|
f.regs.sp++;
|
||||||
f.regs.sp[-1].setUndefined();
|
f.regs.sp[-1].setUndefined();
|
||||||
|
@ -401,14 +403,14 @@ NameOp(VMFrame &f, JSObject *obj, bool callname = false)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::Name(VMFrame &f)
|
stubs::Name(VMFrame &f)
|
||||||
{
|
{
|
||||||
if (!NameOp(f, f.fp()->getScopeChain()))
|
if (!NameOp(f, &f.fp()->scopeChain()))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::GetGlobalName(VMFrame &f)
|
stubs::GetGlobalName(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSObject *globalObj = f.fp()->getScopeChain()->getGlobal();
|
JSObject *globalObj = f.fp()->scopeChain().getGlobal();
|
||||||
if (!NameOp(f, globalObj))
|
if (!NameOp(f, globalObj))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
@ -507,7 +509,7 @@ stubs::GetElem(VMFrame &f)
|
||||||
if (arg < obj->getArgsInitialLength()) {
|
if (arg < obj->getArgsInitialLength()) {
|
||||||
JSStackFrame *afp = (JSStackFrame *) obj->getPrivate();
|
JSStackFrame *afp = (JSStackFrame *) obj->getPrivate();
|
||||||
if (afp) {
|
if (afp) {
|
||||||
copyFrom = &afp->argv[arg];
|
copyFrom = &afp->canonicalActualArg(arg);
|
||||||
goto end_getelem;
|
goto end_getelem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,7 +631,7 @@ stubs::SetElem(VMFrame &f)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::CallName(VMFrame &f)
|
stubs::CallName(VMFrame &f)
|
||||||
{
|
{
|
||||||
JSObject *obj = NameOp(f, f.fp()->getScopeChain(), true);
|
JSObject *obj = NameOp(f, &f.fp()->scopeChain(), true);
|
||||||
if (!obj)
|
if (!obj)
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
@ -843,7 +845,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
|
||||||
* FIXME: bug 476950, although debugger users may also demand some kind
|
* FIXME: bug 476950, although debugger users may also demand some kind
|
||||||
* of scope link for debugger-assisted eval-in-frame.
|
* of scope link for debugger-assisted eval-in-frame.
|
||||||
*/
|
*/
|
||||||
obj2 = fp->getScopeChain();
|
obj2 = &fp->scopeChain();
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(!FUN_FLAT_CLOSURE(fun));
|
JS_ASSERT(!FUN_FLAT_CLOSURE(fun));
|
||||||
|
|
||||||
|
@ -852,7 +854,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
|
||||||
* top-level function.
|
* top-level function.
|
||||||
*/
|
*/
|
||||||
if (!fp->hasBlockChain()) {
|
if (!fp->hasBlockChain()) {
|
||||||
obj2 = fp->getScopeChain();
|
obj2 = &fp->scopeChain();
|
||||||
} else {
|
} else {
|
||||||
obj2 = js_GetScopeChain(cx, fp);
|
obj2 = js_GetScopeChain(cx, fp);
|
||||||
if (!obj2)
|
if (!obj2)
|
||||||
|
@ -875,21 +877,11 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Protect obj from any GC hiding below JSObject::setProperty or
|
|
||||||
* JSObject::defineProperty. All paths from here must flow through the
|
|
||||||
* fp->scopeChain code below the parent->defineProperty call.
|
|
||||||
*/
|
|
||||||
MUST_FLOW_THROUGH("restore_scope");
|
|
||||||
fp->setScopeChain(obj);
|
|
||||||
|
|
||||||
Value rval = ObjectValue(*obj);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ECMA requires functions defined when entering Eval code to be
|
* ECMA requires functions defined when entering Eval code to be
|
||||||
* impermanent.
|
* impermanent.
|
||||||
*/
|
*/
|
||||||
uintN attrs = (fp->flags & JSFRAME_EVAL)
|
uintN attrs = fp->isEvalFrame()
|
||||||
? JSPROP_ENUMERATE
|
? JSPROP_ENUMERATE
|
||||||
: JSPROP_ENUMERATE | JSPROP_PERMANENT;
|
: JSPROP_ENUMERATE | JSPROP_PERMANENT;
|
||||||
|
|
||||||
|
@ -898,8 +890,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
|
||||||
* current scope chain even for the case of function expression statements
|
* current scope chain even for the case of function expression statements
|
||||||
* and functions defined by eval inside let or with blocks.
|
* and functions defined by eval inside let or with blocks.
|
||||||
*/
|
*/
|
||||||
JSObject *parent = fp->varobj(cx);
|
JSObject *parent = &fp->varobj(cx);
|
||||||
JS_ASSERT(parent);
|
|
||||||
|
|
||||||
uint32 old;
|
uint32 old;
|
||||||
bool doSet;
|
bool doSet;
|
||||||
|
@ -914,7 +905,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
|
||||||
JSObject *pobj;
|
JSObject *pobj;
|
||||||
JSBool ok = CheckRedeclaration(cx, parent, id, attrs, &pobj, &prop);
|
JSBool ok = CheckRedeclaration(cx, parent, id, attrs, &pobj, &prop);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
goto restore_scope;
|
THROW();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We deviate from 10.1.2 in ECMA 262 v3 and under eval use for function
|
* We deviate from 10.1.2 in ECMA 262 v3 and under eval use for function
|
||||||
|
@ -928,7 +919,7 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
|
||||||
* see bug 467495.
|
* see bug 467495.
|
||||||
*/
|
*/
|
||||||
doSet = (attrs == JSPROP_ENUMERATE);
|
doSet = (attrs == JSPROP_ENUMERATE);
|
||||||
JS_ASSERT_IF(doSet, fp->flags & JSFRAME_EVAL);
|
JS_ASSERT_IF(doSet, fp->isEvalFrame());
|
||||||
if (prop) {
|
if (prop) {
|
||||||
if (parent == pobj &&
|
if (parent == pobj &&
|
||||||
parent->isCall() &&
|
parent->isCall() &&
|
||||||
|
@ -945,13 +936,10 @@ stubs::DefFun(VMFrame &f, JSFunction *fun)
|
||||||
}
|
}
|
||||||
pobj->dropProperty(cx, prop);
|
pobj->dropProperty(cx, prop);
|
||||||
}
|
}
|
||||||
|
Value rval = ObjectValue(*obj);
|
||||||
ok = doSet
|
ok = doSet
|
||||||
? parent->setProperty(cx, id, &rval)
|
? parent->setProperty(cx, id, &rval)
|
||||||
: parent->defineProperty(cx, id, rval, PropertyStub, PropertyStub, attrs);
|
: parent->defineProperty(cx, id, rval, PropertyStub, PropertyStub, attrs);
|
||||||
|
|
||||||
restore_scope:
|
|
||||||
/* Restore fp->scopeChain now that obj is defined in fp->callobj. */
|
|
||||||
fp->setScopeChain(obj2);
|
|
||||||
if (!ok)
|
if (!ok)
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
@ -1325,7 +1313,7 @@ stubs::Debugger(VMFrame &f, jsbytecode *pc)
|
||||||
JSDebuggerHandler handler = f.cx->debugHooks->debuggerHandler;
|
JSDebuggerHandler handler = f.cx->debugHooks->debuggerHandler;
|
||||||
if (handler) {
|
if (handler) {
|
||||||
Value rval;
|
Value rval;
|
||||||
switch (handler(f.cx, f.cx->fp()->getScript(), pc, Jsvalify(&rval),
|
switch (handler(f.cx, f.cx->fp()->script(), pc, Jsvalify(&rval),
|
||||||
f.cx->debugHooks->debuggerHandlerData)) {
|
f.cx->debugHooks->debuggerHandlerData)) {
|
||||||
case JSTRAP_THROW:
|
case JSTRAP_THROW:
|
||||||
f.cx->throwing = JS_TRUE;
|
f.cx->throwing = JS_TRUE;
|
||||||
|
@ -1366,7 +1354,7 @@ stubs::Trap(VMFrame &f, jsbytecode *pc)
|
||||||
{
|
{
|
||||||
Value rval;
|
Value rval;
|
||||||
|
|
||||||
switch (JS_HandleTrap(f.cx, f.cx->fp()->getScript(), pc, Jsvalify(&rval))) {
|
switch (JS_HandleTrap(f.cx, f.cx->fp()->script(), pc, Jsvalify(&rval))) {
|
||||||
case JSTRAP_THROW:
|
case JSTRAP_THROW:
|
||||||
f.cx->throwing = JS_TRUE;
|
f.cx->throwing = JS_TRUE;
|
||||||
f.cx->exception = rval;
|
f.cx->exception = rval;
|
||||||
|
@ -1396,15 +1384,16 @@ stubs::Trap(VMFrame &f, jsbytecode *pc)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::This(VMFrame &f)
|
stubs::This(VMFrame &f)
|
||||||
{
|
{
|
||||||
if (!f.fp()->getThisObject(f.cx))
|
JSObject *obj = f.fp()->computeThisObject(f.cx);
|
||||||
|
if (!obj)
|
||||||
THROW();
|
THROW();
|
||||||
f.regs.sp[-1] = f.fp()->getThisValue();
|
f.regs.sp[-1].setObject(*obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::ComputeThis(VMFrame &f)
|
stubs::ComputeThis(VMFrame &f)
|
||||||
{
|
{
|
||||||
if (!f.fp()->getThisObject(f.cx))
|
if (!f.fp()->computeThisObject(f.cx))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1488,7 +1477,7 @@ void JS_FASTCALL
|
||||||
stubs::GetUpvar(VMFrame &f, uint32 ck)
|
stubs::GetUpvar(VMFrame &f, uint32 ck)
|
||||||
{
|
{
|
||||||
/* :FIXME: We can do better, this stub isn't needed. */
|
/* :FIXME: We can do better, this stub isn't needed. */
|
||||||
uint32 staticLevel = f.fp()->getScript()->staticLevel;
|
uint32 staticLevel = f.fp()->script()->staticLevel;
|
||||||
UpvarCookie cookie;
|
UpvarCookie cookie;
|
||||||
cookie.fromInteger(ck);
|
cookie.fromInteger(ck);
|
||||||
f.regs.sp[0] = GetUpvar(f.cx, staticLevel, cookie);
|
f.regs.sp[0] = GetUpvar(f.cx, staticLevel, cookie);
|
||||||
|
@ -1509,7 +1498,7 @@ stubs::DefLocalFun(VMFrame &f, JSFunction *fun)
|
||||||
JSObject *obj = FUN_OBJECT(fun);
|
JSObject *obj = FUN_OBJECT(fun);
|
||||||
|
|
||||||
if (FUN_NULL_CLOSURE(fun)) {
|
if (FUN_NULL_CLOSURE(fun)) {
|
||||||
obj = CloneFunctionObject(f.cx, fun, f.fp()->getScopeChain());
|
obj = CloneFunctionObject(f.cx, fun, &f.fp()->scopeChain());
|
||||||
if (!obj)
|
if (!obj)
|
||||||
THROWV(NULL);
|
THROWV(NULL);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1544,11 +1533,11 @@ stubs::RegExp(VMFrame &f, JSObject *regex)
|
||||||
* bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was
|
* bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was
|
||||||
* flouted by many browser-based implementations.
|
* flouted by many browser-based implementations.
|
||||||
*
|
*
|
||||||
* We avoid the js_GetScopeChain call here and pass fp->getScopeChain() as
|
* We avoid the js_GetScopeChain call here and pass fp->scopeChain() as
|
||||||
* js_GetClassPrototype uses the latter only to locate the global.
|
* js_GetClassPrototype uses the latter only to locate the global.
|
||||||
*/
|
*/
|
||||||
JSObject *proto;
|
JSObject *proto;
|
||||||
if (!js_GetClassPrototype(f.cx, f.fp()->getScopeChain(), JSProto_RegExp, &proto))
|
if (!js_GetClassPrototype(f.cx, &f.fp()->scopeChain(), JSProto_RegExp, &proto))
|
||||||
THROWV(NULL);
|
THROWV(NULL);
|
||||||
JS_ASSERT(proto);
|
JS_ASSERT(proto);
|
||||||
JSObject *obj = js_CloneRegExpObject(f.cx, regex, proto);
|
JSObject *obj = js_CloneRegExpObject(f.cx, regex, proto);
|
||||||
|
@ -1561,8 +1550,8 @@ JSObject * JS_FASTCALL
|
||||||
stubs::LambdaForInit(VMFrame &f, JSFunction *fun)
|
stubs::LambdaForInit(VMFrame &f, JSFunction *fun)
|
||||||
{
|
{
|
||||||
JSObject *obj = FUN_OBJECT(fun);
|
JSObject *obj = FUN_OBJECT(fun);
|
||||||
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == f.fp()->getScopeChain()) {
|
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
|
||||||
fun->setMethodAtom(f.fp()->getScript()->getAtom(GET_SLOTNO(f.regs.pc + JSOP_LAMBDA_LENGTH)));
|
fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(f.regs.pc + JSOP_LAMBDA_LENGTH)));
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
return Lambda(f, fun);
|
return Lambda(f, fun);
|
||||||
|
@ -1572,10 +1561,10 @@ JSObject * JS_FASTCALL
|
||||||
stubs::LambdaForSet(VMFrame &f, JSFunction *fun)
|
stubs::LambdaForSet(VMFrame &f, JSFunction *fun)
|
||||||
{
|
{
|
||||||
JSObject *obj = FUN_OBJECT(fun);
|
JSObject *obj = FUN_OBJECT(fun);
|
||||||
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == f.fp()->getScopeChain()) {
|
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
|
||||||
const Value &lref = f.regs.sp[-1];
|
const Value &lref = f.regs.sp[-1];
|
||||||
if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) {
|
if (lref.isObject() && lref.toObject().canHaveMethodBarrier()) {
|
||||||
fun->setMethodAtom(f.fp()->getScript()->getAtom(GET_SLOTNO(f.regs.pc + JSOP_LAMBDA_LENGTH)));
|
fun->setMethodAtom(f.fp()->script()->getAtom(GET_SLOTNO(f.regs.pc + JSOP_LAMBDA_LENGTH)));
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1586,7 +1575,7 @@ JSObject * JS_FASTCALL
|
||||||
stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *fun)
|
stubs::LambdaJoinableForCall(VMFrame &f, JSFunction *fun)
|
||||||
{
|
{
|
||||||
JSObject *obj = FUN_OBJECT(fun);
|
JSObject *obj = FUN_OBJECT(fun);
|
||||||
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == f.fp()->getScopeChain()) {
|
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
|
||||||
/*
|
/*
|
||||||
* Array.prototype.sort and String.prototype.replace are
|
* Array.prototype.sort and String.prototype.replace are
|
||||||
* optimized as if they are special form. We know that they
|
* optimized as if they are special form. We know that they
|
||||||
|
@ -1623,7 +1612,7 @@ JSObject * JS_FASTCALL
|
||||||
stubs::LambdaJoinableForNull(VMFrame &f, JSFunction *fun)
|
stubs::LambdaJoinableForNull(VMFrame &f, JSFunction *fun)
|
||||||
{
|
{
|
||||||
JSObject *obj = FUN_OBJECT(fun);
|
JSObject *obj = FUN_OBJECT(fun);
|
||||||
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == f.fp()->getScopeChain()) {
|
if (FUN_NULL_CLOSURE(fun) && obj->getParent() == &f.fp()->scopeChain()) {
|
||||||
jsbytecode *pc2 = f.regs.pc + JSOP_LAMBDA_LENGTH + JSOP_NULL_LENGTH;
|
jsbytecode *pc2 = f.regs.pc + JSOP_LAMBDA_LENGTH + JSOP_NULL_LENGTH;
|
||||||
JSOp op2 = JSOp(*pc2);
|
JSOp op2 = JSOp(*pc2);
|
||||||
|
|
||||||
|
@ -1640,7 +1629,7 @@ stubs::Lambda(VMFrame &f, JSFunction *fun)
|
||||||
|
|
||||||
JSObject *parent;
|
JSObject *parent;
|
||||||
if (FUN_NULL_CLOSURE(fun)) {
|
if (FUN_NULL_CLOSURE(fun)) {
|
||||||
parent = f.fp()->getScopeChain();
|
parent = &f.fp()->scopeChain();
|
||||||
} else {
|
} else {
|
||||||
parent = js_GetScopeChain(f.cx, f.fp());
|
parent = js_GetScopeChain(f.cx, f.fp());
|
||||||
if (!parent)
|
if (!parent)
|
||||||
|
@ -1680,9 +1669,9 @@ ObjIncOp(VMFrame &f, JSObject *obj, jsid id)
|
||||||
ref.getInt32Ref() = tmp + N;
|
ref.getInt32Ref() = tmp + N;
|
||||||
else
|
else
|
||||||
ref.getInt32Ref() = tmp += N;
|
ref.getInt32Ref() = tmp += N;
|
||||||
fp->flags |= JSFRAME_ASSIGNING;
|
fp->setAssigning();
|
||||||
JSBool ok = obj->setProperty(cx, id, &ref);
|
JSBool ok = obj->setProperty(cx, id, &ref);
|
||||||
fp->flags &= ~JSFRAME_ASSIGNING;
|
fp->clearAssigning();
|
||||||
if (!ok)
|
if (!ok)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1704,9 +1693,9 @@ ObjIncOp(VMFrame &f, JSObject *obj, jsid id)
|
||||||
ref.setDouble(d);
|
ref.setDouble(d);
|
||||||
}
|
}
|
||||||
v.setDouble(d);
|
v.setDouble(d);
|
||||||
fp->flags |= JSFRAME_ASSIGNING;
|
fp->setAssigning();
|
||||||
JSBool ok = obj->setProperty(cx, id, &v);
|
JSBool ok = obj->setProperty(cx, id, &v);
|
||||||
fp->flags &= ~JSFRAME_ASSIGNING;
|
fp->clearAssigning();
|
||||||
if (!ok)
|
if (!ok)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1857,7 +1846,7 @@ stubs::DecElem(VMFrame &f)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::NameInc(VMFrame &f, JSAtom *atom)
|
stubs::NameInc(VMFrame &f, JSAtom *atom)
|
||||||
{
|
{
|
||||||
JSObject *obj = f.fp()->getScopeChain();
|
JSObject *obj = &f.fp()->scopeChain();
|
||||||
if (!NameIncDec<1, true>(f, obj, atom))
|
if (!NameIncDec<1, true>(f, obj, atom))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
@ -1865,7 +1854,7 @@ stubs::NameInc(VMFrame &f, JSAtom *atom)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::NameDec(VMFrame &f, JSAtom *atom)
|
stubs::NameDec(VMFrame &f, JSAtom *atom)
|
||||||
{
|
{
|
||||||
JSObject *obj = f.fp()->getScopeChain();
|
JSObject *obj = &f.fp()->scopeChain();
|
||||||
if (!NameIncDec<-1, true>(f, obj, atom))
|
if (!NameIncDec<-1, true>(f, obj, atom))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
@ -1873,7 +1862,7 @@ stubs::NameDec(VMFrame &f, JSAtom *atom)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::IncName(VMFrame &f, JSAtom *atom)
|
stubs::IncName(VMFrame &f, JSAtom *atom)
|
||||||
{
|
{
|
||||||
JSObject *obj = f.fp()->getScopeChain();
|
JSObject *obj = &f.fp()->scopeChain();
|
||||||
if (!NameIncDec<1, false>(f, obj, atom))
|
if (!NameIncDec<1, false>(f, obj, atom))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
@ -1881,7 +1870,7 @@ stubs::IncName(VMFrame &f, JSAtom *atom)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::DecName(VMFrame &f, JSAtom *atom)
|
stubs::DecName(VMFrame &f, JSAtom *atom)
|
||||||
{
|
{
|
||||||
JSObject *obj = f.fp()->getScopeChain();
|
JSObject *obj = &f.fp()->scopeChain();
|
||||||
if (!NameIncDec<-1, false>(f, obj, atom))
|
if (!NameIncDec<-1, false>(f, obj, atom))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
@ -1889,7 +1878,7 @@ stubs::DecName(VMFrame &f, JSAtom *atom)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::GlobalNameInc(VMFrame &f, JSAtom *atom)
|
stubs::GlobalNameInc(VMFrame &f, JSAtom *atom)
|
||||||
{
|
{
|
||||||
JSObject *obj = f.fp()->getScopeChain()->getGlobal();
|
JSObject *obj = f.fp()->scopeChain().getGlobal();
|
||||||
if (!NameIncDec<1, true>(f, obj, atom))
|
if (!NameIncDec<1, true>(f, obj, atom))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
@ -1897,7 +1886,7 @@ stubs::GlobalNameInc(VMFrame &f, JSAtom *atom)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::GlobalNameDec(VMFrame &f, JSAtom *atom)
|
stubs::GlobalNameDec(VMFrame &f, JSAtom *atom)
|
||||||
{
|
{
|
||||||
JSObject *obj = f.fp()->getScopeChain()->getGlobal();
|
JSObject *obj = f.fp()->scopeChain().getGlobal();
|
||||||
if (!NameIncDec<-1, true>(f, obj, atom))
|
if (!NameIncDec<-1, true>(f, obj, atom))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
@ -1905,7 +1894,7 @@ stubs::GlobalNameDec(VMFrame &f, JSAtom *atom)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::IncGlobalName(VMFrame &f, JSAtom *atom)
|
stubs::IncGlobalName(VMFrame &f, JSAtom *atom)
|
||||||
{
|
{
|
||||||
JSObject *obj = f.fp()->getScopeChain()->getGlobal();
|
JSObject *obj = f.fp()->scopeChain().getGlobal();
|
||||||
if (!NameIncDec<1, false>(f, obj, atom))
|
if (!NameIncDec<1, false>(f, obj, atom))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
@ -1913,7 +1902,7 @@ stubs::IncGlobalName(VMFrame &f, JSAtom *atom)
|
||||||
void JS_FASTCALL
|
void JS_FASTCALL
|
||||||
stubs::DecGlobalName(VMFrame &f, JSAtom *atom)
|
stubs::DecGlobalName(VMFrame &f, JSAtom *atom)
|
||||||
{
|
{
|
||||||
JSObject *obj = f.fp()->getScopeChain()->getGlobal();
|
JSObject *obj = f.fp()->scopeChain().getGlobal();
|
||||||
if (!NameIncDec<-1, false>(f, obj, atom))
|
if (!NameIncDec<-1, false>(f, obj, atom))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
@ -1953,7 +1942,7 @@ InlineGetProp(VMFrame &f)
|
||||||
JS_ASSERT(entry->vword.isShape());
|
JS_ASSERT(entry->vword.isShape());
|
||||||
const Shape *shape = entry->vword.toShape();
|
const Shape *shape = entry->vword.toShape();
|
||||||
NATIVE_GET(cx, obj, obj2, shape,
|
NATIVE_GET(cx, obj, obj2, shape,
|
||||||
f.fp()->hasIMacroPC() ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER,
|
f.fp()->hasImacropc() ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER,
|
||||||
&rval, return false);
|
&rval, return false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1962,7 +1951,7 @@ InlineGetProp(VMFrame &f)
|
||||||
jsid id = ATOM_TO_JSID(atom);
|
jsid id = ATOM_TO_JSID(atom);
|
||||||
if (JS_LIKELY(!aobj->getOps()->getProperty)
|
if (JS_LIKELY(!aobj->getOps()->getProperty)
|
||||||
? !js_GetPropertyHelper(cx, obj, id,
|
? !js_GetPropertyHelper(cx, obj, id,
|
||||||
f.fp()->hasIMacroPC()
|
f.fp()->hasImacropc()
|
||||||
? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
|
? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
|
||||||
: JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
|
: JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
|
||||||
&rval)
|
&rval)
|
||||||
|
@ -2386,7 +2375,7 @@ stubs::EnterBlock(VMFrame &f, JSObject *obj)
|
||||||
JS_ASSERT(fp->base() + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp);
|
JS_ASSERT(fp->base() + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp);
|
||||||
Value *vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj);
|
Value *vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj);
|
||||||
JS_ASSERT(regs.sp < vp);
|
JS_ASSERT(regs.sp < vp);
|
||||||
JS_ASSERT(vp <= fp->slots() + fp->getScript()->nslots);
|
JS_ASSERT(vp <= fp->slots() + fp->script()->nslots);
|
||||||
SetValueRangeToUndefined(regs.sp, vp);
|
SetValueRangeToUndefined(regs.sp, vp);
|
||||||
regs.sp = vp;
|
regs.sp = vp;
|
||||||
|
|
||||||
|
@ -2395,13 +2384,13 @@ stubs::EnterBlock(VMFrame &f, JSObject *obj)
|
||||||
JS_ASSERT(fp->maybeBlockChain() == obj->getParent());
|
JS_ASSERT(fp->maybeBlockChain() == obj->getParent());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The young end of fp->getScopeChain() may omit blocks if we haven't closed
|
* The young end of fp->scopeChain() may omit blocks if we haven't closed
|
||||||
* over them, but if there are any closure blocks on fp->getScopeChain(), they'd
|
* over them, but if there are any closure blocks on fp->scopeChain(), they'd
|
||||||
* better be (clones of) ancestors of the block we're entering now;
|
* better be (clones of) ancestors of the block we're entering now;
|
||||||
* anything else we should have popped off fp->getScopeChain() when we left its
|
* anything else we should have popped off fp->scopeChain() when we left its
|
||||||
* static scope.
|
* static scope.
|
||||||
*/
|
*/
|
||||||
JSObject *obj2 = fp->getScopeChain();
|
JSObject *obj2 = &fp->scopeChain();
|
||||||
Class *clasp;
|
Class *clasp;
|
||||||
while ((clasp = obj2->getClass()) == &js_WithClass)
|
while ((clasp = obj2->getClass()) == &js_WithClass)
|
||||||
obj2 = obj2->getParent();
|
obj2 = obj2->getParent();
|
||||||
|
@ -2425,32 +2414,32 @@ stubs::LeaveBlock(VMFrame &f)
|
||||||
JSStackFrame *fp = f.fp();
|
JSStackFrame *fp = f.fp();
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
JS_ASSERT(fp->getBlockChain()->getClass() == &js_BlockClass);
|
JS_ASSERT(fp->blockChain()->getClass() == &js_BlockClass);
|
||||||
uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->getBlockChain());
|
uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->blockChain());
|
||||||
|
|
||||||
JS_ASSERT(blockDepth <= StackDepth(fp->getScript()));
|
JS_ASSERT(blockDepth <= StackDepth(fp->script()));
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
* If we're about to leave the dynamic scope of a block that has been
|
* If we're about to leave the dynamic scope of a block that has been
|
||||||
* cloned onto fp->getScopeChain(), clear its private data, move its locals from
|
* cloned onto fp->scopeChain(), clear its private data, move its locals from
|
||||||
* the stack into the clone, and pop it off the chain.
|
* the stack into the clone, and pop it off the chain.
|
||||||
*/
|
*/
|
||||||
JSObject *obj = fp->getScopeChain();
|
JSObject *obj = &fp->scopeChain();
|
||||||
if (obj->getProto() == fp->getBlockChain()) {
|
if (obj->getProto() == fp->blockChain()) {
|
||||||
JS_ASSERT(obj->getClass() == &js_BlockClass);
|
JS_ASSERT(obj->getClass() == &js_BlockClass);
|
||||||
if (!js_PutBlockObject(cx, JS_TRUE))
|
if (!js_PutBlockObject(cx, JS_TRUE))
|
||||||
THROW();
|
THROW();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pop the block chain, too. */
|
/* Pop the block chain, too. */
|
||||||
fp->setBlockChain(fp->getBlockChain()->getParent());
|
fp->setBlockChain(fp->blockChain()->getParent());
|
||||||
}
|
}
|
||||||
|
|
||||||
void * JS_FASTCALL
|
void * JS_FASTCALL
|
||||||
stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
|
stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
|
||||||
{
|
{
|
||||||
jsbytecode *jpc = pc;
|
jsbytecode *jpc = pc;
|
||||||
JSScript *script = f.fp()->getScript();
|
JSScript *script = f.fp()->script();
|
||||||
|
|
||||||
/* This is correct because the compiler adjusts the stack beforehand. */
|
/* This is correct because the compiler adjusts the stack beforehand. */
|
||||||
Value lval = f.regs.sp[-1];
|
Value lval = f.regs.sp[-1];
|
||||||
|
@ -2519,7 +2508,7 @@ stubs::TableSwitch(VMFrame &f, jsbytecode *origPc)
|
||||||
{
|
{
|
||||||
jsbytecode * const originalPC = origPc;
|
jsbytecode * const originalPC = origPc;
|
||||||
jsbytecode *pc = originalPC;
|
jsbytecode *pc = originalPC;
|
||||||
JSScript *script = f.fp()->getScript();
|
JSScript *script = f.fp()->script();
|
||||||
uint32 jumpOffset = GET_JUMP_OFFSET(pc);
|
uint32 jumpOffset = GET_JUMP_OFFSET(pc);
|
||||||
pc += JUMP_OFFSET_LEN;
|
pc += JUMP_OFFSET_LEN;
|
||||||
|
|
||||||
|
|
|
@ -59,9 +59,9 @@ void JS_FASTCALL InitElem(VMFrame &f, uint32 last);
|
||||||
void JS_FASTCALL InitProp(VMFrame &f, JSAtom *atom);
|
void JS_FASTCALL InitProp(VMFrame &f, JSAtom *atom);
|
||||||
void JS_FASTCALL InitMethod(VMFrame &f, JSAtom *atom);
|
void JS_FASTCALL InitMethod(VMFrame &f, JSAtom *atom);
|
||||||
|
|
||||||
void JS_FASTCALL CheckStackQuota(VMFrame &f);
|
void JS_FASTCALL HitStackQuota(VMFrame &f);
|
||||||
void * JS_FASTCALL CheckArity(VMFrame &f);
|
void * JS_FASTCALL FixupArity(VMFrame &f, uint32 argc);
|
||||||
void * JS_FASTCALL CompileFunction(VMFrame &f);
|
void * JS_FASTCALL CompileFunction(VMFrame &f, uint32 argc);
|
||||||
void JS_FASTCALL SlowNew(VMFrame &f, uint32 argc);
|
void JS_FASTCALL SlowNew(VMFrame &f, uint32 argc);
|
||||||
void JS_FASTCALL SlowCall(VMFrame &f, uint32 argc);
|
void JS_FASTCALL SlowCall(VMFrame &f, uint32 argc);
|
||||||
void * JS_FASTCALL UncachedNew(VMFrame &f, uint32 argc);
|
void * JS_FASTCALL UncachedNew(VMFrame &f, uint32 argc);
|
||||||
|
@ -70,7 +70,7 @@ void * JS_FASTCALL UncachedCall(VMFrame &f, uint32 argc);
|
||||||
JSBool JS_FASTCALL NewObject(VMFrame &f, uint32 argc);
|
JSBool JS_FASTCALL NewObject(VMFrame &f, uint32 argc);
|
||||||
void JS_FASTCALL Throw(VMFrame &f);
|
void JS_FASTCALL Throw(VMFrame &f);
|
||||||
void JS_FASTCALL PutCallObject(VMFrame &f);
|
void JS_FASTCALL PutCallObject(VMFrame &f);
|
||||||
void JS_FASTCALL PutArgsObject(VMFrame &f);
|
void JS_FASTCALL PutActivationObjects(VMFrame &f);
|
||||||
void JS_FASTCALL GetCallObject(VMFrame &f);
|
void JS_FASTCALL GetCallObject(VMFrame &f);
|
||||||
void JS_FASTCALL WrapPrimitiveThis(VMFrame &f);
|
void JS_FASTCALL WrapPrimitiveThis(VMFrame &f);
|
||||||
#if JS_MONOIC
|
#if JS_MONOIC
|
||||||
|
|
|
@ -117,28 +117,21 @@ TrampolineCompiler::compileTrampoline(void **where, JSC::ExecutablePool **pool,
|
||||||
bool
|
bool
|
||||||
TrampolineCompiler::generateForceReturn(Assembler &masm)
|
TrampolineCompiler::generateForceReturn(Assembler &masm)
|
||||||
{
|
{
|
||||||
/* if (!callobj) stubs::PutCallObject */
|
/* if (hasArgsObj() || hasCallObj()) stubs::PutActivationObjects() */
|
||||||
Jump noCallObj = masm.branchPtr(Assembler::Equal,
|
Jump noActObjs = masm.branchTest32(Assembler::Zero,
|
||||||
Address(JSFrameReg, JSStackFrame::offsetCallObj()),
|
Address(JSFrameReg, JSStackFrame::offsetOfFlags()),
|
||||||
ImmPtr(0));
|
Imm32(JSFRAME_HAS_CALL_OBJ | JSFRAME_HAS_ARGS_OBJ));
|
||||||
masm.stubCall(stubs::PutCallObject, NULL, 0);
|
masm.stubCall(stubs::PutActivationObjects, NULL, 0);
|
||||||
noCallObj.linkTo(masm.label(), &masm);
|
noActObjs.linkTo(masm.label(), &masm);
|
||||||
|
|
||||||
/* if (arguments) stubs::PutArgsObject */
|
|
||||||
Jump noArgsObj = masm.branchPtr(Assembler::Equal,
|
|
||||||
Address(JSFrameReg, JSStackFrame::offsetArgsObj()),
|
|
||||||
ImmIntPtr(0));
|
|
||||||
masm.stubCall(stubs::PutArgsObject, NULL, 0);
|
|
||||||
noArgsObj.linkTo(masm.label(), &masm);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* r = fp->down
|
* r = fp->prev
|
||||||
* f.fp = r
|
* f.fp = r
|
||||||
*/
|
*/
|
||||||
masm.loadPtr(Address(JSFrameReg, offsetof(JSStackFrame, down)), Registers::ReturnReg);
|
masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfPrev()), Registers::ReturnReg);
|
||||||
masm.storePtr(Registers::ReturnReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
masm.storePtr(Registers::ReturnReg, FrameAddress(offsetof(VMFrame, regs.fp)));
|
||||||
|
|
||||||
Address rval(JSFrameReg, JSStackFrame::offsetReturnValue());
|
Address rval(JSFrameReg, JSStackFrame::offsetOfReturnValue());
|
||||||
masm.loadPayload(rval, JSReturnReg_Data);
|
masm.loadPayload(rval, JSReturnReg_Data);
|
||||||
masm.loadTypeTag(rval, JSReturnReg_Type);
|
masm.loadTypeTag(rval, JSReturnReg_Type);
|
||||||
|
|
||||||
|
@ -146,8 +139,8 @@ TrampolineCompiler::generateForceReturn(Assembler &masm)
|
||||||
|
|
||||||
masm.move(Registers::ReturnReg, JSFrameReg);
|
masm.move(Registers::ReturnReg, JSFrameReg);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
masm.storePtr(ImmPtr(JSStackFrame::sInvalidPC),
|
masm.storePtr(ImmPtr(JSStackFrame::sInvalidpc),
|
||||||
Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
|
Address(JSFrameReg, JSStackFrame::offsetOfSavedpc()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
masm.ret();
|
masm.ret();
|
||||||
|
|
|
@ -154,7 +154,7 @@ JaegerThrowpoline ENDP
|
||||||
SafePointTrampoline PROC FRAME
|
SafePointTrampoline PROC FRAME
|
||||||
.ENDPROLOG
|
.ENDPROLOG
|
||||||
pop rax
|
pop rax
|
||||||
mov qword ptr [rbx+60h], rax
|
mov qword ptr [rbx+50h], rax ; fp->ncode_
|
||||||
jmp qword ptr [rsp+8]
|
jmp qword ptr [rsp+8]
|
||||||
SafePointTrampoline ENDP
|
SafePointTrampoline ENDP
|
||||||
|
|
||||||
|
@ -162,8 +162,8 @@ SafePointTrampoline ENDP
|
||||||
; void InjectJaegerReturn();
|
; void InjectJaegerReturn();
|
||||||
InjectJaegerReturn PROC FRAME
|
InjectJaegerReturn PROC FRAME
|
||||||
.ENDPROLOG
|
.ENDPROLOG
|
||||||
mov rcx, qword ptr [rbx+40h] ; load value into typeReg
|
mov rcx, qword ptr [rbx+30h] ; load fp->rval_ into typeReg
|
||||||
mov rax, qword ptr [rbx+60h] ; fp->ncode
|
mov rax, qword ptr [rbx+50h] ; fp->ncode_
|
||||||
|
|
||||||
; Reimplementation of PunboxAssembler::loadValueAsComponents()
|
; Reimplementation of PunboxAssembler::loadValueAsComponents()
|
||||||
mov rdx, r14
|
mov rdx, r14
|
||||||
|
|
|
@ -121,9 +121,9 @@ throwpoline_exit:
|
||||||
.global InjectJaegerReturn
|
.global InjectJaegerReturn
|
||||||
.type InjectJaegerReturn, @function
|
.type InjectJaegerReturn, @function
|
||||||
InjectJaegerReturn:
|
InjectJaegerReturn:
|
||||||
movl 0x24(%ebx), %edx /* fp->rval data */
|
movl 0x18(%ebx), %edx /* fp->rval_ data */
|
||||||
movl 0x28(%ebx), %ecx /* fp->rval type */
|
movl 0x1C(%ebx), %ecx /* fp->rval_ type */
|
||||||
movl 0x38(%ebx), %eax /* fp->ncode */
|
movl 0x2c(%ebx), %eax /* fp->ncode_ */
|
||||||
/* For Sun Studio there is no fast call. */
|
/* For Sun Studio there is no fast call. */
|
||||||
/* We add the stack by 8 before. */
|
/* We add the stack by 8 before. */
|
||||||
addl $0x8, %esp
|
addl $0x8, %esp
|
||||||
|
@ -141,6 +141,6 @@ InjectJaegerReturn:
|
||||||
.type SafePointTrampoline, @function
|
.type SafePointTrampoline, @function
|
||||||
SafePointTrampoline:
|
SafePointTrampoline:
|
||||||
popl %eax
|
popl %eax
|
||||||
movl %eax, 0x38(%ebx)
|
movl %eax, 0x2c(%ebx)
|
||||||
jmp *24(%ebp)
|
jmp *24(%ebp)
|
||||||
.size SafePointTrampoline, . - SafePointTrampoline
|
.size SafePointTrampoline, . - SafePointTrampoline
|
||||||
|
|
|
@ -92,6 +92,7 @@
|
||||||
|
|
||||||
#include "jsworkers.h"
|
#include "jsworkers.h"
|
||||||
|
|
||||||
|
#include "jsinterpinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
#include "jsscriptinlines.h"
|
#include "jsscriptinlines.h"
|
||||||
|
|
||||||
|
@ -1172,7 +1173,7 @@ AssertJit(JSContext *cx, uintN argc, jsval *vp)
|
||||||
{
|
{
|
||||||
#ifdef JS_METHODJIT
|
#ifdef JS_METHODJIT
|
||||||
if (JS_GetOptions(cx) & JSOPTION_METHODJIT) {
|
if (JS_GetOptions(cx) & JSOPTION_METHODJIT) {
|
||||||
if (cx->fp()->getScript()->nmap == NULL) {
|
if (cx->fp()->script()->nmap == NULL) {
|
||||||
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_ASSERT_JIT_FAILED);
|
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_ASSERT_JIT_FAILED);
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1459,7 +1460,7 @@ ValueToScript(JSContext *cx, jsval v)
|
||||||
script = (JSScript *) JS_GetPrivate(cx, obj);
|
script = (JSScript *) JS_GetPrivate(cx, obj);
|
||||||
} else if (clasp == Jsvalify(&js_GeneratorClass)) {
|
} else if (clasp == Jsvalify(&js_GeneratorClass)) {
|
||||||
JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj);
|
JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj);
|
||||||
fun = gen->getFloatingFrame()->getFunction();
|
fun = gen->floatingFrame()->fun();
|
||||||
script = FUN_SCRIPT(fun);
|
script = FUN_SCRIPT(fun);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1501,7 +1502,7 @@ GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp,
|
||||||
uintN intarg;
|
uintN intarg;
|
||||||
JSScript *script;
|
JSScript *script;
|
||||||
|
|
||||||
*scriptp = JS_GetScriptedCaller(cx, NULL)->getScript();
|
*scriptp = JS_GetScriptedCaller(cx, NULL)->script();
|
||||||
*ip = 0;
|
*ip = 0;
|
||||||
if (argc != 0) {
|
if (argc != 0) {
|
||||||
v = argv[0];
|
v = argv[0];
|
||||||
|
@ -1531,8 +1532,8 @@ TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
|
||||||
JSStackFrame *caller = JS_GetScriptedCaller(cx, NULL);
|
JSStackFrame *caller = JS_GetScriptedCaller(cx, NULL);
|
||||||
if (!JS_EvaluateUCInStackFrame(cx, caller,
|
if (!JS_EvaluateUCInStackFrame(cx, caller,
|
||||||
JS_GetStringChars(str), JS_GetStringLength(str),
|
JS_GetStringChars(str), JS_GetStringLength(str),
|
||||||
caller->getScript()->filename,
|
caller->script()->filename,
|
||||||
caller->getScript()->lineno,
|
caller->script()->lineno,
|
||||||
rval)) {
|
rval)) {
|
||||||
return JSTRAP_ERROR;
|
return JSTRAP_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -1634,7 +1635,7 @@ LineToPC(JSContext *cx, uintN argc, jsval *vp)
|
||||||
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE);
|
JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_LINE2PC_USAGE);
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
script = JS_GetScriptedCaller(cx, NULL)->getScript();
|
script = JS_GetScriptedCaller(cx, NULL)->script();
|
||||||
if (!GetTrapArgs(cx, argc, JS_ARGV(cx, vp), &script, &i))
|
if (!GetTrapArgs(cx, argc, JS_ARGV(cx, vp), &script, &i))
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
lineno = (i == 0) ? script->lineno : (uintN)i;
|
lineno = (i == 0) ? script->lineno : (uintN)i;
|
||||||
|
@ -3203,8 +3204,8 @@ EvalInContext(JSContext *cx, uintN argc, jsval *vp)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!JS_EvaluateUCScript(cx, sobj, src, srclen,
|
if (!JS_EvaluateUCScript(cx, sobj, src, srclen,
|
||||||
fp->getScript()->filename,
|
fp->script()->filename,
|
||||||
JS_PCToLineNumber(cx, fp->getScript(), fp->pc(cx)),
|
JS_PCToLineNumber(cx, fp->script(), fp->pc(cx)),
|
||||||
vp)) {
|
vp)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3234,12 +3235,12 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
|
||||||
FrameRegsIter fi(cx);
|
FrameRegsIter fi(cx);
|
||||||
for (uint32 i = 0; i < upCount; ++i, ++fi) {
|
for (uint32 i = 0; i < upCount; ++i, ++fi) {
|
||||||
if (!fi.fp()->down)
|
if (!fi.fp()->prev())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSStackFrame *const fp = fi.fp();
|
JSStackFrame *const fp = fi.fp();
|
||||||
if (!fp->hasScript()) {
|
if (!JS_IsScriptFrame(cx, fp)) {
|
||||||
JS_ReportError(cx, "cannot eval in non-script frame");
|
JS_ReportError(cx, "cannot eval in non-script frame");
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -3249,8 +3250,8 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
|
||||||
oldfp = JS_SaveFrameChain(cx);
|
oldfp = JS_SaveFrameChain(cx);
|
||||||
|
|
||||||
JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, str->chars(), str->length(),
|
JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, str->chars(), str->length(),
|
||||||
fp->getScript()->filename,
|
fp->script()->filename,
|
||||||
JS_PCToLineNumber(cx, fp->getScript(),
|
JS_PCToLineNumber(cx, fp->script(),
|
||||||
fi.pc()),
|
fi.pc()),
|
||||||
vp);
|
vp);
|
||||||
|
|
||||||
|
@ -3975,9 +3976,9 @@ Snarf(JSContext *cx, uintN argc, jsval *vp)
|
||||||
|
|
||||||
/* Get the currently executing script's name. */
|
/* Get the currently executing script's name. */
|
||||||
fp = JS_GetScriptedCaller(cx, NULL);
|
fp = JS_GetScriptedCaller(cx, NULL);
|
||||||
JS_ASSERT(fp && fp->getScript()->filename);
|
JS_ASSERT(fp && fp->script()->filename);
|
||||||
#ifdef XP_UNIX
|
#ifdef XP_UNIX
|
||||||
pathname = MakeAbsolutePathname(cx, fp->getScript()->filename, filename);
|
pathname = MakeAbsolutePathname(cx, fp->script()->filename, filename);
|
||||||
if (!pathname)
|
if (!pathname)
|
||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
var o = {x:42};
|
||||||
|
|
||||||
|
function f(index,param) {
|
||||||
|
arguments[1] = 0;
|
||||||
|
var ret = 0;
|
||||||
|
for (var i = 0; i < 5; ++i)
|
||||||
|
ret = arguments[index].x;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEq(f(2,o,o), 42);
|
||||||
|
assertEq(f(1,o,o), undefined);
|
|
@ -1,3 +1,4 @@
|
||||||
|
var escape;
|
||||||
function testBug458838() {
|
function testBug458838() {
|
||||||
var a = 1;
|
var a = 1;
|
||||||
function g() {
|
function g() {
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
function f(x,y) {
|
||||||
|
eval("assertEq(arguments.callee, f)");
|
||||||
|
}
|
||||||
|
f(1,2);
|
|
@ -1,24 +1,13 @@
|
||||||
// Fun.apply ignores arguments past JS_ARGS_LENGTH_MAX = 2^19 - 1024
|
|
||||||
const numFatArgs = Math.pow(2,19) - 1024;
|
const numFatArgs = Math.pow(2,19) - 1024;
|
||||||
// Recursion on trace is limited to MAX_CALL_STACK_ENTRIES = 500
|
|
||||||
const traceDepth = 490;
|
|
||||||
|
|
||||||
var trace = true;
|
function fun(x) {
|
||||||
|
|
||||||
function doEval() {
|
|
||||||
eval("");
|
|
||||||
}
|
|
||||||
|
|
||||||
function maybeTrace(x) {
|
|
||||||
if (!trace)
|
|
||||||
doEval();
|
|
||||||
if (x <= 0)
|
if (x <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
return maybeTrace(x-1);
|
return fun(x-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function fatStack() {
|
function fatStack() {
|
||||||
return maybeTrace(traceDepth);
|
return fun(10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function assertRightFailure(e) {
|
function assertRightFailure(e) {
|
||||||
|
@ -27,8 +16,6 @@ function assertRightFailure(e) {
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This tests that we conservatively guard against stack space exhaustion
|
|
||||||
// before entering trace.
|
|
||||||
exception = false;
|
exception = false;
|
||||||
try {
|
try {
|
||||||
fatStack.apply(null, new Array(numFatArgs));
|
fatStack.apply(null, new Array(numFatArgs));
|
||||||
|
@ -40,14 +27,3 @@ assertEq(exception, true);
|
||||||
|
|
||||||
// No more trace recursion w/ JM
|
// No more trace recursion w/ JM
|
||||||
checkStats({traceCompleted:0});
|
checkStats({traceCompleted:0});
|
||||||
|
|
||||||
// This tests that, without tracing, we exhaust stack space.
|
|
||||||
trace = false;
|
|
||||||
var exception = false;
|
|
||||||
try {
|
|
||||||
fatStack.apply(null, new Array(numFatArgs));
|
|
||||||
} catch (e) {
|
|
||||||
assertRightFailure(e);
|
|
||||||
exception = true;
|
|
||||||
}
|
|
||||||
assertEq(exception, true);
|
|
||||||
|
|
|
@ -200,7 +200,7 @@ AllowedToAct(JSContext *cx, jsid id)
|
||||||
// Some code is running, we can't make the assumption, as above, but we
|
// Some code is running, we can't make the assumption, as above, but we
|
||||||
// can't use a native frame, so clear fp.
|
// can't use a native frame, so clear fp.
|
||||||
fp = nsnull;
|
fp = nsnull;
|
||||||
} else if (!fp->hasScript()) {
|
} else if (!JS_IsScriptFrame(cx, fp)) {
|
||||||
fp = nsnull;
|
fp = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ AllowedToAct(JSContext *cx, jsid id)
|
||||||
// if they've been cloned into less privileged contexts.
|
// if they've been cloned into less privileged contexts.
|
||||||
const char *filename;
|
const char *filename;
|
||||||
if (fp &&
|
if (fp &&
|
||||||
(filename = fp->getScript()->filename) &&
|
(filename = JS_GetFrameScript(cx, fp)->filename) &&
|
||||||
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
|
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -246,7 +246,7 @@ CheckFilename(JSContext *cx, jsid id, JSStackFrame *fp)
|
||||||
{
|
{
|
||||||
const char *filename;
|
const char *filename;
|
||||||
if (fp &&
|
if (fp &&
|
||||||
(filename = fp->getScript()->filename) &&
|
(filename = JS_GetFrameScript(cx, fp)->filename) &&
|
||||||
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
|
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1310,8 +1310,8 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
|
||||||
JSStackFrame* fp = JS_GetScriptedCaller(cx, NULL);
|
JSStackFrame* fp = JS_GetScriptedCaller(cx, NULL);
|
||||||
if(fp)
|
if(fp)
|
||||||
{
|
{
|
||||||
script = fp->maybeScript();
|
script = JS_GetFrameScript(cx, fp);
|
||||||
callee = fp->callee();
|
callee = JS_GetFrameCalleeObject(cx, fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(ccx.GetXPCContext()->CallerTypeIsNative())
|
else if(ccx.GetXPCContext()->CallerTypeIsNative())
|
||||||
|
|
|
@ -141,9 +141,9 @@ XPCJSStackFrame::CreateStack(JSContext* cx, JSStackFrame* fp,
|
||||||
{
|
{
|
||||||
NS_ADDREF(self);
|
NS_ADDREF(self);
|
||||||
|
|
||||||
if(fp->down)
|
if(fp->prev())
|
||||||
{
|
{
|
||||||
if(NS_FAILED(CreateStack(cx, fp->down,
|
if(NS_FAILED(CreateStack(cx, fp->prev(),
|
||||||
(XPCJSStackFrame**) &self->mCaller)))
|
(XPCJSStackFrame**) &self->mCaller)))
|
||||||
failed = JS_TRUE;
|
failed = JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,7 +207,7 @@ AccessCheck::isSystemOnlyAccessPermitted(JSContext *cx)
|
||||||
// Some code is running, we can't make the assumption, as above, but we
|
// Some code is running, we can't make the assumption, as above, but we
|
||||||
// can't use a native frame, so clear fp.
|
// can't use a native frame, so clear fp.
|
||||||
fp = NULL;
|
fp = NULL;
|
||||||
} else if (!fp->hasScript()) {
|
} else if (!JS_IsScriptFrame(cx, fp)) {
|
||||||
fp = NULL;
|
fp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ AccessCheck::isSystemOnlyAccessPermitted(JSContext *cx)
|
||||||
static const char prefix[] = "chrome://global/";
|
static const char prefix[] = "chrome://global/";
|
||||||
const char *filename;
|
const char *filename;
|
||||||
if (fp &&
|
if (fp &&
|
||||||
(filename = fp->getScript()->filename) &&
|
(filename = JS_GetFrameScript(cx, fp)->filename) &&
|
||||||
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
|
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче