Bug 1090491 - Don't allocate stack slots for aliased locals. r=luke

This commit is contained in:
Jan de Mooij 2014-10-29 13:49:20 +01:00
parent 7b65d193f4
commit f6ade302c6
16 changed files with 210 additions and 71 deletions

View File

@ -386,6 +386,9 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
if (!NameFunctions(cx, pn))
return nullptr;
if (!bce.updateLocalsToFrameSlots())
return nullptr;
if (!EmitTree(cx, &bce, pn))
return nullptr;
@ -423,7 +426,7 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
// frame.
InternalHandle<Bindings*> bindings(script, &script->bindings);
if (!Bindings::initWithTemporaryStorage(cx, bindings, 0, 0, 0,
pc->blockScopeDepth, nullptr))
pc->blockScopeDepth, 0, 0, nullptr))
{
return nullptr;
}

View File

@ -131,6 +131,7 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent,
staticScope(sc->context),
atomIndices(sc->context),
firstLine(lineNum),
localsToFrameSlots_(sc->context),
stackDepth(0), maxStackDepth(0),
arrayCompDepth(0),
emitLevel(0),
@ -155,6 +156,41 @@ BytecodeEmitter::init()
return atomIndices.ensureMap(sc->context);
}
bool
BytecodeEmitter::updateLocalsToFrameSlots()
{
// Assign stack slots to unaliased locals (aliased locals are stored in the
// call object and don't need their own stack slots). We do this by filling
// a Vector that can be used to map a local to its stack slot.
if (localsToFrameSlots_.length() == script->bindings.numLocals()) {
// CompileScript calls updateNumBlockScoped to update the block scope
// depth. Do nothing if the depth didn't change.
return true;
}
localsToFrameSlots_.clear();
if (!localsToFrameSlots_.reserve(script->bindings.numLocals()))
return false;
uint32_t slot = 0;
for (BindingIter bi(script); !bi.done(); bi++) {
if (bi->kind() == Binding::ARGUMENT)
continue;
if (bi->aliased())
localsToFrameSlots_.infallibleAppend(UINT32_MAX);
else
localsToFrameSlots_.infallibleAppend(slot++);
}
for (size_t i = 0; i < script->bindings.numBlockScoped(); i++)
localsToFrameSlots_.infallibleAppend(slot++);
return true;
}
static ptrdiff_t
EmitCheck(ExclusiveContext *cx, BytecodeEmitter *bce, ptrdiff_t delta)
{
@ -771,12 +807,18 @@ AllLocalsAliased(StaticBlockObject &obj)
static bool
ComputeAliasedSlots(ExclusiveContext *cx, BytecodeEmitter *bce, Handle<StaticBlockObject *> blockObj)
{
uint32_t numAliased = bce->script->bindings.numAliasedBodyLevelLocals();
for (unsigned i = 0; i < blockObj->numVariables(); i++) {
Definition *dn = blockObj->definitionParseNode(i);
MOZ_ASSERT(dn->isDefn());
// blockIndexToLocalIndex returns the frame slot following the unaliased
// locals. We add numAliased so that the cookie's slot value comes after
// all (aliased and unaliased) body level locals.
if (!dn->pn_cookie.set(bce->parser->tokenStream, dn->pn_cookie.level(),
blockObj->blockIndexToLocalIndex(dn->frameSlot())))
numAliased + blockObj->blockIndexToLocalIndex(dn->frameSlot())))
{
return false;
}
@ -807,7 +849,9 @@ EmitInternedObjectOp(ExclusiveContext *cx, uint32_t index, JSOp op, BytecodeEmit
static void
ComputeLocalOffset(ExclusiveContext *cx, BytecodeEmitter *bce, Handle<StaticBlockObject *> blockObj)
{
unsigned nbodyfixed = bce->sc->isFunctionBox() ? bce->script->bindings.numBodyLevelLocals() : 0;
unsigned nbodyfixed = bce->sc->isFunctionBox()
? bce->script->bindings.numUnaliasedBodyLevelLocals()
: 0;
unsigned localOffset = nbodyfixed;
if (bce->staticScope) {
@ -1093,6 +1137,12 @@ EmitUnaliasedVarOp(ExclusiveContext *cx, JSOp op, uint32_t slot, MaybeCheckLexic
MOZ_ASSERT(JOF_OPTYPE(op) != JOF_SCOPECOORD);
if (IsLocalOp(op)) {
// Only unaliased locals have stack slots assigned to them. Convert the
// var index (which includes unaliased and aliased locals) to the stack
// slot index.
MOZ_ASSERT(bce->localsToFrameSlots_[slot] <= slot);
slot = bce->localsToFrameSlots_[slot];
if (checkLexical) {
MOZ_ASSERT(op != JSOP_INITLEXICAL);
if (!EmitLocalOp(cx, bce, JSOP_CHECKLEXICAL, slot))
@ -1300,6 +1350,7 @@ EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *
MOZ_ASSERT_IF(bce->sc->isFunctionBox(), local <= bceOfDef->script->bindings.numLocals());
MOZ_ASSERT(bceOfDef->staticScope->is<StaticBlockObject>());
Rooted<StaticBlockObject*> b(cx, &bceOfDef->staticScope->as<StaticBlockObject>());
local = bceOfDef->localsToFrameSlots_[local];
while (local < b->localOffset()) {
if (b->needsClone())
skippedScopes++;
@ -2569,7 +2620,12 @@ InitializeBlockScopedLocalsFromStack(ExclusiveContext *cx, BytecodeEmitter *bce,
if (!EmitAliasedVarOp(cx, JSOP_INITALIASEDLEXICAL, sc, DontCheckLexical, bce))
return false;
} else {
unsigned local = blockObj->blockIndexToLocalIndex(i - 1);
// blockIndexToLocalIndex returns the slot index after the unaliased
// locals stored in the frame. EmitUnaliasedVarOp expects the slot index
// to include both unaliased and aliased locals, so we have to add the
// number of aliased locals.
uint32_t numAliased = bce->script->bindings.numAliasedBodyLevelLocals();
unsigned local = blockObj->blockIndexToLocalIndex(i - 1) + numAliased;
if (!EmitUnaliasedVarOp(cx, JSOP_INITLEXICAL, local, DontCheckLexical, bce))
return false;
}
@ -2949,6 +3005,9 @@ BytecodeEmitter::isRunOnceLambda()
bool
frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *body)
{
if (!bce->updateLocalsToFrameSlots())
return false;
/*
* IonBuilder has assumptions about what may occur immediately after
* script->main (e.g., in the case of destructuring params). Thus, put the
@ -5263,7 +5322,7 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
bi++;
MOZ_ASSERT(bi->kind() == Binding::VARIABLE || bi->kind() == Binding::CONSTANT ||
bi->kind() == Binding::ARGUMENT);
MOZ_ASSERT(bi.frameIndex() < JS_BIT(20));
MOZ_ASSERT(bi.argOrLocalIndex() < JS_BIT(20));
#endif
pn->pn_index = index;
if (!EmitIndexOp(cx, JSOP_LAMBDA, index, bce))

View File

@ -116,6 +116,13 @@ struct BytecodeEmitter
OwnedAtomIndexMapPtr atomIndices; /* literals indexed for mapping */
unsigned firstLine; /* first line, for JSScript::initFromEmitter */
/*
* Only unaliased locals have stack slots assigned to them. This vector is
* used to map a local index (which includes unaliased and aliased locals)
* to its stack slot index.
*/
Vector<uint32_t, 16> localsToFrameSlots_;
int32_t stackDepth; /* current stack depth in script frame */
uint32_t maxStackDepth; /* maximum stack depth so far */
@ -178,6 +185,7 @@ struct BytecodeEmitter
bool insideEval, HandleScript evalCaller, bool hasGlobalScope,
uint32_t lineNum, EmitterMode emitterMode = Normal);
bool init();
bool updateLocalsToFrameSlots();
bool isAliasedName(ParseNode *pn);

View File

@ -320,7 +320,8 @@ ParseContext<ParseHandler>::popLetDecl(JSAtom *atom)
template <typename ParseHandler>
static void
AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec, Binding *dst)
AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec, Binding *dst,
uint32_t *numUnaliased = nullptr)
{
for (size_t i = 0; i < vec.length(); ++i, ++dst) {
Definition *dn = vec[i];
@ -357,6 +358,8 @@ AppendPackedBindings(const ParseContext<ParseHandler> *pc, const DeclVector &vec
pc->decls().lookupFirst(name) == dn);
*dst = Binding(name, kind, aliased);
if (!aliased && numUnaliased)
++*numUnaliased;
}
}
@ -392,13 +395,17 @@ ParseContext<ParseHandler>::generateFunctionBindings(ExclusiveContext *cx, Token
return false;
}
uint32_t numUnaliasedVars = 0;
uint32_t numUnaliasedBodyLevelLexicals = 0;
AppendPackedBindings(this, args_, packedBindings);
AppendPackedBindings(this, vars_, packedBindings + args_.length());
AppendPackedBindings(this, vars_, packedBindings + args_.length(), &numUnaliasedVars);
AppendPackedBindings(this, bodyLevelLexicals_,
packedBindings + args_.length() + vars_.length());
packedBindings + args_.length() + vars_.length(), &numUnaliasedBodyLevelLexicals);
return Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(),
bodyLevelLexicals_.length(), blockScopeDepth,
numUnaliasedVars, numUnaliasedBodyLevelLexicals,
packedBindings);
}

View File

@ -0,0 +1,24 @@
// Make sure the getVariable/setVariable/eval functions work correctly with
// unaliased locals.
var g = newGlobal();
g.eval('\
function g() { debugger; };\
function f(arg) {\
var y = arg - 3;\
var a1 = 1;\
var a2 = 1;\
var b = arg + 9;\
var z = function() { return a1 + a2; };\
g();\
};');
var dbg = new Debugger(g);
dbg.onDebuggerStatement = function handleDebugger(frame) {
assertEq(frame.older.eval("y + b").return, 26);
assertEq(frame.older.environment.getVariable("y"), 7);
frame.older.environment.setVariable("b", 4);
assertEq(frame.older.eval("y + b").return, 11);
};
g.f(10);

View File

@ -93,7 +93,7 @@ BaselineFrame::trace(JSTracer *trc, JitFrameIterator &frameIterator)
// Clear dead block-scoped locals.
while (nfixed > nlivefixed)
unaliasedLocal(--nfixed, DONT_CHECK_ALIASING).setMagic(JS_UNINITIALIZED_LEXICAL);
unaliasedLocal(--nfixed).setMagic(JS_UNINITIALIZED_LEXICAL);
// Mark live locals.
MarkLocals(this, trc, 0, nlivefixed);

View File

@ -188,11 +188,8 @@ class BaselineFrame
return argv()[i];
}
Value &unaliasedLocal(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
Value &unaliasedLocal(uint32_t i) const {
MOZ_ASSERT(i < script()->nfixed());
#ifdef DEBUG
CheckLocalUnaliased(checkAliasing, script(), i);
#endif
return *valueSlot(i);
}

View File

@ -149,11 +149,8 @@ class RematerializedFrame
MOZ_ASSERT(i < script()->nfixed());
return locals()[i];
}
Value &unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) {
Value &unaliasedLocal(unsigned i) {
MOZ_ASSERT(i < script()->nfixed());
#ifdef DEBUG
CheckLocalUnaliased(checkAliasing, script(), i);
#endif
return locals()[i];
}
Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) {

View File

@ -64,19 +64,25 @@ using mozilla::RotateLeft;
typedef Rooted<GlobalObject *> RootedGlobalObject;
/* static */ uint32_t
Bindings::argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle bindings)
Bindings::argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle bindings,
uint32_t *unaliasedSlot)
{
HandlePropertyName arguments = cx->names().arguments;
BindingIter bi(bindings);
while (bi->name() != arguments)
bi++;
return bi.frameIndex();
if (unaliasedSlot)
*unaliasedSlot = bi->aliased() ? UINT32_MAX : bi.frameIndex();
return bi.localIndex();
}
bool
Bindings::initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self,
uint32_t numArgs, uint32_t numVars,
uint32_t numBodyLevelLexicals, uint32_t numBlockScoped,
uint32_t numUnaliasedVars, uint32_t numUnaliasedBodyLevelLexicals,
Binding *bindingArray)
{
MOZ_ASSERT(!self->callObjShape_);
@ -92,11 +98,16 @@ Bindings::initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle
MOZ_ASSERT(totalSlots <= LOCALNO_LIMIT);
MOZ_ASSERT(UINT32_MAX - numArgs >= totalSlots);
MOZ_ASSERT(numUnaliasedVars <= numVars);
MOZ_ASSERT(numUnaliasedBodyLevelLexicals <= numBodyLevelLexicals);
self->bindingArrayAndFlag_ = uintptr_t(bindingArray) | TEMPORARY_STORAGE_BIT;
self->numArgs_ = numArgs;
self->numVars_ = numVars;
self->numBodyLevelLexicals_ = numBodyLevelLexicals;
self->numBlockScoped_ = numBlockScoped;
self->numUnaliasedVars_ = numUnaliasedVars;
self->numUnaliasedBodyLevelLexicals_ = numUnaliasedBodyLevelLexicals;
// Get the initial shape to use when creating CallObjects for this script.
// After creation, a CallObject's shape may change completely (via direct eval() or
@ -123,7 +134,7 @@ Bindings::initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle
if (numBodyLevelLexicals > 0 &&
nslots < aliasedBodyLevelLexicalBegin &&
bi->kind() == Binding::VARIABLE &&
bi.frameIndex() >= numVars)
bi.localIndex() >= numVars)
{
aliasedBodyLevelLexicalBegin = nslots;
}
@ -215,7 +226,10 @@ Bindings::clone(JSContext *cx, InternalBindingsHandle self,
* the source's bindingArray directly.
*/
if (!initWithTemporaryStorage(cx, self, src.numArgs(), src.numVars(),
src.numBodyLevelLexicals(), src.numBlockScoped(),
src.numBodyLevelLexicals(),
src.numBlockScoped(),
src.numUnaliasedVars(),
src.numUnaliasedBodyLevelLexicals(),
src.bindingArray()))
{
return false;
@ -234,7 +248,9 @@ GCMethods<Bindings>::initial()
template<XDRMode mode>
static bool
XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, uint16_t numArgs, uint32_t numVars,
uint16_t numBodyLevelLexicals, uint16_t numBlockScoped, HandleScript script)
uint16_t numBodyLevelLexicals, uint16_t numBlockScoped,
uint32_t numUnaliasedVars, uint16_t numUnaliasedBodyLevelLexicals,
HandleScript script)
{
JSContext *cx = xdr->cx();
@ -281,6 +297,7 @@ XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, uint16_t numArgs, ui
InternalBindingsHandle bindings(script, &script->bindings);
if (!Bindings::initWithTemporaryStorage(cx, bindings, numArgs, numVars,
numBodyLevelLexicals, numBlockScoped,
numUnaliasedVars, numUnaliasedBodyLevelLexicals,
bindingArray))
{
return false;
@ -599,6 +616,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
uint16_t nblocklocals = 0;
uint16_t nbodylevellexicals = 0;
uint32_t nvars = 0;
uint32_t nunaliasedvars = 0;
uint16_t nunaliasedbodylevellexicals = 0;
if (mode == XDR_ENCODE) {
script = scriptp.get();
MOZ_ASSERT_IF(enclosingScript, enclosingScript->compartment() == script->compartment());
@ -607,6 +626,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
nblocklocals = script->bindings.numBlockScoped();
nbodylevellexicals = script->bindings.numBodyLevelLexicals();
nvars = script->bindings.numVars();
nunaliasedvars = script->bindings.numUnaliasedVars();
nunaliasedbodylevellexicals = script->bindings.numUnaliasedBodyLevelLexicals();
}
if (!xdr->codeUint16(&nargs))
return false;
@ -616,6 +637,10 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
return false;
if (!xdr->codeUint32(&nvars))
return false;
if (!xdr->codeUint32(&nunaliasedvars))
return false;
if (!xdr->codeUint16(&nunaliasedbodylevellexicals))
return false;
if (mode == XDR_ENCODE)
length = script->length();
@ -759,7 +784,8 @@ js::XDRScript(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enc
/* JSScript::partiallyInit assumes script->bindings is fully initialized. */
LifoAllocScope las(&cx->tempLifoAlloc());
if (!XDRScriptBindings(xdr, las, nargs, nvars, nbodylevellexicals, nblocklocals, script))
if (!XDRScriptBindings(xdr, las, nargs, nvars, nbodylevellexicals, nblocklocals,
nunaliasedvars, nunaliasedbodylevellexicals, script))
return false;
if (mode == XDR_DECODE) {
@ -3518,7 +3544,8 @@ js::SetFrameArgumentsObject(JSContext *cx, AbstractFramePtr frame,
*/
InternalBindingsHandle bindings(script, &script->bindings);
const uint32_t var = Bindings::argumentsVarIndex(cx, bindings);
uint32_t unaliasedSlot;
const uint32_t var = Bindings::argumentsVarIndex(cx, bindings, &unaliasedSlot);
if (script->varIsAliased(var)) {
/*
@ -3537,8 +3564,8 @@ js::SetFrameArgumentsObject(JSContext *cx, AbstractFramePtr frame,
if (IsOptimizedPlaceholderMagicValue(frame.callObj().as<ScopeObject>().aliasedVar(ScopeCoordinate(pc))))
frame.callObj().as<ScopeObject>().setAliasedVar(cx, ScopeCoordinate(pc), cx->names().arguments, ObjectValue(*argsobj));
} else {
if (IsOptimizedPlaceholderMagicValue(frame.unaliasedLocal(var)))
frame.unaliasedLocal(var) = ObjectValue(*argsobj);
if (IsOptimizedPlaceholderMagicValue(frame.unaliasedLocal(unaliasedSlot)))
frame.unaliasedLocal(unaliasedSlot) = ObjectValue(*argsobj);
}
}

View File

@ -187,7 +187,9 @@ class Bindings
uint16_t numBlockScoped_;
uint16_t numBodyLevelLexicals_;
uint16_t aliasedBodyLevelLexicalBegin_;
uint16_t numUnaliasedBodyLevelLexicals_;
uint32_t numVars_;
uint32_t numUnaliasedVars_;
#if JS_BITS_PER_WORD == 32
// Bindings is allocated inline inside JSScript, which needs to be
@ -227,6 +229,7 @@ class Bindings
static bool initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self,
uint32_t numArgs, uint32_t numVars,
uint32_t numBodyLevelLexicals, uint32_t numBlockScoped,
uint32_t numUnaliasedVars, uint32_t numUnaliasedBodyLevelLexicals,
Binding *bindingArray);
// CompileScript parses and compiles one statement at a time, but the result
@ -257,10 +260,16 @@ class Bindings
uint32_t numBodyLevelLexicals() const { return numBodyLevelLexicals_; }
uint32_t numBlockScoped() const { return numBlockScoped_; }
uint32_t numBodyLevelLocals() const { return numVars_ + numBodyLevelLexicals_; }
uint32_t numUnaliasedBodyLevelLocals() const { return numUnaliasedVars_ + numUnaliasedBodyLevelLexicals_; }
uint32_t numAliasedBodyLevelLocals() const { return numBodyLevelLocals() - numUnaliasedBodyLevelLocals(); }
uint32_t numLocals() const { return numVars() + numBodyLevelLexicals() + numBlockScoped(); }
uint32_t numUnaliasedLocals() const { return numUnaliasedVars() + numUnaliasedBodyLevelLexicals() + numBlockScoped(); }
uint32_t lexicalBegin() const { return numArgs() + numVars(); }
uint32_t aliasedBodyLevelLexicalBegin() const { return aliasedBodyLevelLexicalBegin_; }
uint32_t numUnaliasedVars() const { return numUnaliasedVars_; }
uint32_t numUnaliasedBodyLevelLexicals() const { return numUnaliasedBodyLevelLexicals_; }
// Return the size of the bindingArray.
uint32_t count() const { return numArgs() + numVars() + numBodyLevelLexicals(); }
@ -268,7 +277,8 @@ class Bindings
Shape *callObjShape() const { return callObjShape_; }
/* Convenience method to get the var index of 'arguments'. */
static uint32_t argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle);
static uint32_t argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle,
uint32_t *unaliasedSlot = nullptr);
/* Return whether the binding at bindingIndex is aliased. */
bool bindingIsAliased(uint32_t bindingIndex);
@ -1053,20 +1063,20 @@ class JSScript : public js::gc::TenuredCell
// The fixed part of a stack frame is comprised of vars (in function code)
// and block-scoped locals (in all kinds of code).
size_t nfixed() const {
return function_ ? bindings.numLocals() : bindings.numBlockScoped();
return function_ ? bindings.numUnaliasedLocals() : bindings.numBlockScoped();
}
// Number of fixed slots reserved for vars. Only nonzero for function
// code.
size_t nfixedvars() const {
return function_ ? bindings.numVars() : 0;
return function_ ? bindings.numUnaliasedVars() : 0;
}
// Number of fixed slots reserved for body-level lexicals and vars. This
// value minus nfixedvars() is the number of body-level lexicals. Only
// nonzero for function code.
size_t nbodyfixed() const {
return function_ ? bindings.numBodyLevelLocals() : 0;
return function_ ? bindings.numUnaliasedBodyLevelLocals() : 0;
}
// Aliases for clarity when dealing with lexical slots.
@ -1684,22 +1694,52 @@ class BindingIter
{
const InternalBindingsHandle bindings_;
uint32_t i_;
uint32_t unaliasedLocal_;
friend class Bindings;
public:
explicit BindingIter(const InternalBindingsHandle &bindings) : bindings_(bindings), i_(0) {}
explicit BindingIter(const HandleScript &script) : bindings_(script, &script->bindings), i_(0) {}
explicit BindingIter(const InternalBindingsHandle &bindings)
: bindings_(bindings), i_(0), unaliasedLocal_(0) {}
explicit BindingIter(const HandleScript &script)
: bindings_(script, &script->bindings), i_(0), unaliasedLocal_(0) {}
bool done() const { return i_ == bindings_->count(); }
operator bool() const { return !done(); }
void operator++(int) { MOZ_ASSERT(!done()); i_++; }
BindingIter &operator++() { (*this)++; return *this; }
void operator++(int) {
MOZ_ASSERT(!done());
const Binding &binding = **this;
if (binding.kind() != Binding::ARGUMENT && !binding.aliased())
unaliasedLocal_++;
i_++;
}
// Stack slots are assigned to arguments and unaliased locals. frameIndex()
// returns the slot index. It's invalid to call this method when the
// iterator is stopped on an aliased local, as it has no stack slot.
uint32_t frameIndex() const {
MOZ_ASSERT(!done());
if (i_ < bindings_->numArgs())
return i_;
MOZ_ASSERT(!(*this)->aliased());
return unaliasedLocal_;
}
uint32_t argIndex() const {
MOZ_ASSERT(!done());
MOZ_ASSERT(i_ < bindings_->numArgs());
return i_;
}
uint32_t argOrLocalIndex() const {
MOZ_ASSERT(!done());
return i_ < bindings_->numArgs() ? i_ : i_ - bindings_->numArgs();
}
uint32_t localIndex() const {
MOZ_ASSERT(!done());
MOZ_ASSERT(i_ >= bindings_->numArgs());
return i_ - bindings_->numArgs();
}
const Binding &operator*() const { MOZ_ASSERT(!done()); return bindings_->bindingArray()[i_]; }
const Binding *operator->() const { MOZ_ASSERT(!done()); return &bindings_->bindingArray()[i_]; }

View File

@ -23,7 +23,9 @@ namespace js {
inline
Bindings::Bindings()
: callObjShape_(nullptr), bindingArrayAndFlag_(TEMPORARY_STORAGE_BIT),
numArgs_(0), numBlockScoped_(0), numVars_(0)
numArgs_(0), numBlockScoped_(0),
numBodyLevelLexicals_(0), numUnaliasedBodyLevelLexicals_(0),
numVars_(0), numUnaliasedVars_(0)
{}
inline

View File

@ -1130,7 +1130,7 @@ ForkJoinOperation::reportBailoutWarnings()
else
arg = frame->unaliasedActual(i, DONT_CHECK_ALIASING);
} else {
arg = frame->unaliasedLocal(i - frame->numFormalArgs(), DONT_CHECK_ALIASING);
arg = frame->unaliasedLocal(i - frame->numFormalArgs());
}
JSAutoByteString valueBytes;

View File

@ -1349,10 +1349,10 @@ class DebugScopeProxy : public BaseProxyHandler
return true;
if (bi->kind() == Binding::VARIABLE || bi->kind() == Binding::CONSTANT) {
uint32_t i = bi.frameIndex();
if (script->bodyLevelLocalIsAliased(i))
if (script->bodyLevelLocalIsAliased(bi.localIndex()))
return true;
uint32_t i = bi.frameIndex();
if (maybeLiveScope) {
AbstractFramePtr frame = maybeLiveScope->frame();
if (action == GET)
@ -1373,7 +1373,7 @@ class DebugScopeProxy : public BaseProxyHandler
}
} else {
MOZ_ASSERT(bi->kind() == Binding::ARGUMENT);
unsigned i = bi.frameIndex();
unsigned i = bi.argIndex();
if (script->formalIsAliased(i))
return true;

View File

@ -118,12 +118,9 @@ InterpreterFrame::unaliasedVar(uint32_t i, MaybeCheckAliasing checkAliasing)
}
inline Value &
InterpreterFrame::unaliasedLocal(uint32_t i, MaybeCheckAliasing checkAliasing)
InterpreterFrame::unaliasedLocal(uint32_t i)
{
MOZ_ASSERT(i < script()->nfixed());
#ifdef DEBUG
CheckLocalUnaliased(checkAliasing, script(), i);
#endif
return slots()[i];
}
@ -502,13 +499,13 @@ AbstractFramePtr::unaliasedVar(uint32_t i, MaybeCheckAliasing checkAliasing)
}
inline Value &
AbstractFramePtr::unaliasedLocal(uint32_t i, MaybeCheckAliasing checkAliasing)
AbstractFramePtr::unaliasedLocal(uint32_t i)
{
if (isInterpreterFrame())
return asInterpreterFrame()->unaliasedLocal(i, checkAliasing);
return asInterpreterFrame()->unaliasedLocal(i);
if (isBaselineFrame())
return asBaselineFrame()->unaliasedLocal(i, checkAliasing);
return asRematerializedFrame()->unaliasedLocal(i, checkAliasing);
return asBaselineFrame()->unaliasedLocal(i);
return asRematerializedFrame()->unaliasedLocal(i);
}
inline Value &

View File

@ -368,7 +368,7 @@ InterpreterFrame::markValues(JSTracer *trc, Value *sp, jsbytecode *pc)
// Clear dead block-scoped locals.
while (nfixed > nlivefixed)
unaliasedLocal(--nfixed, DONT_CHECK_ALIASING).setMagic(JS_UNINITIALIZED_LEXICAL);
unaliasedLocal(--nfixed).setMagic(JS_UNINITIALIZED_LEXICAL);
// Mark live locals.
markValues(trc, 0, nlivefixed);
@ -1348,23 +1348,6 @@ AbstractFramePtr::hasPushedSPSFrame() const
return asBaselineFrame()->hasPushedSPSFrame();
}
#ifdef DEBUG
void
js::CheckLocalUnaliased(MaybeCheckAliasing checkAliasing, JSScript *script, uint32_t i)
{
if (!checkAliasing)
return;
MOZ_ASSERT(i < script->nfixed());
if (i < script->bindings.numVars()) {
MOZ_ASSERT(!script->varIsAliased(i));
} else {
// FIXME: The callers of this function do not easily have the PC of the
// current frame, and so they do not know the block scope.
}
}
#endif
jit::JitActivation::JitActivation(JSContext *cx, bool active)
: Activation(cx, Jit),
active_(active),

View File

@ -68,11 +68,6 @@ enum MaybeCheckLexical { CheckLexical = true, DontCheckLexical = false };
/*****************************************************************************/
#ifdef DEBUG
extern void
CheckLocalUnaliased(MaybeCheckAliasing checkAliasing, JSScript *script, uint32_t i);
#endif
namespace jit {
class BaselineFrame;
class RematerializedFrame;
@ -217,7 +212,7 @@ class AbstractFramePtr
inline bool copyRawFrameSlots(AutoValueVector *vec) const;
inline Value &unaliasedVar(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
inline Value &unaliasedLocal(uint32_t i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
inline Value &unaliasedLocal(uint32_t i);
inline Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
inline Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING);
template <class Op> inline void unaliasedForEachActual(JSContext *cx, Op op);
@ -517,7 +512,7 @@ class InterpreterFrame
*/
inline Value &unaliasedVar(uint32_t i, MaybeCheckAliasing = CHECK_ALIASING);
inline Value &unaliasedLocal(uint32_t i, MaybeCheckAliasing = CHECK_ALIASING);
inline Value &unaliasedLocal(uint32_t i);
bool hasArgs() const { return isNonEvalFunctionFrame(); }
inline Value &unaliasedFormal(unsigned i, MaybeCheckAliasing = CHECK_ALIASING);