Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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_NameAnalysis_h
8 : #define frontend_NameAnalysis_h
9 :
10 : #include "jsopcode.h"
11 :
12 : #include "vm/Scope.h"
13 :
14 : namespace js {
15 :
16 : // An "environment coordinate" describes how to get from head of the
17 : // environment chain to a given lexically-enclosing variable. An environment
18 : // coordinate has two dimensions:
19 : // - hops: the number of environment objects on the scope chain to skip
20 : // - slot: the slot on the environment object holding the variable's value
21 : class EnvironmentCoordinate
22 : {
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:
33 13299 : explicit inline EnvironmentCoordinate(jsbytecode* pc)
34 13299 : : hops_(GET_ENVCOORD_HOPS(pc)), slot_(GET_ENVCOORD_SLOT(pc + ENVCOORD_HOPS_LEN))
35 : {
36 13299 : MOZ_ASSERT(JOF_OPTYPE(JSOp(*pc)) == JOF_ENVCOORD);
37 13299 : }
38 :
39 8054 : EnvironmentCoordinate() {}
40 :
41 8054 : void setHops(uint32_t hops) {
42 8054 : MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT);
43 8054 : hops_ = hops;
44 8054 : }
45 :
46 8054 : void setSlot(uint32_t slot) {
47 8054 : MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT);
48 8054 : slot_ = slot;
49 8054 : }
50 :
51 20394 : uint32_t hops() const {
52 20394 : MOZ_ASSERT(hops_ < ENVCOORD_HOPS_LIMIT);
53 20394 : return hops_;
54 : }
55 :
56 20345 : uint32_t slot() const {
57 20345 : MOZ_ASSERT(slot_ < ENVCOORD_SLOT_LIMIT);
58 20345 : return slot_;
59 : }
60 :
61 2 : bool operator==(const EnvironmentCoordinate& rhs) const {
62 2 : return hops() == rhs.hops() && slot() == rhs.slot();
63 : }
64 : };
65 :
66 : namespace frontend {
67 :
68 : // A detailed kind used for tracking declarations in the Parser. Used for
69 : // specific early error semantics and better error messages.
70 : enum class DeclarationKind : uint8_t
71 : {
72 : PositionalFormalParameter,
73 : FormalParameter,
74 : CoverArrowParameter,
75 : Var,
76 : ForOfVar,
77 : Let,
78 : Const,
79 : Import,
80 : BodyLevelFunction,
81 : ModuleBodyLevelFunction,
82 : LexicalFunction,
83 : SloppyLexicalFunction,
84 : VarForAnnexBLexicalFunction,
85 : SimpleCatchParameter,
86 : CatchParameter
87 : };
88 :
89 : static inline BindingKind
90 47373 : DeclarationKindToBindingKind(DeclarationKind kind)
91 : {
92 47373 : switch (kind) {
93 : case DeclarationKind::PositionalFormalParameter:
94 : case DeclarationKind::FormalParameter:
95 : case DeclarationKind::CoverArrowParameter:
96 12286 : return BindingKind::FormalParameter;
97 :
98 : case DeclarationKind::Var:
99 : case DeclarationKind::BodyLevelFunction:
100 : case DeclarationKind::ModuleBodyLevelFunction:
101 : case DeclarationKind::VarForAnnexBLexicalFunction:
102 : case DeclarationKind::ForOfVar:
103 18198 : return BindingKind::Var;
104 :
105 : case DeclarationKind::Let:
106 : case DeclarationKind::LexicalFunction:
107 : case DeclarationKind::SloppyLexicalFunction:
108 : case DeclarationKind::SimpleCatchParameter:
109 : case DeclarationKind::CatchParameter:
110 13410 : return BindingKind::Let;
111 :
112 : case DeclarationKind::Const:
113 3479 : return BindingKind::Const;
114 :
115 : case DeclarationKind::Import:
116 0 : return BindingKind::Import;
117 : }
118 :
119 0 : MOZ_CRASH("Bad DeclarationKind");
120 : }
121 :
122 : static inline bool
123 3001 : DeclarationKindIsLexical(DeclarationKind kind)
124 : {
125 3001 : return BindingKindIsLexical(DeclarationKindToBindingKind(kind));
126 : }
127 :
128 : // Used in Parser to track declared names.
129 : class DeclaredNameInfo
130 : {
131 : uint32_t pos_;
132 : DeclarationKind kind_;
133 :
134 : // If the declared name is a binding, whether the binding is closed
135 : // over. Its value is meaningless if the declared name is not a binding
136 : // (i.e., a 'var' declared name in a non-var scope).
137 : bool closedOver_;
138 :
139 : public:
140 29316 : explicit DeclaredNameInfo(DeclarationKind kind, uint32_t pos)
141 29316 : : pos_(pos),
142 : kind_(kind),
143 29316 : closedOver_(false)
144 29316 : { }
145 :
146 : // Needed for InlineMap.
147 : DeclaredNameInfo() = default;
148 :
149 55131 : DeclarationKind kind() const {
150 55131 : return kind_;
151 : }
152 :
153 : static const uint32_t npos = uint32_t(-1);
154 :
155 655 : uint32_t pos() const {
156 655 : return pos_;
157 : }
158 :
159 0 : void alterKind(DeclarationKind kind) {
160 0 : kind_ = kind;
161 0 : }
162 :
163 1503 : void setClosedOver() {
164 1503 : closedOver_ = true;
165 1503 : }
166 :
167 41986 : bool closedOver() const {
168 41986 : return closedOver_;
169 : }
170 : };
171 :
172 : // Used in BytecodeEmitter to map names to locations.
173 : class NameLocation
174 : {
175 : public:
176 : enum class Kind : uint8_t
177 : {
178 : // Cannot statically determine where the name lives. Needs to walk the
179 : // environment chain to search for the name.
180 : Dynamic,
181 :
182 : // The name lives on the global or is a global lexical binding. Search
183 : // for the name on the global scope.
184 : Global,
185 :
186 : // Special mode used only when emitting self-hosted scripts. See
187 : // BytecodeEmitter::lookupName.
188 : Intrinsic,
189 :
190 : // In a named lambda, the name is the callee itself.
191 : NamedLambdaCallee,
192 :
193 : // The name is a positional formal parameter name and can be retrieved
194 : // directly from the stack using slot_.
195 : ArgumentSlot,
196 :
197 : // The name is not closed over and lives on the frame in slot_.
198 : FrameSlot,
199 :
200 : // The name is closed over and lives on an environment hops_ away in slot_.
201 : EnvironmentCoordinate,
202 :
203 : // An imported name in a module.
204 : Import,
205 :
206 : // Cannot statically determine where the synthesized var for Annex
207 : // B.3.3 lives.
208 : DynamicAnnexBVar
209 : };
210 :
211 : private:
212 : // Where the name lives.
213 : Kind kind_;
214 :
215 : // If the name is not Dynamic or DynamicAnnexBVar, the kind of the
216 : // binding.
217 : BindingKind bindingKind_;
218 :
219 : // If the name is closed over and accessed via EnvironmentCoordinate, the
220 : // number of dynamic environments to skip.
221 : //
222 : // Otherwise UINT8_MAX.
223 : uint8_t hops_;
224 :
225 : // If the name lives on the frame, the slot frame.
226 : //
227 : // If the name is closed over and accessed via EnvironmentCoordinate, the
228 : // slot on the environment.
229 : //
230 : // Otherwise LOCALNO_LIMIT/ENVCOORD_SLOT_LIMIT.
231 : uint32_t slot_ : ENVCOORD_SLOT_BITS;
232 :
233 : static_assert(LOCALNO_BITS == ENVCOORD_SLOT_BITS,
234 : "Frame and environment slots must be same sized.");
235 :
236 25437 : NameLocation(Kind kind, BindingKind bindingKind,
237 : uint8_t hops = UINT8_MAX, uint32_t slot = ENVCOORD_SLOT_LIMIT)
238 25437 : : kind_(kind),
239 : bindingKind_(bindingKind),
240 : hops_(hops),
241 25437 : slot_(slot)
242 25437 : { }
243 :
244 : public:
245 : // Default constructor for InlineMap.
246 13 : NameLocation() = default;
247 :
248 803 : static NameLocation Dynamic() {
249 803 : return NameLocation();
250 : }
251 :
252 3397 : static NameLocation Global(BindingKind bindKind) {
253 3397 : MOZ_ASSERT(bindKind != BindingKind::FormalParameter);
254 3397 : return NameLocation(Kind::Global, bindKind);
255 : }
256 :
257 3 : static NameLocation Intrinsic() {
258 3 : return NameLocation(Kind::Intrinsic, BindingKind::Var);
259 : }
260 :
261 384 : static NameLocation NamedLambdaCallee() {
262 384 : return NameLocation(Kind::NamedLambdaCallee, BindingKind::NamedLambdaCallee);
263 : }
264 :
265 5459 : static NameLocation ArgumentSlot(uint16_t slot) {
266 5459 : return NameLocation(Kind::ArgumentSlot, BindingKind::FormalParameter, 0, slot);
267 : }
268 :
269 11260 : static NameLocation FrameSlot(BindingKind bindKind, uint32_t slot) {
270 11260 : MOZ_ASSERT(slot < LOCALNO_LIMIT);
271 11260 : return NameLocation(Kind::FrameSlot, bindKind, 0, slot);
272 : }
273 :
274 2219 : static NameLocation EnvironmentCoordinate(BindingKind bindKind, uint8_t hops, uint32_t slot) {
275 2219 : MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT);
276 2219 : return NameLocation(Kind::EnvironmentCoordinate, bindKind, hops, slot);
277 : }
278 :
279 0 : static NameLocation Import() {
280 0 : return NameLocation(Kind::Import, BindingKind::Import);
281 : }
282 :
283 0 : static NameLocation DynamicAnnexBVar() {
284 0 : return NameLocation(Kind::DynamicAnnexBVar, BindingKind::Var);
285 : }
286 :
287 20767 : static NameLocation fromBinding(BindingKind bindKind, const BindingLocation& bl) {
288 20767 : switch (bl.kind()) {
289 : case BindingLocation::Kind::Global:
290 1924 : return Global(bindKind);
291 : case BindingLocation::Kind::Argument:
292 5459 : return ArgumentSlot(bl.argumentSlot());
293 : case BindingLocation::Kind::Frame:
294 11247 : return FrameSlot(bindKind, bl.slot());
295 : case BindingLocation::Kind::Environment:
296 1753 : return EnvironmentCoordinate(bindKind, 0, bl.slot());
297 : case BindingLocation::Kind::Import:
298 0 : return Import();
299 : case BindingLocation::Kind::NamedLambdaCallee:
300 384 : return NamedLambdaCallee();
301 : }
302 0 : MOZ_CRASH("Bad BindingKind");
303 : }
304 :
305 15 : bool operator==(const NameLocation& other) const {
306 45 : return kind_ == other.kind_ && bindingKind_ == other.bindingKind_ &&
307 45 : hops_ == other.hops_ && slot_ == other.slot_;
308 : }
309 :
310 : bool operator!=(const NameLocation& other) const {
311 : return !(*this == other);
312 : }
313 :
314 138908 : Kind kind() const {
315 138908 : return kind_;
316 : }
317 :
318 14330 : uint16_t argumentSlot() const {
319 14330 : MOZ_ASSERT(kind_ == Kind::ArgumentSlot);
320 14330 : return mozilla::AssertedCast<uint16_t>(slot_);
321 : }
322 :
323 43134 : uint32_t frameSlot() const {
324 43134 : MOZ_ASSERT(kind_ == Kind::FrameSlot);
325 43134 : return slot_;
326 : }
327 :
328 2715 : NameLocation addHops(uint8_t more) {
329 2715 : MOZ_ASSERT(hops_ < ENVCOORD_HOPS_LIMIT - more);
330 2715 : MOZ_ASSERT(kind_ == Kind::EnvironmentCoordinate);
331 2715 : return NameLocation(kind_, bindingKind_, hops_ + more, slot_);
332 : }
333 :
334 8054 : class EnvironmentCoordinate environmentCoordinate() const {
335 8054 : MOZ_ASSERT(kind_ == Kind::EnvironmentCoordinate);
336 8054 : class EnvironmentCoordinate coord;
337 8054 : coord.setHops(hops_);
338 8054 : coord.setSlot(slot_);
339 8054 : return coord;
340 : }
341 :
342 68916 : BindingKind bindingKind() const {
343 68916 : MOZ_ASSERT(kind_ != Kind::Dynamic);
344 68916 : return bindingKind_;
345 : }
346 :
347 64679 : bool isLexical() const {
348 64679 : return BindingKindIsLexical(bindingKind());
349 : }
350 :
351 984 : bool isConst() const {
352 984 : return bindingKind() == BindingKind::Const;
353 : }
354 :
355 15250 : bool hasKnownSlot() const {
356 30500 : return kind_ == Kind::ArgumentSlot ||
357 17600 : kind_ == Kind::FrameSlot ||
358 17600 : kind_ == Kind::EnvironmentCoordinate;
359 : }
360 : };
361 :
362 : // This type is declared here for LazyScript::Create.
363 : using AtomVector = Vector<JSAtom*, 24, SystemAllocPolicy>;
364 :
365 : } // namespace frontend
366 : } // namespace js
367 :
368 : namespace mozilla {
369 :
370 : template <>
371 : struct IsPod<js::frontend::DeclaredNameInfo> : TrueType {};
372 :
373 : template <>
374 : struct IsPod<js::frontend::NameLocation> : TrueType {};
375 :
376 : } // namespace mozilla
377 :
378 : #endif // frontend_NameAnalysis_h
|