Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / EmitterScope.h
blob8f985faffe684f695bfc1ff09115398db8615af2
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"
12 #include <stdint.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
22 namespace js {
23 namespace frontend {
25 struct BytecodeEmitter;
26 class EvalSharedContext;
27 class FunctionBox;
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
37 // current scope.
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.
46 bool hasEnvironment_;
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.
64 uint32_t noteIndex_;
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,
77 NameLocation loc);
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,
95 ScopeIndex index);
96 [[nodiscard]] bool appendScopeNote(BytecodeEmitter* bce);
98 [[nodiscard]] bool clearFrameSlotRange(BytecodeEmitter* bce, JSOp opcode,
99 uint32_t slotStart,
100 uint32_t slotEnd) const;
102 [[nodiscard]] bool deadZoneFrameSlotRange(BytecodeEmitter* bce,
103 uint32_t slotStart,
104 uint32_t slotEnd) const {
105 return clearFrameSlotRange(bce, JSOp::Uninitialized, slotStart, slotEnd);
108 public:
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?");
135 return scopeIndex_;
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_;
150 return 0;
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:
168 // class Outer {
169 // #outerMethod() { reutrn "ok"; }
171 // test() {
172 // class Inner {
173 // #innerMethod() {}
174 // test(outer) {
175 // return outer.#outerMethod();
176 // }
177 // }
178 // return new Inner().test(this);
179 // }
180 // }
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 */
208 } /* namespace js */
210 #endif /* frontend_EmitterScope_h */