/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef frontend_EmitterScope_h #define frontend_EmitterScope_h #include "mozilla/Attributes.h" #include "mozilla/Maybe.h" #include #include "ds/Nestable.h" #include "frontend/AbstractScopePtr.h" #include "frontend/NameAnalysisTypes.h" #include "frontend/NameCollections.h" #include "frontend/ParseContext.h" #include "frontend/SharedContext.h" #include "js/TypeDecls.h" #include "vm/BytecodeUtil.h" // JSOp #include "vm/SharedStencil.h" // GCThingIndex namespace js { class Scope; namespace frontend { struct BytecodeEmitter; // A scope that introduces bindings. class EmitterScope : public Nestable { // The cache of bound names that may be looked up in the // scope. Initially populated as the set of names this scope binds. As // names are looked up in enclosing scopes, they are cached on the // current scope. PooledMapPtr nameCache_; // If this scope's cache does not include free names, such as the // global scope, the NameLocation to return. mozilla::Maybe fallbackFreeNameLocation_; // True if there is a corresponding EnvironmentObject on the environment // chain, false if all bindings are stored in frame slots on the stack. bool hasEnvironment_; // The number of enclosing environments. Used for error checking. uint8_t environmentChainLength_; // The next usable slot on the frame for not-closed over bindings. // // The initial frame slot when assigning slots to bindings is the // enclosing scope's nextFrameSlot. For the first scope in a frame, // the initial frame slot is 0. uint32_t nextFrameSlot_; // The index in the BytecodeEmitter's interned scope vector, otherwise // ScopeNote::NoScopeIndex. GCThingIndex scopeIndex_; // If kind is Lexical, Catch, or With, the index in the BytecodeEmitter's // block scope note list. Otherwise ScopeNote::NoScopeNote. uint32_t noteIndex_; MOZ_MUST_USE bool ensureCache(BytecodeEmitter* bce); MOZ_MUST_USE bool checkSlotLimits(BytecodeEmitter* bce, const ParserBindingIter& bi); MOZ_MUST_USE bool checkEnvironmentChainLength(BytecodeEmitter* bce); void updateFrameFixedSlots(BytecodeEmitter* bce, const ParserBindingIter& bi); MOZ_MUST_USE bool putNameInCache(BytecodeEmitter* bce, const ParserAtom* name, NameLocation loc); mozilla::Maybe lookupInCache(BytecodeEmitter* bce, const ParserAtom* name); EmitterScope* enclosing(BytecodeEmitter** bce) const; mozilla::Maybe enclosingScopeIndex(BytecodeEmitter* bce) const; static bool nameCanBeFree(BytecodeEmitter* bce, const ParserAtom* name); static NameLocation searchInEnclosingScope(JSAtom* name, Scope* scope, uint8_t hops); NameLocation searchAndCache(BytecodeEmitter* bce, const ParserAtom* name); MOZ_MUST_USE bool internEmptyGlobalScopeAsBody(BytecodeEmitter* bce); template MOZ_MUST_USE bool internScopeCreationData(BytecodeEmitter* bce, ScopeCreator createScope); template MOZ_MUST_USE bool internBodyScopeCreationData(BytecodeEmitter* bce, ScopeCreator createScope); MOZ_MUST_USE bool appendScopeNote(BytecodeEmitter* bce); MOZ_MUST_USE bool clearFrameSlotRange(BytecodeEmitter* bce, JSOp opcode, uint32_t slotStart, uint32_t slotEnd) const; MOZ_MUST_USE bool deadZoneFrameSlotRange(BytecodeEmitter* bce, uint32_t slotStart, uint32_t slotEnd) const { return clearFrameSlotRange(bce, JSOp::Uninitialized, slotStart, slotEnd); } public: explicit EmitterScope(BytecodeEmitter* bce); void dump(BytecodeEmitter* bce); MOZ_MUST_USE bool enterLexical(BytecodeEmitter* bce, ScopeKind kind, LexicalScope::ParserData* bindings); MOZ_MUST_USE bool enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox); MOZ_MUST_USE bool enterFunction(BytecodeEmitter* bce, FunctionBox* funbox); MOZ_MUST_USE bool enterFunctionExtraBodyVar(BytecodeEmitter* bce, FunctionBox* funbox); MOZ_MUST_USE bool enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc); MOZ_MUST_USE bool enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc); MOZ_MUST_USE bool enterModule(BytecodeEmitter* module, ModuleSharedContext* modulesc); MOZ_MUST_USE bool enterWith(BytecodeEmitter* bce); MOZ_MUST_USE bool deadZoneFrameSlots(BytecodeEmitter* bce) const; MOZ_MUST_USE bool leave(BytecodeEmitter* bce, bool nonLocal = false); GCThingIndex index() const { MOZ_ASSERT(scopeIndex_ != ScopeNote::NoScopeIndex, "Did you forget to intern a Scope?"); return scopeIndex_; } uint32_t noteIndex() const { return noteIndex_; } AbstractScopePtr scope(const BytecodeEmitter* bce) const; mozilla::Maybe scopeIndex(const BytecodeEmitter* bce) const; bool hasEnvironment() const { return hasEnvironment_; } // The first frame slot used. uint32_t frameSlotStart() const { if (EmitterScope* inFrame = enclosingInFrame()) { return inFrame->nextFrameSlot_; } return 0; } // The last frame slot used + 1. uint32_t frameSlotEnd() const { return nextFrameSlot_; } EmitterScope* enclosingInFrame() const { return Nestable::enclosing(); } NameLocation lookup(BytecodeEmitter* bce, const ParserAtom* name); mozilla::Maybe locationBoundInScope(const ParserAtom* name, EmitterScope* target); }; } /* namespace frontend */ } /* namespace js */ #endif /* frontend_EmitterScope_h */