|
@@ -1,663 +0,0 @@
|
|
|
-# HG changeset patch
|
|
|
-# User Tooru Fujisawa <arai_a@mac.com>
|
|
|
-# Date 1526980228 -32400
|
|
|
-# Tue May 22 18:10:28 2018 +0900
|
|
|
-# Node ID 567757b97ff0f511bb142b966f5b5777bad7fdc2
|
|
|
-# Parent 6ca6ced5189a5760c96afa31a6575cd3d3f56639
|
|
|
-Bug 1454285 - Part 2: Disallow using innermostEmitterScope while the value does not match the bytecode environment. r=jwalden
|
|
|
-
|
|
|
-diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
|
|
|
---- a/js/src/frontend/BytecodeEmitter.cpp
|
|
|
-+++ b/js/src/frontend/BytecodeEmitter.cpp
|
|
|
-@@ -104,17 +104,17 @@ class BytecodeEmitter::NestableControl :
|
|
|
-
|
|
|
- // The innermost scope when this was pushed.
|
|
|
- EmitterScope* emitterScope_;
|
|
|
-
|
|
|
- protected:
|
|
|
- NestableControl(BytecodeEmitter* bce, StatementKind kind)
|
|
|
- : Nestable<NestableControl>(&bce->innermostNestableControl),
|
|
|
- kind_(kind),
|
|
|
-- emitterScope_(bce->innermostEmitterScope)
|
|
|
-+ emitterScope_(bce->innermostEmitterScopeNoCheck())
|
|
|
- { }
|
|
|
-
|
|
|
- public:
|
|
|
- using Nestable<NestableControl>::enclosing;
|
|
|
- using Nestable<NestableControl>::findNearest;
|
|
|
-
|
|
|
- StatementKind kind() const {
|
|
|
- return kind_;
|
|
|
-@@ -443,17 +443,17 @@ class BytecodeEmitter::EmitterScope : pu
|
|
|
- // There is an enclosing scope with access to the same frame.
|
|
|
- if (EmitterScope* inFrame = enclosingInFrame())
|
|
|
- return inFrame;
|
|
|
-
|
|
|
- // We are currently compiling the enclosing script, look in the
|
|
|
- // enclosing BCE.
|
|
|
- if ((*bce)->parent) {
|
|
|
- *bce = (*bce)->parent;
|
|
|
-- return (*bce)->innermostEmitterScope;
|
|
|
-+ return (*bce)->innermostEmitterScopeNoCheck();
|
|
|
- }
|
|
|
-
|
|
|
- return nullptr;
|
|
|
- }
|
|
|
-
|
|
|
- Scope* enclosingScope(BytecodeEmitter* bce) const {
|
|
|
- if (EmitterScope* es = enclosing(&bce))
|
|
|
- return es->scope(bce);
|
|
|
-@@ -477,17 +477,17 @@ class BytecodeEmitter::EmitterScope : pu
|
|
|
- MOZ_MUST_USE bool internBodyScope(BytecodeEmitter* bce, ScopeCreator createScope);
|
|
|
- MOZ_MUST_USE bool appendScopeNote(BytecodeEmitter* bce);
|
|
|
-
|
|
|
- MOZ_MUST_USE bool deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart,
|
|
|
- uint32_t slotEnd);
|
|
|
-
|
|
|
- public:
|
|
|
- explicit EmitterScope(BytecodeEmitter* bce)
|
|
|
-- : Nestable<EmitterScope>(&bce->innermostEmitterScope),
|
|
|
-+ : Nestable<EmitterScope>(&bce->innermostEmitterScope_),
|
|
|
- nameCache_(bce->cx->frontendCollectionPool()),
|
|
|
- hasEnvironment_(false),
|
|
|
- environmentChainLength_(0),
|
|
|
- nextFrameSlot_(0),
|
|
|
- scopeIndex_(ScopeNote::NoScopeIndex),
|
|
|
- noteIndex_(ScopeNote::NoScopeNoteIndex)
|
|
|
- { }
|
|
|
-
|
|
|
-@@ -883,17 +883,17 @@ BytecodeEmitter::EmitterScope::deadZoneF
|
|
|
- return deadZoneFrameSlotRange(bce, frameSlotStart(), frameSlotEnd());
|
|
|
- }
|
|
|
-
|
|
|
- bool
|
|
|
- BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind,
|
|
|
- Handle<LexicalScope::Data*> bindings)
|
|
|
- {
|
|
|
- MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda);
|
|
|
-- MOZ_ASSERT(this == bce->innermostEmitterScope);
|
|
|
-+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
|
|
|
-
|
|
|
- if (!ensureCache(bce))
|
|
|
- return false;
|
|
|
-
|
|
|
- // Marks all names as closed over if the context requires it. This
|
|
|
- // cannot be done in the Parser as we may not know if the context requires
|
|
|
- // all bindings to be closed over until after parsing is finished. For
|
|
|
- // example, legacy generators require all bindings to be closed over but
|
|
|
-@@ -952,17 +952,17 @@ BytecodeEmitter::EmitterScope::enterLexi
|
|
|
- return false;
|
|
|
-
|
|
|
- return checkEnvironmentChainLength(bce);
|
|
|
- }
|
|
|
-
|
|
|
- bool
|
|
|
- BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox)
|
|
|
- {
|
|
|
-- MOZ_ASSERT(this == bce->innermostEmitterScope);
|
|
|
-+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
|
|
|
- MOZ_ASSERT(funbox->namedLambdaBindings());
|
|
|
-
|
|
|
- if (!ensureCache(bce))
|
|
|
- return false;
|
|
|
-
|
|
|
- // See comment in enterLexical about allBindingsClosedOver.
|
|
|
- if (funbox->allBindingsClosedOver())
|
|
|
- MarkAllBindingsClosedOver(*funbox->namedLambdaBindings());
|
|
|
-@@ -989,17 +989,17 @@ BytecodeEmitter::EmitterScope::enterName
|
|
|
- return false;
|
|
|
-
|
|
|
- return checkEnvironmentChainLength(bce);
|
|
|
- }
|
|
|
-
|
|
|
- bool
|
|
|
- BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
|
|
|
- {
|
|
|
-- MOZ_ASSERT(this == bce->innermostEmitterScope);
|
|
|
-+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
|
|
|
-
|
|
|
- if (!ensureCache(bce))
|
|
|
- return false;
|
|
|
-
|
|
|
- // Parameter expressions var scopes have no pre-set bindings and are
|
|
|
- // always extensible, as they are needed for eval.
|
|
|
- fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
|
|
|
-
|
|
|
-@@ -1022,17 +1022,17 @@ BytecodeEmitter::EmitterScope::enterPara
|
|
|
- return false;
|
|
|
-
|
|
|
- return checkEnvironmentChainLength(bce);
|
|
|
- }
|
|
|
-
|
|
|
- bool
|
|
|
- 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 (!funbox->hasExtraBodyVarScope())
|
|
|
- bce->setVarEmitterScope(this);
|
|
|
-
|
|
|
- if (!ensureCache(bce))
|
|
|
- return false;
|
|
|
-
|
|
|
-@@ -1113,17 +1113,17 @@ BytecodeEmitter::EmitterScope::enterFunc
|
|
|
- }
|
|
|
-
|
|
|
- bool
|
|
|
- BytecodeEmitter::EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox)
|
|
|
- {
|
|
|
- MOZ_ASSERT(funbox->hasParameterExprs);
|
|
|
- MOZ_ASSERT(funbox->extraVarScopeBindings() ||
|
|
|
- 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
|
|
|
- // function scope as the var emitter scope.
|
|
|
- bce->setVarEmitterScope(this);
|
|
|
-
|
|
|
- if (!ensureCache(bce))
|
|
|
- return false;
|
|
|
-
|
|
|
-@@ -1199,17 +1199,17 @@ class DynamicBindingIter : public Bindin
|
|
|
- MOZ_CRASH("Bad BindingKind");
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- bool
|
|
|
- BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc)
|
|
|
- {
|
|
|
-- MOZ_ASSERT(this == bce->innermostEmitterScope);
|
|
|
-+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
|
|
|
-
|
|
|
- bce->setVarEmitterScope(this);
|
|
|
-
|
|
|
- if (!ensureCache(bce))
|
|
|
- return false;
|
|
|
-
|
|
|
- if (bce->emitterMode == BytecodeEmitter::SelfHosting) {
|
|
|
- // In self-hosting, it is incorrect to consult the global scope because
|
|
|
-@@ -1259,17 +1259,17 @@ BytecodeEmitter::EmitterScope::enterGlob
|
|
|
- return GlobalScope::create(cx, globalsc->scopeKind(), globalsc->bindings);
|
|
|
- };
|
|
|
- return internBodyScope(bce, createScope);
|
|
|
- }
|
|
|
-
|
|
|
- bool
|
|
|
- BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc)
|
|
|
- {
|
|
|
-- MOZ_ASSERT(this == bce->innermostEmitterScope);
|
|
|
-+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
|
|
|
-
|
|
|
- bce->setVarEmitterScope(this);
|
|
|
-
|
|
|
- if (!ensureCache(bce))
|
|
|
- return false;
|
|
|
-
|
|
|
- // For simplicity, treat all free name lookups in eval scripts as dynamic.
|
|
|
- fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
|
|
|
-@@ -1314,17 +1314,17 @@ BytecodeEmitter::EmitterScope::enterEval
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- bool
|
|
|
- BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc)
|
|
|
- {
|
|
|
-- MOZ_ASSERT(this == bce->innermostEmitterScope);
|
|
|
-+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
|
|
|
-
|
|
|
- bce->setVarEmitterScope(this);
|
|
|
-
|
|
|
- if (!ensureCache(bce))
|
|
|
- return false;
|
|
|
-
|
|
|
- // Resolve body-level bindings, if there are any.
|
|
|
- TDZCheckCache* tdzCache = bce->innermostTDZCheckCache;
|
|
|
-@@ -1371,17 +1371,17 @@ BytecodeEmitter::EmitterScope::enterModu
|
|
|
- return false;
|
|
|
-
|
|
|
- return checkEnvironmentChainLength(bce);
|
|
|
- }
|
|
|
-
|
|
|
- bool
|
|
|
- BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce)
|
|
|
- {
|
|
|
-- MOZ_ASSERT(this == bce->innermostEmitterScope);
|
|
|
-+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
|
|
|
-
|
|
|
- if (!ensureCache(bce))
|
|
|
- return false;
|
|
|
-
|
|
|
- // 'with' make all accesses dynamic and unanalyzable.
|
|
|
- fallbackFreeNameLocation_ = Some(NameLocation::Dynamic());
|
|
|
-
|
|
|
- auto createScope = [](JSContext* cx, HandleScope enclosing) {
|
|
|
-@@ -1399,17 +1399,17 @@ BytecodeEmitter::EmitterScope::enterWith
|
|
|
- return checkEnvironmentChainLength(bce);
|
|
|
- }
|
|
|
-
|
|
|
- bool
|
|
|
- BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
|
|
|
- {
|
|
|
- // If we aren't leaving the scope due to a non-local jump (e.g., break),
|
|
|
- // 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();
|
|
|
- switch (kind) {
|
|
|
- case ScopeKind::Lexical:
|
|
|
- case ScopeKind::SimpleCatch:
|
|
|
- case ScopeKind::Catch:
|
|
|
- if (!bce->emit1(hasEnvironment() ? JSOP_POPLEXICALENV : JSOP_DEBUGLEAVELEXICALENV))
|
|
|
- return false;
|
|
|
-@@ -2263,17 +2263,17 @@ class ForOfLoopControl : public LoopCont
|
|
|
- tryCatch_.reset();
|
|
|
- numYieldsAtBeginCodeNeedingIterClose_ = UINT32_MAX;
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- bool emitIteratorCloseInInnermostScope(BytecodeEmitter* bce,
|
|
|
- CompletionKind completionKind = CompletionKind::Normal) {
|
|
|
-- return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope, completionKind);
|
|
|
-+ return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope(), completionKind);
|
|
|
- }
|
|
|
-
|
|
|
- bool emitIteratorCloseInScope(BytecodeEmitter* bce,
|
|
|
- EmitterScope& currentScope,
|
|
|
- CompletionKind completionKind = CompletionKind::Normal) {
|
|
|
- ptrdiff_t start = bce->offset();
|
|
|
- if (!bce->emitIteratorCloseInScope(currentScope, iterKind_, completionKind,
|
|
|
- allowSelfHosted_))
|
|
|
-@@ -2344,18 +2344,21 @@ BytecodeEmitter::BytecodeEmitter(Bytecod
|
|
|
- firstLine(lineNum),
|
|
|
- maxFixedSlots(0),
|
|
|
- maxStackDepth(0),
|
|
|
- stackDepth(0),
|
|
|
- emitLevel(0),
|
|
|
- bodyScopeIndex(UINT32_MAX),
|
|
|
- varEmitterScope(nullptr),
|
|
|
- innermostNestableControl(nullptr),
|
|
|
-- innermostEmitterScope(nullptr),
|
|
|
-+ innermostEmitterScope_(nullptr),
|
|
|
- innermostTDZCheckCache(nullptr),
|
|
|
-+#ifdef DEBUG
|
|
|
-+ unstableEmitterScope(false),
|
|
|
-+#endif
|
|
|
- constList(cx),
|
|
|
- scopeList(cx),
|
|
|
- tryNoteList(cx),
|
|
|
- scopeNoteList(cx),
|
|
|
- yieldAndAwaitOffsetList(cx),
|
|
|
- typesetCount(0),
|
|
|
- hasSingletons(false),
|
|
|
- hasTryFinally(false),
|
|
|
-@@ -2418,23 +2421,23 @@ T*
|
|
|
- BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const
|
|
|
- {
|
|
|
- return NestableControl::findNearest<T>(innermostNestableControl, predicate);
|
|
|
- }
|
|
|
-
|
|
|
- NameLocation
|
|
|
- BytecodeEmitter::lookupName(JSAtom* name)
|
|
|
- {
|
|
|
-- return innermostEmitterScope->lookup(this, name);
|
|
|
-+ return innermostEmitterScope()->lookup(this, name);
|
|
|
- }
|
|
|
-
|
|
|
- Maybe<NameLocation>
|
|
|
- BytecodeEmitter::locationOfNameBoundInScope(JSAtom* name, EmitterScope* target)
|
|
|
- {
|
|
|
-- return innermostEmitterScope->locationBoundInScope(name, target);
|
|
|
-+ return innermostEmitterScope()->locationBoundInScope(name, target);
|
|
|
- }
|
|
|
-
|
|
|
- Maybe<NameLocation>
|
|
|
- BytecodeEmitter::locationOfNameBoundInFunctionScope(JSAtom* name, EmitterScope* source)
|
|
|
- {
|
|
|
- EmitterScope* funScope = source;
|
|
|
- while (!funScope->scope(this)->is<FunctionScope>())
|
|
|
- funScope = funScope->enclosingInFrame();
|
|
|
-@@ -2899,17 +2902,17 @@ class NonLocalExitControl
|
|
|
-
|
|
|
- MOZ_MUST_USE bool leaveScope(BytecodeEmitter::EmitterScope* scope);
|
|
|
-
|
|
|
- public:
|
|
|
- NonLocalExitControl(BytecodeEmitter* bce, Kind kind)
|
|
|
- : bce_(bce),
|
|
|
- savedScopeNoteIndex_(bce->scopeNoteList.length()),
|
|
|
- savedDepth_(bce->stackDepth),
|
|
|
-- openScopeNoteIndex_(bce->innermostEmitterScope->noteIndex()),
|
|
|
-+ openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()),
|
|
|
- kind_(kind)
|
|
|
- { }
|
|
|
-
|
|
|
- ~NonLocalExitControl() {
|
|
|
- for (uint32_t n = savedScopeNoteIndex_; n < bce_->scopeNoteList.length(); n++)
|
|
|
- bce_->scopeNoteList.recordEnd(n, bce_->offset(), bce_->inPrologue());
|
|
|
- bce_->stackDepth = savedDepth_;
|
|
|
- }
|
|
|
-@@ -2945,19 +2948,21 @@ NonLocalExitControl::leaveScope(Bytecode
|
|
|
- * Emit additional bytecode(s) for non-local jumps.
|
|
|
- */
|
|
|
- bool
|
|
|
- NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* target)
|
|
|
- {
|
|
|
- using NestableControl = BytecodeEmitter::NestableControl;
|
|
|
- using EmitterScope = BytecodeEmitter::EmitterScope;
|
|
|
-
|
|
|
-- EmitterScope* es = bce_->innermostEmitterScope;
|
|
|
-+ EmitterScope* es = bce_->innermostEmitterScope();
|
|
|
- int npops = 0;
|
|
|
-
|
|
|
-+ AutoCheckUnstableEmitterScope cues(bce_);
|
|
|
-+
|
|
|
- // For 'continue', 'break', and 'return' statements, emit IteratorClose
|
|
|
- // bytecode inline. 'continue' statements do not call IteratorClose for
|
|
|
- // the loop they are continuing.
|
|
|
- bool emitIteratorClose = kind_ == Continue || kind_ == Break || kind_ == Return;
|
|
|
- bool emitIteratorCloseAtTarget = emitIteratorClose && kind_ != Continue;
|
|
|
-
|
|
|
- auto flushPops = [&npops](BytecodeEmitter* bce) {
|
|
|
- if (npops && !bce->emitPopN(npops))
|
|
|
-@@ -3070,17 +3075,17 @@ BytecodeEmitter::emitGoto(NestableContro
|
|
|
- }
|
|
|
-
|
|
|
- return emitJump(JSOP_GOTO, jumplist);
|
|
|
- }
|
|
|
-
|
|
|
- Scope*
|
|
|
- BytecodeEmitter::innermostScope() const
|
|
|
- {
|
|
|
-- return innermostEmitterScope->scope(this);
|
|
|
-+ return innermostEmitterScope()->scope(this);
|
|
|
- }
|
|
|
-
|
|
|
- bool
|
|
|
- BytecodeEmitter::emitIndex32(JSOp op, uint32_t index)
|
|
|
- {
|
|
|
- MOZ_ASSERT(checkStrictOrSloppy(op));
|
|
|
-
|
|
|
- const size_t len = 1 + UINT32_INDEX_LEN;
|
|
|
-@@ -3719,17 +3724,17 @@ BytecodeEmitter::checkRunOnceContext()
|
|
|
- bool
|
|
|
- BytecodeEmitter::needsImplicitThis()
|
|
|
- {
|
|
|
- // Short-circuit if there is an enclosing 'with' scope.
|
|
|
- if (sc->inWith())
|
|
|
- return true;
|
|
|
-
|
|
|
- // 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)
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- void
|
|
|
-@@ -5319,17 +5324,17 @@ BytecodeEmitter::emitSetOrInitializeDest
|
|
|
- return false;
|
|
|
- break;
|
|
|
-
|
|
|
- case DestructuringFormalParameterInVarScope: {
|
|
|
- // If there's an parameter expression var scope, the
|
|
|
- // destructuring declaration needs to initialize the name in
|
|
|
- // the function scope. The innermost scope is the var scope,
|
|
|
- // and its enclosing scope is the function scope.
|
|
|
-- EmitterScope* funScope = innermostEmitterScope->enclosingInFrame();
|
|
|
-+ EmitterScope* funScope = innermostEmitterScope()->enclosingInFrame();
|
|
|
- NameLocation paramLoc = *locationOfNameBoundInScope(name, funScope);
|
|
|
- if (!emitSetOrInitializeNameAtLocation(name, paramLoc, emitSwapScopeAndRhs, true))
|
|
|
- return false;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- case DestructuringAssignment:
|
|
|
- if (!emitSetName(name, emitSwapScopeAndRhs))
|
|
|
-@@ -7394,17 +7399,17 @@ BytecodeEmitter::emitForOf(ParseNode* fo
|
|
|
- // The environment chain only includes an environment for the for-of
|
|
|
- // loop head *if* a scope binding is captured, thereby requiring
|
|
|
- // recreation each iteration. If a lexical scope exists for the head,
|
|
|
- // it must be the innermost one. If that scope has closed-over
|
|
|
- // bindings inducing an environment, recreate the current environment.
|
|
|
- DebugOnly<ParseNode*> forOfTarget = forOfHead->pn_kid1;
|
|
|
- MOZ_ASSERT(forOfTarget->isKind(ParseNodeKind::Let) ||
|
|
|
- forOfTarget->isKind(ParseNodeKind::Const));
|
|
|
-- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
|
|
|
-+ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
|
|
|
- MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
|
|
|
-
|
|
|
- if (headLexicalEmitterScope->hasEnvironment()) {
|
|
|
- if (!emit1(JSOP_RECREATELEXICALENV)) // NEXT ITER UNDEF
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // For uncaptured bindings, put them back in TDZ.
|
|
|
-@@ -7591,17 +7596,17 @@ BytecodeEmitter::emitForIn(ParseNode* fo
|
|
|
- if (headLexicalEmitterScope) {
|
|
|
- // The environment chain only includes an environment for the for-in
|
|
|
- // loop head *if* a scope binding is captured, thereby requiring
|
|
|
- // recreation each iteration. If a lexical scope exists for the head,
|
|
|
- // it must be the innermost one. If that scope has closed-over
|
|
|
- // bindings inducing an environment, recreate the current environment.
|
|
|
- MOZ_ASSERT(forInTarget->isKind(ParseNodeKind::Let) ||
|
|
|
- forInTarget->isKind(ParseNodeKind::Const));
|
|
|
-- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
|
|
|
-+ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
|
|
|
- MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
|
|
|
-
|
|
|
- if (headLexicalEmitterScope->hasEnvironment()) {
|
|
|
- if (!emit1(JSOP_RECREATELEXICALENV)) // ITER ITERVAL
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // For uncaptured bindings, put them back in TDZ.
|
|
|
-@@ -7727,17 +7732,17 @@ BytecodeEmitter::emitCStyleFor(ParseNode
|
|
|
- forLoopRequiresFreshening = init->isKind(ParseNodeKind::Let) && headLexicalEmitterScope;
|
|
|
- if (forLoopRequiresFreshening) {
|
|
|
- // The environment chain only includes an environment for the for(;;)
|
|
|
- // loop head's let-declaration *if* a scope binding is captured, thus
|
|
|
- // requiring a fresh environment each iteration. If a lexical scope
|
|
|
- // exists for the head, it must be the innermost one. If that scope
|
|
|
- // has closed-over bindings inducing an environment, recreate the
|
|
|
- // current environment.
|
|
|
-- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
|
|
|
-+ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
|
|
|
- MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
|
|
|
-
|
|
|
- if (headLexicalEmitterScope->hasEnvironment()) {
|
|
|
- if (!emit1(JSOP_FRESHENLEXICALENV))
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-@@ -7775,17 +7780,17 @@ BytecodeEmitter::emitCStyleFor(ParseNode
|
|
|
- // Set loop and enclosing "update" offsets, for continue. Note that we
|
|
|
- // continue to immediately *before* the block-freshening: continuing must
|
|
|
- // refresh the block.
|
|
|
- if (!emitJumpTarget(&loopInfo.continueTarget))
|
|
|
- return false;
|
|
|
-
|
|
|
- // ES 13.7.4.8 step 3.e. The per-iteration freshening.
|
|
|
- if (forLoopRequiresFreshening) {
|
|
|
-- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
|
|
|
-+ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
|
|
|
- MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
|
|
|
-
|
|
|
- if (headLexicalEmitterScope->hasEnvironment()) {
|
|
|
- if (!emit1(JSOP_FRESHENLEXICALENV))
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-@@ -10282,17 +10287,17 @@ BytecodeEmitter::emitFunctionFormalParam
|
|
|
- return emitterScope.leave(this);
|
|
|
- }
|
|
|
-
|
|
|
- bool
|
|
|
- BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn)
|
|
|
- {
|
|
|
- ParseNode* funBody = pn->last();
|
|
|
- FunctionBox* funbox = sc->asFunctionBox();
|
|
|
-- EmitterScope* funScope = innermostEmitterScope;
|
|
|
-+ EmitterScope* funScope = innermostEmitterScope();
|
|
|
-
|
|
|
- bool hasParameterExprs = funbox->hasParameterExprs;
|
|
|
- bool hasRest = funbox->hasRest();
|
|
|
-
|
|
|
- uint16_t argSlot = 0;
|
|
|
- for (ParseNode* arg = pn->pn_head; arg != funBody; arg = arg->pn_next, argSlot++) {
|
|
|
- ParseNode* bindingElement = arg;
|
|
|
- ParseNode* initializer = nullptr;
|
|
|
-diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h
|
|
|
---- a/js/src/frontend/BytecodeEmitter.h
|
|
|
-+++ b/js/src/frontend/BytecodeEmitter.h
|
|
|
-@@ -235,19 +235,33 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|
|
- int32_t stackDepth; /* current stack depth in script frame */
|
|
|
-
|
|
|
- unsigned emitLevel; /* emitTree recursion level */
|
|
|
-
|
|
|
- uint32_t bodyScopeIndex; /* index into scopeList of the body scope */
|
|
|
-
|
|
|
- EmitterScope* varEmitterScope;
|
|
|
- NestableControl* innermostNestableControl;
|
|
|
-- EmitterScope* innermostEmitterScope;
|
|
|
-+ EmitterScope* innermostEmitterScope_;
|
|
|
- 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 */
|
|
|
- CGObjectList objectList; /* list of emitted objects */
|
|
|
- CGScopeList scopeList; /* list of emitted scopes */
|
|
|
- CGTryNoteList tryNoteList; /* list of emitted try notes */
|
|
|
- CGScopeNoteList scopeNoteList; /* list of emitted block scope notes */
|
|
|
-
|
|
|
- /*
|
|
|
- * For each yield or await op, map the yield and await index (stored as
|
|
|
-@@ -374,17 +388,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|
|
- mozilla::Maybe<NameLocation> locationOfNameBoundInScope(JSAtom* name, EmitterScope* target);
|
|
|
-
|
|
|
- // Get the location of a name known to be bound in the function scope,
|
|
|
- // starting at the source scope.
|
|
|
- mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope(JSAtom* name,
|
|
|
- EmitterScope* source);
|
|
|
-
|
|
|
- mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope(JSAtom* name) {
|
|
|
-- return locationOfNameBoundInFunctionScope(name, innermostEmitterScope);
|
|
|
-+ return locationOfNameBoundInFunctionScope(name, innermostEmitterScope());
|
|
|
- }
|
|
|
-
|
|
|
- void setVarEmitterScope(EmitterScope* emitterScope) {
|
|
|
- MOZ_ASSERT(emitterScope);
|
|
|
- MOZ_ASSERT(!varEmitterScope);
|
|
|
- varEmitterScope = emitterScope;
|
|
|
- }
|
|
|
-
|
|
|
-@@ -673,26 +687,26 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|
|
- MOZ_MUST_USE bool emitNewInit(JSProtoKey key);
|
|
|
- MOZ_MUST_USE bool emitSingletonInitialiser(ParseNode* pn);
|
|
|
-
|
|
|
- MOZ_MUST_USE bool emitPrepareIteratorResult();
|
|
|
- MOZ_MUST_USE bool emitFinishIteratorResult(bool done);
|
|
|
- MOZ_MUST_USE bool iteratorResultShape(unsigned* shape);
|
|
|
-
|
|
|
- MOZ_MUST_USE bool emitGetDotGeneratorInInnermostScope() {
|
|
|
-- return emitGetDotGeneratorInScope(*innermostEmitterScope);
|
|
|
-+ return emitGetDotGeneratorInScope(*innermostEmitterScope());
|
|
|
- }
|
|
|
- MOZ_MUST_USE bool emitGetDotGeneratorInScope(EmitterScope& currentScope);
|
|
|
-
|
|
|
- MOZ_MUST_USE bool emitInitialYield(ParseNode* pn);
|
|
|
- MOZ_MUST_USE bool emitYield(ParseNode* pn);
|
|
|
- MOZ_MUST_USE bool emitYieldOp(JSOp op);
|
|
|
- MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
|
|
|
- MOZ_MUST_USE bool emitAwaitInInnermostScope() {
|
|
|
-- return emitAwaitInScope(*innermostEmitterScope);
|
|
|
-+ return emitAwaitInScope(*innermostEmitterScope());
|
|
|
- }
|
|
|
- MOZ_MUST_USE bool emitAwaitInInnermostScope(ParseNode* pn);
|
|
|
- MOZ_MUST_USE bool emitAwaitInScope(EmitterScope& currentScope);
|
|
|
-
|
|
|
- MOZ_MUST_USE bool emitPropLHS(ParseNode* pn);
|
|
|
- MOZ_MUST_USE bool emitPropOp(ParseNode* pn, JSOp op);
|
|
|
- MOZ_MUST_USE bool emitPropIncDec(ParseNode* pn);
|
|
|
-
|
|
|
-@@ -789,17 +803,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|
|
- bool allowSelfHosted = false);
|
|
|
- MOZ_MUST_USE bool emitIteratorCloseInScope(EmitterScope& currentScope,
|
|
|
- IteratorKind iterKind = IteratorKind::Sync,
|
|
|
- CompletionKind completionKind = CompletionKind::Normal,
|
|
|
- bool allowSelfHosted = false);
|
|
|
- MOZ_MUST_USE bool emitIteratorCloseInInnermostScope(IteratorKind iterKind = IteratorKind::Sync,
|
|
|
- CompletionKind completionKind = CompletionKind::Normal,
|
|
|
- bool allowSelfHosted = false) {
|
|
|
-- return emitIteratorCloseInScope(*innermostEmitterScope, iterKind, completionKind,
|
|
|
-+ return emitIteratorCloseInScope(*innermostEmitterScope(), iterKind, completionKind,
|
|
|
- allowSelfHosted);
|
|
|
- }
|
|
|
-
|
|
|
- template <typename InnerEmitter>
|
|
|
- MOZ_MUST_USE bool wrapWithDestructuringIteratorCloseTryNote(int32_t iterDepth,
|
|
|
- InnerEmitter emitter);
|
|
|
-
|
|
|
- // Check if the value on top of the stack is "undefined". If so, replace
|
|
|
-@@ -891,12 +905,37 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|
|
-
|
|
|
- MOZ_MUST_USE bool emitCallee(ParseNode* callee, ParseNode* call, bool* callop);
|
|
|
-
|
|
|
- MOZ_MUST_USE bool emitPipeline(ParseNode* pn);
|
|
|
-
|
|
|
- MOZ_MUST_USE bool emitExportDefault(ParseNode* pn);
|
|
|
- };
|
|
|
-
|
|
|
-+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 js */
|
|
|
-
|
|
|
- #endif /* frontend_BytecodeEmitter_h */
|