mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1090491 - Don't allocate stack slots for aliased locals. r=luke
This commit is contained in:
parent
7b65d193f4
commit
f6ade302c6
@ -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;
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
24
js/src/jit-test/tests/debug/Frame-eval-24.js
Normal file
24
js/src/jit-test/tests/debug/Frame-eval-24.js
Normal 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);
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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_]; }
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 &
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user