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 ca6f7896a8
commit c24123088d
10 changed files with 66 additions and 204 deletions

View File

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

View File

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

View File

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

View File

@ -778,7 +778,7 @@ PrepareOsrTempData(JSContext *cx, ICUseCount_Fallback *stub, BaselineFrame *fram
// //
// Copy formal args and thisv. // 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. // Initialize ScopeChain, Exec, and Flags fields in StackFrame struct.
uint8_t *stackFrame = info->stackFrame; 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|. // arguments and the number of formal arguments. It accounts for |this|.
int maxArgc = 0; int maxArgc = 0;
Value *maxArgv = NULL; Value *maxArgv = NULL;
int numActualArgs = 0; unsigned numActualArgs = 0;
RootedValue thisv(cx); RootedValue thisv(cx);
void *calleeToken; void *calleeToken;
if (fp->isNonEvalFunctionFrame()) { 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(); numActualArgs = fp->numActualArgs();
maxArgc = Max(numActualArgs, fp->numFormalArgs()) + 1; // +1 = include |this|
// We do not need to handle underflow because formal arguments are pad maxArgv = fp->argv() - 1; // -1 = include |this|
// 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));
}
calleeToken = CalleeToToken(&fp->callee()); calleeToken = CalleeToToken(&fp->callee());
} else { } else {
// For eval function frames, set the callee token to the enclosing function. // 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|. // arguments and the number of formal arguments. It accounts for |this|.
int maxArgc = 0; int maxArgc = 0;
Value *maxArgv = NULL; Value *maxArgv = NULL;
int numActualArgs = 0; unsigned numActualArgs = 0;
RootedValue thisv(cx); RootedValue thisv(cx);
void *calleeToken; void *calleeToken;
if (fp->isFunctionFrame()) { 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(); numActualArgs = fp->numActualArgs();
maxArgc = Max(numActualArgs, fp->numFormalArgs()) + 1; // +1 = include |this|
// We do not need to handle underflow because formal arguments are pad maxArgv = fp->argv() - 1; // -1 = include |this|
// 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));
}
calleeToken = CalleeToToken(&fp->callee()); calleeToken = CalleeToToken(&fp->callee());
} else { } else {
calleeToken = CalleeToToken(fp->script()); 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()); JS_ASSERT_IF(frame.isStackFrame(), !frame.asStackFrame()->runningInIon());
unsigned numActuals = frame.numActualArgs(); JS_ASSERT(Max(frame.numActualArgs(), frame.numFormalArgs()) == totalArgs);
unsigned numFormals = frame.callee()->nargs;
JS_ASSERT(numActuals <= totalArgs);
JS_ASSERT(numFormals <= totalArgs);
JS_ASSERT(Max(numActuals, numFormals) == totalArgs);
/* Copy formal arguments. */ /* Copy arguments. */
Value *src = frame.formals(); Value *src = frame.argv();
Value *end = src + numFormals; Value *end = src + totalArgs;
while (src != end) while (src != end)
(dst++)->init(*src++); (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 /* static */ void

View File

@ -99,9 +99,7 @@ inline void
StackFrame::initCallFrame(JSContext *cx, JSFunction &callee, StackFrame::initCallFrame(JSContext *cx, JSFunction &callee,
JSScript *script, uint32_t nactual, StackFrame::Flags flagsArg) JSScript *script, uint32_t nactual, StackFrame::Flags flagsArg)
{ {
JS_ASSERT((flagsArg & ~(CONSTRUCTING | JS_ASSERT((flagsArg & ~CONSTRUCTING) == 0);
OVERFLOW_ARGS |
UNDERFLOW_ARGS)) == 0);
JS_ASSERT(callee.nonLazyScript() == script); JS_ASSERT(callee.nonLazyScript() == script);
/* Initialize stack frame members. */ /* Initialize stack frame members. */
@ -129,7 +127,7 @@ StackFrame::createRestParameter(JSContext *cx)
JS_ASSERT(fun()->hasRest()); JS_ASSERT(fun()->hasRest());
unsigned nformal = fun()->nargs - 1, nactual = numActualArgs(); unsigned nformal = fun()->nargs - 1, nactual = numActualArgs();
unsigned nrest = (nactual > nformal) ? nactual - nformal : 0; unsigned nrest = (nactual > nformal) ? nactual - nformal : 0;
return NewDenseCopiedArray(cx, nrest, actuals() + nformal, NULL); return NewDenseCopiedArray(cx, nrest, argv() + nformal, NULL);
} }
inline Value & inline Value &
@ -155,7 +153,7 @@ StackFrame::unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing)
JS_ASSERT(i < numFormalArgs()); JS_ASSERT(i < numFormalArgs());
JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals()); JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
JS_ASSERT_IF(checkAliasing, !script()->formalIsAliased(i)); JS_ASSERT_IF(checkAliasing, !script()->formalIsAliased(i));
return formals()[i]; return argv()[i];
} }
inline Value & inline Value &
@ -164,7 +162,7 @@ StackFrame::unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing)
JS_ASSERT(i < numActualArgs()); JS_ASSERT(i < numActualArgs());
JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals()); JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
JS_ASSERT_IF(checkAliasing && i < numFormalArgs(), !script()->formalIsAliased(i)); JS_ASSERT_IF(checkAliasing && i < numFormalArgs(), !script()->formalIsAliased(i));
return i < numFormalArgs() ? formals()[i] : actuals()[i]; return argv()[i];
} }
template <class Op> template <class Op>
@ -174,25 +172,9 @@ StackFrame::forEachUnaliasedActual(Op op)
JS_ASSERT(!script()->funHasAnyAliasedFormal); JS_ASSERT(!script()->funHasAnyAliasedFormal);
JS_ASSERT(!script()->needsArgsObj()); JS_ASSERT(!script()->needsArgsObj());
unsigned nformal = numFormalArgs(); const Value *argsEnd = argv() + numActualArgs();
unsigned nactual = numActualArgs(); for (const Value *p = argv(); p < argsEnd; ++p)
op(*p);
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);
}
} }
struct CopyTo struct CopyTo
@ -209,30 +191,6 @@ struct CopyToHeap
void operator()(const Value &src) { dst->init(src); ++dst; } 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 & inline ArgumentsObject &
StackFrame::argsObj() const StackFrame::argsObj() const
{ {
@ -315,31 +273,19 @@ ContextStack::getCallFrame(JSContext *cx, MaybeReportError report, const CallArg
unsigned nvals = VALUES_PER_STACK_FRAME + script->nslots; 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)) if (!space().ensureSpace(cx, report, firstUnused, nvals))
return NULL; return NULL;
return reinterpret_cast<StackFrame *>(firstUnused); return reinterpret_cast<StackFrame *>(firstUnused);
} }
if (args.length() < nformal) { /* Pad any missing arguments with |undefined|. */
*flags = StackFrame::Flags(*flags | StackFrame::UNDERFLOW_ARGS); JS_ASSERT(args.length() < nformal);
unsigned nmissing = nformal - args.length(); unsigned nmissing = nformal - args.length();
if (!space().ensureSpace(cx, report, firstUnused, nmissing + nvals)) 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))
return NULL; return NULL;
Value *dst = firstUnused; SetValueRangeToUndefined(firstUnused, nmissing);
Value *src = args.base(); return reinterpret_cast<StackFrame *>(firstUnused + nmissing);
mozilla::PodCopy(dst, src, ncopy);
return reinterpret_cast<StackFrame *>(firstUnused + ncopy);
} }
JS_ALWAYS_INLINE bool JS_ALWAYS_INLINE bool
@ -386,7 +332,7 @@ ContextStack::popInlineFrame(FrameRegs &regs)
JS_ASSERT(&regs == &seg_->regs()); JS_ASSERT(&regs == &seg_->regs());
StackFrame *fp = regs.fp(); StackFrame *fp = regs.fp();
Value *newsp = fp->actuals() - 1; Value *newsp = fp->argv() - 1;
JS_ASSERT(newsp >= fp->prev()->base()); JS_ASSERT(newsp >= fp->prev()->base());
newsp[-1] = fp->returnValue(); newsp[-1] = fp->returnValue();
@ -815,27 +761,17 @@ AbstractFramePtr::isStrictEvalFrame() const
} }
inline Value * inline Value *
AbstractFramePtr::formals() const AbstractFramePtr::argv() const
{ {
if (isStackFrame()) if (isStackFrame())
return asStackFrame()->formals(); return asStackFrame()->argv();
#ifdef JS_ION #ifdef JS_ION
return asBaselineFrame()->formals(); return asBaselineFrame()->argv();
#else
JS_NOT_REACHED("Invalid frame");
#endif
}
inline Value *
AbstractFramePtr::actuals() const
{
if (isStackFrame())
return asStackFrame()->actuals();
#ifdef JS_ION
return asBaselineFrame()->actuals();
#else #else
JS_NOT_REACHED("Invalid frame"); JS_NOT_REACHED("Invalid frame");
#endif #endif
} }
inline bool inline bool
AbstractFramePtr::hasArgsObj() const AbstractFramePtr::hasArgsObj() const
{ {

View File

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

View File

@ -218,8 +218,7 @@ class AbstractFramePtr
inline unsigned numActualArgs() const; inline unsigned numActualArgs() const;
inline unsigned numFormalArgs() const; inline unsigned numFormalArgs() const;
inline Value *formals() const; inline Value *argv() const;
inline Value *actuals() const;
inline bool hasArgsObj() const; inline bool hasArgsObj() const;
inline ArgumentsObject &argsObj() const; inline ArgumentsObject &argsObj() const;
@ -293,33 +292,29 @@ class StackFrame
YIELDING = 0x40, /* Interpret dispatched JSOP_YIELD */ YIELDING = 0x40, /* Interpret dispatched JSOP_YIELD */
FINISHED_IN_INTERP = 0x80, /* set if frame finished in Interpret() */ 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 */ /* Function prologue state */
HAS_CALL_OBJ = 0x400, /* CallObject created for heavyweight fun */ HAS_CALL_OBJ = 0x100, /* CallObject created for heavyweight fun */
HAS_ARGS_OBJ = 0x800, /* ArgumentsObject created for needsArgsObj script */ HAS_ARGS_OBJ = 0x200, /* ArgumentsObject created for needsArgsObj script */
/* Lazy frame initialization */ /* Lazy frame initialization */
HAS_HOOK_DATA = 0x1000, /* frame has hookData_ set */ HAS_HOOK_DATA = 0x400, /* frame has hookData_ set */
HAS_RVAL = 0x2000, /* frame has rval_ set */ HAS_RVAL = 0x800, /* frame has rval_ set */
HAS_SCOPECHAIN = 0x4000, /* frame has scopeChain_ set */ HAS_SCOPECHAIN = 0x1000, /* frame has scopeChain_ set */
HAS_PREVPC = 0x8000, /* frame has prevpc_ and prevInline_ set */ HAS_PREVPC = 0x2000, /* frame has prevpc_ and prevInline_ set */
HAS_BLOCKCHAIN = 0x10000, /* frame has blockChain_ set */ HAS_BLOCKCHAIN = 0x4000, /* frame has blockChain_ set */
/* Debugger state */ /* 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) */ /* 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 */ /* Ion frame state */
RUNNING_IN_ION = 0x80000, /* frame is running in Ion */ RUNNING_IN_ION = 0x20000, /* frame is running in Ion */
CALLING_INTO_ION = 0x100000, /* frame is calling into Ion */ CALLING_INTO_ION = 0x40000, /* frame is calling into Ion */
/* Miscellaneous state. */ /* 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: private:
@ -362,9 +357,7 @@ class StackFrame
public: public:
Value *slots() const { return (Value *)(this + 1); } Value *slots() const { return (Value *)(this + 1); }
Value *base() const { return slots() + script()->nfixed; } Value *base() const { return slots() + script()->nfixed; }
Value *formals() const { return (Value *)this - fun()->nargs; } Value *argv() const { return (Value *)this - Max(numActualArgs(), numFormalArgs()); }
Value *actuals() const { return formals() - (flags_ & OVERFLOW_ARGS ? 2 + u.nactual : 0); }
unsigned nactual() const { return u.nactual; }
private: private:
friend class FrameRegs; friend class FrameRegs;
@ -514,15 +507,8 @@ class StackFrame
* *
* Only non-eval function frames have arguments. The arguments pushed by * Only non-eval function frames have arguments. The arguments pushed by
* the caller are the 'actual' arguments. The declared arguments of the * the caller are the 'actual' arguments. The declared arguments of the
* callee are the 'formal' arguments. When the caller passes less or equal * callee are the 'formal' arguments. When the caller passes less actual
* actual arguments, the actual and formal arguments are the same array * arguments, missing formal arguments are padded with |undefined|.
* (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.
* *
* When a local/formal variable is "aliased" (accessed by nested closures, * When a local/formal variable is "aliased" (accessed by nested closures,
* dynamic scope operations, or 'arguments), the canonical location for * dynamic scope operations, or 'arguments), the canonical location for
@ -544,8 +530,8 @@ class StackFrame
bool copyRawFrameSlots(AutoValueVector *v); bool copyRawFrameSlots(AutoValueVector *v);
inline unsigned numFormalArgs() const; unsigned numFormalArgs() const { JS_ASSERT(hasArgs()); return fun()->nargs; }
inline unsigned numActualArgs() const; unsigned numActualArgs() const { JS_ASSERT(hasArgs()); return u.nactual; }
inline Value &canonicalActualArg(unsigned i) const; inline Value &canonicalActualArg(unsigned i) const;
template <class Op> template <class Op>
@ -714,18 +700,18 @@ class StackFrame
JS_ASSERT(isFunctionFrame()); JS_ASSERT(isFunctionFrame());
if (isEvalFrame()) if (isEvalFrame())
return ((Value *)this)[-1]; return ((Value *)this)[-1];
return formals()[-1]; return argv()[-1];
} }
JSObject &constructorThis() const { JSObject &constructorThis() const {
JS_ASSERT(hasArgs()); JS_ASSERT(hasArgs());
return formals()[-1].toObject(); return argv()[-1].toObject();
} }
Value &thisValue() const { Value &thisValue() const {
if (flags_ & (EVAL | GLOBAL)) if (flags_ & (EVAL | GLOBAL))
return ((Value *)this)[-1]; return ((Value *)this)[-1];
return formals()[-1]; return argv()[-1];
} }
/* /*
@ -750,7 +736,7 @@ class StackFrame
const Value &maybeCalleev() const { const Value &maybeCalleev() const {
Value &calleev = flags_ & (EVAL | GLOBAL) Value &calleev = flags_ & (EVAL | GLOBAL)
? ((Value *)this)[-2] ? ((Value *)this)[-2]
: formals()[-2]; : argv()[-2];
JS_ASSERT(calleev.isObjectOrNull()); JS_ASSERT(calleev.isObjectOrNull());
return calleev; return calleev;
} }
@ -759,11 +745,11 @@ class StackFrame
JS_ASSERT(isFunctionFrame()); JS_ASSERT(isFunctionFrame());
if (isEvalFrame()) if (isEvalFrame())
return ((Value *)this)[-2]; return ((Value *)this)[-2];
return formals()[-2]; return argv()[-2];
} }
CallReceiver callReceiver() const { CallReceiver callReceiver() const {
return CallReceiverFromArgv(formals()); return CallReceiverFromArgv(argv());
} }
/* /*
@ -858,7 +844,7 @@ class StackFrame
Value *generatorArgsSnapshotBegin() const { Value *generatorArgsSnapshotBegin() const {
JS_ASSERT(isGeneratorFrame()); JS_ASSERT(isGeneratorFrame());
return actuals() - 2; return argv() - 2;
} }
Value *generatorArgsSnapshotEnd() const { Value *generatorArgsSnapshotEnd() const {
@ -955,10 +941,6 @@ class StackFrame
flags_ |= PREV_UP_TO_DATE; flags_ |= PREV_UP_TO_DATE;
} }
bool hasOverflowArgs() const {
return !!(flags_ & OVERFLOW_ARGS);
}
bool isYielding() { bool isYielding() {
return !!(flags_ & YIELDING); return !!(flags_ & YIELDING);
} }