Backed out changeset 8f976ed899d7 (bug 1847231) for causing bc failures on browser_se...
[gecko.git] / js / src / vm / Scope.h
bloba914a14f286e2046cf9f2c261b1eacbf7d447ae5
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 vm_Scope_h
8 #define vm_Scope_h
10 #include "mozilla/Assertions.h" // MOZ_ASSERT, MOZ_ASSERT_IF
11 #include "mozilla/Attributes.h" // MOZ_IMPLICIT, MOZ_INIT_OUTSIDE_CTOR, MOZ_STACK_CLASS
12 #include "mozilla/Casting.h" // mozilla::AssertedCast
13 #include "mozilla/Maybe.h" // mozilla::Maybe
14 #include "mozilla/MemoryReporting.h" // mozilla::MallocSizeOf
15 #include "mozilla/Span.h" // mozilla::Span
17 #include <algorithm> // std::fill_n
18 #include <stddef.h> // size_t
19 #include <stdint.h> // uint8_t, uint16_t, uint32_t, uintptr_t
20 #include <type_traits> // std::is_same_v, std::is_base_of_v
22 #include "builtin/ModuleObject.h" // ModuleObject, Handle<ModuleObject*>
23 #include "frontend/ParserAtom.h" // frontend::TaggedParserAtomIndex
24 #include "gc/Barrier.h" // HeapPtr
25 #include "gc/Cell.h" // TenuredCellWithNonGCPointer
26 #include "js/GCPolicyAPI.h" // GCPolicy, IgnoreGCPolicy
27 #include "js/HeapAPI.h" // CellFlagBitsReservedForGC
28 #include "js/RootingAPI.h" // Handle, MutableHandle
29 #include "js/TraceKind.h" // JS::TraceKind
30 #include "js/TypeDecls.h" // HandleFunction
31 #include "js/UbiNode.h" // ubi::*
32 #include "js/UniquePtr.h" // UniquePtr
33 #include "util/Poison.h" // AlwaysPoison, JS_SCOPE_DATA_TRAILING_NAMES_PATTERN, MemCheckKind
34 #include "vm/JSFunction.h" // JSFunction
35 #include "vm/ScopeKind.h" // ScopeKind
36 #include "vm/Shape.h" // Shape
37 #include "wasm/WasmJS.h" // WasmInstanceObject
39 class JSAtom;
40 class JSScript;
41 class JSTracer;
42 struct JSContext;
44 namespace js {
46 class JS_PUBLIC_API GenericPrinter;
48 namespace frontend {
49 class ScopeStencil;
50 struct ScopeStencilRef;
51 class RuntimeScopeBindingCache;
52 } // namespace frontend
54 template <typename NameT>
55 class AbstractBaseScopeData;
57 template <typename NameT>
58 class BaseAbstractBindingIter;
60 template <typename NameT>
61 class AbstractBindingIter;
63 template <typename NameT>
64 class AbstractPositionalFormalParameterIter;
66 using BindingIter = AbstractBindingIter<JSAtom>;
68 class AbstractScopePtr;
70 static inline bool ScopeKindIsCatch(ScopeKind kind) {
71 return kind == ScopeKind::SimpleCatch || kind == ScopeKind::Catch;
74 static inline bool ScopeKindIsInBody(ScopeKind kind) {
75 return kind == ScopeKind::Lexical || kind == ScopeKind::SimpleCatch ||
76 kind == ScopeKind::Catch || kind == ScopeKind::With ||
77 kind == ScopeKind::FunctionLexical ||
78 kind == ScopeKind::FunctionBodyVar || kind == ScopeKind::ClassBody;
81 const char* BindingKindString(BindingKind kind);
82 const char* ScopeKindString(ScopeKind kind);
84 template <typename NameT>
85 class AbstractBindingName;
87 template <>
88 class AbstractBindingName<JSAtom> {
89 public:
90 using NameT = JSAtom;
91 using NamePointerT = NameT*;
93 private:
94 // A JSAtom* with its low bit used as a tag for the:
95 // * whether it is closed over (i.e., exists in the environment shape)
96 // * whether it is a top-level function binding in global or eval scope,
97 // instead of var binding (both are in the same range in Scope data)
98 uintptr_t bits_;
100 static constexpr uintptr_t ClosedOverFlag = 0x1;
101 // TODO: We should reuse this bit for let vs class distinction to
102 // show the better redeclaration error message (bug 1428672).
103 static constexpr uintptr_t TopLevelFunctionFlag = 0x2;
104 static constexpr uintptr_t FlagMask = 0x3;
106 public:
107 AbstractBindingName() : bits_(0) {}
109 AbstractBindingName(NameT* name, bool closedOver,
110 bool isTopLevelFunction = false)
111 : bits_(uintptr_t(name) | (closedOver ? ClosedOverFlag : 0x0) |
112 (isTopLevelFunction ? TopLevelFunctionFlag : 0x0)) {}
114 NamePointerT name() const {
115 return reinterpret_cast<NameT*>(bits_ & ~FlagMask);
118 bool closedOver() const { return bits_ & ClosedOverFlag; }
120 private:
121 friend class BaseAbstractBindingIter<NameT>;
123 // This method should be called only for binding names in `vars` range in
124 // BindingIter.
125 bool isTopLevelFunction() const { return bits_ & TopLevelFunctionFlag; }
127 public:
128 void trace(JSTracer* trc) {
129 if (JSAtom* atom = name()) {
130 TraceManuallyBarrieredEdge(trc, &atom, "binding name");
135 template <>
136 class AbstractBindingName<frontend::TaggedParserAtomIndex> {
137 uint32_t bits_;
139 using TaggedParserAtomIndex = frontend::TaggedParserAtomIndex;
141 public:
142 using NameT = TaggedParserAtomIndex;
143 using NamePointerT = NameT;
145 private:
146 static constexpr size_t TaggedIndexBit = TaggedParserAtomIndex::IndexBit + 2;
148 static constexpr size_t FlagShift = TaggedIndexBit;
149 static constexpr size_t FlagBit = 2;
150 static constexpr uint32_t FlagMask = BitMask(FlagBit) << FlagShift;
152 static constexpr uint32_t ClosedOverFlag = 1 << FlagShift;
153 static constexpr uint32_t TopLevelFunctionFlag = 2 << FlagShift;
155 public:
156 AbstractBindingName() : bits_(TaggedParserAtomIndex::NullTag) {
157 // TaggedParserAtomIndex's tags shouldn't overlap with flags.
158 static_assert((TaggedParserAtomIndex::NullTag & FlagMask) == 0);
159 static_assert((TaggedParserAtomIndex::ParserAtomIndexTag & FlagMask) == 0);
160 static_assert((TaggedParserAtomIndex::WellKnownTag & FlagMask) == 0);
163 AbstractBindingName(TaggedParserAtomIndex name, bool closedOver,
164 bool isTopLevelFunction = false)
165 : bits_(name.rawData() | (closedOver ? ClosedOverFlag : 0x0) |
166 (isTopLevelFunction ? TopLevelFunctionFlag : 0x0)) {}
168 public:
169 NamePointerT name() const {
170 return TaggedParserAtomIndex::fromRaw(bits_ & ~FlagMask);
173 bool closedOver() const { return bits_ & ClosedOverFlag; }
175 AbstractBindingName<JSAtom> copyWithNewAtom(JSAtom* newName) const {
176 return AbstractBindingName<JSAtom>(newName, closedOver(),
177 isTopLevelFunction());
180 void updateNameAfterStencilMerge(TaggedParserAtomIndex name) {
181 bits_ = (bits_ & FlagMask) | name.rawData();
184 private:
185 friend class BaseAbstractBindingIter<TaggedParserAtomIndex>;
186 friend class frontend::ScopeStencil;
188 // This method should be called only for binding names in `vars` range in
189 // BindingIter.
190 bool isTopLevelFunction() const { return bits_ & TopLevelFunctionFlag; }
193 using BindingName = AbstractBindingName<JSAtom>;
195 static inline void TraceBindingNames(JSTracer* trc, BindingName* names,
196 uint32_t length) {
197 for (uint32_t i = 0; i < length; i++) {
198 JSAtom* name = names[i].name();
199 MOZ_ASSERT(name);
200 TraceManuallyBarrieredEdge(trc, &name, "scope name");
203 static inline void TraceNullableBindingNames(JSTracer* trc, BindingName* names,
204 uint32_t length) {
205 for (uint32_t i = 0; i < length; i++) {
206 if (JSAtom* name = names[i].name()) {
207 TraceManuallyBarrieredEdge(trc, &name, "scope name");
212 const size_t ScopeDataAlignBytes = size_t(1) << gc::CellFlagBitsReservedForGC;
215 * Base class for scope {Runtime,Parser}Data classes to inherit from.
217 * `js::Scope` stores a pointer to RuntimeData classes in their first word, so
218 * they must be suitably aligned to allow storing GC flags in the low bits.
220 template <typename NameT>
221 class AbstractBaseScopeData {
222 public:
223 using NameType = NameT;
225 // The length of names after specialized ScopeData subclasses.
226 uint32_t length = 0;
229 template <typename ScopeDataT>
230 static inline void AssertDerivedScopeData() {
231 static_assert(
232 !std::is_same_v<ScopeDataT,
233 AbstractBaseScopeData<typename ScopeDataT::NameType>>,
234 "ScopeDataT shouldn't be AbstractBaseScopeData");
235 static_assert(
236 std::is_base_of_v<AbstractBaseScopeData<typename ScopeDataT::NameType>,
237 ScopeDataT>,
238 "ScopeDataT should be subclass of AbstractBaseScopeData");
241 template <typename ScopeDataT>
242 static inline size_t GetOffsetOfScopeDataTrailingNames() {
243 AssertDerivedScopeData<ScopeDataT>();
244 return sizeof(ScopeDataT);
247 template <typename ScopeDataT>
248 static inline AbstractBindingName<typename ScopeDataT::NameType>*
249 GetScopeDataTrailingNamesPointer(ScopeDataT* data) {
250 AssertDerivedScopeData<ScopeDataT>();
251 return reinterpret_cast<AbstractBindingName<typename ScopeDataT::NameType>*>(
252 data + 1);
255 template <typename ScopeDataT>
256 static inline const AbstractBindingName<typename ScopeDataT::NameType>*
257 GetScopeDataTrailingNamesPointer(const ScopeDataT* data) {
258 AssertDerivedScopeData<ScopeDataT>();
259 return reinterpret_cast<
260 const AbstractBindingName<typename ScopeDataT::NameType>*>(data + 1);
263 template <typename ScopeDataT>
264 static inline mozilla::Span<AbstractBindingName<typename ScopeDataT::NameType>>
265 GetScopeDataTrailingNames(ScopeDataT* data) {
266 return mozilla::Span(GetScopeDataTrailingNamesPointer(data), data->length);
269 template <typename ScopeDataT>
270 static inline mozilla::Span<
271 const AbstractBindingName<typename ScopeDataT::NameType>>
272 GetScopeDataTrailingNames(const ScopeDataT* data) {
273 return mozilla::Span(GetScopeDataTrailingNamesPointer(data), data->length);
276 using BaseScopeData = AbstractBaseScopeData<JSAtom>;
278 inline void PoisonNames(AbstractBindingName<JSAtom>* data, uint32_t length) {
279 AlwaysPoison(data, JS_SCOPE_DATA_TRAILING_NAMES_PATTERN,
280 sizeof(AbstractBindingName<JSAtom>) * length,
281 MemCheckKind::MakeUndefined);
284 // frontend::TaggedParserAtomIndex doesn't require poison value.
285 // Fill with null value instead.
286 inline void PoisonNames(
287 AbstractBindingName<frontend::TaggedParserAtomIndex>* data,
288 uint32_t length) {
289 std::fill_n(data, length,
290 AbstractBindingName<frontend::TaggedParserAtomIndex>());
293 template <typename ScopeDataT>
294 static inline void PoisonNames(ScopeDataT* data, uint32_t length) {
295 if (length) {
296 PoisonNames(GetScopeDataTrailingNamesPointer(data), length);
301 // Allow using is<T> and as<T> on Rooted<Scope*> and Handle<Scope*>.
303 template <typename Wrapper>
304 class WrappedPtrOperations<Scope*, Wrapper> {
305 public:
306 template <class U>
307 JS::Handle<U*> as() const {
308 const Wrapper& self = *static_cast<const Wrapper*>(this);
309 MOZ_ASSERT_IF(self, self->template is<U>());
310 return Handle<U*>::fromMarkedLocation(
311 reinterpret_cast<U* const*>(self.address()));
316 // The base class of all Scopes.
318 class Scope : public gc::TenuredCellWithNonGCPointer<BaseScopeData> {
319 friend class GCMarker;
320 friend class frontend::ScopeStencil;
321 friend class js::AbstractBindingIter<JSAtom>;
322 friend class js::frontend::RuntimeScopeBindingCache;
323 friend class gc::CellAllocator;
325 protected:
326 // The raw data pointer, stored in the cell header.
327 BaseScopeData* rawData() { return headerPtr(); }
328 const BaseScopeData* rawData() const { return headerPtr(); }
330 // The kind determines data_.
331 const ScopeKind kind_;
333 // If there are any aliased bindings, the shape for the
334 // EnvironmentObject. Otherwise nullptr.
335 const HeapPtr<SharedShape*> environmentShape_;
337 // The enclosing scope or nullptr.
338 HeapPtr<Scope*> enclosingScope_;
340 Scope(ScopeKind kind, Scope* enclosing, SharedShape* environmentShape)
341 : TenuredCellWithNonGCPointer(nullptr),
342 kind_(kind),
343 environmentShape_(environmentShape),
344 enclosingScope_(enclosing) {}
346 static Scope* create(JSContext* cx, ScopeKind kind, Handle<Scope*> enclosing,
347 Handle<SharedShape*> envShape);
349 template <typename ConcreteScope>
350 void initData(
351 MutableHandle<UniquePtr<typename ConcreteScope::RuntimeData>> data);
353 template <typename F>
354 void applyScopeDataTyped(F&& f);
356 static void updateEnvShapeIfRequired(mozilla::Maybe<uint32_t>* envShape,
357 bool needsEnvironment);
359 public:
360 template <typename ConcreteScope>
361 static ConcreteScope* create(
362 JSContext* cx, ScopeKind kind, Handle<Scope*> enclosing,
363 Handle<SharedShape*> envShape,
364 MutableHandle<UniquePtr<typename ConcreteScope::RuntimeData>> data);
366 static const JS::TraceKind TraceKind = JS::TraceKind::Scope;
368 template <typename T>
369 bool is() const {
370 return kind_ == T::classScopeKind_;
373 template <typename T>
374 T& as() {
375 MOZ_ASSERT(this->is<T>());
376 return *static_cast<T*>(this);
379 template <typename T>
380 const T& as() const {
381 MOZ_ASSERT(this->is<T>());
382 return *static_cast<const T*>(this);
385 ScopeKind kind() const { return kind_; }
387 bool isNamedLambda() const {
388 return kind() == ScopeKind::NamedLambda ||
389 kind() == ScopeKind::StrictNamedLambda;
392 SharedShape* environmentShape() const { return environmentShape_; }
394 Scope* enclosing() const { return enclosingScope_; }
396 static bool hasEnvironment(ScopeKind kind, bool hasEnvironmentShape = false) {
397 switch (kind) {
398 case ScopeKind::With:
399 case ScopeKind::Global:
400 case ScopeKind::NonSyntactic:
401 return true;
402 default:
403 // If there's a shape, an environment must be created for this scope.
404 return hasEnvironmentShape;
408 bool hasEnvironment() const {
409 return hasEnvironment(kind_, !!environmentShape());
412 uint32_t firstFrameSlot() const;
414 uint32_t chainLength() const;
415 uint32_t environmentChainLength() const;
417 template <typename T>
418 bool hasOnChain() const {
419 for (const Scope* it = this; it; it = it->enclosing()) {
420 if (it->is<T>()) {
421 return true;
424 return false;
427 bool hasOnChain(ScopeKind kind) const {
428 for (const Scope* it = this; it; it = it->enclosing()) {
429 if (it->kind() == kind) {
430 return true;
433 return false;
436 void traceChildren(JSTracer* trc);
437 void finalize(JS::GCContext* gcx);
439 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
441 void dump();
442 #if defined(DEBUG) || defined(JS_JITSPEW)
443 static bool dumpForDisassemble(JSContext* cx, JS::Handle<Scope*> scope,
444 GenericPrinter& out, const char* indent);
445 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
448 template <class DataT>
449 inline size_t SizeOfScopeData(uint32_t length) {
450 using BindingT = AbstractBindingName<typename DataT::NameType>;
451 return GetOffsetOfScopeDataTrailingNames<DataT>() + length * sizeof(BindingT);
455 // A useful typedef for selecting between a gc-aware wrappers
456 // around pointers to BaseScopeData-derived types, and around raw
457 // pointer wrappers around BaseParserScopeData-derived types.
459 template <typename ScopeT, typename AtomT>
460 using AbstractScopeData = typename ScopeT::template AbstractData<AtomT>;
462 // Binding names are stored from `this+1`.
463 // Make sure the class aligns the binding name size.
464 template <typename SlotInfo>
465 struct alignas(alignof(AbstractBindingName<frontend::TaggedParserAtomIndex>))
466 ParserScopeData
467 : public AbstractBaseScopeData<frontend::TaggedParserAtomIndex> {
468 SlotInfo slotInfo;
470 explicit ParserScopeData(size_t length) { PoisonNames(this, length); }
471 ParserScopeData() = delete;
474 // RuntimeScopeData has 2 requirements:
475 // * It aligns with `BindingName`, that is stored after `this+1`
476 // * It aligns with ScopeDataAlignBytes, in order to put it in the first
477 // word of `js::Scope`
478 static_assert(alignof(BindingName) <= ScopeDataAlignBytes);
479 template <typename SlotInfo>
480 struct alignas(ScopeDataAlignBytes) RuntimeScopeData
481 : public AbstractBaseScopeData<JSAtom> {
482 SlotInfo slotInfo;
484 explicit RuntimeScopeData(size_t length) { PoisonNames(this, length); }
485 RuntimeScopeData() = delete;
487 void trace(JSTracer* trc);
491 // A lexical scope that holds let and const bindings. There are 4 kinds of
492 // LexicalScopes.
494 // Lexical
495 // A plain lexical scope.
497 // SimpleCatch
498 // Holds the single catch parameter of a catch block.
500 // Catch
501 // Holds the catch parameters (and only the catch parameters) of a catch
502 // block.
504 // NamedLambda
505 // StrictNamedLambda
506 // Holds the single name of the callee for a named lambda expression.
508 // All kinds of LexicalScopes correspond to LexicalEnvironmentObjects on the
509 // environment chain.
511 class LexicalScope : public Scope {
512 friend class Scope;
513 friend class AbstractBindingIter<JSAtom>;
514 friend class GCMarker;
515 friend class frontend::ScopeStencil;
517 public:
518 struct SlotInfo {
519 // Frame slots [0, nextFrameSlot) are live when this is the innermost
520 // scope.
521 uint32_t nextFrameSlot = 0;
523 // Bindings are sorted by kind in both frames and environments.
525 // lets - [0, constStart)
526 // consts - [constStart, length)
527 uint32_t constStart = 0;
530 using RuntimeData = RuntimeScopeData<SlotInfo>;
531 using ParserData = ParserScopeData<SlotInfo>;
533 template <typename NameT>
534 using AbstractData =
535 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
536 RuntimeData, ParserData>;
538 private:
539 static void prepareForScopeCreation(ScopeKind kind, uint32_t firstFrameSlot,
540 LexicalScope::ParserData* data,
541 mozilla::Maybe<uint32_t>* envShape);
543 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
544 const RuntimeData& data() const {
545 return *static_cast<const RuntimeData*>(rawData());
548 public:
549 static uint32_t nextFrameSlot(Scope* scope);
551 uint32_t nextFrameSlot() const { return data().slotInfo.nextFrameSlot; }
553 // Returns an empty shape for extensible global and non-syntactic lexical
554 // scopes.
555 static SharedShape* getEmptyExtensibleEnvironmentShape(JSContext* cx);
558 template <>
559 inline bool Scope::is<LexicalScope>() const {
560 return kind_ == ScopeKind::Lexical || kind_ == ScopeKind::SimpleCatch ||
561 kind_ == ScopeKind::Catch || kind_ == ScopeKind::NamedLambda ||
562 kind_ == ScopeKind::StrictNamedLambda ||
563 kind_ == ScopeKind::FunctionLexical;
566 // The body scope of a JS class, containing only synthetic bindings for private
567 // class members. (The binding for the class name, `C` in the example below, is
568 // in another scope, a `LexicalScope`, that encloses the `ClassBodyScope`.)
569 // Example:
571 // class C {
572 // #f = 0;
573 // #m() {
574 // return this.#f++;
575 // }
576 // }
578 // This class has a ClassBodyScope with four synthetic bindings:
579 // - `#f` (private name)
580 // - `#m` (private name)
581 // - `#m.method` (function object)
582 // - `.privateBrand` (the class's private brand)
583 class ClassBodyScope : public Scope {
584 friend class Scope;
585 friend class AbstractBindingIter<JSAtom>;
586 friend class GCMarker;
587 friend class frontend::ScopeStencil;
588 friend class AbstractScopePtr;
590 static const ScopeKind classScopeKind_ = ScopeKind::ClassBody;
592 public:
593 struct SlotInfo {
594 // Frame slots [0, nextFrameSlot) are live when this is the innermost
595 // scope.
596 uint32_t nextFrameSlot = 0;
598 // Bindings are sorted by kind in both frames and environments.
600 // synthetic - [0, privateMethodStart)
601 // privateMethod - [privateMethodStart, length)
602 uint32_t privateMethodStart = 0;
605 using RuntimeData = RuntimeScopeData<SlotInfo>;
606 using ParserData = ParserScopeData<SlotInfo>;
608 template <typename NameT>
609 using AbstractData =
610 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
611 RuntimeData, ParserData>;
613 private:
614 static void prepareForScopeCreation(ScopeKind kind, uint32_t firstFrameSlot,
615 ClassBodyScope::ParserData* data,
616 mozilla::Maybe<uint32_t>* envShape);
618 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
619 const RuntimeData& data() const {
620 return *static_cast<const RuntimeData*>(rawData());
623 public:
624 static uint32_t nextFrameSlot(Scope* scope);
626 uint32_t nextFrameSlot() const { return data().slotInfo.nextFrameSlot; }
628 // Returns an empty shape for extensible global and non-syntactic lexical
629 // scopes.
630 static SharedShape* getEmptyExtensibleEnvironmentShape(JSContext* cx);
634 // Scope corresponding to a function. Holds formal parameter names, special
635 // internal names (see FunctionScope::isSpecialName), and, if the function
636 // parameters contain no expressions that might possibly be evaluated, the
637 // function's var bindings. For example, in these functions, the FunctionScope
638 // will store a/b/c bindings but not d/e/f bindings:
640 // function f1(a, b) {
641 // var c;
642 // let e;
643 // const f = 3;
644 // }
645 // function f2([a], b = 4, ...c) {
646 // var d, e, f; // stored in VarScope
647 // }
649 // Corresponds to CallObject on environment chain.
651 class FunctionScope : public Scope {
652 friend class GCMarker;
653 friend class AbstractBindingIter<JSAtom>;
654 friend class AbstractPositionalFormalParameterIter<JSAtom>;
655 friend class Scope;
656 friend class AbstractScopePtr;
657 static const ScopeKind classScopeKind_ = ScopeKind::Function;
659 public:
660 struct SlotInfo {
661 // Frame slots [0, nextFrameSlot) are live when this is the innermost
662 // scope.
663 uint32_t nextFrameSlot = 0;
665 // Flag bits.
666 // This uses uint32_t in order to make this struct packed.
667 uint32_t flags = 0;
669 // If parameter expressions are present, parameters act like lexical
670 // bindings.
671 static constexpr uint32_t HasParameterExprsFlag = 1;
673 // Bindings are sorted by kind in both frames and environments.
675 // Positional formal parameter names are those that are not
676 // destructured. They may be referred to by argument slots if
677 // !script()->hasParameterExprs().
679 // An argument slot that needs to be skipped due to being destructured
680 // or having defaults will have a nullptr name in the name array to
681 // advance the argument slot.
683 // Rest parameter binding is also included in positional formals.
684 // This also becomes nullptr if destructuring.
686 // The number of positional formals is equal to function.length if
687 // there's no rest, function.length+1 otherwise.
689 // Destructuring parameters and destructuring rest are included in
690 // "other formals" below.
692 // "vars" contains the following:
693 // * function's top level vars if !script()->hasParameterExprs()
694 // * special internal names (arguments, .this, .generator) if
695 // they're used.
697 // positional formals - [0, nonPositionalFormalStart)
698 // other formals - [nonPositionalParamStart, varStart)
699 // vars - [varStart, length)
700 uint16_t nonPositionalFormalStart = 0;
701 uint16_t varStart = 0;
703 bool hasParameterExprs() const { return flags & HasParameterExprsFlag; }
704 void setHasParameterExprs() { flags |= HasParameterExprsFlag; }
707 struct alignas(ScopeDataAlignBytes) RuntimeData
708 : public AbstractBaseScopeData<JSAtom> {
709 SlotInfo slotInfo;
710 // The canonical function of the scope, as during a scope walk we
711 // often query properties of the JSFunction (e.g., is the function an
712 // arrow).
713 HeapPtr<JSFunction*> canonicalFunction = {};
715 explicit RuntimeData(size_t length) { PoisonNames(this, length); }
716 RuntimeData() = delete;
718 void trace(JSTracer* trc);
721 using ParserData = ParserScopeData<SlotInfo>;
723 template <typename NameT>
724 using AbstractData =
725 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
726 RuntimeData, ParserData>;
728 static void prepareForScopeCreation(FunctionScope::ParserData* data,
729 bool hasParameterExprs,
730 bool needsEnvironment,
731 mozilla::Maybe<uint32_t>* envShape);
733 private:
734 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
736 const RuntimeData& data() const {
737 return *static_cast<const RuntimeData*>(rawData());
740 public:
741 uint32_t nextFrameSlot() const { return data().slotInfo.nextFrameSlot; }
743 JSFunction* canonicalFunction() const { return data().canonicalFunction; }
744 void initCanonicalFunction(JSFunction* fun) {
745 data().canonicalFunction.init(fun);
748 JSScript* script() const;
750 bool hasParameterExprs() const { return data().slotInfo.hasParameterExprs(); }
752 uint32_t numPositionalFormalParameters() const {
753 return data().slotInfo.nonPositionalFormalStart;
756 static bool isSpecialName(frontend::TaggedParserAtomIndex name);
760 // Scope holding only vars. There is a single kind of VarScopes.
762 // FunctionBodyVar
763 // Corresponds to the extra var scope present in functions with parameter
764 // expressions. See examples in comment above FunctionScope.
766 // Corresponds to VarEnvironmentObject on environment chain.
768 class VarScope : public Scope {
769 friend class GCMarker;
770 friend class AbstractBindingIter<JSAtom>;
771 friend class Scope;
772 friend class frontend::ScopeStencil;
774 public:
775 struct SlotInfo {
776 // Frame slots [0, nextFrameSlot) are live when this is the innermost
777 // scope.
778 uint32_t nextFrameSlot = 0;
780 // All bindings are vars.
782 // vars - [0, length)
785 using RuntimeData = RuntimeScopeData<SlotInfo>;
786 using ParserData = ParserScopeData<SlotInfo>;
788 template <typename NameT>
789 using AbstractData =
790 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
791 RuntimeData, ParserData>;
793 private:
794 static void prepareForScopeCreation(ScopeKind kind,
795 VarScope::ParserData* data,
796 uint32_t firstFrameSlot,
797 bool needsEnvironment,
798 mozilla::Maybe<uint32_t>* envShape);
800 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
802 const RuntimeData& data() const {
803 return *static_cast<const RuntimeData*>(rawData());
806 public:
807 uint32_t nextFrameSlot() const { return data().slotInfo.nextFrameSlot; }
810 template <>
811 inline bool Scope::is<VarScope>() const {
812 return kind_ == ScopeKind::FunctionBodyVar;
816 // Scope corresponding to both the global object scope and the global lexical
817 // scope.
819 // Both are extensible and are singletons across <script> tags, so these
820 // scopes are a fragment of the names in global scope. In other words, two
821 // global scripts may have two different GlobalScopes despite having the same
822 // GlobalObject.
824 // There are 2 kinds of GlobalScopes.
826 // Global
827 // Corresponds to a GlobalObject and its GlobalLexicalEnvironmentObject on
828 // the environment chain.
830 // NonSyntactic
831 // Corresponds to a non-GlobalObject created by the embedding on the
832 // environment chain. This distinction is important for optimizations.
834 class GlobalScope : public Scope {
835 friend class Scope;
836 friend class AbstractBindingIter<JSAtom>;
837 friend class GCMarker;
839 public:
840 struct SlotInfo {
841 // Bindings are sorted by kind.
842 // `vars` includes top-level functions which is distinguished by a bit
843 // on the BindingName.
845 // vars - [0, letStart)
846 // lets - [letStart, constStart)
847 // consts - [constStart, length)
848 uint32_t letStart = 0;
849 uint32_t constStart = 0;
852 using RuntimeData = RuntimeScopeData<SlotInfo>;
853 using ParserData = ParserScopeData<SlotInfo>;
855 template <typename NameT>
856 using AbstractData =
857 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
858 RuntimeData, ParserData>;
860 static GlobalScope* createEmpty(JSContext* cx, ScopeKind kind);
862 private:
863 static GlobalScope* createWithData(
864 JSContext* cx, ScopeKind kind,
865 MutableHandle<UniquePtr<RuntimeData>> data);
867 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
869 const RuntimeData& data() const {
870 return *static_cast<const RuntimeData*>(rawData());
873 public:
874 bool isSyntactic() const { return kind() != ScopeKind::NonSyntactic; }
876 bool hasBindings() const { return data().length > 0; }
879 template <>
880 inline bool Scope::is<GlobalScope>() const {
881 return kind_ == ScopeKind::Global || kind_ == ScopeKind::NonSyntactic;
885 // Scope of a 'with' statement. Has no bindings.
887 // Corresponds to a WithEnvironmentObject on the environment chain.
888 class WithScope : public Scope {
889 friend class Scope;
890 friend class AbstractScopePtr;
891 static const ScopeKind classScopeKind_ = ScopeKind::With;
893 public:
894 static WithScope* create(JSContext* cx, Handle<Scope*> enclosing);
898 // Scope of an eval. Holds var bindings. There are 2 kinds of EvalScopes.
900 // StrictEval
901 // A strict eval. Corresponds to a VarEnvironmentObject, where its var
902 // bindings lives.
904 // Eval
905 // A sloppy eval. This is an empty scope, used only in the frontend, to
906 // detect redeclaration errors. It has no Environment. Any `var`s declared
907 // in the eval code are bound on the nearest enclosing var environment.
909 class EvalScope : public Scope {
910 friend class Scope;
911 friend class AbstractBindingIter<JSAtom>;
912 friend class GCMarker;
913 friend class frontend::ScopeStencil;
915 public:
916 struct SlotInfo {
917 // Frame slots [0, nextFrameSlot) are live when this is the innermost
918 // scope.
919 uint32_t nextFrameSlot = 0;
921 // All bindings in an eval script are 'var' bindings. The implicit
922 // lexical scope around the eval is present regardless of strictness
923 // and is its own LexicalScope.
924 // `vars` includes top-level functions which is distinguished by a bit
925 // on the BindingName.
927 // vars - [0, length)
930 using RuntimeData = RuntimeScopeData<SlotInfo>;
931 using ParserData = ParserScopeData<SlotInfo>;
933 template <typename NameT>
934 using AbstractData =
935 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
936 RuntimeData, ParserData>;
938 private:
939 static void prepareForScopeCreation(ScopeKind scopeKind,
940 EvalScope::ParserData* data,
941 mozilla::Maybe<uint32_t>* envShape);
943 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
945 const RuntimeData& data() const {
946 return *static_cast<const RuntimeData*>(rawData());
949 public:
950 // Starting a scope, the nearest var scope that a direct eval can
951 // introduce vars on.
952 static Scope* nearestVarScopeForDirectEval(Scope* scope);
954 uint32_t nextFrameSlot() const { return data().slotInfo.nextFrameSlot; }
956 bool strict() const { return kind() == ScopeKind::StrictEval; }
958 bool hasBindings() const { return data().length > 0; }
960 bool isNonGlobal() const {
961 if (strict()) {
962 return true;
964 return !nearestVarScopeForDirectEval(enclosing())->is<GlobalScope>();
968 template <>
969 inline bool Scope::is<EvalScope>() const {
970 return kind_ == ScopeKind::Eval || kind_ == ScopeKind::StrictEval;
974 // Scope corresponding to the toplevel script in an ES module.
976 // Like GlobalScopes, these scopes contain both vars and lexical bindings, as
977 // the treating of imports and exports requires putting them in one scope.
979 // Corresponds to a ModuleEnvironmentObject on the environment chain.
981 class ModuleScope : public Scope {
982 friend class GCMarker;
983 friend class AbstractBindingIter<JSAtom>;
984 friend class Scope;
985 friend class AbstractScopePtr;
986 friend class frontend::ScopeStencil;
987 static const ScopeKind classScopeKind_ = ScopeKind::Module;
989 public:
990 struct SlotInfo {
991 // Frame slots [0, nextFrameSlot) are live when this is the innermost
992 // scope.
993 uint32_t nextFrameSlot = 0;
995 // Bindings are sorted by kind.
997 // imports - [0, varStart)
998 // vars - [varStart, letStart)
999 // lets - [letStart, constStart)
1000 // consts - [constStart, length)
1001 uint32_t varStart = 0;
1002 uint32_t letStart = 0;
1003 uint32_t constStart = 0;
1006 struct alignas(ScopeDataAlignBytes) RuntimeData
1007 : public AbstractBaseScopeData<JSAtom> {
1008 SlotInfo slotInfo;
1009 // The module of the scope.
1010 HeapPtr<ModuleObject*> module = {};
1012 explicit RuntimeData(size_t length);
1013 RuntimeData() = delete;
1015 void trace(JSTracer* trc);
1018 using ParserData = ParserScopeData<SlotInfo>;
1020 template <typename NameT>
1021 using AbstractData =
1022 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
1023 RuntimeData, ParserData>;
1025 private:
1026 static void prepareForScopeCreation(ModuleScope::ParserData* data,
1027 mozilla::Maybe<uint32_t>* envShape);
1029 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
1031 const RuntimeData& data() const {
1032 return *static_cast<const RuntimeData*>(rawData());
1035 public:
1036 uint32_t nextFrameSlot() const { return data().slotInfo.nextFrameSlot; }
1038 ModuleObject* module() const { return data().module; }
1039 void initModule(ModuleObject* mod) { return data().module.init(mod); }
1041 // Off-thread compilation needs to calculate environmentChainLength for
1042 // an emptyGlobalScope where the global may not be available.
1043 static const size_t EnclosingEnvironmentChainLength = 1;
1046 class WasmInstanceScope : public Scope {
1047 friend class AbstractBindingIter<JSAtom>;
1048 friend class Scope;
1049 friend class GCMarker;
1050 friend class AbstractScopePtr;
1051 static const ScopeKind classScopeKind_ = ScopeKind::WasmInstance;
1053 public:
1054 struct SlotInfo {
1055 // Frame slots [0, nextFrameSlot) are live when this is the innermost
1056 // scope.
1057 uint32_t nextFrameSlot = 0;
1059 // Bindings list the WASM memories and globals.
1061 // memories - [0, globalsStart)
1062 // globals - [globalsStart, length)
1063 uint32_t memoriesStart = 0;
1064 uint32_t globalsStart = 0;
1067 struct alignas(ScopeDataAlignBytes) RuntimeData
1068 : public AbstractBaseScopeData<JSAtom> {
1069 SlotInfo slotInfo;
1070 // The wasm instance of the scope.
1071 HeapPtr<WasmInstanceObject*> instance = {};
1073 explicit RuntimeData(size_t length);
1074 RuntimeData() = delete;
1076 void trace(JSTracer* trc);
1079 using ParserData = ParserScopeData<SlotInfo>;
1081 template <typename NameT>
1082 using AbstractData =
1083 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
1084 RuntimeData, ParserData>;
1086 static WasmInstanceScope* create(JSContext* cx, WasmInstanceObject* instance);
1088 private:
1089 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
1091 const RuntimeData& data() const {
1092 return *static_cast<const RuntimeData*>(rawData());
1095 public:
1096 WasmInstanceObject* instance() const { return data().instance; }
1098 uint32_t memoriesStart() const { return data().slotInfo.memoriesStart; }
1100 uint32_t globalsStart() const { return data().slotInfo.globalsStart; }
1102 uint32_t namesCount() const { return data().length; }
1105 // Scope corresponding to the wasm function. A WasmFunctionScope is used by
1106 // Debugger only, and not for wasm execution.
1108 class WasmFunctionScope : public Scope {
1109 friend class AbstractBindingIter<JSAtom>;
1110 friend class Scope;
1111 friend class GCMarker;
1112 friend class AbstractScopePtr;
1113 static const ScopeKind classScopeKind_ = ScopeKind::WasmFunction;
1115 public:
1116 struct SlotInfo {
1117 // Frame slots [0, nextFrameSlot) are live when this is the innermost
1118 // scope.
1119 uint32_t nextFrameSlot = 0;
1121 // Bindings are the local variable names.
1123 // vars - [0, length)
1126 using RuntimeData = RuntimeScopeData<SlotInfo>;
1127 using ParserData = ParserScopeData<SlotInfo>;
1129 template <typename NameT>
1130 using AbstractData =
1131 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
1132 RuntimeData, ParserData>;
1134 static WasmFunctionScope* create(JSContext* cx, Handle<Scope*> enclosing,
1135 uint32_t funcIndex);
1137 private:
1138 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
1140 const RuntimeData& data() const {
1141 return *static_cast<const RuntimeData*>(rawData());
1145 template <typename F>
1146 void Scope::applyScopeDataTyped(F&& f) {
1147 switch (kind()) {
1148 case ScopeKind::Function: {
1149 f(&as<FunctionScope>().data());
1150 break;
1151 case ScopeKind::FunctionBodyVar:
1152 f(&as<VarScope>().data());
1153 break;
1154 case ScopeKind::Lexical:
1155 case ScopeKind::SimpleCatch:
1156 case ScopeKind::Catch:
1157 case ScopeKind::NamedLambda:
1158 case ScopeKind::StrictNamedLambda:
1159 case ScopeKind::FunctionLexical:
1160 f(&as<LexicalScope>().data());
1161 break;
1162 case ScopeKind::ClassBody:
1163 f(&as<ClassBodyScope>().data());
1164 break;
1165 case ScopeKind::With:
1166 // With scopes do not have data.
1167 break;
1168 case ScopeKind::Eval:
1169 case ScopeKind::StrictEval:
1170 f(&as<EvalScope>().data());
1171 break;
1172 case ScopeKind::Global:
1173 case ScopeKind::NonSyntactic:
1174 f(&as<GlobalScope>().data());
1175 break;
1176 case ScopeKind::Module:
1177 f(&as<ModuleScope>().data());
1178 break;
1179 case ScopeKind::WasmInstance:
1180 f(&as<WasmInstanceScope>().data());
1181 break;
1182 case ScopeKind::WasmFunction:
1183 f(&as<WasmFunctionScope>().data());
1184 break;
1190 // An iterator for a Scope's bindings. This is the source of truth for frame
1191 // and environment object layout.
1193 // It may be placed in GC containers; for example:
1195 // for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
1196 // use(bi);
1197 // SomeMayGCOperation();
1198 // use(bi);
1199 // }
1201 template <typename NameT>
1202 class BaseAbstractBindingIter {
1203 protected:
1204 // Bindings are sorted by kind. Because different Scopes have differently
1205 // laid out {Runtime,Parser}Data for packing, BindingIter must handle all
1206 // binding kinds.
1208 // Kind ranges:
1210 // imports - [0, positionalFormalStart)
1211 // positional formals - [positionalFormalStart, nonPositionalFormalStart)
1212 // other formals - [nonPositionalParamStart, varStart)
1213 // vars - [varStart, letStart)
1214 // lets - [letStart, constStart)
1215 // consts - [constStart, syntheticStart)
1216 // synthetic - [syntheticStart, privateMethodStart)
1217 // private methods = [privateMethodStart, length)
1219 // Access method when not closed over:
1221 // imports - name
1222 // positional formals - argument slot
1223 // other formals - frame slot
1224 // vars - frame slot
1225 // lets - frame slot
1226 // consts - frame slot
1227 // synthetic - frame slot
1228 // private methods - frame slot
1230 // Access method when closed over:
1232 // imports - name
1233 // positional formals - environment slot or name
1234 // other formals - environment slot or name
1235 // vars - environment slot or name
1236 // lets - environment slot or name
1237 // consts - environment slot or name
1238 // synthetic - environment slot or name
1239 // private methods - environment slot or name
1240 MOZ_INIT_OUTSIDE_CTOR uint32_t positionalFormalStart_;
1241 MOZ_INIT_OUTSIDE_CTOR uint32_t nonPositionalFormalStart_;
1242 MOZ_INIT_OUTSIDE_CTOR uint32_t varStart_;
1243 MOZ_INIT_OUTSIDE_CTOR uint32_t letStart_;
1244 MOZ_INIT_OUTSIDE_CTOR uint32_t constStart_;
1245 MOZ_INIT_OUTSIDE_CTOR uint32_t syntheticStart_;
1246 MOZ_INIT_OUTSIDE_CTOR uint32_t privateMethodStart_;
1247 MOZ_INIT_OUTSIDE_CTOR uint32_t length_;
1249 MOZ_INIT_OUTSIDE_CTOR uint32_t index_;
1251 enum Flags : uint8_t {
1252 CannotHaveSlots = 0,
1253 CanHaveArgumentSlots = 1 << 0,
1254 CanHaveFrameSlots = 1 << 1,
1255 CanHaveEnvironmentSlots = 1 << 2,
1257 // See comment in settle below.
1258 HasFormalParameterExprs = 1 << 3,
1259 IgnoreDestructuredFormalParameters = 1 << 4,
1261 // Truly I hate named lambdas.
1262 IsNamedLambda = 1 << 5
1265 static const uint8_t CanHaveSlotsMask = 0x7;
1267 MOZ_INIT_OUTSIDE_CTOR uint8_t flags_;
1268 MOZ_INIT_OUTSIDE_CTOR uint16_t argumentSlot_;
1269 MOZ_INIT_OUTSIDE_CTOR uint32_t frameSlot_;
1270 MOZ_INIT_OUTSIDE_CTOR uint32_t environmentSlot_;
1272 MOZ_INIT_OUTSIDE_CTOR AbstractBindingName<NameT>* names_;
1274 void init(uint32_t positionalFormalStart, uint32_t nonPositionalFormalStart,
1275 uint32_t varStart, uint32_t letStart, uint32_t constStart,
1276 uint32_t syntheticStart, uint32_t privateMethodStart, uint8_t flags,
1277 uint32_t firstFrameSlot, uint32_t firstEnvironmentSlot,
1278 mozilla::Span<AbstractBindingName<NameT>> names) {
1279 positionalFormalStart_ = positionalFormalStart;
1280 nonPositionalFormalStart_ = nonPositionalFormalStart;
1281 varStart_ = varStart;
1282 letStart_ = letStart;
1283 constStart_ = constStart;
1284 syntheticStart_ = syntheticStart;
1285 privateMethodStart_ = privateMethodStart;
1286 length_ = names.size();
1288 index_ = 0;
1289 flags_ = flags;
1290 argumentSlot_ = 0;
1291 frameSlot_ = firstFrameSlot;
1292 environmentSlot_ = firstEnvironmentSlot;
1293 names_ = names.data();
1295 settle();
1298 void init(LexicalScope::AbstractData<NameT>& data, uint32_t firstFrameSlot,
1299 uint8_t flags);
1301 void init(ClassBodyScope::AbstractData<NameT>& data, uint32_t firstFrameSlot);
1302 void init(FunctionScope::AbstractData<NameT>& data, uint8_t flags);
1304 void init(VarScope::AbstractData<NameT>& data, uint32_t firstFrameSlot);
1305 void init(GlobalScope::AbstractData<NameT>& data);
1306 void init(EvalScope::AbstractData<NameT>& data, bool strict);
1307 void init(ModuleScope::AbstractData<NameT>& data);
1308 void init(WasmInstanceScope::AbstractData<NameT>& data);
1309 void init(WasmFunctionScope::AbstractData<NameT>& data);
1311 bool hasFormalParameterExprs() const {
1312 return flags_ & HasFormalParameterExprs;
1315 bool ignoreDestructuredFormalParameters() const {
1316 return flags_ & IgnoreDestructuredFormalParameters;
1319 bool isNamedLambda() const { return flags_ & IsNamedLambda; }
1321 void increment() {
1322 MOZ_ASSERT(!done());
1323 if (flags_ & CanHaveSlotsMask) {
1324 if (canHaveArgumentSlots()) {
1325 if (index_ < nonPositionalFormalStart_) {
1326 MOZ_ASSERT(index_ >= positionalFormalStart_);
1327 argumentSlot_++;
1330 if (closedOver()) {
1331 // Imports must not be given known slots. They are
1332 // indirect bindings.
1333 MOZ_ASSERT(kind() != BindingKind::Import);
1334 MOZ_ASSERT(canHaveEnvironmentSlots());
1335 environmentSlot_++;
1336 } else if (canHaveFrameSlots()) {
1337 // Usually positional formal parameters don't have frame
1338 // slots, except when there are parameter expressions, in
1339 // which case they act like lets.
1340 if (index_ >= nonPositionalFormalStart_ ||
1341 (hasFormalParameterExprs() && name())) {
1342 frameSlot_++;
1346 index_++;
1349 void settle() {
1350 if (ignoreDestructuredFormalParameters()) {
1351 while (!done() && !name()) {
1352 increment();
1357 BaseAbstractBindingIter() = default;
1359 public:
1360 BaseAbstractBindingIter(LexicalScope::AbstractData<NameT>& data,
1361 uint32_t firstFrameSlot, bool isNamedLambda) {
1362 init(data, firstFrameSlot, isNamedLambda ? IsNamedLambda : 0);
1365 BaseAbstractBindingIter(ClassBodyScope::AbstractData<NameT>& data,
1366 uint32_t firstFrameSlot) {
1367 init(data, firstFrameSlot);
1370 BaseAbstractBindingIter(FunctionScope::AbstractData<NameT>& data,
1371 bool hasParameterExprs) {
1372 init(data, IgnoreDestructuredFormalParameters |
1373 (hasParameterExprs ? HasFormalParameterExprs : 0));
1376 BaseAbstractBindingIter(VarScope::AbstractData<NameT>& data,
1377 uint32_t firstFrameSlot) {
1378 init(data, firstFrameSlot);
1381 explicit BaseAbstractBindingIter(GlobalScope::AbstractData<NameT>& data) {
1382 init(data);
1385 explicit BaseAbstractBindingIter(ModuleScope::AbstractData<NameT>& data) {
1386 init(data);
1389 explicit BaseAbstractBindingIter(
1390 WasmFunctionScope::AbstractData<NameT>& data) {
1391 init(data);
1394 BaseAbstractBindingIter(EvalScope::AbstractData<NameT>& data, bool strict) {
1395 init(data, strict);
1398 MOZ_IMPLICIT BaseAbstractBindingIter(
1399 const BaseAbstractBindingIter<NameT>& bi) = default;
1401 bool done() const { return index_ == length_; }
1403 explicit operator bool() const { return !done(); }
1405 void operator++(int) {
1406 increment();
1407 settle();
1410 bool isLast() const {
1411 MOZ_ASSERT(!done());
1412 return index_ + 1 == length_;
1415 bool canHaveArgumentSlots() const { return flags_ & CanHaveArgumentSlots; }
1417 bool canHaveFrameSlots() const { return flags_ & CanHaveFrameSlots; }
1419 bool canHaveEnvironmentSlots() const {
1420 return flags_ & CanHaveEnvironmentSlots;
1423 typename AbstractBindingName<NameT>::NamePointerT name() const {
1424 MOZ_ASSERT(!done());
1425 return names_[index_].name();
1428 bool closedOver() const {
1429 MOZ_ASSERT(!done());
1430 return names_[index_].closedOver();
1433 BindingLocation location() const {
1434 MOZ_ASSERT(!done());
1435 if (!(flags_ & CanHaveSlotsMask)) {
1436 return BindingLocation::Global();
1438 if (index_ < positionalFormalStart_) {
1439 return BindingLocation::Import();
1441 if (closedOver()) {
1442 MOZ_ASSERT(canHaveEnvironmentSlots());
1443 return BindingLocation::Environment(environmentSlot_);
1445 if (index_ < nonPositionalFormalStart_ && canHaveArgumentSlots()) {
1446 return BindingLocation::Argument(argumentSlot_);
1448 if (canHaveFrameSlots()) {
1449 return BindingLocation::Frame(frameSlot_);
1451 MOZ_ASSERT(isNamedLambda());
1452 return BindingLocation::NamedLambdaCallee();
1455 BindingKind kind() const {
1456 MOZ_ASSERT(!done());
1457 if (index_ < positionalFormalStart_) {
1458 return BindingKind::Import;
1460 if (index_ < varStart_) {
1461 // When the parameter list has expressions, the parameters act
1462 // like lexical bindings and have TDZ.
1463 if (hasFormalParameterExprs()) {
1464 return BindingKind::Let;
1466 return BindingKind::FormalParameter;
1468 if (index_ < letStart_) {
1469 return BindingKind::Var;
1471 if (index_ < constStart_) {
1472 return BindingKind::Let;
1474 if (index_ < syntheticStart_) {
1475 return isNamedLambda() ? BindingKind::NamedLambdaCallee
1476 : BindingKind::Const;
1478 if (index_ < privateMethodStart_) {
1479 return BindingKind::Synthetic;
1481 return BindingKind::PrivateMethod;
1484 js::frontend::NameLocation nameLocation() const {
1485 using js::frontend::NameLocation;
1487 BindingKind bindKind = kind();
1488 BindingLocation bl = location();
1489 switch (bl.kind()) {
1490 case BindingLocation::Kind::Global:
1491 return NameLocation::Global(bindKind);
1492 case BindingLocation::Kind::Argument:
1493 return NameLocation::ArgumentSlot(bl.argumentSlot());
1494 case BindingLocation::Kind::Frame:
1495 return NameLocation::FrameSlot(bindKind, bl.slot());
1496 case BindingLocation::Kind::Environment:
1497 return NameLocation::EnvironmentCoordinate(bindKind, 0, bl.slot());
1498 case BindingLocation::Kind::Import:
1499 return NameLocation::Import();
1500 case BindingLocation::Kind::NamedLambdaCallee:
1501 return NameLocation::NamedLambdaCallee();
1503 MOZ_CRASH("Bad BindingKind");
1506 bool isTopLevelFunction() const {
1507 MOZ_ASSERT(!done());
1508 bool result = names_[index_].isTopLevelFunction();
1509 MOZ_ASSERT_IF(result, kind() == BindingKind::Var);
1510 return result;
1513 bool hasArgumentSlot() const {
1514 MOZ_ASSERT(!done());
1515 if (hasFormalParameterExprs()) {
1516 return false;
1518 return index_ >= positionalFormalStart_ &&
1519 index_ < nonPositionalFormalStart_;
1522 uint16_t argumentSlot() const {
1523 MOZ_ASSERT(canHaveArgumentSlots());
1524 return mozilla::AssertedCast<uint16_t>(index_);
1527 uint32_t nextFrameSlot() const {
1528 MOZ_ASSERT(canHaveFrameSlots());
1529 return frameSlot_;
1532 uint32_t nextEnvironmentSlot() const {
1533 MOZ_ASSERT(canHaveEnvironmentSlots());
1534 return environmentSlot_;
1538 template <typename NameT>
1539 class AbstractBindingIter;
1541 template <>
1542 class AbstractBindingIter<JSAtom> : public BaseAbstractBindingIter<JSAtom> {
1543 using Base = BaseAbstractBindingIter<JSAtom>;
1545 public:
1546 AbstractBindingIter(ScopeKind kind, BaseScopeData* data,
1547 uint32_t firstFrameSlot);
1549 explicit AbstractBindingIter(Scope* scope);
1550 explicit AbstractBindingIter(JSScript* script);
1552 using Base::Base;
1554 inline void trace(JSTracer* trc) {
1555 TraceNullableBindingNames(trc, names_, length_);
1559 template <>
1560 class AbstractBindingIter<frontend::TaggedParserAtomIndex>
1561 : public BaseAbstractBindingIter<frontend::TaggedParserAtomIndex> {
1562 using Base = BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>;
1564 public:
1565 explicit AbstractBindingIter(const frontend::ScopeStencilRef& ref);
1567 using Base::Base;
1570 void DumpBindings(JSContext* cx, Scope* scope);
1571 JSAtom* FrameSlotName(JSScript* script, jsbytecode* pc);
1573 SharedShape* EmptyEnvironmentShape(JSContext* cx, const JSClass* cls,
1574 uint32_t numSlots, ObjectFlags objectFlags);
1576 template <class T>
1577 SharedShape* EmptyEnvironmentShape(JSContext* cx) {
1578 return EmptyEnvironmentShape(cx, &T::class_, T::RESERVED_SLOTS,
1579 T::OBJECT_FLAGS);
1583 // PositionalFormalParameterIter is a refinement BindingIter that only iterates
1584 // over positional formal parameters of a function.
1586 template <typename NameT>
1587 class BasePositionalFormalParamterIter : public AbstractBindingIter<NameT> {
1588 using Base = AbstractBindingIter<NameT>;
1590 protected:
1591 void settle() {
1592 if (this->index_ >= this->nonPositionalFormalStart_) {
1593 this->index_ = this->length_;
1597 public:
1598 using Base::Base;
1600 void operator++(int) {
1601 Base::operator++(1);
1602 settle();
1605 bool isDestructured() const { return !this->name(); }
1608 template <typename NameT>
1609 class AbstractPositionalFormalParameterIter;
1611 template <>
1612 class AbstractPositionalFormalParameterIter<JSAtom>
1613 : public BasePositionalFormalParamterIter<JSAtom> {
1614 using Base = BasePositionalFormalParamterIter<JSAtom>;
1616 public:
1617 explicit AbstractPositionalFormalParameterIter(Scope* scope);
1618 explicit AbstractPositionalFormalParameterIter(JSScript* script);
1620 using Base::Base;
1623 template <>
1624 class AbstractPositionalFormalParameterIter<frontend::TaggedParserAtomIndex>
1625 : public BasePositionalFormalParamterIter<frontend::TaggedParserAtomIndex> {
1626 using Base =
1627 BasePositionalFormalParamterIter<frontend::TaggedParserAtomIndex>;
1629 public:
1630 AbstractPositionalFormalParameterIter(
1631 FunctionScope::AbstractData<frontend::TaggedParserAtomIndex>& data,
1632 bool hasParameterExprs)
1633 : Base(data, hasParameterExprs) {
1634 settle();
1637 using Base::Base;
1640 using PositionalFormalParameterIter =
1641 AbstractPositionalFormalParameterIter<JSAtom>;
1644 // Iterator for walking the scope chain.
1646 // It may be placed in GC containers; for example:
1648 // for (Rooted<ScopeIter> si(cx, ScopeIter(scope)); si; si++) {
1649 // use(si);
1650 // SomeMayGCOperation();
1651 // use(si);
1652 // }
1654 class MOZ_STACK_CLASS ScopeIter {
1655 Scope* scope_;
1657 public:
1658 explicit ScopeIter(Scope* scope) : scope_(scope) {}
1660 explicit ScopeIter(JSScript* script);
1662 explicit ScopeIter(const ScopeIter& si) = default;
1664 bool done() const { return !scope_; }
1666 explicit operator bool() const { return !done(); }
1668 void operator++(int) {
1669 MOZ_ASSERT(!done());
1670 scope_ = scope_->enclosing();
1673 Scope* scope() const {
1674 MOZ_ASSERT(!done());
1675 return scope_;
1678 ScopeKind kind() const {
1679 MOZ_ASSERT(!done());
1680 return scope_->kind();
1683 // Returns the shape of the environment if it is known. It is possible to
1684 // hasSyntacticEnvironment and to have no known shape, e.g., eval.
1685 SharedShape* environmentShape() const { return scope()->environmentShape(); }
1687 // Returns whether this scope has a syntactic environment (i.e., an
1688 // Environment that isn't a non-syntactic With or NonSyntacticVariables)
1689 // on the environment chain.
1690 bool hasSyntacticEnvironment() const;
1692 void trace(JSTracer* trc) {
1693 if (scope_) {
1694 TraceRoot(trc, &scope_, "scope iter scope");
1700 // Specializations of Rooted containers for the iterators.
1703 template <typename Wrapper>
1704 class WrappedPtrOperations<BindingIter, Wrapper> {
1705 const BindingIter& iter() const {
1706 return static_cast<const Wrapper*>(this)->get();
1709 public:
1710 bool done() const { return iter().done(); }
1711 explicit operator bool() const { return !done(); }
1712 bool isLast() const { return iter().isLast(); }
1713 bool canHaveArgumentSlots() const { return iter().canHaveArgumentSlots(); }
1714 bool canHaveFrameSlots() const { return iter().canHaveFrameSlots(); }
1715 bool canHaveEnvironmentSlots() const {
1716 return iter().canHaveEnvironmentSlots();
1718 JSAtom* name() const { return iter().name(); }
1719 bool closedOver() const { return iter().closedOver(); }
1720 BindingLocation location() const { return iter().location(); }
1721 BindingKind kind() const { return iter().kind(); }
1722 bool isTopLevelFunction() const { return iter().isTopLevelFunction(); }
1723 bool hasArgumentSlot() const { return iter().hasArgumentSlot(); }
1724 uint16_t argumentSlot() const { return iter().argumentSlot(); }
1725 uint32_t nextFrameSlot() const { return iter().nextFrameSlot(); }
1726 uint32_t nextEnvironmentSlot() const { return iter().nextEnvironmentSlot(); }
1729 template <typename Wrapper>
1730 class MutableWrappedPtrOperations<BindingIter, Wrapper>
1731 : public WrappedPtrOperations<BindingIter, Wrapper> {
1732 BindingIter& iter() { return static_cast<Wrapper*>(this)->get(); }
1734 public:
1735 void operator++(int) { iter().operator++(1); }
1738 template <typename Wrapper>
1739 class WrappedPtrOperations<ScopeIter, Wrapper> {
1740 const ScopeIter& iter() const {
1741 return static_cast<const Wrapper*>(this)->get();
1744 public:
1745 bool done() const { return iter().done(); }
1746 explicit operator bool() const { return !done(); }
1747 Scope* scope() const { return iter().scope(); }
1748 ScopeKind kind() const { return iter().kind(); }
1749 SharedShape* environmentShape() const { return iter().environmentShape(); }
1750 bool hasSyntacticEnvironment() const {
1751 return iter().hasSyntacticEnvironment();
1755 template <typename Wrapper>
1756 class MutableWrappedPtrOperations<ScopeIter, Wrapper>
1757 : public WrappedPtrOperations<ScopeIter, Wrapper> {
1758 ScopeIter& iter() { return static_cast<Wrapper*>(this)->get(); }
1760 public:
1761 void operator++(int) { iter().operator++(1); }
1764 SharedShape* CreateEnvironmentShape(JSContext* cx, BindingIter& bi,
1765 const JSClass* cls, uint32_t numSlots,
1766 ObjectFlags objectFlags);
1768 SharedShape* EmptyEnvironmentShape(JSContext* cx, const JSClass* cls,
1769 uint32_t numSlots, ObjectFlags objectFlags);
1771 static inline size_t GetOffsetOfParserScopeDataTrailingNames(ScopeKind kind) {
1772 switch (kind) {
1773 // FunctionScope
1774 case ScopeKind::Function:
1775 return GetOffsetOfScopeDataTrailingNames<FunctionScope::ParserData>();
1777 // VarScope
1778 case ScopeKind::FunctionBodyVar:
1779 return GetOffsetOfScopeDataTrailingNames<VarScope::ParserData>();
1781 // LexicalScope
1782 case ScopeKind::Lexical:
1783 case ScopeKind::SimpleCatch:
1784 case ScopeKind::Catch:
1785 case ScopeKind::NamedLambda:
1786 case ScopeKind::StrictNamedLambda:
1787 case ScopeKind::FunctionLexical:
1788 return GetOffsetOfScopeDataTrailingNames<LexicalScope::ParserData>();
1790 // ClassBodyScope
1791 case ScopeKind::ClassBody:
1792 return GetOffsetOfScopeDataTrailingNames<ClassBodyScope::ParserData>();
1794 // EvalScope
1795 case ScopeKind::Eval:
1796 case ScopeKind::StrictEval:
1797 return GetOffsetOfScopeDataTrailingNames<EvalScope::ParserData>();
1799 // GlobalScope
1800 case ScopeKind::Global:
1801 case ScopeKind::NonSyntactic:
1802 return GetOffsetOfScopeDataTrailingNames<GlobalScope::ParserData>();
1804 // ModuleScope
1805 case ScopeKind::Module:
1806 return GetOffsetOfScopeDataTrailingNames<ModuleScope::ParserData>();
1808 // WasmInstanceScope
1809 case ScopeKind::WasmInstance:
1810 return GetOffsetOfScopeDataTrailingNames<WasmInstanceScope::ParserData>();
1812 // WasmFunctionScope
1813 case ScopeKind::WasmFunction:
1814 return GetOffsetOfScopeDataTrailingNames<WasmFunctionScope::ParserData>();
1816 // WithScope doesn't have ScopeData.
1817 case ScopeKind::With:
1818 default:
1819 MOZ_CRASH("Unexpected ScopeKind");
1822 return 0;
1825 inline size_t SizeOfParserScopeData(ScopeKind kind, uint32_t length) {
1826 return GetOffsetOfParserScopeDataTrailingNames(kind) +
1827 sizeof(AbstractBindingName<frontend::TaggedParserAtomIndex>) * length;
1830 inline mozilla::Span<AbstractBindingName<frontend::TaggedParserAtomIndex>>
1831 GetParserScopeDataTrailingNames(
1832 ScopeKind kind,
1833 AbstractBaseScopeData<frontend::TaggedParserAtomIndex>* data) {
1834 return mozilla::Span(
1835 reinterpret_cast<AbstractBindingName<frontend::TaggedParserAtomIndex>*>(
1836 uintptr_t(data) + GetOffsetOfParserScopeDataTrailingNames(kind)),
1837 data->length);
1840 } // namespace js
1842 namespace JS {
1844 template <>
1845 struct GCPolicy<js::ScopeKind> : public IgnoreGCPolicy<js::ScopeKind> {};
1847 template <typename T>
1848 struct ScopeDataGCPolicy : public NonGCPointerPolicy<T> {};
1850 #define DEFINE_SCOPE_DATA_GCPOLICY(Data) \
1851 template <> \
1852 struct MapTypeToRootKind<Data*> { \
1853 static const RootKind kind = RootKind::Traceable; \
1854 }; \
1855 template <> \
1856 struct GCPolicy<Data*> : public ScopeDataGCPolicy<Data*> {}
1858 DEFINE_SCOPE_DATA_GCPOLICY(js::LexicalScope::RuntimeData);
1859 DEFINE_SCOPE_DATA_GCPOLICY(js::ClassBodyScope::RuntimeData);
1860 DEFINE_SCOPE_DATA_GCPOLICY(js::FunctionScope::RuntimeData);
1861 DEFINE_SCOPE_DATA_GCPOLICY(js::VarScope::RuntimeData);
1862 DEFINE_SCOPE_DATA_GCPOLICY(js::GlobalScope::RuntimeData);
1863 DEFINE_SCOPE_DATA_GCPOLICY(js::EvalScope::RuntimeData);
1864 DEFINE_SCOPE_DATA_GCPOLICY(js::ModuleScope::RuntimeData);
1865 DEFINE_SCOPE_DATA_GCPOLICY(js::WasmFunctionScope::RuntimeData);
1867 #undef DEFINE_SCOPE_DATA_GCPOLICY
1869 namespace ubi {
1871 template <>
1872 class Concrete<js::Scope> : TracerConcrete<js::Scope> {
1873 protected:
1874 explicit Concrete(js::Scope* ptr) : TracerConcrete<js::Scope>(ptr) {}
1876 public:
1877 static void construct(void* storage, js::Scope* ptr) {
1878 new (storage) Concrete(ptr);
1881 CoarseType coarseType() const final { return CoarseType::Script; }
1883 Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
1885 const char16_t* typeName() const override { return concreteTypeName; }
1886 static const char16_t concreteTypeName[];
1889 } // namespace ubi
1890 } // namespace JS
1892 #endif // vm_Scope_h