Bug 1454285 - Part 2: Disallow using innermostEmitterScope while the value does not match the bytecode environment.

Tag #1287
This commit is contained in:
Gaming4JC 2019-12-12 22:41:21 -05:00 • committed by Roy Tam
commit d16b90c099
2 changed files with 76 additions and 32 deletions

View file

@ -100,7 +100,7 @@ class BytecodeEmitter::NestableControl : public Nestable<BytecodeEmitter::Nestab
NestableControl(BytecodeEmitter* bce, StatementKind kind) NestableControl(BytecodeEmitter* bce, StatementKind kind)
: Nestable<NestableControl>(&bce->innermostNestableControl), : Nestable<NestableControl>(&bce->innermostNestableControl),
kind_(kind), kind_(kind),
emitterScope_(bce->innermostEmitterScope) emitterScope_(bce->innermostEmitterScopeNoCheck())
{ } { }
public: public:
@ -426,7 +426,7 @@ class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterSc
// enclosing BCE. // enclosing BCE.
if ((*bce)->parent) { if ((*bce)->parent) {
*bce = (*bce)->parent; *bce = (*bce)->parent;
return (*bce)->innermostEmitterScope; return (*bce)->innermostEmitterScopeNoCheck();
} }
return nullptr; return nullptr;
@ -460,7 +460,7 @@ class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterSc
public: public:
explicit EmitterScope(BytecodeEmitter* bce) explicit EmitterScope(BytecodeEmitter* bce)
: Nestable<EmitterScope>(&bce->innermostEmitterScope), : Nestable<EmitterScope>(&bce->innermostEmitterScope_),
nameCache_(bce->cx->frontendCollectionPool()), nameCache_(bce->cx->frontendCollectionPool()),
hasEnvironment_(false), hasEnvironment_(false),
environmentChainLength_(0), environmentChainLength_(0),
@ -866,7 +866,7 @@ BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind
Handle<LexicalScope::Data*> bindings) Handle<LexicalScope::Data*> bindings)
{ {
MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda); MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda);
MOZ_ASSERT(this == bce->innermostEmitterScope); MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
if (!ensureCache(bce)) if (!ensureCache(bce))
return false; return false;
@ -935,7 +935,7 @@ BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind
bool bool
BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox) BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox)
{ {
MOZ_ASSERT(this == bce->innermostEmitterScope); MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
MOZ_ASSERT(funbox->namedLambdaBindings()); MOZ_ASSERT(funbox->namedLambdaBindings());
if (!ensureCache(bce)) if (!ensureCache(bce))
@ -1002,7 +1002,7 @@ BytecodeEmitter::EmitterScope::enterComprehensionFor(BytecodeEmitter* bce,
bool bool
BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce) BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
{ {
MOZ_ASSERT(this == bce->innermostEmitterScope); MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
if (!ensureCache(bce)) if (!ensureCache(bce))
return false; return false;
@ -1035,7 +1035,7 @@ BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
bool bool
BytecodeEmitter::EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox) BytecodeEmitter::EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox)
{ {
MOZ_ASSERT(this == bce->innermostEmitterScope); MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
// If there are parameter expressions, there is an extra var scope. // If there are parameter expressions, there is an extra var scope.
if (!funbox->hasExtraBodyVarScope()) if (!funbox->hasExtraBodyVarScope())
@ -1126,7 +1126,7 @@ BytecodeEmitter::EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, F
MOZ_ASSERT(funbox->hasParameterExprs); MOZ_ASSERT(funbox->hasParameterExprs);
MOZ_ASSERT(funbox->extraVarScopeBindings() || MOZ_ASSERT(funbox->extraVarScopeBindings() ||
funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings()); funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings());
MOZ_ASSERT(this == bce->innermostEmitterScope); MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
// The extra var scope is never popped once it's entered. It replaces the // The extra var scope is never popped once it's entered. It replaces the
// function scope as the var emitter scope. // function scope as the var emitter scope.
@ -1212,7 +1212,7 @@ class DynamicBindingIter : public BindingIter
bool bool
BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc) BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc)
{ {
MOZ_ASSERT(this == bce->innermostEmitterScope); MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
bce->setVarEmitterScope(this); bce->setVarEmitterScope(this);
@ -1272,7 +1272,7 @@ BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedCon
bool bool
BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc) BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc)
{ {
MOZ_ASSERT(this == bce->innermostEmitterScope); MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
bce->setVarEmitterScope(this); bce->setVarEmitterScope(this);
@ -1327,7 +1327,7 @@ BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext
bool bool
BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc) BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc)
{ {
MOZ_ASSERT(this == bce->innermostEmitterScope); MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
bce->setVarEmitterScope(this); bce->setVarEmitterScope(this);
@ -1384,7 +1384,7 @@ BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedCon
bool bool
BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce) BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce)
{ {
MOZ_ASSERT(this == bce->innermostEmitterScope); MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
if (!ensureCache(bce)) if (!ensureCache(bce))
return false; return false;
@ -1412,7 +1412,7 @@ BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
{ {
// If we aren't leaving the scope due to a non-local jump (e.g., break), // If we aren't leaving the scope due to a non-local jump (e.g., break),
// we must be the innermost scope. // we must be the innermost scope.
MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScope); MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScopeNoCheck());
ScopeKind kind = scope(bce)->kind(); ScopeKind kind = scope(bce)->kind();
switch (kind) { switch (kind) {
@ -2123,7 +2123,7 @@ class ForOfLoopControl : public LoopControl
bool emitIteratorCloseInInnermostScope(BytecodeEmitter* bce, bool emitIteratorCloseInInnermostScope(BytecodeEmitter* bce,
CompletionKind completionKind = CompletionKind::Normal) { CompletionKind completionKind = CompletionKind::Normal) {
return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope, completionKind); return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope(), completionKind);
} }
bool emitIteratorCloseInScope(BytecodeEmitter* bce, bool emitIteratorCloseInScope(BytecodeEmitter* bce,
@ -2201,8 +2201,11 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
bodyScopeIndex(UINT32_MAX), bodyScopeIndex(UINT32_MAX),
varEmitterScope(nullptr), varEmitterScope(nullptr),
innermostNestableControl(nullptr), innermostNestableControl(nullptr),
innermostEmitterScope(nullptr), innermostEmitterScope_(nullptr),
innermostTDZCheckCache(nullptr), innermostTDZCheckCache(nullptr),
#ifdef DEBUG
unstableEmitterScope(false),
#endif
constList(cx), constList(cx),
scopeList(cx), scopeList(cx),
tryNoteList(cx), tryNoteList(cx),
@ -2259,13 +2262,13 @@ BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const
NameLocation NameLocation
BytecodeEmitter::lookupName(JSAtom* name) BytecodeEmitter::lookupName(JSAtom* name)
{ {
return innermostEmitterScope->lookup(this, name); return innermostEmitterScope()->lookup(this, name);
} }
Maybe<NameLocation> Maybe<NameLocation>
BytecodeEmitter::locationOfNameBoundInScope(JSAtom* name, EmitterScope* target) BytecodeEmitter::locationOfNameBoundInScope(JSAtom* name, EmitterScope* target)
{ {
return innermostEmitterScope->locationBoundInScope(this, name, target); return innermostEmitterScope()->locationBoundInScope(this, name, target);
} }
Maybe<NameLocation> Maybe<NameLocation>
@ -2726,7 +2729,7 @@ class NonLocalExitControl
: bce_(bce), : bce_(bce),
savedScopeNoteIndex_(bce->scopeNoteList.length()), savedScopeNoteIndex_(bce->scopeNoteList.length()),
savedDepth_(bce->stackDepth), savedDepth_(bce->stackDepth),
openScopeNoteIndex_(bce->innermostEmitterScope->noteIndex()), openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()),
kind_(kind) kind_(kind)
{ } { }
@ -2772,9 +2775,11 @@ NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* ta
using NestableControl = BytecodeEmitter::NestableControl; using NestableControl = BytecodeEmitter::NestableControl;
using EmitterScope = BytecodeEmitter::EmitterScope; using EmitterScope = BytecodeEmitter::EmitterScope;
EmitterScope* es = bce_->innermostEmitterScope; EmitterScope* es = bce_->innermostEmitterScope();
int npops = 0; int npops = 0;
AutoCheckUnstableEmitterScope cues(bce_);
// For 'continue', 'break', and 'return' statements, emit IteratorClose // For 'continue', 'break', and 'return' statements, emit IteratorClose
// bytecode inline. 'continue' statements do not call IteratorClose for // bytecode inline. 'continue' statements do not call IteratorClose for
// the loop they are continuing. // the loop they are continuing.
@ -2895,7 +2900,7 @@ BytecodeEmitter::emitGoto(NestableControl* target, JumpList* jumplist, SrcNoteTy
Scope* Scope*
BytecodeEmitter::innermostScope() const BytecodeEmitter::innermostScope() const
{ {
return innermostEmitterScope->scope(this); return innermostEmitterScope()->scope(this);
} }
bool bool
@ -3555,7 +3560,7 @@ BytecodeEmitter::needsImplicitThis()
return true; return true;
// Otherwise see if the current point is under a 'with'. // Otherwise see if the current point is under a 'with'.
for (EmitterScope* es = innermostEmitterScope; es; es = es->enclosingInFrame()) { for (EmitterScope* es = innermostEmitterScope(); es; es = es->enclosingInFrame()) {
if (es->scope(this)->kind() == ScopeKind::With) if (es->scope(this)->kind() == ScopeKind::With)
return true; return true;
} }
@ -5206,7 +5211,7 @@ BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, Destructuri
// destructuring declaration needs to initialize the name in // destructuring declaration needs to initialize the name in
// the function scope. The innermost scope is the var scope, // the function scope. The innermost scope is the var scope,
// and its enclosing scope is the function scope. // and its enclosing scope is the function scope.
EmitterScope* funScope = innermostEmitterScope->enclosingInFrame(); EmitterScope* funScope = innermostEmitterScope()->enclosingInFrame();
NameLocation paramLoc = *locationOfNameBoundInScope(name, funScope); NameLocation paramLoc = *locationOfNameBoundInScope(name, funScope);
if (!emitSetOrInitializeNameAtLocation(name, paramLoc, emitSwapScopeAndRhs, true)) if (!emitSetOrInitializeNameAtLocation(name, paramLoc, emitSwapScopeAndRhs, true))
return false; return false;
@ -7308,7 +7313,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
// bindings inducing an environment, recreate the current environment. // bindings inducing an environment, recreate the current environment.
DebugOnly<ParseNode*> forOfTarget = forOfHead->pn_kid1; DebugOnly<ParseNode*> forOfTarget = forOfHead->pn_kid1;
MOZ_ASSERT(forOfTarget->isKind(PNK_LET) || forOfTarget->isKind(PNK_CONST)); MOZ_ASSERT(forOfTarget->isKind(PNK_LET) || forOfTarget->isKind(PNK_CONST));
MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope); MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical); MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
if (headLexicalEmitterScope->hasEnvironment()) { if (headLexicalEmitterScope->hasEnvironment()) {
@ -7490,7 +7495,7 @@ BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitte
// it must be the innermost one. If that scope has closed-over // it must be the innermost one. If that scope has closed-over
// bindings inducing an environment, recreate the current environment. // bindings inducing an environment, recreate the current environment.
MOZ_ASSERT(forInTarget->isKind(PNK_LET) || forInTarget->isKind(PNK_CONST)); MOZ_ASSERT(forInTarget->isKind(PNK_LET) || forInTarget->isKind(PNK_CONST));
MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope); MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical); MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
if (headLexicalEmitterScope->hasEnvironment()) { if (headLexicalEmitterScope->hasEnvironment()) {
@ -7619,7 +7624,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc
// exists for the head, it must be the innermost one. If that scope // exists for the head, it must be the innermost one. If that scope
// has closed-over bindings inducing an environment, recreate the // has closed-over bindings inducing an environment, recreate the
// current environment. // current environment.
MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope); MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical); MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
if (headLexicalEmitterScope->hasEnvironment()) { if (headLexicalEmitterScope->hasEnvironment()) {
@ -7667,7 +7672,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc
// ES 13.7.4.8 step 3.e. The per-iteration freshening. // ES 13.7.4.8 step 3.e. The per-iteration freshening.
if (forLoopRequiresFreshening) { if (forLoopRequiresFreshening) {
MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope); MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical); MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
if (headLexicalEmitterScope->hasEnvironment()) { if (headLexicalEmitterScope->hasEnvironment()) {
@ -10367,7 +10372,7 @@ BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn)
{ {
ParseNode* funBody = pn->last(); ParseNode* funBody = pn->last();
FunctionBox* funbox = sc->asFunctionBox(); FunctionBox* funbox = sc->asFunctionBox();
EmitterScope* funScope = innermostEmitterScope; EmitterScope* funScope = innermostEmitterScope();
bool hasParameterExprs = funbox->hasParameterExprs; bool hasParameterExprs = funbox->hasParameterExprs;
bool hasRest = funbox->hasRest(); bool hasRest = funbox->hasRest();

View file

@ -228,9 +228,23 @@ struct MOZ_STACK_CLASS BytecodeEmitter
EmitterScope* varEmitterScope; EmitterScope* varEmitterScope;
NestableControl* innermostNestableControl; NestableControl* innermostNestableControl;
EmitterScope* innermostEmitterScope; EmitterScope* innermostEmitterScope_;
TDZCheckCache* innermostTDZCheckCache; TDZCheckCache* innermostTDZCheckCache;
#ifdef DEBUG
bool unstableEmitterScope;
friend class AutoCheckUnstableEmitterScope;
#endif
EmitterScope* innermostEmitterScope() const {
MOZ_ASSERT(!unstableEmitterScope);
return innermostEmitterScopeNoCheck();
}
EmitterScope* innermostEmitterScopeNoCheck() const {
return innermostEmitterScope_;
}
CGConstList constList; /* constants to be included with the script */ CGConstList constList; /* constants to be included with the script */
CGObjectList objectList; /* list of emitted objects */ CGObjectList objectList; /* list of emitted objects */
CGScopeList scopeList; /* list of emitted scopes */ CGScopeList scopeList; /* list of emitted scopes */
@ -319,7 +333,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
EmitterScope* source); EmitterScope* source);
mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope(JSAtom* name) { mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope(JSAtom* name) {
return locationOfNameBoundInFunctionScope(name, innermostEmitterScope); return locationOfNameBoundInFunctionScope(name, innermostEmitterScope());
} }
void setVarEmitterScope(EmitterScope* emitterScope) { void setVarEmitterScope(EmitterScope* emitterScope) {
@ -610,7 +624,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitToIteratorResult(bool done); MOZ_MUST_USE bool emitToIteratorResult(bool done);
MOZ_MUST_USE bool emitGetDotGeneratorInInnermostScope() { MOZ_MUST_USE bool emitGetDotGeneratorInInnermostScope() {
return emitGetDotGeneratorInScope(*innermostEmitterScope); return emitGetDotGeneratorInScope(*innermostEmitterScope());
} }
MOZ_MUST_USE bool emitGetDotGeneratorInScope(EmitterScope& currentScope); MOZ_MUST_USE bool emitGetDotGeneratorInScope(EmitterScope& currentScope);
@ -619,7 +633,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitYieldOp(JSOp op); MOZ_MUST_USE bool emitYieldOp(JSOp op);
MOZ_MUST_USE bool emitYieldStar(ParseNode* iter); MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
MOZ_MUST_USE bool emitAwaitInInnermostScope() { MOZ_MUST_USE bool emitAwaitInInnermostScope() {
return emitAwaitInScope(*innermostEmitterScope); return emitAwaitInScope(*innermostEmitterScope());
} }
MOZ_MUST_USE bool emitAwaitInInnermostScope(ParseNode* pn); MOZ_MUST_USE bool emitAwaitInInnermostScope(ParseNode* pn);
MOZ_MUST_USE bool emitAwaitInScope(EmitterScope& currentScope); MOZ_MUST_USE bool emitAwaitInScope(EmitterScope& currentScope);
@ -729,7 +743,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitIteratorCloseInInnermostScope(IteratorKind iterKind = IteratorKind::Sync, MOZ_MUST_USE bool emitIteratorCloseInInnermostScope(IteratorKind iterKind = IteratorKind::Sync,
CompletionKind completionKind = CompletionKind::Normal, CompletionKind completionKind = CompletionKind::Normal,
bool allowSelfHosted = false) { bool allowSelfHosted = false) {
return emitIteratorCloseInScope(*innermostEmitterScope, iterKind, completionKind, return emitIteratorCloseInScope(*innermostEmitterScope(), iterKind, completionKind,
allowSelfHosted); allowSelfHosted);
} }
@ -829,6 +843,31 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false); MOZ_MUST_USE bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
}; };
class MOZ_RAII AutoCheckUnstableEmitterScope {
#ifdef DEBUG
bool prev_;
BytecodeEmitter* bce_;
#endif
public:
AutoCheckUnstableEmitterScope() = delete;
explicit AutoCheckUnstableEmitterScope(BytecodeEmitter* bce)
#ifdef DEBUG
: bce_(bce)
#endif
{
#ifdef DEBUG
prev_ = bce_->unstableEmitterScope;
bce_->unstableEmitterScope = true;
#endif
}
~AutoCheckUnstableEmitterScope() {
#ifdef DEBUG
bce_->unstableEmitterScope = prev_;
#endif
}
};
} /* namespace frontend */ } /* namespace frontend */
} /* namespace js */ } /* namespace js */