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 vm_Scope_h
8 : #define vm_Scope_h
9 :
10 : #include "mozilla/Maybe.h"
11 : #include "mozilla/TypeTraits.h"
12 : #include "mozilla/Variant.h"
13 :
14 : #include <stddef.h>
15 :
16 : #include "jsutil.h"
17 :
18 : #include "gc/DeletePolicy.h"
19 : #include "gc/Heap.h"
20 : #include "gc/Policy.h"
21 : #include "js/UbiNode.h"
22 : #include "js/UniquePtr.h"
23 : #include "vm/BytecodeUtil.h"
24 : #include "vm/JSObject.h"
25 : #include "vm/Xdr.h"
26 :
27 : namespace js {
28 :
29 : class ModuleObject;
30 : class Scope;
31 :
32 : enum class BindingKind : uint8_t
33 : {
34 : Import,
35 : FormalParameter,
36 : Var,
37 : Let,
38 : Const,
39 :
40 : // So you think named lambda callee names are consts? Nope! They don't
41 : // throw when being assigned to in sloppy mode.
42 : NamedLambdaCallee
43 : };
44 :
45 0 : static inline bool
46 : BindingKindIsLexical(BindingKind kind)
47 : {
48 : return kind == BindingKind::Let || kind == BindingKind::Const;
49 : }
50 :
51 : enum class ScopeKind : uint8_t
52 : {
53 : // FunctionScope
54 : Function,
55 :
56 : // VarScope
57 : FunctionBodyVar,
58 : ParameterExpressionVar,
59 :
60 : // LexicalScope
61 : Lexical,
62 : SimpleCatch,
63 : Catch,
64 : NamedLambda,
65 : StrictNamedLambda,
66 :
67 : // WithScope
68 : With,
69 :
70 : // EvalScope
71 : Eval,
72 : StrictEval,
73 :
74 : // GlobalScope
75 : Global,
76 : NonSyntactic,
77 :
78 : // ModuleScope
79 : Module,
80 :
81 : // WasmInstanceScope
82 : WasmInstance,
83 :
84 : // WasmFunctionScope
85 : WasmFunction
86 : };
87 :
88 0 : static inline bool
89 : ScopeKindIsCatch(ScopeKind kind)
90 : {
91 : return kind == ScopeKind::SimpleCatch || kind == ScopeKind::Catch;
92 : }
93 :
94 : static inline bool
95 0 : ScopeKindIsInBody(ScopeKind kind)
96 0 : {
97 0 : return kind == ScopeKind::Lexical ||
98 0 : kind == ScopeKind::SimpleCatch ||
99 : kind == ScopeKind::Catch ||
100 : kind == ScopeKind::With ||
101 : kind == ScopeKind::FunctionBodyVar ||
102 : kind == ScopeKind::ParameterExpressionVar;
103 : }
104 :
105 : const char* BindingKindString(BindingKind kind);
106 : const char* ScopeKindString(ScopeKind kind);
107 :
108 : class BindingName
109 : {
110 : // A JSAtom* with its low bit used as a tag for the:
111 : // * whether it is closed over (i.e., exists in the environment shape)
112 : // * whether it is a top-level function binding in global or eval scope,
113 : // instead of var binding (both are in the same range in Scope data)
114 : uintptr_t bits_;
115 :
116 : static const uintptr_t ClosedOverFlag = 0x1;
117 : // TODO: We should reuse this bit for let vs class distinction to
118 : // show the better redeclaration error message (bug 1428672).
119 : static const uintptr_t TopLevelFunctionFlag = 0x2;
120 : static const uintptr_t FlagMask = 0x3;
121 13507 :
122 : public:
123 : BindingName()
124 : : bits_(0)
125 158886 : { }
126 87315 :
127 74060 : BindingName(JSAtom* name, bool closedOver, bool isTopLevelFunction = false)
128 : : bits_(uintptr_t(name) |
129 : (closedOver ? ClosedOverFlag : 0x0) |
130 : (isTopLevelFunction? TopLevelFunctionFlag : 0x0))
131 320488 : { }
132 :
133 : private:
134 : // For fromXDR.
135 327211 : BindingName(JSAtom* name, uint8_t flags)
136 : : bits_(uintptr_t(name) | flags)
137 : {
138 : static_assert(FlagMask < alignof(JSAtom),
139 : "Flags should fit into unused bits of JSAtom pointer");
140 : MOZ_ASSERT((flags & FlagMask) == flags);
141 : }
142 :
143 3855 : public:
144 : static BindingName fromXDR(JSAtom* name, uint8_t flags) {
145 : return BindingName(name, flags);
146 : }
147 :
148 : uint8_t flagsForXDR() const {
149 : return static_cast<uint8_t>(bits_ & FlagMask);
150 : }
151 :
152 : JSAtom* name() const {
153 : return reinterpret_cast<JSAtom*>(bits_ & ~FlagMask);
154 : }
155 :
156 : bool closedOver() const {
157 : return bits_ & ClosedOverFlag;
158 : }
159 :
160 : private:
161 : friend class BindingIter;
162 : // This method should be called only for binding names in `vars` range in
163 : // BindingIter.
164 : bool isTopLevelFunction() const {
165 : return bits_ & TopLevelFunctionFlag;
166 : }
167 :
168 : public:
169 : void trace(JSTracer* trc);
170 : };
171 :
172 : /**
173 : * The various {Global,Module,...}Scope::Data classes consist of always-present
174 252784 : * bits, then a trailing array of BindingNames. The various Data classes all
175 : * end in a TrailingNamesArray that contains sized/aligned space for *one*
176 : * BindingName. Data instances that contain N BindingNames, are then allocated
177 : * in sizeof(Data) + (space for (N - 1) BindingNames). Because this class's
178 : * |data_| field is properly sized/aligned, the N-BindingName array can start
179 : * at |data_|.
180 : *
181 : * This is concededly a very low-level representation, but we want to only
182 23319 : * allocate once for data+bindings both, and this does so approximately as
183 23319 : * elegantly as C++ allows.
184 21171 : */
185 : class TrailingNamesArray
186 : {
187 254975 : private:
188 : alignas(BindingName) unsigned char data_[sizeof(BindingName)];
189 70051 :
190 : private:
191 : // Some versions of GCC treat it as a -Wstrict-aliasing violation (ergo a
192 : // -Werror compile error) to reinterpret_cast<> |data_| to |T*|, even
193 : // through |void*|. Placing the latter cast in these separate functions
194 : // breaks the chain such that affected GCC versions no longer warn/error.
195 : void* ptr() {
196 : return data_;
197 : }
198 :
199 : public:
200 : // Explicitly ensure no one accidentally allocates scope data without
201 : // poisoning its trailing names.
202 : TrailingNamesArray() = delete;
203 :
204 : explicit TrailingNamesArray(size_t nameCount) {
205 : if (nameCount)
206 : JS_POISON(&data_, 0xCC, sizeof(BindingName) * nameCount, MemCheckKind::MakeUndefined);
207 : }
208 :
209 : BindingName* start() { return reinterpret_cast<BindingName*>(ptr()); }
210 :
211 : BindingName& operator[](size_t i) { return start()[i]; }
212 : };
213 :
214 : class BindingLocation
215 3455 : {
216 : public:
217 : enum class Kind {
218 : Global,
219 11155 : Argument,
220 : Frame,
221 : Environment,
222 24678 : Import,
223 24678 : NamedLambdaCallee
224 24678 : };
225 :
226 : private:
227 33049 : Kind kind_;
228 33049 : uint32_t slot_;
229 33049 :
230 : BindingLocation(Kind kind, uint32_t slot)
231 : : kind_(kind),
232 : slot_(slot)
233 0 : { }
234 :
235 : public:
236 : static BindingLocation Global() {
237 0 : return BindingLocation(Kind::Global, UINT32_MAX);
238 : }
239 :
240 : static BindingLocation Argument(uint16_t slot) {
241 : return BindingLocation(Kind::Argument, slot);
242 : }
243 :
244 : static BindingLocation Frame(uint32_t slot) {
245 : MOZ_ASSERT(slot < LOCALNO_LIMIT);
246 : return BindingLocation(Kind::Frame, slot);
247 : }
248 :
249 : static BindingLocation Environment(uint32_t slot) {
250 : MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT);
251 : return BindingLocation(Kind::Environment, slot);
252 45134 : }
253 45134 :
254 45134 : static BindingLocation Import() {
255 : return BindingLocation(Kind::Import, UINT32_MAX);
256 : }
257 0 :
258 0 : static BindingLocation NamedLambdaCallee() {
259 10518 : return BindingLocation(Kind::NamedLambdaCallee, UINT32_MAX);
260 : }
261 :
262 : bool operator==(const BindingLocation& other) const {
263 : return kind_ == other.kind_ && slot_ == other.slot_;
264 : }
265 :
266 : bool operator!=(const BindingLocation& other) const {
267 : return !operator==(other);
268 : }
269 :
270 : Kind kind() const {
271 39950 : return kind_;
272 39950 : }
273 97441 :
274 79900 : uint32_t slot() const {
275 : MOZ_ASSERT(kind_ == Kind::Frame || kind_ == Kind::Environment);
276 : return slot_;
277 : }
278 :
279 : uint16_t argumentSlot() const {
280 : MOZ_ASSERT(kind_ == Kind::Argument);
281 : return mozilla::AssertedCast<uint16_t>(slot_);
282 : }
283 : };
284 :
285 : //
286 : // Allow using is<T> and as<T> on Rooted<Scope*> and Handle<Scope*>.
287 : //
288 : template <typename Wrapper>
289 : class WrappedPtrOperations<Scope*, Wrapper>
290 : {
291 : public:
292 : template <class U>
293 : JS::Handle<U*> as() const {
294 : const Wrapper& self = *static_cast<const Wrapper*>(this);
295 : MOZ_ASSERT_IF(self, self->template is<U>());
296 : return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
297 : }
298 : };
299 :
300 : //
301 : // The base class of all Scopes.
302 : //
303 : class Scope : public js::gc::TenuredCell
304 : {
305 : friend class GCMarker;
306 26139 :
307 : // The kind determines data_.
308 78417 : //
309 : // The memory here must be fully initialized, since otherwise the magic_
310 26139 : // value for gc::RelocationOverlay will land in the padding and may be
311 26139 : // stale.
312 : union {
313 : ScopeKind kind_;
314 : uintptr_t paddedKind_;
315 : };
316 :
317 : // The enclosing scope or nullptr.
318 : GCPtrScope enclosing_;
319 :
320 : // If there are any aliased bindings, the shape for the
321 : // EnvironmentObject. Otherwise nullptr.
322 : GCPtrShape environmentShape_;
323 :
324 : protected:
325 : uintptr_t data_;
326 :
327 : Scope(ScopeKind kind, Scope* enclosing, Shape* environmentShape)
328 0 : : enclosing_(enclosing),
329 26139 : environmentShape_(environmentShape),
330 26139 : data_(0)
331 26139 : {
332 : paddedKind_ = 0;
333 : kind_ = kind;
334 : }
335 :
336 : static Scope* create(JSContext* cx, ScopeKind kind, HandleScope enclosing,
337 : HandleShape envShape);
338 0 :
339 : template <typename T, typename D>
340 : static Scope* create(JSContext* cx, ScopeKind kind, HandleScope enclosing,
341 : HandleShape envShape, mozilla::UniquePtr<T, D> data);
342 0 :
343 973775 : template <typename ConcreteScope, XDRMode mode>
344 911394 : static XDRResult XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
345 : MutableHandle<typename ConcreteScope::Data*> data);
346 :
347 : Shape* maybeCloneEnvironmentShape(JSContext* cx);
348 :
349 : template <typename T, typename D>
350 : void initData(mozilla::UniquePtr<T, D> data) {
351 : MOZ_ASSERT(!data_);
352 : data_ = reinterpret_cast<uintptr_t>(data.release());
353 : }
354 :
355 : public:
356 : static const JS::TraceKind TraceKind = JS::TraceKind::Scope;
357 :
358 424144 : template <typename T>
359 : bool is() const {
360 : return kind_ == T::classScopeKind_;
361 : }
362 165270 :
363 : template <typename T>
364 : T& as() {
365 : MOZ_ASSERT(this->is<T>());
366 136122 : return *static_cast<T*>(this);
367 : }
368 :
369 : template <typename T>
370 : const T& as() const {
371 : MOZ_ASSERT(this->is<T>());
372 : return *static_cast<const T*>(this);
373 366782 : }
374 :
375 : ScopeKind kind() const {
376 : return kind_;
377 : }
378 :
379 : Scope* enclosing() const {
380 : return enclosing_;
381 : }
382 :
383 : Shape* environmentShape() const {
384 : return environmentShape_;
385 : }
386 :
387 : bool hasEnvironment() const {
388 : switch (kind()) {
389 : case ScopeKind::With:
390 79586 : case ScopeKind::Global:
391 41506 : case ScopeKind::NonSyntactic:
392 : return true;
393 : default:
394 : // If there's a shape, an environment must be created for this scope.
395 : return environmentShape_ != nullptr;
396 : }
397 : }
398 :
399 : uint32_t chainLength() const;
400 : uint32_t environmentChainLength() const;
401 :
402 : template <typename T>
403 : bool hasOnChain() const {
404 : for (const Scope* it = this; it; it = it->enclosing()) {
405 : if (it->is<T>())
406 : return true;
407 : }
408 : return false;
409 : }
410 :
411 : bool hasOnChain(ScopeKind kind) const {
412 : for (const Scope* it = this; it; it = it->enclosing()) {
413 : if (it->kind() == kind)
414 : return true;
415 : }
416 : return false;
417 : }
418 :
419 : static Scope* clone(JSContext* cx, HandleScope scope, HandleScope enclosing);
420 :
421 : void traceChildren(JSTracer* trc);
422 : void finalize(FreeOp* fop);
423 :
424 : size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
425 :
426 : void dump();
427 : };
428 :
429 : /** Empty base class for scope Data classes to inherit from. */
430 : class BaseScopeData
431 : {};
432 :
433 : template<class Data>
434 : inline size_t
435 : SizeOfData(uint32_t numBindings)
436 : {
437 : static_assert(mozilla::IsBaseOf<BaseScopeData, Data>::value,
438 : "Data must be the correct sort of data, i.e. it must "
439 : "inherit from BaseScopeData");
440 : return sizeof(Data) + (numBindings ? numBindings - 1 : 0) * sizeof(BindingName);
441 : }
442 :
443 : //
444 : // A lexical scope that holds let and const bindings. There are 4 kinds of
445 : // LexicalScopes.
446 : //
447 : // Lexical
448 : // A plain lexical scope.
449 : //
450 : // SimpleCatch
451 : // Holds the single catch parameter of a catch block.
452 : //
453 9615 : // Catch
454 : // Holds the catch parameters (and only the catch parameters) of a catch
455 : // block.
456 : //
457 : // NamedLambda
458 : // StrictNamedLambda
459 : // Holds the single name of the callee for a named lambda expression.
460 20068 : //
461 : // All kinds of LexicalScopes correspond to LexicalEnvironmentObjects on the
462 : // environment chain.
463 : //
464 20906 : class LexicalScope : public Scope
465 0 : {
466 : friend class Scope;
467 : friend class BindingIter;
468 :
469 : public:
470 : // Data is public because it is created by the frontend. See
471 : // Parser<FullParseHandler>::newLexicalScopeData.
472 : struct Data : BaseScopeData
473 : {
474 : // Bindings are sorted by kind in both frames and environments.
475 : //
476 : // lets - [0, constStart)
477 : // consts - [constStart, length)
478 : uint32_t constStart = 0;
479 : uint32_t length = 0;
480 :
481 32293 : // Frame slots [0, nextFrameSlot) are live when this is the innermost
482 : // scope.
483 : uint32_t nextFrameSlot = 0;
484 :
485 11461 : // The array of tagged JSAtom* names, allocated beyond the end of the
486 : // struct.
487 : TrailingNamesArray trailingNames;
488 :
489 : explicit Data(size_t nameCount) : trailingNames(nameCount) {}
490 : Data() = delete;
491 :
492 : void trace(JSTracer* trc);
493 : };
494 22922 :
495 : static LexicalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data,
496 : uint32_t firstFrameSlot, HandleScope enclosing);
497 :
498 : template <XDRMode mode>
499 : static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
500 : MutableHandleScope scope);
501 :
502 : private:
503 : static LexicalScope* createWithData(JSContext* cx, ScopeKind kind,
504 : MutableHandle<UniquePtr<Data>> data,
505 : uint32_t firstFrameSlot, HandleScope enclosing);
506 :
507 : Data& data() {
508 : return *reinterpret_cast<Data*>(data_);
509 90643 : }
510 :
511 : const Data& data() const {
512 : return *reinterpret_cast<Data*>(data_);
513 : }
514 :
515 : static uint32_t nextFrameSlot(Scope* start);
516 :
517 : public:
518 : uint32_t firstFrameSlot() const;
519 :
520 : uint32_t nextFrameSlot() const {
521 : return data().nextFrameSlot;
522 : }
523 :
524 : // Returns an empty shape for extensible global and non-syntactic lexical
525 : // scopes.
526 : static Shape* getEmptyExtensibleEnvironmentShape(JSContext* cx);
527 : };
528 :
529 : template <>
530 : inline bool
531 : Scope::is<LexicalScope>() const
532 : {
533 : return kind_ == ScopeKind::Lexical ||
534 : kind_ == ScopeKind::SimpleCatch ||
535 : kind_ == ScopeKind::Catch ||
536 : kind_ == ScopeKind::NamedLambda ||
537 : kind_ == ScopeKind::StrictNamedLambda;
538 : }
539 :
540 : //
541 : // Scope corresponding to a function. Holds formal parameter names, special
542 26334 : // internal names (see FunctionScope::isSpecialName), and, if the function
543 : // parameters contain no expressions that might possibly be evaluated, the
544 : // function's var bindings. For example, in these functions, the FunctionScope
545 : // will store a/b/c bindings but not d/e/f bindings:
546 : //
547 : // function f1(a, b) {
548 : // var c;
549 : // let e;
550 : // const f = 3;
551 : // }
552 : // function f2([a], b = 4, ...c) {
553 : // var d, e, f; // stored in VarScope
554 : // }
555 : //
556 : // Corresponds to CallObject on environment chain.
557 : //
558 : class FunctionScope : public Scope
559 : {
560 : friend class GCMarker;
561 : friend class BindingIter;
562 : friend class PositionalFormalParameterIter;
563 : friend class Scope;
564 : static const ScopeKind classScopeKind_ = ScopeKind::Function;
565 :
566 : public:
567 : // Data is public because it is created by the
568 : // frontend. See Parser<FullParseHandler>::newFunctionScopeData.
569 : struct Data : BaseScopeData
570 : {
571 : // The canonical function of the scope, as during a scope walk we
572 : // often query properties of the JSFunction (e.g., is the function an
573 : // arrow).
574 : GCPtrFunction canonicalFunction = {};
575 :
576 : // If parameter expressions are present, parameters act like lexical
577 : // bindings.
578 39249 : bool hasParameterExprs = false;
579 :
580 : // Bindings are sorted by kind in both frames and environments.
581 : //
582 : // Positional formal parameter names are those that are not
583 : // destructured. They may be referred to by argument slots if
584 : // !script()->hasParameterExprs().
585 : //
586 26250 : // An argument slot that needs to be skipped due to being destructured
587 : // or having defaults will have a nullptr name in the name array to
588 : // advance the argument slot.
589 : //
590 26334 : // positional formals - [0, nonPositionalFormalStart)
591 13167 : // other formals - [nonPositionalParamStart, varStart)
592 : // vars - [varStart, length)
593 : uint16_t nonPositionalFormalStart = 0;
594 : uint16_t varStart = 0;
595 : uint32_t length = 0;
596 :
597 : // Frame slots [0, nextFrameSlot) are live when this is the innermost
598 : // scope.
599 : uint32_t nextFrameSlot = 0;
600 :
601 : // The array of tagged JSAtom* names, allocated beyond the end of the
602 : // struct.
603 : TrailingNamesArray trailingNames;
604 :
605 : explicit Data(size_t nameCount) : trailingNames(nameCount) {}
606 : Data() = delete;
607 :
608 : void trace(JSTracer* trc);
609 : Zone* zone() const;
610 : };
611 137225 :
612 : static FunctionScope* create(JSContext* cx, Handle<Data*> data,
613 : bool hasParameterExprs, bool needsEnvironment,
614 : HandleFunction fun, HandleScope enclosing);
615 739670 :
616 : static FunctionScope* clone(JSContext* cx, Handle<FunctionScope*> scope, HandleFunction fun,
617 : HandleScope enclosing);
618 :
619 : template <XDRMode mode>
620 30888 : static XDRResult XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosing,
621 : MutableHandleScope scope);
622 :
623 : private:
624 1888491 : static FunctionScope* createWithData(JSContext* cx, MutableHandle<UniquePtr<Data>> data,
625 : bool hasParameterExprs, bool needsEnvironment,
626 : HandleFunction fun, HandleScope enclosing);
627 :
628 : Data& data() {
629 : return *reinterpret_cast<Data*>(data_);
630 189456 : }
631 :
632 : const Data& data() const {
633 : return *reinterpret_cast<Data*>(data_);
634 2 : }
635 :
636 : public:
637 : uint32_t nextFrameSlot() const {
638 : return data().nextFrameSlot;
639 : }
640 :
641 : JSFunction* canonicalFunction() const {
642 : return data().canonicalFunction;
643 : }
644 :
645 : JSScript* script() const;
646 :
647 : bool hasParameterExprs() const {
648 : return data().hasParameterExprs;
649 : }
650 :
651 : uint32_t numPositionalFormalParameters() const {
652 : return data().nonPositionalFormalStart;
653 : }
654 :
655 : static bool isSpecialName(JSContext* cx, JSAtom* name);
656 :
657 : static Shape* getEmptyEnvironmentShape(JSContext* cx, bool hasParameterExprs);
658 : };
659 :
660 : //
661 : // Scope holding only vars. There are 2 kinds of VarScopes.
662 : //
663 : // FunctionBodyVar
664 : // Corresponds to the extra var scope present in functions with parameter
665 : // expressions. See examples in comment above FunctionScope.
666 : //
667 : // ParameterExpressionVar
668 : // Each parameter expression is evaluated in its own var environment. For
669 : // example, f() below will print 'fml', then 'global'. That's right.
670 : //
671 : // var a = 'global';
672 : // function f(x = (eval(`var a = 'fml'`), a), y = a) {
673 : // print(x);
674 : // print(y);
675 : // };
676 : //
677 : // Corresponds to VarEnvironmentObject on environment chain.
678 : //
679 : class VarScope : public Scope
680 : {
681 : friend class GCMarker;
682 : friend class BindingIter;
683 59 : friend class Scope;
684 :
685 : public:
686 : // Data is public because it is created by the
687 : // frontend. See Parser<FullParseHandler>::newVarScopeData.
688 : struct Data : BaseScopeData
689 : {
690 97 : // All bindings are vars.
691 : uint32_t length = 0;
692 :
693 : // Frame slots [firstFrameSlot(), nextFrameSlot) are live when this is
694 76 : // the innermost scope.
695 38 : uint32_t nextFrameSlot = 0;
696 :
697 : // The array of tagged JSAtom* names, allocated beyond the end of the
698 : // struct.
699 : TrailingNamesArray trailingNames;
700 :
701 : explicit Data(size_t nameCount) : trailingNames(nameCount) {}
702 : Data() = delete;
703 :
704 : void trace(JSTracer* trc);
705 : };
706 :
707 : static VarScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data,
708 : uint32_t firstFrameSlot, bool needsEnvironment,
709 : HandleScope enclosing);
710 :
711 : template <XDRMode mode>
712 164 : static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
713 : MutableHandleScope scope);
714 :
715 : private:
716 121 : static VarScope* createWithData(JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data,
717 : uint32_t firstFrameSlot, bool needsEnvironment,
718 : HandleScope enclosing);
719 :
720 : Data& data() {
721 : return *reinterpret_cast<Data*>(data_);
722 : }
723 242 :
724 : const Data& data() const {
725 : return *reinterpret_cast<Data*>(data_);
726 : }
727 :
728 : public:
729 : uint32_t firstFrameSlot() const;
730 :
731 : uint32_t nextFrameSlot() const {
732 : return data().nextFrameSlot;
733 5746 : }
734 :
735 : static Shape* getEmptyEnvironmentShape(JSContext* cx);
736 : };
737 :
738 : template <>
739 : inline bool
740 : Scope::is<VarScope>() const
741 : {
742 : return kind_ == ScopeKind::FunctionBodyVar || kind_ == ScopeKind::ParameterExpressionVar;
743 : }
744 :
745 : //
746 : // Scope corresponding to both the global object scope and the global lexical
747 : // scope.
748 : //
749 : // Both are extensible and are singletons across <script> tags, so these
750 : // scopes are a fragment of the names in global scope. In other words, two
751 : // global scripts may have two different GlobalScopes despite having the same
752 : // GlobalObject.
753 : //
754 : // There are 2 kinds of GlobalScopes.
755 : //
756 : // Global
757 : // Corresponds to a GlobalObject and its global LexicalEnvironmentObject on
758 : // the environment chain.
759 : //
760 : // NonSyntactic
761 : // Corresponds to a non-GlobalObject created by the embedding on the
762 : // environment chain. This distinction is important for optimizations.
763 : //
764 : class GlobalScope : public Scope
765 : {
766 : friend class Scope;
767 : friend class BindingIter;
768 :
769 : public:
770 : // Data is public because it is created by the frontend. See
771 : // Parser<FullParseHandler>::newGlobalScopeData.
772 : struct Data : BaseScopeData
773 : {
774 : // Bindings are sorted by kind.
775 : // `vars` includes top-level functions which is distinguished by a bit
776 : // on the BindingName.
777 : //
778 : // vars - [0, letStart)
779 : // lets - [letStart, constStart)
780 544 : // consts - [constStart, length)
781 : uint32_t letStart = 0;
782 : uint32_t constStart = 0;
783 : uint32_t length = 0;
784 :
785 : // The array of tagged JSAtom* names, allocated beyond the end of the
786 : // struct.
787 862 : TrailingNamesArray trailingNames;
788 :
789 : explicit Data(size_t nameCount) : trailingNames(nameCount) {}
790 : Data() = delete;
791 636 :
792 318 : void trace(JSTracer* trc);
793 : };
794 :
795 : static GlobalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data);
796 :
797 : static GlobalScope* createEmpty(JSContext* cx, ScopeKind kind) {
798 154 : return create(cx, kind, nullptr);
799 : }
800 :
801 : static GlobalScope* clone(JSContext* cx, Handle<GlobalScope*> scope, ScopeKind kind);
802 :
803 : template <XDRMode mode>
804 : static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, MutableHandleScope scope);
805 :
806 : private:
807 : static GlobalScope* createWithData(JSContext* cx, ScopeKind kind,
808 : MutableHandle<UniquePtr<Data>> data);
809 :
810 : Data& data() {
811 1999 : return *reinterpret_cast<Data*>(data_);
812 : }
813 :
814 : const Data& data() const {
815 0 : return *reinterpret_cast<Data*>(data_);
816 : }
817 :
818 : public:
819 : bool isSyntactic() const {
820 0 : return kind() != ScopeKind::NonSyntactic;
821 : }
822 :
823 : bool hasBindings() const {
824 0 : return data().length > 0;
825 : }
826 : };
827 :
828 : template <>
829 : inline bool
830 : Scope::is<GlobalScope>() const
831 : {
832 48123 : return kind_ == ScopeKind::Global || kind_ == ScopeKind::NonSyntactic;
833 : }
834 :
835 : //
836 : // Scope of a 'with' statement. Has no bindings.
837 : //
838 : // Corresponds to a WithEnvironmentObject on the environment chain.
839 : class WithScope : public Scope
840 : {
841 : friend class Scope;
842 : static const ScopeKind classScopeKind_ = ScopeKind::With;
843 :
844 : public:
845 : static WithScope* create(JSContext* cx, HandleScope enclosing);
846 : };
847 :
848 : //
849 : // Scope of an eval. Holds var bindings. There are 2 kinds of EvalScopes.
850 : //
851 : // StrictEval
852 : // A strict eval. Corresponds to a VarEnvironmentObject, where its var
853 : // bindings lives.
854 : //
855 : // Eval
856 : // A sloppy eval. This is an empty scope, used only in the frontend, to
857 : // detect redeclaration errors. It has no Environment. Any `var`s declared
858 : // in the eval code are bound on the nearest enclosing var environment.
859 : //
860 : class EvalScope : public Scope
861 : {
862 : friend class Scope;
863 : friend class BindingIter;
864 :
865 : public:
866 : // Data is public because it is created by the frontend. See
867 : // Parser<FullParseHandler>::newEvalScopeData.
868 : struct Data : BaseScopeData
869 : {
870 : // All bindings in an eval script are 'var' bindings. The implicit
871 : // lexical scope around the eval is present regardless of strictness
872 : // and is its own LexicalScope.
873 : // `vars` includes top-level functions which is distinguished by a bit
874 : // on the BindingName.
875 : //
876 : // vars - [0, length)
877 : uint32_t varStart = 0;
878 : uint32_t length = 0;
879 :
880 : // Frame slots [0, nextFrameSlot) are live when this is the innermost
881 : // scope.
882 : uint32_t nextFrameSlot = 0;
883 :
884 : // The array of tagged JSAtom* names, allocated beyond the end of the
885 : // struct.
886 : TrailingNamesArray trailingNames;
887 :
888 18 : explicit Data(size_t nameCount) : trailingNames(nameCount) {}
889 : Data() = delete;
890 :
891 : void trace(JSTracer* trc);
892 : };
893 :
894 : static EvalScope* create(JSContext* cx, ScopeKind kind, Handle<Data*> data,
895 33 : HandleScope enclosing);
896 :
897 : template <XDRMode mode>
898 : static XDRResult XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
899 0 : MutableHandleScope scope);
900 15 :
901 : private:
902 : static EvalScope* createWithData(JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<Data>> data,
903 : HandleScope enclosing);
904 :
905 : Data& data() {
906 : return *reinterpret_cast<Data*>(data_);
907 : }
908 :
909 : const Data& data() const {
910 : return *reinterpret_cast<Data*>(data_);
911 : }
912 :
913 : public:
914 : // Starting a scope, the nearest var scope that a direct eval can
915 0 : // introduce vars on.
916 : static Scope* nearestVarScopeForDirectEval(Scope* scope);
917 :
918 : uint32_t nextFrameSlot() const {
919 19 : return data().nextFrameSlot;
920 : }
921 :
922 : bool strict() const {
923 : return kind() == ScopeKind::StrictEval;
924 : }
925 :
926 : bool hasBindings() const {
927 : return data().length > 0;
928 38 : }
929 :
930 : bool isNonGlobal() const {
931 : if (strict())
932 0 : return true;
933 : return !nearestVarScopeForDirectEval(enclosing())->is<GlobalScope>();
934 : }
935 :
936 0 : static Shape* getEmptyEnvironmentShape(JSContext* cx);
937 : };
938 :
939 : template <>
940 0 : inline bool
941 : Scope::is<EvalScope>() const
942 0 : {
943 : return kind_ == ScopeKind::Eval || kind_ == ScopeKind::StrictEval;
944 : }
945 :
946 : //
947 : // Scope corresponding to the toplevel script in an ES module.
948 : //
949 : // Like GlobalScopes, these scopes contain both vars and lexical bindings, as
950 : // the treating of imports and exports requires putting them in one scope.
951 : //
952 7451 : // Corresponds to a ModuleEnvironmentObject on the environment chain.
953 : //
954 : class ModuleScope : public Scope
955 : {
956 : friend class GCMarker;
957 : friend class BindingIter;
958 : friend class Scope;
959 : static const ScopeKind classScopeKind_ = ScopeKind::Module;
960 :
961 : public:
962 : // Data is public because it is created by the frontend. See
963 : // Parser<FullParseHandler>::newModuleScopeData.
964 : struct Data : BaseScopeData
965 : {
966 : // The module of the scope.
967 : GCPtr<ModuleObject*> module = {};
968 :
969 : // Bindings are sorted by kind.
970 : //
971 : // imports - [0, varStart)
972 : // vars - [varStart, letStart)
973 0 : // lets - [letStart, constStart)
974 : // consts - [constStart, length)
975 : uint32_t varStart = 0;
976 : uint32_t letStart = 0;
977 : uint32_t constStart = 0;
978 : uint32_t length = 0;
979 :
980 : // Frame slots [0, nextFrameSlot) are live when this is the innermost
981 : // scope.
982 : uint32_t nextFrameSlot = 0;
983 :
984 : // The array of tagged JSAtom* names, allocated beyond the end of the
985 : // struct.
986 : TrailingNamesArray trailingNames;
987 :
988 : explicit Data(size_t nameCount) : trailingNames(nameCount) {}
989 : Data() = delete;
990 :
991 : void trace(JSTracer* trc);
992 : Zone* zone() const;
993 : };
994 :
995 : static ModuleScope* create(JSContext* cx, Handle<Data*> data,
996 : Handle<ModuleObject*> module, HandleScope enclosing);
997 0 :
998 : private:
999 : static ModuleScope* createWithData(JSContext* cx, MutableHandle<UniquePtr<Data>> data,
1000 : Handle<ModuleObject*> module, HandleScope enclosing);
1001 :
1002 : Data& data() {
1003 : return *reinterpret_cast<Data*>(data_);
1004 : }
1005 0 :
1006 : const Data& data() const {
1007 : return *reinterpret_cast<Data*>(data_);
1008 : }
1009 0 :
1010 0 : public:
1011 : uint32_t nextFrameSlot() const {
1012 : return data().nextFrameSlot;
1013 : }
1014 :
1015 : ModuleObject* module() const {
1016 : return data().module;
1017 : }
1018 :
1019 : JSScript* script() const;
1020 :
1021 0 : static Shape* getEmptyEnvironmentShape(JSContext* cx);
1022 : };
1023 :
1024 : class WasmInstanceScope : public Scope
1025 0 : {
1026 : friend class BindingIter;
1027 : friend class Scope;
1028 : static const ScopeKind classScopeKind_ = ScopeKind::WasmInstance;
1029 :
1030 0 : public:
1031 : struct Data : BaseScopeData
1032 : {
1033 : uint32_t memoriesStart = 0;
1034 0 : uint32_t globalsStart = 0;
1035 : uint32_t length = 0;
1036 : uint32_t nextFrameSlot = 0;
1037 :
1038 : // The wasm instance of the scope.
1039 : GCPtr<WasmInstanceObject*> instance = {};
1040 :
1041 : TrailingNamesArray trailingNames;
1042 :
1043 : explicit Data(size_t nameCount) : trailingNames(nameCount) {}
1044 : Data() = delete;
1045 :
1046 : void trace(JSTracer* trc);
1047 : };
1048 :
1049 0 : static WasmInstanceScope* create(JSContext* cx, WasmInstanceObject* instance);
1050 :
1051 : private:
1052 : Data& data() {
1053 : return *reinterpret_cast<Data*>(data_);
1054 : }
1055 :
1056 : const Data& data() const {
1057 : return *reinterpret_cast<Data*>(data_);
1058 : }
1059 :
1060 : public:
1061 0 : WasmInstanceObject* instance() const {
1062 : return data().instance;
1063 : }
1064 :
1065 : uint32_t memoriesStart() const {
1066 : return data().memoriesStart;
1067 : }
1068 :
1069 : uint32_t globalsStart() const {
1070 0 : return data().globalsStart;
1071 : }
1072 :
1073 : uint32_t namesCount() const {
1074 : return data().length;
1075 0 : }
1076 :
1077 : static Shape* getEmptyEnvironmentShape(JSContext* cx);
1078 : };
1079 0 :
1080 : // Scope corresponding to the wasm function. A WasmFunctionScope is used by
1081 : // Debugger only, and not for wasm execution.
1082 : //
1083 : class WasmFunctionScope : public Scope
1084 0 : {
1085 : friend class BindingIter;
1086 : friend class Scope;
1087 : static const ScopeKind classScopeKind_ = ScopeKind::WasmFunction;
1088 0 :
1089 : public:
1090 : struct Data : BaseScopeData
1091 : {
1092 0 : uint32_t length = 0;
1093 : uint32_t nextFrameSlot = 0;
1094 : uint32_t funcIndex = 0;
1095 :
1096 0 : TrailingNamesArray trailingNames;
1097 :
1098 : explicit Data(size_t nameCount) : trailingNames(nameCount) {}
1099 : Data() = delete;
1100 :
1101 : void trace(JSTracer* trc);
1102 : };
1103 :
1104 : static WasmFunctionScope* create(JSContext* cx, HandleScope enclosing, uint32_t funcIndex);
1105 :
1106 : private:
1107 : Data& data() {
1108 : return *reinterpret_cast<Data*>(data_);
1109 : }
1110 :
1111 : const Data& data() const {
1112 : return *reinterpret_cast<Data*>(data_);
1113 : }
1114 :
1115 : public:
1116 : uint32_t funcIndex() const {
1117 : return data().funcIndex;
1118 : }
1119 :
1120 0 : static Shape* getEmptyEnvironmentShape(JSContext* cx);
1121 : };
1122 :
1123 : //
1124 : // An iterator for a Scope's bindings. This is the source of truth for frame
1125 : // and environment object layout.
1126 : //
1127 : // It may be placed in GC containers; for example:
1128 : //
1129 0 : // for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
1130 : // use(bi);
1131 : // SomeMayGCOperation();
1132 : // use(bi);
1133 : // }
1134 0 : //
1135 : class BindingIter
1136 : {
1137 : protected:
1138 : // Bindings are sorted by kind. Because different Scopes have differently
1139 : // laid out Data for packing, BindingIter must handle all binding kinds.
1140 : //
1141 : // Kind ranges:
1142 : //
1143 : // imports - [0, positionalFormalStart)
1144 : // positional formals - [positionalFormalStart, nonPositionalFormalStart)
1145 : // other formals - [nonPositionalParamStart, varStart)
1146 : // vars - [varStart, letStart)
1147 : // lets - [letStart, constStart)
1148 : // consts - [constStart, length)
1149 : //
1150 : // Access method when not closed over:
1151 : //
1152 : // imports - name
1153 : // positional formals - argument slot
1154 : // other formals - frame slot
1155 : // vars - frame slot
1156 : // lets - frame slot
1157 : // consts - frame slot
1158 : //
1159 : // Access method when closed over:
1160 : //
1161 : // imports - name
1162 : // positional formals - environment slot or name
1163 : // other formals - environment slot or name
1164 : // vars - environment slot or name
1165 : // lets - environment slot or name
1166 : // consts - environment slot or name
1167 : MOZ_INIT_OUTSIDE_CTOR uint32_t positionalFormalStart_;
1168 : MOZ_INIT_OUTSIDE_CTOR uint32_t nonPositionalFormalStart_;
1169 : MOZ_INIT_OUTSIDE_CTOR uint32_t varStart_;
1170 : MOZ_INIT_OUTSIDE_CTOR uint32_t letStart_;
1171 : MOZ_INIT_OUTSIDE_CTOR uint32_t constStart_;
1172 : MOZ_INIT_OUTSIDE_CTOR uint32_t length_;
1173 :
1174 : MOZ_INIT_OUTSIDE_CTOR uint32_t index_;
1175 :
1176 : enum Flags : uint8_t {
1177 : CannotHaveSlots = 0,
1178 : CanHaveArgumentSlots = 1 << 0,
1179 : CanHaveFrameSlots = 1 << 1,
1180 : CanHaveEnvironmentSlots = 1 << 2,
1181 :
1182 : // See comment in settle below.
1183 : HasFormalParameterExprs = 1 << 3,
1184 : IgnoreDestructuredFormalParameters = 1 << 4,
1185 :
1186 : // Truly I hate named lambdas.
1187 : IsNamedLambda = 1 << 5
1188 : };
1189 :
1190 : static const uint8_t CanHaveSlotsMask = 0x7;
1191 :
1192 : MOZ_INIT_OUTSIDE_CTOR uint8_t flags_;
1193 : MOZ_INIT_OUTSIDE_CTOR uint16_t argumentSlot_;
1194 : MOZ_INIT_OUTSIDE_CTOR uint32_t frameSlot_;
1195 : MOZ_INIT_OUTSIDE_CTOR uint32_t environmentSlot_;
1196 :
1197 : MOZ_INIT_OUTSIDE_CTOR BindingName* names_;
1198 :
1199 : void init(uint32_t positionalFormalStart, uint32_t nonPositionalFormalStart,
1200 : uint32_t varStart, uint32_t letStart, uint32_t constStart,
1201 : uint8_t flags, uint32_t firstFrameSlot, uint32_t firstEnvironmentSlot,
1202 : BindingName* names, uint32_t length)
1203 : {
1204 : positionalFormalStart_ = positionalFormalStart;
1205 : nonPositionalFormalStart_ = nonPositionalFormalStart;
1206 : varStart_ = varStart;
1207 : letStart_ = letStart;
1208 : constStart_ = constStart;
1209 : length_ = length;
1210 : index_ = 0;
1211 : flags_ = flags;
1212 : argumentSlot_ = 0;
1213 : frameSlot_ = firstFrameSlot;
1214 : environmentSlot_ = firstEnvironmentSlot;
1215 : names_ = names;
1216 :
1217 : settle();
1218 : }
1219 :
1220 : void init(LexicalScope::Data& data, uint32_t firstFrameSlot, uint8_t flags);
1221 : void init(FunctionScope::Data& data, uint8_t flags);
1222 : void init(VarScope::Data& data, uint32_t firstFrameSlot);
1223 : void init(GlobalScope::Data& data);
1224 : void init(EvalScope::Data& data, bool strict);
1225 : void init(ModuleScope::Data& data);
1226 : void init(WasmInstanceScope::Data& data);
1227 : void init(WasmFunctionScope::Data& data);
1228 :
1229 : bool hasFormalParameterExprs() const {
1230 0 : return flags_ & HasFormalParameterExprs;
1231 0 : }
1232 139764 :
1233 0 : bool ignoreDestructuredFormalParameters() const {
1234 139764 : return flags_ & IgnoreDestructuredFormalParameters;
1235 139764 : }
1236 139764 :
1237 139764 : bool isNamedLambda() const {
1238 139764 : return flags_ & IsNamedLambda;
1239 139764 : }
1240 139764 :
1241 139764 : void increment() {
1242 : MOZ_ASSERT(!done());
1243 139764 : if (flags_ & CanHaveSlotsMask) {
1244 : if (canHaveArgumentSlots()) {
1245 : if (index_ < nonPositionalFormalStart_) {
1246 : MOZ_ASSERT(index_ >= positionalFormalStart_);
1247 : argumentSlot_++;
1248 : }
1249 : }
1250 : if (closedOver()) {
1251 : // Imports must not be given known slots. They are
1252 : // indirect bindings.
1253 : MOZ_ASSERT(kind() != BindingKind::Import);
1254 : MOZ_ASSERT(canHaveEnvironmentSlots());
1255 : environmentSlot_++;
1256 : } else if (canHaveFrameSlots()) {
1257 : // Usually positional formal parameters don't have frame
1258 : // slots, except when there are parameter expressions, in
1259 : // which case they act like lets.
1260 : if (index_ >= nonPositionalFormalStart_ || (hasFormalParameterExprs() && name()))
1261 : frameSlot_++;
1262 : }
1263 : }
1264 : index_++;
1265 : }
1266 :
1267 144325 : void settle() {
1268 288650 : if (ignoreDestructuredFormalParameters()) {
1269 0 : while (!done() && !name())
1270 0 : increment();
1271 0 : }
1272 0 : }
1273 71652 :
1274 : public:
1275 : explicit BindingIter(Scope* scope);
1276 0 : explicit BindingIter(JSScript* script);
1277 :
1278 : BindingIter(LexicalScope::Data& data, uint32_t firstFrameSlot, bool isNamedLambda) {
1279 32919 : init(data, firstFrameSlot, isNamedLambda ? IsNamedLambda : 0);
1280 0 : }
1281 0 :
1282 104442 : BindingIter(FunctionScope::Data& data, bool hasParameterExprs) {
1283 : init(data,
1284 : IgnoreDestructuredFormalParameters |
1285 : (hasParameterExprs ? HasFormalParameterExprs : 0));
1286 0 : }
1287 44446 :
1288 : BindingIter(VarScope::Data& data, uint32_t firstFrameSlot) {
1289 : init(data, firstFrameSlot);
1290 144326 : }
1291 144326 :
1292 : explicit BindingIter(GlobalScope::Data& data) {
1293 283661 : init(data);
1294 0 : }
1295 0 :
1296 417 : explicit BindingIter(ModuleScope::Data& data) {
1297 : init(data);
1298 0 : }
1299 :
1300 : explicit BindingIter(WasmFunctionScope::Data& data) {
1301 : init(data);
1302 : }
1303 :
1304 0 : BindingIter(EvalScope::Data& data, bool strict) {
1305 0 : init(data, strict);
1306 : }
1307 :
1308 0 : explicit BindingIter(const BindingIter& bi) = default;
1309 0 :
1310 : bool done() const {
1311 24754 : return index_ == length_;
1312 : }
1313 :
1314 85 : explicit operator bool() const {
1315 85 : return !done();
1316 : }
1317 :
1318 277 : void operator++(int) {
1319 277 : increment();
1320 : settle();
1321 : }
1322 0 :
1323 0 : bool isLast() const {
1324 : MOZ_ASSERT(!done());
1325 : return index_ + 1 == length_;
1326 : }
1327 :
1328 : bool canHaveArgumentSlots() const {
1329 : return flags_ & CanHaveArgumentSlots;
1330 18 : }
1331 0 :
1332 : bool canHaveFrameSlots() const {
1333 : return flags_ & CanHaveFrameSlots;
1334 : }
1335 :
1336 : bool canHaveEnvironmentSlots() const {
1337 781937 : return flags_ & CanHaveEnvironmentSlots;
1338 : }
1339 :
1340 : JSAtom* name() const {
1341 0 : MOZ_ASSERT(!done());
1342 : return names_[index_].name();
1343 : }
1344 :
1345 143914 : bool closedOver() const {
1346 143914 : MOZ_ASSERT(!done());
1347 : return names_[index_].closedOver();
1348 : }
1349 0 :
1350 0 : BindingLocation location() const {
1351 0 : MOZ_ASSERT(!done());
1352 : if (!(flags_ & CanHaveSlotsMask))
1353 : return BindingLocation::Global();
1354 : if (index_ < positionalFormalStart_)
1355 : return BindingLocation::Import();
1356 : if (closedOver()) {
1357 : MOZ_ASSERT(canHaveEnvironmentSlots());
1358 : return BindingLocation::Environment(environmentSlot_);
1359 : }
1360 : if (index_ < nonPositionalFormalStart_ && canHaveArgumentSlots())
1361 : return BindingLocation::Argument(argumentSlot_);
1362 : if (canHaveFrameSlots())
1363 : return BindingLocation::Frame(frameSlot_);
1364 : MOZ_ASSERT(isNamedLambda());
1365 : return BindingLocation::NamedLambdaCallee();
1366 0 : }
1367 0 :
1368 0 : BindingKind kind() const {
1369 : MOZ_ASSERT(!done());
1370 : if (index_ < positionalFormalStart_)
1371 261577 : return BindingKind::Import;
1372 0 : if (index_ < varStart_) {
1373 0 : // When the parameter list has expressions, the parameters act
1374 : // like lexical bindings and have TDZ.
1375 : if (hasFormalParameterExprs())
1376 0 : return BindingKind::Let;
1377 0 : return BindingKind::FormalParameter;
1378 0 : }
1379 : if (index_ < letStart_)
1380 0 : return BindingKind::Var;
1381 : if (index_ < constStart_)
1382 70088 : return BindingKind::Let;
1383 33049 : if (isNamedLambda())
1384 0 : return BindingKind::NamedLambdaCallee;
1385 : return BindingKind::Const;
1386 0 : }
1387 11155 :
1388 0 : bool isTopLevelFunction() const {
1389 24678 : MOZ_ASSERT(!done());
1390 1207 : bool result = names_[index_].isTopLevelFunction();
1391 : MOZ_ASSERT_IF(result, kind() == BindingKind::Var);
1392 : return result;
1393 : }
1394 93744 :
1395 0 : bool hasArgumentSlot() const {
1396 93744 : MOZ_ASSERT(!done());
1397 : if (hasFormalParameterExprs())
1398 93746 : return false;
1399 : return index_ >= positionalFormalStart_ && index_ < nonPositionalFormalStart_;
1400 : }
1401 0 :
1402 : uint16_t argumentSlot() const {
1403 28664 : MOZ_ASSERT(canHaveArgumentSlots());
1404 : return mozilla::AssertedCast<uint16_t>(index_);
1405 0 : }
1406 :
1407 32835 : uint32_t nextFrameSlot() const {
1408 : MOZ_ASSERT(canHaveFrameSlots());
1409 0 : return frameSlot_;
1410 : }
1411 0 :
1412 : uint32_t nextEnvironmentSlot() const {
1413 : MOZ_ASSERT(canHaveEnvironmentSlots());
1414 3855 : return environmentSlot_;
1415 7710 : }
1416 0 :
1417 0 : void trace(JSTracer* trc);
1418 0 : };
1419 :
1420 : void DumpBindings(JSContext* cx, Scope* scope);
1421 0 : JSAtom* FrameSlotName(JSScript* script, jsbytecode* pc);
1422 0 :
1423 0 : //
1424 : // A refinement BindingIter that only iterates over positional formal
1425 0 : // parameters of a function.
1426 : //
1427 : class PositionalFormalParameterIter : public BindingIter
1428 0 : {
1429 48858 : void settle() {
1430 48858 : if (index_ >= nonPositionalFormalStart_)
1431 : index_ = length_;
1432 : }
1433 78523 :
1434 78523 : public:
1435 78523 : explicit PositionalFormalParameterIter(JSScript* script);
1436 :
1437 : void operator++(int) {
1438 63989 : BindingIter::operator++(1);
1439 63989 : settle();
1440 63989 : }
1441 :
1442 : bool isDestructured() const {
1443 : return !name();
1444 : }
1445 : };
1446 :
1447 : //
1448 : // Iterator for walking the scope chain.
1449 : //
1450 : // It may be placed in GC containers; for example:
1451 : //
1452 : // for (Rooted<ScopeIter> si(cx, ScopeIter(scope)); si; si++) {
1453 : // use(si);
1454 : // SomeMayGCOperation();
1455 : // use(si);
1456 90619 : // }
1457 0 : //
1458 : class MOZ_STACK_CLASS ScopeIter
1459 : {
1460 : Scope* scope_;
1461 :
1462 : public:
1463 44181 : explicit ScopeIter(Scope* scope)
1464 88362 : : scope_(scope)
1465 44181 : { }
1466 44181 :
1467 : explicit ScopeIter(JSScript* script);
1468 :
1469 1 : explicit ScopeIter(const ScopeIter& si)
1470 : : scope_(si.scope_)
1471 : { }
1472 :
1473 : bool done() const {
1474 : return !scope_;
1475 : }
1476 :
1477 : explicit operator bool() const {
1478 : return !done();
1479 : }
1480 :
1481 : void operator++(int) {
1482 : MOZ_ASSERT(!done());
1483 : scope_ = scope_->enclosing();
1484 : }
1485 :
1486 : Scope* scope() const {
1487 : MOZ_ASSERT(!done());
1488 : return scope_;
1489 : }
1490 66019 :
1491 : ScopeKind kind() const {
1492 : MOZ_ASSERT(!done());
1493 : return scope_->kind();
1494 : }
1495 :
1496 0 : // Returns the shape of the environment if it is known. It is possible to
1497 : // hasSyntacticEnvironment and to have no known shape, e.g., eval.
1498 : Shape* environmentShape() const {
1499 : return scope()->environmentShape();
1500 0 : }
1501 :
1502 : // Returns whether this scope has a syntactic environment (i.e., an
1503 : // Environment that isn't a non-syntactic With or NonSyntacticVariables)
1504 81284 : // on the environment chain.
1505 : bool hasSyntacticEnvironment() const;
1506 :
1507 0 : void trace(JSTracer* trc) {
1508 54662 : if (scope_)
1509 109324 : TraceRoot(trc, &scope_, "scope iter scope");
1510 54662 : }
1511 : };
1512 267753 :
1513 0 : //
1514 267753 : // Specializations of Rooted containers for the iterators.
1515 : //
1516 :
1517 118359 : template <typename Wrapper>
1518 118359 : class WrappedPtrOperations<BindingIter, Wrapper>
1519 118359 : {
1520 : const BindingIter& iter() const { return static_cast<const Wrapper*>(this)->get(); }
1521 :
1522 : public:
1523 : bool done() const { return iter().done(); }
1524 : explicit operator bool() const { return !done(); }
1525 5200 : bool isLast() const { return iter().isLast(); }
1526 : bool canHaveArgumentSlots() const { return iter().canHaveArgumentSlots(); }
1527 : bool canHaveFrameSlots() const { return iter().canHaveFrameSlots(); }
1528 : bool canHaveEnvironmentSlots() const { return iter().canHaveEnvironmentSlots(); }
1529 : JSAtom* name() const { return iter().name(); }
1530 : bool closedOver() const { return iter().closedOver(); }
1531 : BindingLocation location() const { return iter().location(); }
1532 : BindingKind kind() const { return iter().kind(); }
1533 0 : bool isTopLevelFunction() const { return iter().isTopLevelFunction(); }
1534 0 : bool hasArgumentSlot() const { return iter().hasArgumentSlot(); }
1535 0 : uint16_t argumentSlot() const { return iter().argumentSlot(); }
1536 0 : uint32_t nextFrameSlot() const { return iter().nextFrameSlot(); }
1537 : uint32_t nextEnvironmentSlot() const { return iter().nextEnvironmentSlot(); }
1538 : };
1539 :
1540 : template <typename Wrapper>
1541 : class MutableWrappedPtrOperations<BindingIter, Wrapper>
1542 : : public WrappedPtrOperations<BindingIter, Wrapper>
1543 : {
1544 : BindingIter& iter() { return static_cast<Wrapper*>(this)->get(); }
1545 :
1546 0 : public:
1547 : void operator++(int) { iter().operator++(1); }
1548 : };
1549 4320 :
1550 4320 : template <typename Wrapper>
1551 0 : class WrappedPtrOperations<ScopeIter, Wrapper>
1552 : {
1553 : const ScopeIter& iter() const { return static_cast<const Wrapper*>(this)->get(); }
1554 :
1555 0 : public:
1556 0 : bool done() const { return iter().done(); }
1557 0 : explicit operator bool() const { return !done(); }
1558 0 : Scope* scope() const { return iter().scope(); }
1559 400 : ScopeKind kind() const { return iter().kind(); }
1560 : Shape* environmentShape() const { return iter().environmentShape(); }
1561 : bool hasSyntacticEnvironment() const { return iter().hasSyntacticEnvironment(); }
1562 : };
1563 :
1564 : template <typename Wrapper>
1565 : class MutableWrappedPtrOperations<ScopeIter, Wrapper>
1566 : : public WrappedPtrOperations<ScopeIter, Wrapper>
1567 0 : {
1568 : ScopeIter& iter() { return static_cast<Wrapper*>(this)->get(); }
1569 :
1570 0 : public:
1571 : void operator++(int) { iter().operator++(1); }
1572 : };
1573 0 :
1574 : } // namespace js
1575 :
1576 : namespace JS {
1577 :
1578 : template <>
1579 0 : struct GCPolicy<js::ScopeKind> : public IgnoreGCPolicy<js::ScopeKind>
1580 : { };
1581 :
1582 0 : template <typename T>
1583 67976 : struct ScopeDataGCPolicy : public NonGCPointerPolicy<T> {};
1584 99312 :
1585 0 : #define DEFINE_SCOPE_DATA_GCPOLICY(Data) \
1586 : template <> \
1587 51739 : struct MapTypeToRootKind<Data*> { \
1588 : static const RootKind kind = RootKind::Traceable; \
1589 : }; \
1590 : template <> \
1591 15636 : struct GCPolicy<Data*> : public ScopeDataGCPolicy<Data*> \
1592 : { }
1593 :
1594 17334 : DEFINE_SCOPE_DATA_GCPOLICY(js::LexicalScope::Data);
1595 : DEFINE_SCOPE_DATA_GCPOLICY(js::FunctionScope::Data);
1596 : DEFINE_SCOPE_DATA_GCPOLICY(js::VarScope::Data);
1597 17334 : DEFINE_SCOPE_DATA_GCPOLICY(js::GlobalScope::Data);
1598 : DEFINE_SCOPE_DATA_GCPOLICY(js::EvalScope::Data);
1599 : DEFINE_SCOPE_DATA_GCPOLICY(js::ModuleScope::Data);
1600 : DEFINE_SCOPE_DATA_GCPOLICY(js::WasmFunctionScope::Data);
1601 :
1602 : #undef DEFINE_SCOPE_DATA_GCPOLICY
1603 :
1604 : // Scope data that contain GCPtrs must use the correct DeletePolicy.
1605 :
1606 : template <>
1607 : struct DeletePolicy<js::FunctionScope::Data>
1608 : : public js::GCManagedDeletePolicy<js::FunctionScope::Data>
1609 : {};
1610 :
1611 : template <>
1612 : struct DeletePolicy<js::ModuleScope::Data>
1613 : : public js::GCManagedDeletePolicy<js::ModuleScope::Data>
1614 : {};
1615 :
1616 : template <>
1617 : struct DeletePolicy<js::WasmInstanceScope::Data>
1618 : : public js::GCManagedDeletePolicy<js::WasmInstanceScope::Data>
1619 : { };
1620 :
1621 : namespace ubi {
1622 :
1623 : template <>
1624 : class Concrete<js::Scope> : TracerConcrete<js::Scope>
1625 : {
1626 : protected:
1627 : explicit Concrete(js::Scope* ptr) : TracerConcrete<js::Scope>(ptr) { }
1628 :
1629 : public:
1630 : static void construct(void* storage, js::Scope* ptr) {
1631 : new (storage) Concrete(ptr);
1632 : }
1633 :
1634 : CoarseType coarseType() const final { return CoarseType::Script; }
1635 :
1636 : Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
1637 :
1638 : const char16_t* typeName() const override { return concreteTypeName; }
1639 : static const char16_t concreteTypeName[];
1640 : };
1641 :
1642 : } // namespace ubi
1643 : } // namespace JS
1644 :
1645 : #endif // vm_Scope_h
|