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/. */
6 
7 #ifndef frontend_NameAnalysisTypes_h
8 #define frontend_NameAnalysisTypes_h
9 
10 #include <type_traits>
11 
12 #include "vm/BytecodeUtil.h"
13 #include "vm/Scope.h"
14 
15 namespace js {
16 
17 // An "environment coordinate" describes how to get from head of the
18 // environment chain to a given lexically-enclosing variable. An environment
19 // coordinate has two dimensions:
20 //  - hops: the number of environment objects on the scope chain to skip
21 //  - slot: the slot on the environment object holding the variable's value
22 class EnvironmentCoordinate {
23   uint32_t hops_;
24   uint32_t slot_;
25 
26   // Technically, hops_/slot_ are ENVCOORD_(HOPS|SLOT)_BITS wide.  Since
27   // EnvironmentCoordinate is a temporary value, don't bother with a bitfield as
28   // this only adds overhead.
29   static_assert(ENVCOORD_HOPS_BITS <= 32, "We have enough bits below");
30   static_assert(ENVCOORD_SLOT_BITS <= 32, "We have enough bits below");
31 
32  public:
EnvironmentCoordinate(jsbytecode * pc)33   explicit inline EnvironmentCoordinate(jsbytecode* pc)
34       : hops_(GET_ENVCOORD_HOPS(pc)),
35         slot_(GET_ENVCOORD_SLOT(pc + ENVCOORD_HOPS_LEN)) {
36     MOZ_ASSERT(JOF_OPTYPE(JSOp(*pc)) == JOF_ENVCOORD);
37   }
38 
39   EnvironmentCoordinate() = default;
40 
setHops(uint32_t hops)41   void setHops(uint32_t hops) {
42     MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT);
43     hops_ = hops;
44   }
45 
setSlot(uint32_t slot)46   void setSlot(uint32_t slot) {
47     MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT);
48     slot_ = slot;
49   }
50 
hops()51   uint32_t hops() const {
52     MOZ_ASSERT(hops_ < ENVCOORD_HOPS_LIMIT);
53     return hops_;
54   }
55 
slot()56   uint32_t slot() const {
57     MOZ_ASSERT(slot_ < ENVCOORD_SLOT_LIMIT);
58     return slot_;
59   }
60 
61   bool operator==(const EnvironmentCoordinate& rhs) const {
62     return hops() == rhs.hops() && slot() == rhs.slot();
63   }
64 };
65 
66 namespace frontend {
67 
68 enum class ParseGoal : uint8_t { Script, Module };
69 
70 // A detailed kind used for tracking declarations in the Parser. Used for
71 // specific early error semantics and better error messages.
72 enum class DeclarationKind : uint8_t {
73   PositionalFormalParameter,
74   FormalParameter,
75   CoverArrowParameter,
76   Var,
77   Let,
78   Const,
79   Class,  // Handled as same as `let` after parsing.
80   Import,
81   BodyLevelFunction,
82   ModuleBodyLevelFunction,
83   LexicalFunction,
84   SloppyLexicalFunction,
85   VarForAnnexBLexicalFunction,
86   SimpleCatchParameter,
87   CatchParameter
88 };
89 
DeclarationKindToBindingKind(DeclarationKind kind)90 static inline BindingKind DeclarationKindToBindingKind(DeclarationKind kind) {
91   switch (kind) {
92     case DeclarationKind::PositionalFormalParameter:
93     case DeclarationKind::FormalParameter:
94     case DeclarationKind::CoverArrowParameter:
95       return BindingKind::FormalParameter;
96 
97     case DeclarationKind::Var:
98     case DeclarationKind::BodyLevelFunction:
99     case DeclarationKind::ModuleBodyLevelFunction:
100     case DeclarationKind::VarForAnnexBLexicalFunction:
101       return BindingKind::Var;
102 
103     case DeclarationKind::Let:
104     case DeclarationKind::Class:
105     case DeclarationKind::LexicalFunction:
106     case DeclarationKind::SloppyLexicalFunction:
107     case DeclarationKind::SimpleCatchParameter:
108     case DeclarationKind::CatchParameter:
109       return BindingKind::Let;
110 
111     case DeclarationKind::Const:
112       return BindingKind::Const;
113 
114     case DeclarationKind::Import:
115       return BindingKind::Import;
116   }
117 
118   MOZ_CRASH("Bad DeclarationKind");
119 }
120 
DeclarationKindIsLexical(DeclarationKind kind)121 static inline bool DeclarationKindIsLexical(DeclarationKind kind) {
122   return BindingKindIsLexical(DeclarationKindToBindingKind(kind));
123 }
124 
125 // Used in Parser to track declared names.
126 class DeclaredNameInfo {
127   uint32_t pos_;
128   DeclarationKind kind_;
129 
130   // If the declared name is a binding, whether the binding is closed
131   // over. Its value is meaningless if the declared name is not a binding
132   // (i.e., a 'var' declared name in a non-var scope).
133   bool closedOver_;
134 
135  public:
DeclaredNameInfo(DeclarationKind kind,uint32_t pos)136   explicit DeclaredNameInfo(DeclarationKind kind, uint32_t pos)
137       : pos_(pos), kind_(kind), closedOver_(false) {}
138 
139   // Needed for InlineMap.
140   DeclaredNameInfo() = default;
141 
kind()142   DeclarationKind kind() const { return kind_; }
143 
144   static const uint32_t npos = uint32_t(-1);
145 
pos()146   uint32_t pos() const { return pos_; }
147 
alterKind(DeclarationKind kind)148   void alterKind(DeclarationKind kind) { kind_ = kind; }
149 
setClosedOver()150   void setClosedOver() { closedOver_ = true; }
151 
closedOver()152   bool closedOver() const { return closedOver_; }
153 };
154 
155 // Used in BytecodeEmitter to map names to locations.
156 class NameLocation {
157  public:
158   enum class Kind : uint8_t {
159     // Cannot statically determine where the name lives. Needs to walk the
160     // environment chain to search for the name.
161     Dynamic,
162 
163     // The name lives on the global or is a global lexical binding. Search
164     // for the name on the global scope.
165     Global,
166 
167     // Special mode used only when emitting self-hosted scripts. See
168     // BytecodeEmitter::lookupName.
169     Intrinsic,
170 
171     // In a named lambda, the name is the callee itself.
172     NamedLambdaCallee,
173 
174     // The name is a positional formal parameter name and can be retrieved
175     // directly from the stack using slot_.
176     ArgumentSlot,
177 
178     // The name is not closed over and lives on the frame in slot_.
179     FrameSlot,
180 
181     // The name is closed over and lives on an environment hops_ away in slot_.
182     EnvironmentCoordinate,
183 
184     // An imported name in a module.
185     Import,
186 
187     // Cannot statically determine where the synthesized var for Annex
188     // B.3.3 lives.
189     DynamicAnnexBVar
190   };
191 
192  private:
193   // Where the name lives.
194   Kind kind_;
195 
196   // If the name is not Dynamic or DynamicAnnexBVar, the kind of the
197   // binding.
198   BindingKind bindingKind_;
199 
200   // If the name is closed over and accessed via EnvironmentCoordinate, the
201   // number of dynamic environments to skip.
202   //
203   // Otherwise UINT8_MAX.
204   uint8_t hops_;
205 
206   // If the name lives on the frame, the slot frame.
207   //
208   // If the name is closed over and accessed via EnvironmentCoordinate, the
209   // slot on the environment.
210   //
211   // Otherwise LOCALNO_LIMIT/ENVCOORD_SLOT_LIMIT.
212   uint32_t slot_ : ENVCOORD_SLOT_BITS;
213 
214   static_assert(LOCALNO_BITS == ENVCOORD_SLOT_BITS,
215                 "Frame and environment slots must be same sized.");
216 
217   NameLocation(Kind kind, BindingKind bindingKind, uint8_t hops = UINT8_MAX,
218                uint32_t slot = ENVCOORD_SLOT_LIMIT)
kind_(kind)219       : kind_(kind), bindingKind_(bindingKind), hops_(hops), slot_(slot) {}
220 
221  public:
222   // Default constructor for InlineMap.
223   NameLocation() = default;
224 
Dynamic()225   static NameLocation Dynamic() { return NameLocation(); }
226 
Global(BindingKind bindKind)227   static NameLocation Global(BindingKind bindKind) {
228     MOZ_ASSERT(bindKind != BindingKind::FormalParameter);
229     return NameLocation(Kind::Global, bindKind);
230   }
231 
Intrinsic()232   static NameLocation Intrinsic() {
233     return NameLocation(Kind::Intrinsic, BindingKind::Var);
234   }
235 
NamedLambdaCallee()236   static NameLocation NamedLambdaCallee() {
237     return NameLocation(Kind::NamedLambdaCallee,
238                         BindingKind::NamedLambdaCallee);
239   }
240 
ArgumentSlot(uint16_t slot)241   static NameLocation ArgumentSlot(uint16_t slot) {
242     return NameLocation(Kind::ArgumentSlot, BindingKind::FormalParameter, 0,
243                         slot);
244   }
245 
FrameSlot(BindingKind bindKind,uint32_t slot)246   static NameLocation FrameSlot(BindingKind bindKind, uint32_t slot) {
247     MOZ_ASSERT(slot < LOCALNO_LIMIT);
248     return NameLocation(Kind::FrameSlot, bindKind, 0, slot);
249   }
250 
EnvironmentCoordinate(BindingKind bindKind,uint8_t hops,uint32_t slot)251   static NameLocation EnvironmentCoordinate(BindingKind bindKind, uint8_t hops,
252                                             uint32_t slot) {
253     MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT);
254     return NameLocation(Kind::EnvironmentCoordinate, bindKind, hops, slot);
255   }
256 
Import()257   static NameLocation Import() {
258     return NameLocation(Kind::Import, BindingKind::Import);
259   }
260 
DynamicAnnexBVar()261   static NameLocation DynamicAnnexBVar() {
262     return NameLocation(Kind::DynamicAnnexBVar, BindingKind::Var);
263   }
264 
fromBinding(BindingKind bindKind,const BindingLocation & bl)265   static NameLocation fromBinding(BindingKind bindKind,
266                                   const BindingLocation& bl) {
267     switch (bl.kind()) {
268       case BindingLocation::Kind::Global:
269         return Global(bindKind);
270       case BindingLocation::Kind::Argument:
271         return ArgumentSlot(bl.argumentSlot());
272       case BindingLocation::Kind::Frame:
273         return FrameSlot(bindKind, bl.slot());
274       case BindingLocation::Kind::Environment:
275         return EnvironmentCoordinate(bindKind, 0, bl.slot());
276       case BindingLocation::Kind::Import:
277         return Import();
278       case BindingLocation::Kind::NamedLambdaCallee:
279         return NamedLambdaCallee();
280     }
281     MOZ_CRASH("Bad BindingKind");
282   }
283 
284   bool operator==(const NameLocation& other) const {
285     return kind_ == other.kind_ && bindingKind_ == other.bindingKind_ &&
286            hops_ == other.hops_ && slot_ == other.slot_;
287   }
288 
289   bool operator!=(const NameLocation& other) const { return !(*this == other); }
290 
kind()291   Kind kind() const { return kind_; }
292 
argumentSlot()293   uint16_t argumentSlot() const {
294     MOZ_ASSERT(kind_ == Kind::ArgumentSlot);
295     return mozilla::AssertedCast<uint16_t>(slot_);
296   }
297 
frameSlot()298   uint32_t frameSlot() const {
299     MOZ_ASSERT(kind_ == Kind::FrameSlot);
300     return slot_;
301   }
302 
addHops(uint8_t more)303   NameLocation addHops(uint8_t more) {
304     MOZ_ASSERT(hops_ < ENVCOORD_HOPS_LIMIT - more);
305     MOZ_ASSERT(kind_ == Kind::EnvironmentCoordinate);
306     return NameLocation(kind_, bindingKind_, hops_ + more, slot_);
307   }
308 
environmentCoordinate()309   class EnvironmentCoordinate environmentCoordinate() const {
310     MOZ_ASSERT(kind_ == Kind::EnvironmentCoordinate);
311     class EnvironmentCoordinate coord;
312     coord.setHops(hops_);
313     coord.setSlot(slot_);
314     return coord;
315   }
316 
bindingKind()317   BindingKind bindingKind() const {
318     MOZ_ASSERT(kind_ != Kind::Dynamic);
319     return bindingKind_;
320   }
321 
isLexical()322   bool isLexical() const { return BindingKindIsLexical(bindingKind()); }
323 
isConst()324   bool isConst() const { return bindingKind() == BindingKind::Const; }
325 
hasKnownSlot()326   bool hasKnownSlot() const {
327     return kind_ == Kind::ArgumentSlot || kind_ == Kind::FrameSlot ||
328            kind_ == Kind::EnvironmentCoordinate;
329   }
330 };
331 
332 // These types are declared here for BaseScript::CreateLazy.
333 using AtomVector = Vector<JSAtom*, 24, SystemAllocPolicy>;
334 
335 class FunctionBox;
336 // FunctionBoxes stored in this type are required to be rooted
337 // by the parser
338 using FunctionBoxVector = Vector<const FunctionBox*, 8>;
339 
340 }  // namespace frontend
341 }  // namespace js
342 
343 #endif  // frontend_NameAnalysisTypes_h
344