Bug 873155 - Remove StackFrame argument duplication. r=luke

This commit is contained in:
Jan de Mooij 2013-05-21 16:09:01 +02:00
parent 58c6661d63
commit b14b043ee4
10 changed files with 66 additions and 204 deletions

View File

@ -132,7 +132,7 @@ StackFrame::initFromBailout(JSContext *cx, SnapshotIterator &iter)
if (isFunctionFrame()) {
Value thisv = iter.read();
formals()[-1] = thisv;
argv()[-1] = thisv;
// The new |this| must have already been constructed prior to an Ion
// constructor running.
@ -145,7 +145,7 @@ StackFrame::initFromBailout(JSContext *cx, SnapshotIterator &iter)
for (uint32_t i = 0; i < fun()->nargs; i++) {
Value arg = iter.read();
formals()[i] = arg;
argv()[i] = arg;
}
}
exprStackSlots -= CountArgSlots(script(), maybeFun());
@ -197,7 +197,7 @@ PushInlinedFrame(JSContext *cx, StackFrame *callerFrame)
JS_ASSERT(js_CodeSpec[*regs.pc].format & JOF_INVOKE);
int callerArgc = GET_ARGC(regs.pc);
if (JSOp(*regs.pc) == JSOP_FUNAPPLY)
callerArgc = callerFrame->nactual();
callerArgc = callerFrame->numActualArgs();
const Value &calleeVal = regs.sp[-callerArgc - 2];
RootedFunction fun(cx, calleeVal.toObject().toFunction());
@ -219,7 +219,7 @@ PushInlinedFrame(JSContext *cx, StackFrame *callerFrame)
JS_ASSERT(fp == regs.fp());
JS_ASSERT(fp->prev() == callerFrame);
fp->formals()[-2].setObject(*fun);
fp->argv()[-2].setObject(*fun);
return fp;
}
@ -285,7 +285,7 @@ ConvertFrames(JSContext *cx, IonActivation *activation, IonBailoutIterator &it)
JSFunction *callee = it.maybeCallee();
if (callee)
fp->formals()[-2].setObject(*callee);
fp->argv()[-2].setObject(*callee);
if (it.isConstructing())
fp->setConstructing();

View File

@ -27,8 +27,7 @@ BaselineFrame::trace(JSTracer *trc)
// Mark actual and formal args.
if (isNonEvalFunctionFrame()) {
unsigned numArgs = js::Max(numActualArgs(), numFormalArgs());
JS_ASSERT(actuals() == formals());
gc::MarkValueRootRange(trc, numArgs, actuals(), "baseline-args");
gc::MarkValueRootRange(trc, numArgs, argv(), "baseline-args");
}
// Mark scope chain.
@ -62,7 +61,7 @@ BaselineFrame::copyRawFrameSlots(AutoValueVector *vec) const
if (!vec->resize(nformals + nfixed))
return false;
mozilla::PodCopy(vec->begin(), formals(), nformals);
mozilla::PodCopy(vec->begin(), argv(), nformals);
for (unsigned i = 0; i < nfixed; i++)
(*vec)[nformals + i] = *valueSlot(i);
return true;

View File

@ -154,14 +154,14 @@ class BaselineFrame
JS_ASSERT(i < numFormalArgs());
JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
JS_ASSERT_IF(checkAliasing, !script()->formalIsAliased(i));
return formals()[i];
return argv()[i];
}
Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) const {
JS_ASSERT(i < numActualArgs());
JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
JS_ASSERT_IF(checkAliasing && i < numFormalArgs(), !script()->formalIsAliased(i));
return actuals()[i];
return argv()[i];
}
Value &unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
@ -184,14 +184,11 @@ class BaselineFrame
BaselineFrame::Size() +
offsetOfThis());
}
Value *formals() const {
Value *argv() const {
return (Value *)(reinterpret_cast<const uint8_t *>(this) +
BaselineFrame::Size() +
offsetOfArg(0));
}
Value *actuals() const {
return formals();
}
bool copyRawFrameSlots(AutoValueVector *vec) const;

View File

@ -778,7 +778,7 @@ PrepareOsrTempData(JSContext *cx, ICUseCount_Fallback *stub, BaselineFrame *fram
//
// Copy formal args and thisv.
memcpy(stackFrameStart, frame->formals() - 1, (numFormalArgs + 1) * sizeof(Value));
memcpy(stackFrameStart, frame->argv() - 1, (numFormalArgs + 1) * sizeof(Value));
// Initialize ScopeChain, Exec, and Flags fields in StackFrame struct.
uint8_t *stackFrame = info->stackFrame;

View File

@ -89,34 +89,14 @@ EnterBaseline(JSContext *cx, StackFrame *fp, void *jitcode, bool osr)
// arguments and the number of formal arguments. It accounts for |this|.
int maxArgc = 0;
Value *maxArgv = NULL;
int numActualArgs = 0;
unsigned numActualArgs = 0;
RootedValue thisv(cx);
void *calleeToken;
if (fp->isNonEvalFunctionFrame()) {
// CountArgSlot include |this| and the |scopeChain|, and maybe |argumentsObj|
// Want to keep including this, but remove the scopeChain and any argumentsObj.
maxArgc = CountArgSlots(fp->script(), fp->fun()) - StartArgSlot(fp->script(), fp->fun());
maxArgv = fp->formals() - 1; // -1 = include |this|
// Formal arguments are the argument corresponding to the function
// definition and actual arguments are corresponding to the call-site
// arguments.
numActualArgs = fp->numActualArgs();
// We do not need to handle underflow because formal arguments are pad
// with |undefined| values but we need to distinguish between the
if (fp->hasOverflowArgs()) {
int formalArgc = maxArgc;
Value *formalArgv = maxArgv;
maxArgc = numActualArgs + 1; // +1 = include |this|
maxArgv = fp->actuals() - 1; // -1 = include |this|
// The beginning of the actual args is not updated, so we just copy
// the formal args into the actual args to get a linear vector which
// can be copied by generateEnterJit.
memcpy(maxArgv, formalArgv, formalArgc * sizeof(Value));
}
maxArgc = Max(numActualArgs, fp->numFormalArgs()) + 1; // +1 = include |this|
maxArgv = fp->argv() - 1; // -1 = include |this|
calleeToken = CalleeToToken(&fp->callee());
} else {
// For eval function frames, set the callee token to the enclosing function.

View File

@ -1939,34 +1939,14 @@ EnterIon(JSContext *cx, StackFrame *fp, void *jitcode)
// arguments and the number of formal arguments. It accounts for |this|.
int maxArgc = 0;
Value *maxArgv = NULL;
int numActualArgs = 0;
unsigned numActualArgs = 0;
RootedValue thisv(cx);
void *calleeToken;
if (fp->isFunctionFrame()) {
// CountArgSlot include |this| and the |scopeChain| and maybe |argumentsObj|.
// Keep |this|, but discard the others.
maxArgc = CountArgSlots(fp->script(), fp->fun()) - StartArgSlot(fp->script(), fp->fun());
maxArgv = fp->formals() - 1; // -1 = include |this|
// Formal arguments are the argument corresponding to the function
// definition and actual arguments are corresponding to the call-site
// arguments.
numActualArgs = fp->numActualArgs();
// We do not need to handle underflow because formal arguments are pad
// with |undefined| values but we need to distinguish between the
if (fp->hasOverflowArgs()) {
int formalArgc = maxArgc;
Value *formalArgv = maxArgv;
maxArgc = numActualArgs + 1; // +1 = include |this|
maxArgv = fp->actuals() - 1; // -1 = include |this|
// The beginning of the actual args is not updated, so we just copy
// the formal args into the actual args to get a linear vector which
// can be copied by generateEnterJit.
memcpy(maxArgv, formalArgv, formalArgc * sizeof(Value));
}
maxArgc = Max(numActualArgs, fp->numFormalArgs()) + 1; // +1 = include |this|
maxArgv = fp->argv() - 1; // -1 = include |this|
calleeToken = CalleeToToken(&fp->callee());
} else {
calleeToken = CalleeToToken(fp->script());

View File

@ -30,25 +30,13 @@ CopyStackFrameArguments(const AbstractFramePtr frame, HeapValue *dst, unsigned t
{
JS_ASSERT_IF(frame.isStackFrame(), !frame.asStackFrame()->runningInIon());
unsigned numActuals = frame.numActualArgs();
unsigned numFormals = frame.callee()->nargs;
JS_ASSERT(numActuals <= totalArgs);
JS_ASSERT(numFormals <= totalArgs);
JS_ASSERT(Max(numActuals, numFormals) == totalArgs);
JS_ASSERT(Max(frame.numActualArgs(), frame.numFormalArgs()) == totalArgs);
/* Copy formal arguments. */
Value *src = frame.formals();
Value *end = src + numFormals;
/* Copy arguments. */
Value *src = frame.argv();
Value *end = src + totalArgs;
while (src != end)
(dst++)->init(*src++);
/* Copy actual argument which are not contignous. */
if (numFormals < numActuals) {
src = frame.actuals() + numFormals;
end = src + (numActuals - numFormals);
while (src != end)
(dst++)->init(*src++);
}
}
/* static */ void

View File

@ -99,9 +99,7 @@ inline void
StackFrame::initCallFrame(JSContext *cx, JSFunction &callee,
JSScript *script, uint32_t nactual, StackFrame::Flags flagsArg)
{
JS_ASSERT((flagsArg & ~(CONSTRUCTING |
OVERFLOW_ARGS |
UNDERFLOW_ARGS)) == 0);
JS_ASSERT((flagsArg & ~CONSTRUCTING) == 0);
JS_ASSERT(callee.nonLazyScript() == script);
/* Initialize stack frame members. */
@ -129,7 +127,7 @@ StackFrame::createRestParameter(JSContext *cx)
JS_ASSERT(fun()->hasRest());
unsigned nformal = fun()->nargs - 1, nactual = numActualArgs();
unsigned nrest = (nactual > nformal) ? nactual - nformal : 0;
return NewDenseCopiedArray(cx, nrest, actuals() + nformal, NULL);
return NewDenseCopiedArray(cx, nrest, argv() + nformal, NULL);
}
inline Value &
@ -155,7 +153,7 @@ StackFrame::unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing)
JS_ASSERT(i < numFormalArgs());
JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
JS_ASSERT_IF(checkAliasing, !script()->formalIsAliased(i));
return formals()[i];
return argv()[i];
}
inline Value &
@ -164,7 +162,7 @@ StackFrame::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing)
JS_ASSERT(i < numActualArgs());
JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
JS_ASSERT_IF(checkAliasing && i < numFormalArgs(), !script()->formalIsAliased(i));
return i < numFormalArgs() ? formals()[i] : actuals()[i];
return argv()[i];
}
template <class Op>
@ -174,25 +172,9 @@ StackFrame::forEachUnaliasedActual(Op op)
JS_ASSERT(!script()->funHasAnyAliasedFormal);
JS_ASSERT(!script()->needsArgsObj());
unsigned nformal = numFormalArgs();
unsigned nactual = numActualArgs();
const Value *formalsEnd = (const Value *)this;
const Value *formals = formalsEnd - nformal;
if (nactual <= nformal) {
const Value *actualsEnd = formals + nactual;
for (const Value *p = formals; p < actualsEnd; ++p)
op(*p);
} else {
for (const Value *p = formals; p < formalsEnd; ++p)
op(*p);
const Value *actualsEnd = formals - 2;
const Value *actuals = actualsEnd - nactual;
for (const Value *p = actuals + nformal; p < actualsEnd; ++p)
op(*p);
}
const Value *argsEnd = argv() + numActualArgs();
for (const Value *p = argv(); p < argsEnd; ++p)
op(*p);
}
struct CopyTo
@ -209,30 +191,6 @@ struct CopyToHeap
void operator()(const Value &src) { dst->init(src); ++dst; }
};
inline unsigned
StackFrame::numFormalArgs() const
{
JS_ASSERT(hasArgs());
return fun()->nargs;
}
inline unsigned
StackFrame::numActualArgs() const
{
/*
* u.nactual is always coherent, except for method JIT frames where the
* callee does not access its arguments and the number of actual arguments
* matches the number of formal arguments. The JIT requires that all frames
* which do not have an arguments object and use their arguments have a
* coherent u.nactual (even though the below code may not use it), as
* JIT code may access the field directly.
*/
JS_ASSERT(hasArgs());
if (JS_UNLIKELY(flags_ & (OVERFLOW_ARGS | UNDERFLOW_ARGS)))
return u.nactual;
return numFormalArgs();
}
inline ArgumentsObject &
StackFrame::argsObj() const
{
@ -315,31 +273,19 @@ ContextStack::getCallFrame(JSContext *cx, MaybeReportError report, const CallArg
unsigned nvals = VALUES_PER_STACK_FRAME + script->nslots;
/* Maintain layout invariant: &formals[0] == ((Value *)fp) - nformal. */
if (args.length() == nformal) {
if (args.length() >= nformal) {
if (!space().ensureSpace(cx, report, firstUnused, nvals))
return NULL;
return reinterpret_cast<StackFrame *>(firstUnused);
}
if (args.length() < nformal) {
*flags = StackFrame::Flags(*flags | StackFrame::UNDERFLOW_ARGS);
unsigned nmissing = nformal - args.length();
if (!space().ensureSpace(cx, report, firstUnused, nmissing + nvals))
return NULL;
SetValueRangeToUndefined(firstUnused, nmissing);
return reinterpret_cast<StackFrame *>(firstUnused + nmissing);
}
*flags = StackFrame::Flags(*flags | StackFrame::OVERFLOW_ARGS);
unsigned ncopy = 2 + nformal;
if (!space().ensureSpace(cx, report, firstUnused, ncopy + nvals))
/* Pad any missing arguments with |undefined|. */
JS_ASSERT(args.length() < nformal);
unsigned nmissing = nformal - args.length();
if (!space().ensureSpace(cx, report, firstUnused, nmissing + nvals))
return NULL;
Value *dst = firstUnused;
Value *src = args.base();
mozilla::PodCopy(dst, src, ncopy);
return reinterpret_cast<StackFrame *>(firstUnused + ncopy);
SetValueRangeToUndefined(firstUnused, nmissing);
return reinterpret_cast<StackFrame *>(firstUnused + nmissing);
}
JS_ALWAYS_INLINE bool
@ -386,7 +332,7 @@ ContextStack::popInlineFrame(FrameRegs &regs)
JS_ASSERT(&regs == &seg_->regs());
StackFrame *fp = regs.fp();
Value *newsp = fp->actuals() - 1;
Value *newsp = fp->argv() - 1;
JS_ASSERT(newsp >= fp->prev()->base());
newsp[-1] = fp->returnValue();
@ -815,27 +761,17 @@ AbstractFramePtr::isStrictEvalFrame() const
}
inline Value *
AbstractFramePtr::formals() const
AbstractFramePtr::argv() const
{
if (isStackFrame())
return asStackFrame()->formals();
return asStackFrame()->argv();
#ifdef JS_ION
return asBaselineFrame()->formals();
#else
JS_NOT_REACHED("Invalid frame");
#endif
}
inline Value *
AbstractFramePtr::actuals() const
{
if (isStackFrame())
return asStackFrame()->actuals();
#ifdef JS_ION
return asBaselineFrame()->actuals();
return asBaselineFrame()->argv();
#else
JS_NOT_REACHED("Invalid frame");
#endif
}
inline bool
AbstractFramePtr::hasArgsObj() const
{

View File

@ -222,7 +222,7 @@ StackFrame::copyRawFrameSlots(AutoValueVector *vec)
{
if (!vec->resize(numFormalArgs() + script()->nfixed))
return false;
PodCopy(vec->begin(), formals(), numFormalArgs());
PodCopy(vec->begin(), argv(), numFormalArgs());
PodCopy(vec->begin() + numFormalArgs(), slots(), script()->nfixed);
return true;
}

View File

@ -218,8 +218,7 @@ class AbstractFramePtr
inline unsigned numActualArgs() const;
inline unsigned numFormalArgs() const;
inline Value *formals() const;
inline Value *actuals() const;
inline Value *argv() const;
inline bool hasArgsObj() const;
inline ArgumentsObject &argsObj() const;
@ -293,33 +292,29 @@ class StackFrame
YIELDING = 0x40, /* Interpret dispatched JSOP_YIELD */
FINISHED_IN_INTERP = 0x80, /* set if frame finished in Interpret() */
/* Function arguments */
OVERFLOW_ARGS = 0x100, /* numActualArgs > numFormalArgs */
UNDERFLOW_ARGS = 0x200, /* numActualArgs < numFormalArgs */
/* Function prologue state */
HAS_CALL_OBJ = 0x400, /* CallObject created for heavyweight fun */
HAS_ARGS_OBJ = 0x800, /* ArgumentsObject created for needsArgsObj script */
HAS_CALL_OBJ = 0x100, /* CallObject created for heavyweight fun */
HAS_ARGS_OBJ = 0x200, /* ArgumentsObject created for needsArgsObj script */
/* Lazy frame initialization */
HAS_HOOK_DATA = 0x1000, /* frame has hookData_ set */
HAS_RVAL = 0x2000, /* frame has rval_ set */
HAS_SCOPECHAIN = 0x4000, /* frame has scopeChain_ set */
HAS_PREVPC = 0x8000, /* frame has prevpc_ and prevInline_ set */
HAS_BLOCKCHAIN = 0x10000, /* frame has blockChain_ set */
HAS_HOOK_DATA = 0x400, /* frame has hookData_ set */
HAS_RVAL = 0x800, /* frame has rval_ set */
HAS_SCOPECHAIN = 0x1000, /* frame has scopeChain_ set */
HAS_PREVPC = 0x2000, /* frame has prevpc_ and prevInline_ set */
HAS_BLOCKCHAIN = 0x4000, /* frame has blockChain_ set */
/* Debugger state */
PREV_UP_TO_DATE = 0x20000, /* see DebugScopes::updateLiveScopes */
PREV_UP_TO_DATE = 0x8000, /* see DebugScopes::updateLiveScopes */
/* Used in tracking calls and profiling (see vm/SPSProfiler.cpp) */
HAS_PUSHED_SPS_FRAME = 0x40000, /* SPS was notified of enty */
HAS_PUSHED_SPS_FRAME = 0x10000, /* SPS was notified of enty */
/* Ion frame state */
RUNNING_IN_ION = 0x80000, /* frame is running in Ion */
CALLING_INTO_ION = 0x100000, /* frame is calling into Ion */
RUNNING_IN_ION = 0x20000, /* frame is running in Ion */
CALLING_INTO_ION = 0x40000, /* frame is calling into Ion */
/* Miscellaneous state. */
USE_NEW_TYPE = 0x200000 /* Use new type for constructed |this| object. */
USE_NEW_TYPE = 0x80000 /* Use new type for constructed |this| object. */
};
private:
@ -362,9 +357,7 @@ class StackFrame
public:
Value *slots() const { return (Value *)(this + 1); }
Value *base() const { return slots() + script()->nfixed; }
Value *formals() const { return (Value *)this - fun()->nargs; }
Value *actuals() const { return formals() - (flags_ & OVERFLOW_ARGS ? 2 + u.nactual : 0); }
unsigned nactual() const { return u.nactual; }
Value *argv() const { return (Value *)this - Max(numActualArgs(), numFormalArgs()); }
private:
friend class FrameRegs;
@ -514,15 +507,8 @@ class StackFrame
*
* Only non-eval function frames have arguments. The arguments pushed by
* the caller are the 'actual' arguments. The declared arguments of the
* callee are the 'formal' arguments. When the caller passes less or equal
* actual arguments, the actual and formal arguments are the same array
* (but with different extents). When the caller passes too many arguments,
* the formal subset of the actual arguments is copied onto the top of the
* stack. This allows the engine to maintain a jit-time constant offset of
* arguments from the frame pointer. Since the formal subset of the actual
* arguments is potentially on the stack twice, it is important for all
* reads/writes to refer to the same canonical memory location. This is
* abstracted by the unaliased{Formal,Actual} methods.
* callee are the 'formal' arguments. When the caller passes less actual
* arguments, missing formal arguments are padded with |undefined|.
*
* When a local/formal variable is "aliased" (accessed by nested closures,
* dynamic scope operations, or 'arguments), the canonical location for
@ -544,8 +530,8 @@ class StackFrame
bool copyRawFrameSlots(AutoValueVector *v);
inline unsigned numFormalArgs() const;
inline unsigned numActualArgs() const;
unsigned numFormalArgs() const { JS_ASSERT(hasArgs()); return fun()->nargs; }
unsigned numActualArgs() const { JS_ASSERT(hasArgs()); return u.nactual; }
inline Value &canonicalActualArg(unsigned i) const;
template <class Op>
@ -714,18 +700,18 @@ class StackFrame
JS_ASSERT(isFunctionFrame());
if (isEvalFrame())
return ((Value *)this)[-1];
return formals()[-1];
return argv()[-1];
}
JSObject &constructorThis() const {
JS_ASSERT(hasArgs());
return formals()[-1].toObject();
return argv()[-1].toObject();
}
Value &thisValue() const {
if (flags_ & (EVAL | GLOBAL))
return ((Value *)this)[-1];
return formals()[-1];
return argv()[-1];
}
/*
@ -750,7 +736,7 @@ class StackFrame
const Value &maybeCalleev() const {
Value &calleev = flags_ & (EVAL | GLOBAL)
? ((Value *)this)[-2]
: formals()[-2];
: argv()[-2];
JS_ASSERT(calleev.isObjectOrNull());
return calleev;
}
@ -759,11 +745,11 @@ class StackFrame
JS_ASSERT(isFunctionFrame());
if (isEvalFrame())
return ((Value *)this)[-2];
return formals()[-2];
return argv()[-2];
}
CallReceiver callReceiver() const {
return CallReceiverFromArgv(formals());
return CallReceiverFromArgv(argv());
}
/*
@ -858,7 +844,7 @@ class StackFrame
Value *generatorArgsSnapshotBegin() const {
JS_ASSERT(isGeneratorFrame());
return actuals() - 2;
return argv() - 2;
}
Value *generatorArgsSnapshotEnd() const {
@ -955,10 +941,6 @@ class StackFrame
flags_ |= PREV_UP_TO_DATE;
}
bool hasOverflowArgs() const {
return !!(flags_ & OVERFLOW_ARGS);
}
bool isYielding() {
return !!(flags_ & YIELDING);
}