1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef frontend_EmitterScope_h
8 #define frontend_EmitterScope_h
10 #include "mozilla/Maybe.h"
14 #include "ds/Nestable.h"
15 #include "frontend/AbstractScopePtr.h"
16 #include "frontend/NameAnalysisTypes.h"
17 #include "frontend/NameCollections.h"
18 #include "frontend/Stencil.h"
19 #include "vm/Opcodes.h" // JSOp
20 #include "vm/SharedStencil.h" // GCThingIndex
25 struct BytecodeEmitter
;
26 class EvalSharedContext
;
28 class GlobalSharedContext
;
29 class ModuleSharedContext
;
30 class TaggedParserAtomIndex
;
32 // A scope that introduces bindings.
33 class EmitterScope
: public Nestable
<EmitterScope
> {
34 // The cache of bound names that may be looked up in the
35 // scope. Initially populated as the set of names this scope binds. As
36 // names are looked up in enclosing scopes, they are cached on the
38 PooledMapPtr
<NameLocationMap
> nameCache_
;
40 // If this scope's cache does not include free names, such as the
41 // global scope, the NameLocation to return.
42 mozilla::Maybe
<NameLocation
> fallbackFreeNameLocation_
;
44 // True if there is a corresponding EnvironmentObject on the environment
45 // chain, false if all bindings are stored in frame slots on the stack.
48 // The number of enclosing environments. Used for error checking.
49 uint8_t environmentChainLength_
;
51 // The next usable slot on the frame for not-closed over bindings.
53 // The initial frame slot when assigning slots to bindings is the
54 // enclosing scope's nextFrameSlot. For the first scope in a frame,
55 // the initial frame slot is 0.
56 uint32_t nextFrameSlot_
;
58 // The index in the BytecodeEmitter's interned scope vector, otherwise
59 // ScopeNote::NoScopeIndex.
60 GCThingIndex scopeIndex_
;
62 // If kind is Lexical, Catch, or With, the index in the BytecodeEmitter's
63 // block scope note list. Otherwise ScopeNote::NoScopeNote.
66 [[nodiscard
]] bool ensureCache(BytecodeEmitter
* bce
);
68 [[nodiscard
]] bool checkSlotLimits(BytecodeEmitter
* bce
,
69 const ParserBindingIter
& bi
);
71 [[nodiscard
]] bool checkEnvironmentChainLength(BytecodeEmitter
* bce
);
73 void updateFrameFixedSlots(BytecodeEmitter
* bce
, const ParserBindingIter
& bi
);
75 [[nodiscard
]] bool putNameInCache(BytecodeEmitter
* bce
,
76 TaggedParserAtomIndex name
,
79 mozilla::Maybe
<NameLocation
> lookupInCache(BytecodeEmitter
* bce
,
80 TaggedParserAtomIndex name
);
82 EmitterScope
* enclosing(BytecodeEmitter
** bce
) const;
84 mozilla::Maybe
<ScopeIndex
> enclosingScopeIndex(BytecodeEmitter
* bce
) const;
86 static bool nameCanBeFree(BytecodeEmitter
* bce
, TaggedParserAtomIndex name
);
88 NameLocation
searchAndCache(BytecodeEmitter
* bce
, TaggedParserAtomIndex name
);
90 [[nodiscard
]] bool internEmptyGlobalScopeAsBody(BytecodeEmitter
* bce
);
92 [[nodiscard
]] bool internScopeStencil(BytecodeEmitter
* bce
, ScopeIndex index
);
94 [[nodiscard
]] bool internBodyScopeStencil(BytecodeEmitter
* bce
,
96 [[nodiscard
]] bool appendScopeNote(BytecodeEmitter
* bce
);
98 [[nodiscard
]] bool clearFrameSlotRange(BytecodeEmitter
* bce
, JSOp opcode
,
100 uint32_t slotEnd
) const;
102 [[nodiscard
]] bool deadZoneFrameSlotRange(BytecodeEmitter
* bce
,
104 uint32_t slotEnd
) const {
105 return clearFrameSlotRange(bce
, JSOp::Uninitialized
, slotStart
, slotEnd
);
109 explicit EmitterScope(BytecodeEmitter
* bce
);
111 void dump(BytecodeEmitter
* bce
);
113 [[nodiscard
]] bool enterLexical(BytecodeEmitter
* bce
, ScopeKind kind
,
114 LexicalScope::ParserData
* bindings
);
115 [[nodiscard
]] bool enterClassBody(BytecodeEmitter
* bce
, ScopeKind kind
,
116 ClassBodyScope::ParserData
* bindings
);
117 [[nodiscard
]] bool enterNamedLambda(BytecodeEmitter
* bce
,
118 FunctionBox
* funbox
);
119 [[nodiscard
]] bool enterFunction(BytecodeEmitter
* bce
, FunctionBox
* funbox
);
120 [[nodiscard
]] bool enterFunctionExtraBodyVar(BytecodeEmitter
* bce
,
121 FunctionBox
* funbox
);
122 [[nodiscard
]] bool enterGlobal(BytecodeEmitter
* bce
,
123 GlobalSharedContext
* globalsc
);
124 [[nodiscard
]] bool enterEval(BytecodeEmitter
* bce
, EvalSharedContext
* evalsc
);
125 [[nodiscard
]] bool enterModule(BytecodeEmitter
* module
,
126 ModuleSharedContext
* modulesc
);
127 [[nodiscard
]] bool enterWith(BytecodeEmitter
* bce
);
128 [[nodiscard
]] bool deadZoneFrameSlots(BytecodeEmitter
* bce
) const;
130 [[nodiscard
]] bool leave(BytecodeEmitter
* bce
, bool nonLocal
= false);
132 GCThingIndex
index() const {
133 MOZ_ASSERT(scopeIndex_
!= ScopeNote::NoScopeIndex
,
134 "Did you forget to intern a Scope?");
138 uint32_t noteIndex() const { return noteIndex_
; }
140 AbstractScopePtr
scope(const BytecodeEmitter
* bce
) const;
141 mozilla::Maybe
<ScopeIndex
> scopeIndex(const BytecodeEmitter
* bce
) const;
143 bool hasEnvironment() const { return hasEnvironment_
; }
145 // The first frame slot used.
146 uint32_t frameSlotStart() const {
147 if (EmitterScope
* inFrame
= enclosingInFrame()) {
148 return inFrame
->nextFrameSlot_
;
153 // The last frame slot used + 1.
154 uint32_t frameSlotEnd() const { return nextFrameSlot_
; }
156 EmitterScope
* enclosingInFrame() const {
157 return Nestable
<EmitterScope
>::enclosing();
160 NameLocation
lookup(BytecodeEmitter
* bce
, TaggedParserAtomIndex name
);
162 // Find both the slot associated with a private name and the location of the
163 // corresponding `.privateBrand` binding.
165 // Simply doing two separate lookups, one for `name` and another for
166 // `.privateBrand`, would give the wrong answer in this case:
169 // #outerMethod() { reutrn "ok"; }
175 // return outer.#outerMethod();
178 // return new Inner().test(this);
182 // new Outer().test(); // should return "ok"
184 // At the point in Inner.test where `#outerMethod` is called, we need to
185 // check for the private brand of `Outer`, not `Inner`; but both class bodies
186 // have `.privateBrand` bindings. In a normal `lookup`, the inner binding
187 // would shadow the outer one.
189 // This method instead sets `brandLoc` to the location of the `.privateBrand`
190 // binding in the same class body as the private name `name`, ignoring
191 // shadowing. If `name` refers to a name that is actually stamped onto the
192 // target object (anything other than a non-static private method), then
193 // `brandLoc` is set to Nothing.
194 void lookupPrivate(BytecodeEmitter
* bce
, TaggedParserAtomIndex name
,
195 NameLocation
& loc
, mozilla::Maybe
<NameLocation
>& brandLoc
);
197 mozilla::Maybe
<NameLocation
> locationBoundInScope(TaggedParserAtomIndex name
,
198 EmitterScope
* target
);
200 // For a given emitter scope, return the number of enclosing environments in
201 // the current compilation (this excludes environments that could enclose the
202 // compilation, like would happen for an eval copmilation).
203 static uint32_t CountEnclosingCompilationEnvironments(
204 BytecodeEmitter
* bce
, EmitterScope
* emitterScope
);
207 } /* namespace frontend */
210 #endif /* frontend_EmitterScope_h */