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_NameAnalysisTypes_h
8 #define frontend_NameAnalysisTypes_h
10 #include "mozilla/Assertions.h" // MOZ_ASSERT, MOZ_CRASH
11 #include "mozilla/Casting.h" // mozilla::AssertedCast
13 #include <stdint.h> // uint8_t, uint16_t, uint32_t
15 #include "vm/BindingKind.h" // BindingKind, BindingLocation
16 #include "vm/BytecodeFormatFlags.h" // JOF_ENVCOORD
17 #include "vm/BytecodeUtil.h" // ENVCOORD_HOPS_BITS, ENVCOORD_SLOT_BITS, GET_ENVCOORD_HOPS, GET_ENVCOORD_SLOT, ENVCOORD_HOPS_LEN, JOF_OPTYPE, JSOp, LOCALNO_LIMIT
21 // An "environment coordinate" describes how to get from head of the
22 // environment chain to a given lexically-enclosing variable. An environment
23 // coordinate has two dimensions:
24 // - hops: the number of environment objects on the scope chain to skip
25 // - slot: the slot on the environment object holding the variable's value
26 class EnvironmentCoordinate
{
30 // Technically, hops_/slot_ are ENVCOORD_(HOPS|SLOT)_BITS wide. Since
31 // EnvironmentCoordinate is a temporary value, don't bother with a bitfield as
32 // this only adds overhead.
33 static_assert(ENVCOORD_HOPS_BITS
<= 32, "We have enough bits below");
34 static_assert(ENVCOORD_SLOT_BITS
<= 32, "We have enough bits below");
37 explicit inline EnvironmentCoordinate(jsbytecode
* pc
)
38 : hops_(GET_ENVCOORD_HOPS(pc
)),
39 slot_(GET_ENVCOORD_SLOT(pc
+ ENVCOORD_HOPS_LEN
)) {
40 MOZ_ASSERT(JOF_OPTYPE(JSOp(*pc
)) == JOF_ENVCOORD
||
41 JOF_OPTYPE(JSOp(*pc
)) == JOF_DEBUGCOORD
);
44 EnvironmentCoordinate() = default;
46 void setHops(uint32_t hops
) {
47 MOZ_ASSERT(hops
< ENVCOORD_HOPS_LIMIT
);
51 void setSlot(uint32_t slot
) {
52 MOZ_ASSERT(slot
< ENVCOORD_SLOT_LIMIT
);
56 uint32_t hops() const {
57 MOZ_ASSERT(hops_
< ENVCOORD_HOPS_LIMIT
);
61 uint32_t slot() const {
62 MOZ_ASSERT(slot_
< ENVCOORD_SLOT_LIMIT
);
66 bool operator==(const EnvironmentCoordinate
& rhs
) const {
67 return hops() == rhs
.hops() && slot() == rhs
.slot();
73 enum class ParseGoal
: uint8_t { Script
, Module
};
75 // A detailed kind used for tracking declarations in the Parser. Used for
76 // specific early error semantics and better error messages.
77 enum class DeclarationKind
: uint8_t {
78 PositionalFormalParameter
,
84 Class
, // Handled as same as `let` after parsing.
87 ModuleBodyLevelFunction
,
89 SloppyLexicalFunction
,
90 VarForAnnexBLexicalFunction
,
95 PrivateMethod
, // slot to store nonstatic private method
99 enum class FieldPlacement
: uint8_t { Unspecified
, Instance
, Static
};
101 static inline BindingKind
DeclarationKindToBindingKind(DeclarationKind kind
) {
103 case DeclarationKind::PositionalFormalParameter
:
104 case DeclarationKind::FormalParameter
:
105 case DeclarationKind::CoverArrowParameter
:
106 return BindingKind::FormalParameter
;
108 case DeclarationKind::Var
:
109 case DeclarationKind::BodyLevelFunction
:
110 case DeclarationKind::ModuleBodyLevelFunction
:
111 case DeclarationKind::VarForAnnexBLexicalFunction
:
112 return BindingKind::Var
;
114 case DeclarationKind::Let
:
115 case DeclarationKind::Class
:
116 case DeclarationKind::LexicalFunction
:
117 case DeclarationKind::SloppyLexicalFunction
:
118 case DeclarationKind::SimpleCatchParameter
:
119 case DeclarationKind::CatchParameter
:
120 return BindingKind::Let
;
122 case DeclarationKind::Const
:
123 return BindingKind::Const
;
125 case DeclarationKind::Import
:
126 return BindingKind::Import
;
128 case DeclarationKind::Synthetic
:
129 case DeclarationKind::PrivateName
:
130 return BindingKind::Synthetic
;
132 case DeclarationKind::PrivateMethod
:
133 return BindingKind::PrivateMethod
;
136 MOZ_CRASH("Bad DeclarationKind");
139 static inline bool DeclarationKindIsLexical(DeclarationKind kind
) {
140 return BindingKindIsLexical(DeclarationKindToBindingKind(kind
));
143 // Used in Parser and BytecodeEmitter to track the kind of a private name.
144 enum class PrivateNameKind
: uint8_t {
153 enum class ClosedOver
: bool { No
= false, Yes
= true };
155 // Used in Parser to track declared names.
156 class DeclaredNameInfo
{
158 DeclarationKind kind_
;
160 // If the declared name is a binding, whether the binding is closed
161 // over. Its value is meaningless if the declared name is not a binding
162 // (i.e., a 'var' declared name in a non-var scope).
165 PrivateNameKind privateNameKind_
;
167 // Only updated for private names (see noteDeclaredPrivateName),
168 // tracks if declaration was instance or static to allow issuing
169 // early errors in the case where we mismatch instance and static
170 // private getter/setters.
171 FieldPlacement placement_
;
174 explicit DeclaredNameInfo(DeclarationKind kind
, uint32_t pos
,
175 ClosedOver closedOver
= ClosedOver::No
)
178 closedOver_(bool(closedOver
)),
179 privateNameKind_(PrivateNameKind::None
),
180 placement_(FieldPlacement::Unspecified
) {}
182 // Needed for InlineMap.
183 DeclaredNameInfo() = default;
185 DeclarationKind
kind() const { return kind_
; }
187 static const uint32_t npos
= uint32_t(-1);
189 uint32_t pos() const { return pos_
; }
191 void alterKind(DeclarationKind kind
) { kind_
= kind
; }
193 void setClosedOver() { closedOver_
= true; }
195 bool closedOver() const { return closedOver_
; }
197 void setPrivateNameKind(PrivateNameKind privateNameKind
) {
198 privateNameKind_
= privateNameKind
;
201 void setFieldPlacement(FieldPlacement placement
) {
202 MOZ_ASSERT(placement
!= FieldPlacement::Unspecified
);
203 placement_
= placement
;
206 PrivateNameKind
privateNameKind() const { return privateNameKind_
; }
208 FieldPlacement
placement() const { return placement_
; }
211 // Used in BytecodeEmitter to map names to locations.
214 enum class Kind
: uint8_t {
215 // Cannot statically determine where the name lives. Needs to walk the
216 // environment chain to search for the name.
219 // The name lives on the global or is a global lexical binding. Search
220 // for the name on the global scope.
223 // Special mode used only when emitting self-hosted scripts. See
224 // BytecodeEmitter::lookupName.
227 // In a named lambda, the name is the callee itself.
230 // The name is a positional formal parameter name and can be retrieved
231 // directly from the stack using slot_.
234 // The name is not closed over and lives on the frame in slot_.
237 // The name is closed over and lives on an environment hops_ away in slot_.
238 EnvironmentCoordinate
,
240 // The name is closed over and lives on an environment hops_ away in slot_,
241 // where one or more of the environments may be a DebugEnvironmentProxy
242 DebugEnvironmentCoordinate
,
244 // An imported name in a module.
247 // Cannot statically determine where the synthesized var for Annex
253 // Where the name lives.
256 // If the name is not Dynamic or DynamicAnnexBVar, the kind of the
258 BindingKind bindingKind_
;
260 // If the name is closed over and accessed via EnvironmentCoordinate, the
261 // number of dynamic environments to skip.
263 // Otherwise UINT8_MAX.
266 // If the name lives on the frame, the slot frame.
268 // If the name is closed over and accessed via EnvironmentCoordinate, the
269 // slot on the environment.
272 uint32_t slot_
: ENVCOORD_SLOT_BITS
;
274 static_assert(LOCALNO_BITS
== ENVCOORD_SLOT_BITS
,
275 "Frame and environment slots must be same sized.");
277 NameLocation(Kind kind
, BindingKind bindingKind
, uint8_t hops
= UINT8_MAX
,
279 : kind_(kind
), bindingKind_(bindingKind
), hops_(hops
), slot_(slot
) {}
282 // Default constructor for InlineMap.
283 NameLocation() = default;
285 static NameLocation
Dynamic() {
286 return NameLocation(Kind::Dynamic
, BindingKind::Import
);
289 static NameLocation
Global(BindingKind bindKind
) {
290 MOZ_ASSERT(bindKind
!= BindingKind::FormalParameter
);
291 return NameLocation(Kind::Global
, bindKind
);
294 static NameLocation
Intrinsic() {
295 return NameLocation(Kind::Intrinsic
, BindingKind::Var
);
298 static NameLocation
NamedLambdaCallee() {
299 return NameLocation(Kind::NamedLambdaCallee
,
300 BindingKind::NamedLambdaCallee
);
303 static NameLocation
ArgumentSlot(uint16_t slot
) {
304 return NameLocation(Kind::ArgumentSlot
, BindingKind::FormalParameter
, 0,
308 static NameLocation
FrameSlot(BindingKind bindKind
, uint32_t slot
) {
309 MOZ_ASSERT(slot
< LOCALNO_LIMIT
);
310 return NameLocation(Kind::FrameSlot
, bindKind
, 0, slot
);
313 static NameLocation
EnvironmentCoordinate(BindingKind bindKind
, uint8_t hops
,
315 MOZ_ASSERT(slot
< ENVCOORD_SLOT_LIMIT
);
316 return NameLocation(Kind::EnvironmentCoordinate
, bindKind
, hops
, slot
);
318 static NameLocation
DebugEnvironmentCoordinate(BindingKind bindKind
,
319 uint8_t hops
, uint32_t slot
) {
320 MOZ_ASSERT(slot
< ENVCOORD_SLOT_LIMIT
);
321 return NameLocation(Kind::DebugEnvironmentCoordinate
, bindKind
, hops
, slot
);
324 static NameLocation
Import() {
325 return NameLocation(Kind::Import
, BindingKind::Import
);
328 static NameLocation
DynamicAnnexBVar() {
329 return NameLocation(Kind::DynamicAnnexBVar
, BindingKind::Var
);
332 bool operator==(const NameLocation
& other
) const {
333 return kind_
== other
.kind_
&& bindingKind_
== other
.bindingKind_
&&
334 hops_
== other
.hops_
&& slot_
== other
.slot_
;
337 bool operator!=(const NameLocation
& other
) const { return !(*this == other
); }
339 Kind
kind() const { return kind_
; }
341 uint16_t argumentSlot() const {
342 MOZ_ASSERT(kind_
== Kind::ArgumentSlot
);
343 return mozilla::AssertedCast
<uint16_t>(slot_
);
346 uint32_t frameSlot() const {
347 MOZ_ASSERT(kind_
== Kind::FrameSlot
);
351 NameLocation
addHops(uint8_t more
) {
352 MOZ_ASSERT(hops_
< ENVCOORD_HOPS_LIMIT
- more
);
353 MOZ_ASSERT(kind_
== Kind::EnvironmentCoordinate
);
354 return NameLocation(kind_
, bindingKind_
, hops_
+ more
, slot_
);
357 class EnvironmentCoordinate
environmentCoordinate() const {
358 MOZ_ASSERT(kind_
== Kind::EnvironmentCoordinate
||
359 kind_
== Kind::DebugEnvironmentCoordinate
);
360 class EnvironmentCoordinate coord
;
361 coord
.setHops(hops_
);
362 coord
.setSlot(slot_
);
366 BindingKind
bindingKind() const {
367 MOZ_ASSERT(kind_
!= Kind::Dynamic
);
371 bool isLexical() const { return BindingKindIsLexical(bindingKind()); }
373 bool isConst() const { return bindingKind() == BindingKind::Const
; }
375 bool isSynthetic() const { return bindingKind() == BindingKind::Synthetic
; }
377 bool isPrivateMethod() const {
378 return bindingKind() == BindingKind::PrivateMethod
;
381 bool hasKnownSlot() const {
382 return kind_
== Kind::ArgumentSlot
|| kind_
== Kind::FrameSlot
||
383 kind_
== Kind::EnvironmentCoordinate
;
387 } // namespace frontend
390 #endif // frontend_NameAnalysisTypes_h