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/. */
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
46 class JS_PUBLIC_API GenericPrinter
;
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
;
88 class AbstractBindingName
<JSAtom
> {
91 using NamePointerT
= NameT
*;
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)
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;
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
; }
121 friend class BaseAbstractBindingIter
<NameT
>;
123 // This method should be called only for binding names in `vars` range in
125 bool isTopLevelFunction() const { return bits_
& TopLevelFunctionFlag
; }
128 void trace(JSTracer
* trc
) {
129 if (JSAtom
* atom
= name()) {
130 TraceManuallyBarrieredEdge(trc
, &atom
, "binding name");
136 class AbstractBindingName
<frontend::TaggedParserAtomIndex
> {
139 using TaggedParserAtomIndex
= frontend::TaggedParserAtomIndex
;
142 using NameT
= TaggedParserAtomIndex
;
143 using NamePointerT
= NameT
;
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
;
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)) {}
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();
185 friend class BaseAbstractBindingIter
<TaggedParserAtomIndex
>;
186 friend class frontend::ScopeStencil
;
188 // This method should be called only for binding names in `vars` range in
190 bool isTopLevelFunction() const { return bits_
& TopLevelFunctionFlag
; }
193 using BindingName
= AbstractBindingName
<JSAtom
>;
195 static inline void TraceBindingNames(JSTracer
* trc
, BindingName
* names
,
197 for (uint32_t i
= 0; i
< length
; i
++) {
198 JSAtom
* name
= names
[i
].name();
200 TraceManuallyBarrieredEdge(trc
, &name
, "scope name");
203 static inline void TraceNullableBindingNames(JSTracer
* trc
, BindingName
* names
,
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
{
223 using NameType
= NameT
;
225 // The length of names after specialized ScopeData subclasses.
229 template <typename ScopeDataT
>
230 static inline void AssertDerivedScopeData() {
232 !std::is_same_v
<ScopeDataT
,
233 AbstractBaseScopeData
<typename
ScopeDataT::NameType
>>,
234 "ScopeDataT shouldn't be AbstractBaseScopeData");
236 std::is_base_of_v
<AbstractBaseScopeData
<typename
ScopeDataT::NameType
>,
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
>*>(
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
,
289 std::fill_n(data
, length
,
290 AbstractBindingName
<frontend::TaggedParserAtomIndex
>());
293 template <typename ScopeDataT
>
294 static inline void PoisonNames(ScopeDataT
* data
, uint32_t 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
> {
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
;
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),
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
>
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
);
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
>
370 return kind_
== T::classScopeKind_
;
373 template <typename T
>
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) {
398 case ScopeKind::With
:
399 case ScopeKind::Global
:
400 case ScopeKind::NonSyntactic
:
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()) {
427 bool hasOnChain(ScopeKind kind
) const {
428 for (const Scope
* it
= this; it
; it
= it
->enclosing()) {
429 if (it
->kind() == kind
) {
436 void traceChildren(JSTracer
* trc
);
437 void finalize(JS::GCContext
* gcx
);
439 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
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
>))
467 : public AbstractBaseScopeData
<frontend::TaggedParserAtomIndex
> {
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
> {
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
495 // A plain lexical scope.
498 // Holds the single catch parameter of a catch block.
501 // Holds the catch parameters (and only the catch parameters) of a catch
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
{
513 friend class AbstractBindingIter
<JSAtom
>;
514 friend class GCMarker
;
515 friend class frontend::ScopeStencil
;
519 // Frame slots [0, nextFrameSlot) are live when this is the innermost
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
>
535 typename
std::conditional_t
<std::is_same
<NameT
, JSAtom
>::value
,
536 RuntimeData
, ParserData
>;
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());
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
555 static SharedShape
* getEmptyExtensibleEnvironmentShape(JSContext
* cx
);
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`.)
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
{
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
;
594 // Frame slots [0, nextFrameSlot) are live when this is the innermost
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
>
610 typename
std::conditional_t
<std::is_same
<NameT
, JSAtom
>::value
,
611 RuntimeData
, ParserData
>;
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());
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
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) {
645 // function f2([a], b = 4, ...c) {
646 // var d, e, f; // stored in VarScope
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
>;
656 friend class AbstractScopePtr
;
657 static const ScopeKind classScopeKind_
= ScopeKind::Function
;
661 // Frame slots [0, nextFrameSlot) are live when this is the innermost
663 uint32_t nextFrameSlot
= 0;
666 // This uses uint32_t in order to make this struct packed.
669 // If parameter expressions are present, parameters act like lexical
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
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
> {
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
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
>
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
);
734 RuntimeData
& data() { return *static_cast<RuntimeData
*>(rawData()); }
736 const RuntimeData
& data() const {
737 return *static_cast<const RuntimeData
*>(rawData());
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.
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
>;
772 friend class frontend::ScopeStencil
;
776 // Frame slots [0, nextFrameSlot) are live when this is the innermost
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
>
790 typename
std::conditional_t
<std::is_same
<NameT
, JSAtom
>::value
,
791 RuntimeData
, ParserData
>;
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());
807 uint32_t nextFrameSlot() const { return data().slotInfo
.nextFrameSlot
; }
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
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
824 // There are 2 kinds of GlobalScopes.
827 // Corresponds to a GlobalObject and its GlobalLexicalEnvironmentObject on
828 // the environment chain.
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
{
836 friend class AbstractBindingIter
<JSAtom
>;
837 friend class GCMarker
;
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
>
857 typename
std::conditional_t
<std::is_same
<NameT
, JSAtom
>::value
,
858 RuntimeData
, ParserData
>;
860 static GlobalScope
* createEmpty(JSContext
* cx
, ScopeKind kind
);
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());
874 bool isSyntactic() const { return kind() != ScopeKind::NonSyntactic
; }
876 bool hasBindings() const { return data().length
> 0; }
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
{
890 friend class AbstractScopePtr
;
891 static const ScopeKind classScopeKind_
= ScopeKind::With
;
894 static WithScope
* create(JSContext
* cx
, Handle
<Scope
*> enclosing
);
898 // Scope of an eval. Holds var bindings. There are 2 kinds of EvalScopes.
901 // A strict eval. Corresponds to a VarEnvironmentObject, where its var
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
{
911 friend class AbstractBindingIter
<JSAtom
>;
912 friend class GCMarker
;
913 friend class frontend::ScopeStencil
;
917 // Frame slots [0, nextFrameSlot) are live when this is the innermost
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
>
935 typename
std::conditional_t
<std::is_same
<NameT
, JSAtom
>::value
,
936 RuntimeData
, ParserData
>;
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());
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 {
964 return !nearestVarScopeForDirectEval(enclosing())->is
<GlobalScope
>();
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
>;
985 friend class AbstractScopePtr
;
986 friend class frontend::ScopeStencil
;
987 static const ScopeKind classScopeKind_
= ScopeKind::Module
;
991 // Frame slots [0, nextFrameSlot) are live when this is the innermost
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
> {
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
>;
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());
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
>;
1049 friend class GCMarker
;
1050 friend class AbstractScopePtr
;
1051 static const ScopeKind classScopeKind_
= ScopeKind::WasmInstance
;
1055 // Frame slots [0, nextFrameSlot) are live when this is the innermost
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
> {
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
);
1089 RuntimeData
& data() { return *static_cast<RuntimeData
*>(rawData()); }
1091 const RuntimeData
& data() const {
1092 return *static_cast<const RuntimeData
*>(rawData());
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
>;
1111 friend class GCMarker
;
1112 friend class AbstractScopePtr
;
1113 static const ScopeKind classScopeKind_
= ScopeKind::WasmFunction
;
1117 // Frame slots [0, nextFrameSlot) are live when this is the innermost
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
);
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
) {
1148 case ScopeKind::Function
: {
1149 f(&as
<FunctionScope
>().data());
1151 case ScopeKind::FunctionBodyVar
:
1152 f(&as
<VarScope
>().data());
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());
1162 case ScopeKind::ClassBody
:
1163 f(&as
<ClassBodyScope
>().data());
1165 case ScopeKind::With
:
1166 // With scopes do not have data.
1168 case ScopeKind::Eval
:
1169 case ScopeKind::StrictEval
:
1170 f(&as
<EvalScope
>().data());
1172 case ScopeKind::Global
:
1173 case ScopeKind::NonSyntactic
:
1174 f(&as
<GlobalScope
>().data());
1176 case ScopeKind::Module
:
1177 f(&as
<ModuleScope
>().data());
1179 case ScopeKind::WasmInstance
:
1180 f(&as
<WasmInstanceScope
>().data());
1182 case ScopeKind::WasmFunction
:
1183 f(&as
<WasmFunctionScope
>().data());
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++) {
1197 // SomeMayGCOperation();
1201 template <typename NameT
>
1202 class BaseAbstractBindingIter
{
1204 // Bindings are sorted by kind. Because different Scopes have differently
1205 // laid out {Runtime,Parser}Data for packing, BindingIter must handle all
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:
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:
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();
1291 frameSlot_
= firstFrameSlot
;
1292 environmentSlot_
= firstEnvironmentSlot
;
1293 names_
= names
.data();
1298 void init(LexicalScope::AbstractData
<NameT
>& data
, uint32_t firstFrameSlot
,
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
; }
1322 MOZ_ASSERT(!done());
1323 if (flags_
& CanHaveSlotsMask
) {
1324 if (canHaveArgumentSlots()) {
1325 if (index_
< nonPositionalFormalStart_
) {
1326 MOZ_ASSERT(index_
>= positionalFormalStart_
);
1331 // Imports must not be given known slots. They are
1332 // indirect bindings.
1333 MOZ_ASSERT(kind() != BindingKind::Import
);
1334 MOZ_ASSERT(canHaveEnvironmentSlots());
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())) {
1350 if (ignoreDestructuredFormalParameters()) {
1351 while (!done() && !name()) {
1357 BaseAbstractBindingIter() = default;
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
) {
1385 explicit BaseAbstractBindingIter(ModuleScope::AbstractData
<NameT
>& data
) {
1389 explicit BaseAbstractBindingIter(
1390 WasmFunctionScope::AbstractData
<NameT
>& data
) {
1394 BaseAbstractBindingIter(EvalScope::AbstractData
<NameT
>& data
, bool 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) {
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();
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
);
1513 bool hasArgumentSlot() const {
1514 MOZ_ASSERT(!done());
1515 if (hasFormalParameterExprs()) {
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());
1532 uint32_t nextEnvironmentSlot() const {
1533 MOZ_ASSERT(canHaveEnvironmentSlots());
1534 return environmentSlot_
;
1538 template <typename NameT
>
1539 class AbstractBindingIter
;
1542 class AbstractBindingIter
<JSAtom
> : public BaseAbstractBindingIter
<JSAtom
> {
1543 using Base
= BaseAbstractBindingIter
<JSAtom
>;
1546 AbstractBindingIter(ScopeKind kind
, BaseScopeData
* data
,
1547 uint32_t firstFrameSlot
);
1549 explicit AbstractBindingIter(Scope
* scope
);
1550 explicit AbstractBindingIter(JSScript
* script
);
1554 inline void trace(JSTracer
* trc
) {
1555 TraceNullableBindingNames(trc
, names_
, length_
);
1560 class AbstractBindingIter
<frontend::TaggedParserAtomIndex
>
1561 : public BaseAbstractBindingIter
<frontend::TaggedParserAtomIndex
> {
1562 using Base
= BaseAbstractBindingIter
<frontend::TaggedParserAtomIndex
>;
1565 explicit AbstractBindingIter(const frontend::ScopeStencilRef
& ref
);
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
);
1577 SharedShape
* EmptyEnvironmentShape(JSContext
* cx
) {
1578 return EmptyEnvironmentShape(cx
, &T::class_
, T::RESERVED_SLOTS
,
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
>;
1592 if (this->index_
>= this->nonPositionalFormalStart_
) {
1593 this->index_
= this->length_
;
1600 void operator++(int) {
1601 Base::operator++(1);
1605 bool isDestructured() const { return !this->name(); }
1608 template <typename NameT
>
1609 class AbstractPositionalFormalParameterIter
;
1612 class AbstractPositionalFormalParameterIter
<JSAtom
>
1613 : public BasePositionalFormalParamterIter
<JSAtom
> {
1614 using Base
= BasePositionalFormalParamterIter
<JSAtom
>;
1617 explicit AbstractPositionalFormalParameterIter(Scope
* scope
);
1618 explicit AbstractPositionalFormalParameterIter(JSScript
* script
);
1624 class AbstractPositionalFormalParameterIter
<frontend::TaggedParserAtomIndex
>
1625 : public BasePositionalFormalParamterIter
<frontend::TaggedParserAtomIndex
> {
1627 BasePositionalFormalParamterIter
<frontend::TaggedParserAtomIndex
>;
1630 AbstractPositionalFormalParameterIter(
1631 FunctionScope::AbstractData
<frontend::TaggedParserAtomIndex
>& data
,
1632 bool hasParameterExprs
)
1633 : Base(data
, hasParameterExprs
) {
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++) {
1650 // SomeMayGCOperation();
1654 class MOZ_STACK_CLASS ScopeIter
{
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());
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
) {
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();
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(); }
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();
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(); }
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
* CreateEnvironmentShapeForSyntheticModule(
1769 JSContext
* cx
, const JSClass
* cls
, uint32_t numSlots
,
1770 Handle
<ModuleObject
*> module
);
1772 SharedShape
* EmptyEnvironmentShape(JSContext
* cx
, const JSClass
* cls
,
1773 uint32_t numSlots
, ObjectFlags objectFlags
);
1775 static inline size_t GetOffsetOfParserScopeDataTrailingNames(ScopeKind kind
) {
1778 case ScopeKind::Function
:
1779 return GetOffsetOfScopeDataTrailingNames
<FunctionScope::ParserData
>();
1782 case ScopeKind::FunctionBodyVar
:
1783 return GetOffsetOfScopeDataTrailingNames
<VarScope::ParserData
>();
1786 case ScopeKind::Lexical
:
1787 case ScopeKind::SimpleCatch
:
1788 case ScopeKind::Catch
:
1789 case ScopeKind::NamedLambda
:
1790 case ScopeKind::StrictNamedLambda
:
1791 case ScopeKind::FunctionLexical
:
1792 return GetOffsetOfScopeDataTrailingNames
<LexicalScope::ParserData
>();
1795 case ScopeKind::ClassBody
:
1796 return GetOffsetOfScopeDataTrailingNames
<ClassBodyScope::ParserData
>();
1799 case ScopeKind::Eval
:
1800 case ScopeKind::StrictEval
:
1801 return GetOffsetOfScopeDataTrailingNames
<EvalScope::ParserData
>();
1804 case ScopeKind::Global
:
1805 case ScopeKind::NonSyntactic
:
1806 return GetOffsetOfScopeDataTrailingNames
<GlobalScope::ParserData
>();
1809 case ScopeKind::Module
:
1810 return GetOffsetOfScopeDataTrailingNames
<ModuleScope::ParserData
>();
1812 // WasmInstanceScope
1813 case ScopeKind::WasmInstance
:
1814 return GetOffsetOfScopeDataTrailingNames
<WasmInstanceScope::ParserData
>();
1816 // WasmFunctionScope
1817 case ScopeKind::WasmFunction
:
1818 return GetOffsetOfScopeDataTrailingNames
<WasmFunctionScope::ParserData
>();
1820 // WithScope doesn't have ScopeData.
1821 case ScopeKind::With
:
1823 MOZ_CRASH("Unexpected ScopeKind");
1829 inline size_t SizeOfParserScopeData(ScopeKind kind
, uint32_t length
) {
1830 return GetOffsetOfParserScopeDataTrailingNames(kind
) +
1831 sizeof(AbstractBindingName
<frontend::TaggedParserAtomIndex
>) * length
;
1834 inline mozilla::Span
<AbstractBindingName
<frontend::TaggedParserAtomIndex
>>
1835 GetParserScopeDataTrailingNames(
1837 AbstractBaseScopeData
<frontend::TaggedParserAtomIndex
>* data
) {
1838 return mozilla::Span(
1839 reinterpret_cast<AbstractBindingName
<frontend::TaggedParserAtomIndex
>*>(
1840 uintptr_t(data
) + GetOffsetOfParserScopeDataTrailingNames(kind
)),
1849 struct GCPolicy
<js::ScopeKind
> : public IgnoreGCPolicy
<js::ScopeKind
> {};
1851 template <typename T
>
1852 struct ScopeDataGCPolicy
: public NonGCPointerPolicy
<T
> {};
1854 #define DEFINE_SCOPE_DATA_GCPOLICY(Data) \
1856 struct MapTypeToRootKind<Data*> { \
1857 static const RootKind kind = RootKind::Traceable; \
1860 struct GCPolicy<Data*> : public ScopeDataGCPolicy<Data*> {}
1862 DEFINE_SCOPE_DATA_GCPOLICY(js::LexicalScope::RuntimeData
);
1863 DEFINE_SCOPE_DATA_GCPOLICY(js::ClassBodyScope::RuntimeData
);
1864 DEFINE_SCOPE_DATA_GCPOLICY(js::FunctionScope::RuntimeData
);
1865 DEFINE_SCOPE_DATA_GCPOLICY(js::VarScope::RuntimeData
);
1866 DEFINE_SCOPE_DATA_GCPOLICY(js::GlobalScope::RuntimeData
);
1867 DEFINE_SCOPE_DATA_GCPOLICY(js::EvalScope::RuntimeData
);
1868 DEFINE_SCOPE_DATA_GCPOLICY(js::ModuleScope::RuntimeData
);
1869 DEFINE_SCOPE_DATA_GCPOLICY(js::WasmFunctionScope::RuntimeData
);
1871 #undef DEFINE_SCOPE_DATA_GCPOLICY
1876 class Concrete
<js::Scope
> : TracerConcrete
<js::Scope
> {
1878 explicit Concrete(js::Scope
* ptr
) : TracerConcrete
<js::Scope
>(ptr
) {}
1881 static void construct(void* storage
, js::Scope
* ptr
) {
1882 new (storage
) Concrete(ptr
);
1885 CoarseType
coarseType() const final
{ return CoarseType::Script
; }
1887 Size
size(mozilla::MallocSizeOf mallocSizeOf
) const override
;
1889 const char16_t
* typeName() const override
{ return concreteTypeName
; }
1890 static const char16_t concreteTypeName
[];
1896 #endif // vm_Scope_h