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/. */
6
7 #ifndef vm_Scope_h
8 #define vm_Scope_h
9
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
16
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
21
22 #include "builtin/ModuleObject.h" // ModuleObject, HandleModuleObject
23 #include "frontend/ParserAtom.h" // frontend::TaggedParserAtomIndex
24 #include "gc/Allocator.h" // AllowGC
25 #include "gc/Barrier.h" // HeapPtr
26 #include "gc/Cell.h" // TenuredCellWithNonGCPointer
27 #include "gc/MaybeRooted.h" // MaybeRooted
28 #include "gc/Rooting.h" // HandleScope, HandleShape, MutableHandleShape
29 #include "js/GCPolicyAPI.h" // GCPolicy, IgnoreGCPolicy
30 #include "js/HeapAPI.h" // CellFlagBitsReservedForGC
31 #include "js/RootingAPI.h" // Handle, MutableHandle
32 #include "js/TraceKind.h" // JS::TraceKind
33 #include "js/TypeDecls.h" // HandleFunction
34 #include "js/UbiNode.h" // ubi::*
35 #include "js/UniquePtr.h" // UniquePtr
36 #include "util/Poison.h" // AlwaysPoison, JS_SCOPE_DATA_TRAILING_NAMES_PATTERN, MemCheckKind
37 #include "vm/JSFunction.h" // JSFunction
38 #include "vm/ScopeKind.h" // ScopeKind
39 #include "vm/Shape.h" // Shape
40 #include "wasm/WasmJS.h" // WasmInstanceObject
41
42 class JSAtom;
43 class JSFreeOp;
44 class JSFunction;
45 class JSScript;
46 class JSTracer;
47 struct JSContext;
48
49 namespace JS {
50 class Zone;
51 } // namespace JS
52
53 namespace js {
54
55 class GenericPrinter;
56
57 namespace frontend {
58 struct CompilationAtomCache;
59 class ScopeStencil;
60 struct ScopeStencilRef;
61 } // namespace frontend
62
63 template <typename NameT>
64 class AbstractBaseScopeData;
65
66 template <typename NameT>
67 class BaseAbstractBindingIter;
68
69 template <typename NameT>
70 class AbstractBindingIter;
71
72 using BindingIter = AbstractBindingIter<JSAtom>;
73
74 class AbstractScopePtr;
75
ScopeKindIsCatch(ScopeKind kind)76 static inline bool ScopeKindIsCatch(ScopeKind kind) {
77 return kind == ScopeKind::SimpleCatch || kind == ScopeKind::Catch;
78 }
79
ScopeKindIsInBody(ScopeKind kind)80 static inline bool ScopeKindIsInBody(ScopeKind kind) {
81 return kind == ScopeKind::Lexical || kind == ScopeKind::SimpleCatch ||
82 kind == ScopeKind::Catch || kind == ScopeKind::With ||
83 kind == ScopeKind::FunctionLexical ||
84 kind == ScopeKind::FunctionBodyVar || kind == ScopeKind::ClassBody;
85 }
86
87 const char* BindingKindString(BindingKind kind);
88 const char* ScopeKindString(ScopeKind kind);
89
90 template <typename NameT>
91 class AbstractBindingName;
92
93 template <>
94 class AbstractBindingName<JSAtom> {
95 public:
96 using NameT = JSAtom;
97 using NamePointerT = NameT*;
98
99 private:
100 // A JSAtom* with its low bit used as a tag for the:
101 // * whether it is closed over (i.e., exists in the environment shape)
102 // * whether it is a top-level function binding in global or eval scope,
103 // instead of var binding (both are in the same range in Scope data)
104 uintptr_t bits_;
105
106 static constexpr uintptr_t ClosedOverFlag = 0x1;
107 // TODO: We should reuse this bit for let vs class distinction to
108 // show the better redeclaration error message (bug 1428672).
109 static constexpr uintptr_t TopLevelFunctionFlag = 0x2;
110 static constexpr uintptr_t FlagMask = 0x3;
111
112 public:
AbstractBindingName()113 AbstractBindingName() : bits_(0) {}
114
115 AbstractBindingName(NameT* name, bool closedOver,
116 bool isTopLevelFunction = false)
uintptr_t(name)117 : bits_(uintptr_t(name) | (closedOver ? ClosedOverFlag : 0x0) |
118 (isTopLevelFunction ? TopLevelFunctionFlag : 0x0)) {}
119
name()120 NamePointerT name() const {
121 return reinterpret_cast<NameT*>(bits_ & ~FlagMask);
122 }
123
closedOver()124 bool closedOver() const { return bits_ & ClosedOverFlag; }
125
126 private:
127 friend class BaseAbstractBindingIter<NameT>;
128
129 // This method should be called only for binding names in `vars` range in
130 // BindingIter.
isTopLevelFunction()131 bool isTopLevelFunction() const { return bits_ & TopLevelFunctionFlag; }
132
133 public:
134 void trace(JSTracer* trc);
135 };
136
137 template <>
138 class AbstractBindingName<frontend::TaggedParserAtomIndex> {
139 uint32_t bits_;
140
141 using TaggedParserAtomIndex = frontend::TaggedParserAtomIndex;
142
143 public:
144 using NameT = TaggedParserAtomIndex;
145 using NamePointerT = NameT;
146
147 private:
148 static constexpr size_t TaggedIndexBit = TaggedParserAtomIndex::IndexBit + 2;
149
150 static constexpr size_t FlagShift = TaggedIndexBit;
151 static constexpr size_t FlagBit = 2;
152 static constexpr uint32_t FlagMask = BitMask(FlagBit) << FlagShift;
153
154 static constexpr uint32_t ClosedOverFlag = 1 << FlagShift;
155 static constexpr uint32_t TopLevelFunctionFlag = 2 << FlagShift;
156
157 public:
AbstractBindingName()158 AbstractBindingName() : bits_(TaggedParserAtomIndex::NullTag) {
159 // TaggedParserAtomIndex's tags shouldn't overlap with flags.
160 static_assert((TaggedParserAtomIndex::NullTag & FlagMask) == 0);
161 static_assert((TaggedParserAtomIndex::ParserAtomIndexTag & FlagMask) == 0);
162 static_assert((TaggedParserAtomIndex::WellKnownTag & FlagMask) == 0);
163 }
164
165 AbstractBindingName(TaggedParserAtomIndex name, bool closedOver,
166 bool isTopLevelFunction = false)
167 : bits_(name.rawData() | (closedOver ? ClosedOverFlag : 0x0) |
168 (isTopLevelFunction ? TopLevelFunctionFlag : 0x0)) {}
169
170 public:
name()171 NamePointerT name() const {
172 return TaggedParserAtomIndex::fromRaw(bits_ & ~FlagMask);
173 }
174
closedOver()175 bool closedOver() const { return bits_ & ClosedOverFlag; }
176
copyWithNewAtom(JSAtom * newName)177 AbstractBindingName<JSAtom> copyWithNewAtom(JSAtom* newName) const {
178 return AbstractBindingName<JSAtom>(newName, closedOver(),
179 isTopLevelFunction());
180 }
181
updateNameAfterStencilMerge(TaggedParserAtomIndex name)182 void updateNameAfterStencilMerge(TaggedParserAtomIndex name) {
183 bits_ = (bits_ & FlagMask) | name.rawData();
184 }
185
186 private:
187 friend class BaseAbstractBindingIter<TaggedParserAtomIndex>;
188 friend class frontend::ScopeStencil;
189
190 // This method should be called only for binding names in `vars` range in
191 // BindingIter.
isTopLevelFunction()192 bool isTopLevelFunction() const { return bits_ & TopLevelFunctionFlag; }
193 };
194
195 using BindingName = AbstractBindingName<JSAtom>;
196
197 const size_t ScopeDataAlignBytes = size_t(1) << gc::CellFlagBitsReservedForGC;
198
199 /**
200 * Base class for scope {Runtime,Parser}Data classes to inherit from.
201 *
202 * `js::Scope` stores a pointer to RuntimeData classes in their first word, so
203 * they must be suitably aligned to allow storing GC flags in the low bits.
204 */
205 template <typename NameT>
206 class AbstractBaseScopeData {
207 public:
208 using NameType = NameT;
209
210 // The length of names after specialized ScopeData subclasses.
211 uint32_t length = 0;
212 };
213
214 template <typename ScopeDataT>
AssertDerivedScopeData()215 static inline void AssertDerivedScopeData() {
216 static_assert(
217 !std::is_same_v<ScopeDataT,
218 AbstractBaseScopeData<typename ScopeDataT::NameType>>,
219 "ScopeDataT shouldn't be AbstractBaseScopeData");
220 static_assert(
221 std::is_base_of_v<AbstractBaseScopeData<typename ScopeDataT::NameType>,
222 ScopeDataT>,
223 "ScopeDataT should be subclass of AbstractBaseScopeData");
224 }
225
226 template <typename ScopeDataT>
GetOffsetOfScopeDataTrailingNames()227 static inline size_t GetOffsetOfScopeDataTrailingNames() {
228 AssertDerivedScopeData<ScopeDataT>();
229 return sizeof(ScopeDataT);
230 }
231
232 template <typename ScopeDataT>
233 static inline AbstractBindingName<typename ScopeDataT::NameType>*
GetScopeDataTrailingNamesPointer(ScopeDataT * data)234 GetScopeDataTrailingNamesPointer(ScopeDataT* data) {
235 AssertDerivedScopeData<ScopeDataT>();
236 return reinterpret_cast<AbstractBindingName<typename ScopeDataT::NameType>*>(
237 data + 1);
238 }
239
240 template <typename ScopeDataT>
241 static inline const AbstractBindingName<typename ScopeDataT::NameType>*
GetScopeDataTrailingNamesPointer(const ScopeDataT * data)242 GetScopeDataTrailingNamesPointer(const ScopeDataT* data) {
243 AssertDerivedScopeData<ScopeDataT>();
244 return reinterpret_cast<
245 const AbstractBindingName<typename ScopeDataT::NameType>*>(data + 1);
246 }
247
248 template <typename ScopeDataT>
249 static inline mozilla::Span<AbstractBindingName<typename ScopeDataT::NameType>>
GetScopeDataTrailingNames(ScopeDataT * data)250 GetScopeDataTrailingNames(ScopeDataT* data) {
251 return mozilla::Span(GetScopeDataTrailingNamesPointer(data), data->length);
252 }
253
254 template <typename ScopeDataT>
255 static inline mozilla::Span<
256 const AbstractBindingName<typename ScopeDataT::NameType>>
GetScopeDataTrailingNames(const ScopeDataT * data)257 GetScopeDataTrailingNames(const ScopeDataT* data) {
258 return mozilla::Span(GetScopeDataTrailingNamesPointer(data), data->length);
259 }
260
261 using BaseScopeData = AbstractBaseScopeData<JSAtom>;
262
PoisonNames(AbstractBindingName<JSAtom> * data,uint32_t length)263 inline void PoisonNames(AbstractBindingName<JSAtom>* data, uint32_t length) {
264 AlwaysPoison(data, JS_SCOPE_DATA_TRAILING_NAMES_PATTERN,
265 sizeof(AbstractBindingName<JSAtom>) * length,
266 MemCheckKind::MakeUndefined);
267 }
268
269 // frontend::TaggedParserAtomIndex doesn't require poison value.
270 // Fill with null value instead.
PoisonNames(AbstractBindingName<frontend::TaggedParserAtomIndex> * data,uint32_t length)271 inline void PoisonNames(
272 AbstractBindingName<frontend::TaggedParserAtomIndex>* data,
273 uint32_t length) {
274 std::fill_n(data, length,
275 AbstractBindingName<frontend::TaggedParserAtomIndex>());
276 }
277
278 template <typename ScopeDataT>
PoisonNames(ScopeDataT * data,uint32_t length)279 static inline void PoisonNames(ScopeDataT* data, uint32_t length) {
280 if (length) {
281 PoisonNames(GetScopeDataTrailingNamesPointer(data), length);
282 }
283 }
284
285 //
286 // Allow using is<T> and as<T> on Rooted<Scope*> and Handle<Scope*>.
287 //
288 template <typename Wrapper>
289 class WrappedPtrOperations<Scope*, Wrapper> {
290 public:
291 template <class U>
as()292 JS::Handle<U*> as() const {
293 const Wrapper& self = *static_cast<const Wrapper*>(this);
294 MOZ_ASSERT_IF(self, self->template is<U>());
295 return Handle<U*>::fromMarkedLocation(
296 reinterpret_cast<U* const*>(self.address()));
297 }
298 };
299
300 //
301 // The base class of all Scopes.
302 //
303 class Scope : public gc::TenuredCellWithNonGCPointer<BaseScopeData> {
304 friend class GCMarker;
305 friend class frontend::ScopeStencil;
306 friend class js::AbstractBindingIter<JSAtom>;
307
308 protected:
309 // The raw data pointer, stored in the cell header.
rawData()310 BaseScopeData* rawData() { return headerPtr(); }
rawData()311 const BaseScopeData* rawData() const { return headerPtr(); }
312
313 // The kind determines data_.
314 const ScopeKind kind_;
315
316 // If there are any aliased bindings, the shape for the
317 // EnvironmentObject. Otherwise nullptr.
318 const HeapPtr<Shape*> environmentShape_;
319
320 // The enclosing scope or nullptr.
321 HeapPtr<Scope*> enclosingScope_;
322
Scope(ScopeKind kind,Scope * enclosing,Shape * environmentShape)323 Scope(ScopeKind kind, Scope* enclosing, Shape* environmentShape)
324 : TenuredCellWithNonGCPointer(nullptr),
325 kind_(kind),
326 environmentShape_(environmentShape),
327 enclosingScope_(enclosing) {}
328
329 static Scope* create(JSContext* cx, ScopeKind kind, HandleScope enclosing,
330 HandleShape envShape);
331
332 template <typename ConcreteScope>
333 void initData(
334 MutableHandle<UniquePtr<typename ConcreteScope::RuntimeData>> data);
335
336 template <typename F>
337 void applyScopeDataTyped(F&& f);
338
339 template <typename EnvironmentT>
340 static bool updateEnvShapeIfRequired(JSContext* cx, MutableHandleShape shape,
341 bool needsEnvironment);
342
343 template <typename EnvironmentT>
344 static bool updateEnvShapeIfRequired(JSContext* cx,
345 mozilla::Maybe<uint32_t>* envShape,
346 bool needsEnvironment);
347
348 public:
349 template <typename ConcreteScope>
350 static ConcreteScope* create(
351 JSContext* cx, ScopeKind kind, HandleScope enclosing,
352 HandleShape envShape,
353 MutableHandle<UniquePtr<typename ConcreteScope::RuntimeData>> data);
354
355 static const JS::TraceKind TraceKind = JS::TraceKind::Scope;
356
357 template <typename T>
is()358 bool is() const {
359 return kind_ == T::classScopeKind_;
360 }
361
362 template <typename T>
as()363 T& as() {
364 MOZ_ASSERT(this->is<T>());
365 return *static_cast<T*>(this);
366 }
367
368 template <typename T>
as()369 const T& as() const {
370 MOZ_ASSERT(this->is<T>());
371 return *static_cast<const T*>(this);
372 }
373
kind()374 ScopeKind kind() const { return kind_; }
375
isNamedLambda()376 bool isNamedLambda() const {
377 return kind() == ScopeKind::NamedLambda ||
378 kind() == ScopeKind::StrictNamedLambda;
379 }
380
environmentShape()381 Shape* environmentShape() const { return environmentShape_; }
382
enclosing()383 Scope* enclosing() const { return enclosingScope_; }
384
385 static bool hasEnvironment(ScopeKind kind, bool hasEnvironmentShape = false) {
386 switch (kind) {
387 case ScopeKind::With:
388 case ScopeKind::Global:
389 case ScopeKind::NonSyntactic:
390 return true;
391 default:
392 // If there's a shape, an environment must be created for this scope.
393 return hasEnvironmentShape;
394 }
395 }
396
hasEnvironment()397 bool hasEnvironment() const {
398 return hasEnvironment(kind_, !!environmentShape());
399 }
400
401 uint32_t firstFrameSlot() const;
402
403 uint32_t chainLength() const;
404 uint32_t environmentChainLength() const;
405
406 template <typename T>
hasOnChain()407 bool hasOnChain() const {
408 for (const Scope* it = this; it; it = it->enclosing()) {
409 if (it->is<T>()) {
410 return true;
411 }
412 }
413 return false;
414 }
415
hasOnChain(ScopeKind kind)416 bool hasOnChain(ScopeKind kind) const {
417 for (const Scope* it = this; it; it = it->enclosing()) {
418 if (it->kind() == kind) {
419 return true;
420 }
421 }
422 return false;
423 }
424
425 void traceChildren(JSTracer* trc);
426 void finalize(JSFreeOp* fop);
427
428 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
429
430 void dump();
431 #if defined(DEBUG) || defined(JS_JITSPEW)
432 static bool dumpForDisassemble(JSContext* cx, JS::Handle<Scope*> scope,
433 GenericPrinter& out, const char* indent);
434 #endif /* defined(DEBUG) || defined(JS_JITSPEW) */
435 };
436
437 template <class DataT>
SizeOfScopeData(uint32_t length)438 inline size_t SizeOfScopeData(uint32_t length) {
439 using BindingT = AbstractBindingName<typename DataT::NameType>;
440 return GetOffsetOfScopeDataTrailingNames<DataT>() + length * sizeof(BindingT);
441 }
442
443 //
444 // A useful typedef for selecting between a gc-aware wrappers
445 // around pointers to BaseScopeData-derived types, and around raw
446 // pointer wrappers around BaseParserScopeData-derived types.
447 //
448 template <typename ScopeT, typename AtomT>
449 using AbstractScopeData = typename ScopeT::template AbstractData<AtomT>;
450
451 template <typename ScopeT, typename AtomT>
452 using MaybeRootedScopeData = std::conditional_t<
453 std::is_same_v<AtomT, JSAtom>,
454 MaybeRooted<UniquePtr<typename ScopeT::RuntimeData>, AllowGC::CanGC>,
455 MaybeRooted<AbstractScopeData<ScopeT, AtomT>*, AllowGC::NoGC>>;
456
457 // Binding names are stored from `this+1`.
458 // Make sure the class aligns the binding name size.
459 template <typename SlotInfo>
alignas(alignof (AbstractBindingName<frontend::TaggedParserAtomIndex>))460 struct alignas(alignof(AbstractBindingName<frontend::TaggedParserAtomIndex>))
461 ParserScopeData
462 : public AbstractBaseScopeData<frontend::TaggedParserAtomIndex> {
463 SlotInfo slotInfo;
464
465 explicit ParserScopeData(size_t length) { PoisonNames(this, length); }
466 ParserScopeData() = delete;
467 };
468
469 // RuntimeScopeData has 2 requirements:
470 // * It aligns with `BindingName`, that is stored after `this+1`
471 // * It aligns with ScopeDataAlignBytes, in order to put it in the first
472 // word of `js::Scope`
473 static_assert(alignof(BindingName) <= ScopeDataAlignBytes);
474 template <typename SlotInfo>
alignas(ScopeDataAlignBytes)475 struct alignas(ScopeDataAlignBytes) RuntimeScopeData
476 : public AbstractBaseScopeData<JSAtom> {
477 SlotInfo slotInfo;
478
479 explicit RuntimeScopeData(size_t length) { PoisonNames(this, length); }
480 RuntimeScopeData() = delete;
481
482 void trace(JSTracer* trc);
483 };
484
485 //
486 // A lexical scope that holds let and const bindings. There are 4 kinds of
487 // LexicalScopes.
488 //
489 // Lexical
490 // A plain lexical scope.
491 //
492 // SimpleCatch
493 // Holds the single catch parameter of a catch block.
494 //
495 // Catch
496 // Holds the catch parameters (and only the catch parameters) of a catch
497 // block.
498 //
499 // NamedLambda
500 // StrictNamedLambda
501 // Holds the single name of the callee for a named lambda expression.
502 //
503 // All kinds of LexicalScopes correspond to LexicalEnvironmentObjects on the
504 // environment chain.
505 //
506 class LexicalScope : public Scope {
507 friend class Scope;
508 friend class AbstractBindingIter<JSAtom>;
509 friend class GCMarker;
510 friend class frontend::ScopeStencil;
511
512 public:
513 struct SlotInfo {
514 // Frame slots [0, nextFrameSlot) are live when this is the innermost
515 // scope.
516 uint32_t nextFrameSlot = 0;
517
518 // Bindings are sorted by kind in both frames and environments.
519 //
520 // lets - [0, constStart)
521 // consts - [constStart, length)
522 uint32_t constStart = 0;
523 };
524
525 using RuntimeData = RuntimeScopeData<SlotInfo>;
526 using ParserData = ParserScopeData<SlotInfo>;
527
528 template <typename NameT>
529 using AbstractData =
530 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
531 RuntimeData, ParserData>;
532
533 private:
534 static LexicalScope* createWithData(
535 JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<RuntimeData>> data,
536 uint32_t firstFrameSlot, HandleScope enclosing);
537
538 template <typename AtomT, typename ShapeT>
539 static bool prepareForScopeCreation(
540 JSContext* cx, ScopeKind kind, uint32_t firstFrameSlot,
541 typename MaybeRootedScopeData<LexicalScope, AtomT>::MutableHandleType
542 data,
543 ShapeT envShape);
544
data()545 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
data()546 const RuntimeData& data() const {
547 return *static_cast<const RuntimeData*>(rawData());
548 }
549
550 public:
551 static uint32_t nextFrameSlot(Scope* scope);
552
nextFrameSlot()553 uint32_t nextFrameSlot() const { return data().slotInfo.nextFrameSlot; }
554
555 // Returns an empty shape for extensible global and non-syntactic lexical
556 // scopes.
557 static Shape* getEmptyExtensibleEnvironmentShape(JSContext* cx);
558 };
559
560 template <>
561 inline bool Scope::is<LexicalScope>() const {
562 return kind_ == ScopeKind::Lexical || kind_ == ScopeKind::SimpleCatch ||
563 kind_ == ScopeKind::Catch || kind_ == ScopeKind::NamedLambda ||
564 kind_ == ScopeKind::StrictNamedLambda ||
565 kind_ == ScopeKind::FunctionLexical;
566 }
567
568 // The body scope of a JS class, containing only synthetic bindings for private
569 // class members. (The binding for the class name, `C` in the example below, is
570 // in another scope, a `LexicalScope`, that encloses the `ClassBodyScope`.)
571 // Example:
572 //
573 // class C {
574 // #f = 0;
575 // #m() {
576 // return this.#f++;
577 // }
578 // }
579 //
580 // This class has a ClassBodyScope with four synthetic bindings:
581 // - `#f` (private name)
582 // - `#m` (private name)
583 // - `#m.method` (function object)
584 // - `.privateBrand` (the class's private brand)
585 class ClassBodyScope : public Scope {
586 friend class Scope;
587 friend class AbstractBindingIter<JSAtom>;
588 friend class GCMarker;
589 friend class frontend::ScopeStencil;
590 friend class AbstractScopePtr;
591
592 static const ScopeKind classScopeKind_ = ScopeKind::ClassBody;
593
594 public:
595 struct SlotInfo {
596 // Frame slots [0, nextFrameSlot) are live when this is the innermost
597 // scope.
598 uint32_t nextFrameSlot = 0;
599
600 // Bindings are sorted by kind in both frames and environments.
601 //
602 // synthetic - [0, privateMethodStart)
603 // privateMethod - [privateMethodStart, length)
604 uint32_t privateMethodStart = 0;
605 };
606
607 using RuntimeData = RuntimeScopeData<SlotInfo>;
608 using ParserData = ParserScopeData<SlotInfo>;
609
610 template <typename NameT>
611 using AbstractData =
612 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
613 RuntimeData, ParserData>;
614
615 private:
616 static ClassBodyScope* createWithData(
617 JSContext* cx, ScopeKind kind, MutableHandle<UniquePtr<RuntimeData>> data,
618 uint32_t firstFrameSlot, HandleScope enclosing);
619
620 template <typename AtomT, typename ShapeT>
621 static bool prepareForScopeCreation(
622 JSContext* cx, ScopeKind kind, uint32_t firstFrameSlot,
623 typename MaybeRootedScopeData<ClassBodyScope, AtomT>::MutableHandleType
624 data,
625 ShapeT envShape);
626
data()627 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
data()628 const RuntimeData& data() const {
629 return *static_cast<const RuntimeData*>(rawData());
630 }
631
632 public:
633 static uint32_t nextFrameSlot(Scope* scope);
634
nextFrameSlot()635 uint32_t nextFrameSlot() const { return data().slotInfo.nextFrameSlot; }
636
637 // Returns an empty shape for extensible global and non-syntactic lexical
638 // scopes.
639 static Shape* getEmptyExtensibleEnvironmentShape(JSContext* cx);
640 };
641
642 //
643 // Scope corresponding to a function. Holds formal parameter names, special
644 // internal names (see FunctionScope::isSpecialName), and, if the function
645 // parameters contain no expressions that might possibly be evaluated, the
646 // function's var bindings. For example, in these functions, the FunctionScope
647 // will store a/b/c bindings but not d/e/f bindings:
648 //
649 // function f1(a, b) {
650 // var c;
651 // let e;
652 // const f = 3;
653 // }
654 // function f2([a], b = 4, ...c) {
655 // var d, e, f; // stored in VarScope
656 // }
657 //
658 // Corresponds to CallObject on environment chain.
659 //
660 class FunctionScope : public Scope {
661 friend class GCMarker;
662 friend class AbstractBindingIter<JSAtom>;
663 friend class PositionalFormalParameterIter;
664 friend class Scope;
665 friend class AbstractScopePtr;
666 static const ScopeKind classScopeKind_ = ScopeKind::Function;
667
668 public:
669 struct SlotInfo {
670 // Frame slots [0, nextFrameSlot) are live when this is the innermost
671 // scope.
672 uint32_t nextFrameSlot = 0;
673
674 // Flag bits.
675 // This uses uint32_t in order to make this struct packed.
676 uint32_t flags = 0;
677
678 // If parameter expressions are present, parameters act like lexical
679 // bindings.
680 static constexpr uint32_t HasParameterExprsFlag = 1;
681
682 // Bindings are sorted by kind in both frames and environments.
683 //
684 // Positional formal parameter names are those that are not
685 // destructured. They may be referred to by argument slots if
686 // !script()->hasParameterExprs().
687 //
688 // An argument slot that needs to be skipped due to being destructured
689 // or having defaults will have a nullptr name in the name array to
690 // advance the argument slot.
691 //
692 // Rest parameter binding is also included in positional formals.
693 // This also becomes nullptr if destructuring.
694 //
695 // The number of positional formals is equal to function.length if
696 // there's no rest, function.length+1 otherwise.
697 //
698 // Destructuring parameters and destructuring rest are included in
699 // "other formals" below.
700 //
701 // "vars" contains the following:
702 // * function's top level vars if !script()->hasParameterExprs()
703 // * special internal names (arguments, .this, .generator) if
704 // they're used.
705 //
706 // positional formals - [0, nonPositionalFormalStart)
707 // other formals - [nonPositionalParamStart, varStart)
708 // vars - [varStart, length)
709 uint16_t nonPositionalFormalStart = 0;
710 uint16_t varStart = 0;
711
hasParameterExprsSlotInfo712 bool hasParameterExprs() const { return flags & HasParameterExprsFlag; }
setHasParameterExprsSlotInfo713 void setHasParameterExprs() { flags |= HasParameterExprsFlag; }
714 };
715
alignas(ScopeDataAlignBytes)716 struct alignas(ScopeDataAlignBytes) RuntimeData
717 : public AbstractBaseScopeData<JSAtom> {
718 SlotInfo slotInfo;
719 // The canonical function of the scope, as during a scope walk we
720 // often query properties of the JSFunction (e.g., is the function an
721 // arrow).
722 HeapPtr<JSFunction*> canonicalFunction = {};
723
724 explicit RuntimeData(size_t length) { PoisonNames(this, length); }
725 RuntimeData() = delete;
726
727 void trace(JSTracer* trc);
728 };
729
730 using ParserData = ParserScopeData<SlotInfo>;
731
732 template <typename NameT>
733 using AbstractData =
734 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
735 RuntimeData, ParserData>;
736
737 template <typename AtomT, typename ShapeT>
738 static bool prepareForScopeCreation(
739 JSContext* cx,
740 typename MaybeRootedScopeData<FunctionScope, AtomT>::MutableHandleType
741 data,
742 bool hasParameterExprs, bool needsEnvironment, HandleFunction fun,
743 ShapeT envShape);
744
745 private:
746 static FunctionScope* createWithData(
747 JSContext* cx, MutableHandle<UniquePtr<RuntimeData>> data,
748 bool hasParameterExprs, bool needsEnvironment, HandleFunction fun,
749 HandleScope enclosing);
750
data()751 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
752
data()753 const RuntimeData& data() const {
754 return *static_cast<const RuntimeData*>(rawData());
755 }
756
757 public:
nextFrameSlot()758 uint32_t nextFrameSlot() const { return data().slotInfo.nextFrameSlot; }
759
canonicalFunction()760 JSFunction* canonicalFunction() const { return data().canonicalFunction; }
initCanonicalFunction(JSFunction * fun)761 void initCanonicalFunction(JSFunction* fun) {
762 data().canonicalFunction.init(fun);
763 }
764
765 JSScript* script() const;
766
hasParameterExprs()767 bool hasParameterExprs() const { return data().slotInfo.hasParameterExprs(); }
768
numPositionalFormalParameters()769 uint32_t numPositionalFormalParameters() const {
770 return data().slotInfo.nonPositionalFormalStart;
771 }
772
773 static bool isSpecialName(JSContext* cx, JSAtom* name);
774 static bool isSpecialName(JSContext* cx,
775 frontend::TaggedParserAtomIndex name);
776 };
777
778 //
779 // Scope holding only vars. There is a single kind of VarScopes.
780 //
781 // FunctionBodyVar
782 // Corresponds to the extra var scope present in functions with parameter
783 // expressions. See examples in comment above FunctionScope.
784 //
785 // Corresponds to VarEnvironmentObject on environment chain.
786 //
787 class VarScope : public Scope {
788 friend class GCMarker;
789 friend class AbstractBindingIter<JSAtom>;
790 friend class Scope;
791 friend class frontend::ScopeStencil;
792
793 public:
794 struct SlotInfo {
795 // Frame slots [0, nextFrameSlot) are live when this is the innermost
796 // scope.
797 uint32_t nextFrameSlot = 0;
798
799 // All bindings are vars.
800 //
801 // vars - [0, length)
802 };
803
804 using RuntimeData = RuntimeScopeData<SlotInfo>;
805 using ParserData = ParserScopeData<SlotInfo>;
806
807 template <typename NameT>
808 using AbstractData =
809 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
810 RuntimeData, ParserData>;
811
812 private:
813 static VarScope* createWithData(JSContext* cx, ScopeKind kind,
814 MutableHandle<UniquePtr<RuntimeData>> data,
815 uint32_t firstFrameSlot,
816 bool needsEnvironment, HandleScope enclosing);
817
818 template <typename AtomT, typename ShapeT>
819 static bool prepareForScopeCreation(
820 JSContext* cx, ScopeKind kind,
821 typename MaybeRootedScopeData<VarScope, AtomT>::MutableHandleType data,
822 uint32_t firstFrameSlot, bool needsEnvironment, ShapeT envShape);
823
data()824 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
825
data()826 const RuntimeData& data() const {
827 return *static_cast<const RuntimeData*>(rawData());
828 }
829
830 public:
nextFrameSlot()831 uint32_t nextFrameSlot() const { return data().slotInfo.nextFrameSlot; }
832 };
833
834 template <>
835 inline bool Scope::is<VarScope>() const {
836 return kind_ == ScopeKind::FunctionBodyVar;
837 }
838
839 //
840 // Scope corresponding to both the global object scope and the global lexical
841 // scope.
842 //
843 // Both are extensible and are singletons across <script> tags, so these
844 // scopes are a fragment of the names in global scope. In other words, two
845 // global scripts may have two different GlobalScopes despite having the same
846 // GlobalObject.
847 //
848 // There are 2 kinds of GlobalScopes.
849 //
850 // Global
851 // Corresponds to a GlobalObject and its GlobalLexicalEnvironmentObject on
852 // the environment chain.
853 //
854 // NonSyntactic
855 // Corresponds to a non-GlobalObject created by the embedding on the
856 // environment chain. This distinction is important for optimizations.
857 //
858 class GlobalScope : public Scope {
859 friend class Scope;
860 friend class AbstractBindingIter<JSAtom>;
861 friend class GCMarker;
862
863 public:
864 struct SlotInfo {
865 // Bindings are sorted by kind.
866 // `vars` includes top-level functions which is distinguished by a bit
867 // on the BindingName.
868 //
869 // vars - [0, letStart)
870 // lets - [letStart, constStart)
871 // consts - [constStart, length)
872 uint32_t letStart = 0;
873 uint32_t constStart = 0;
874 };
875
876 using RuntimeData = RuntimeScopeData<SlotInfo>;
877 using ParserData = ParserScopeData<SlotInfo>;
878
879 template <typename NameT>
880 using AbstractData =
881 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
882 RuntimeData, ParserData>;
883
884 static GlobalScope* create(JSContext* cx, ScopeKind kind,
885 Handle<RuntimeData*> data);
886
createEmpty(JSContext * cx,ScopeKind kind)887 static GlobalScope* createEmpty(JSContext* cx, ScopeKind kind) {
888 return create(cx, kind, nullptr);
889 }
890
891 private:
892 static GlobalScope* createWithData(
893 JSContext* cx, ScopeKind kind,
894 MutableHandle<UniquePtr<RuntimeData>> data);
895
data()896 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
897
data()898 const RuntimeData& data() const {
899 return *static_cast<const RuntimeData*>(rawData());
900 }
901
902 public:
isSyntactic()903 bool isSyntactic() const { return kind() != ScopeKind::NonSyntactic; }
904
hasBindings()905 bool hasBindings() const { return data().length > 0; }
906 };
907
908 template <>
909 inline bool Scope::is<GlobalScope>() const {
910 return kind_ == ScopeKind::Global || kind_ == ScopeKind::NonSyntactic;
911 }
912
913 //
914 // Scope of a 'with' statement. Has no bindings.
915 //
916 // Corresponds to a WithEnvironmentObject on the environment chain.
917 class WithScope : public Scope {
918 friend class Scope;
919 friend class AbstractScopePtr;
920 static const ScopeKind classScopeKind_ = ScopeKind::With;
921
922 public:
923 static WithScope* create(JSContext* cx, HandleScope enclosing);
924 };
925
926 //
927 // Scope of an eval. Holds var bindings. There are 2 kinds of EvalScopes.
928 //
929 // StrictEval
930 // A strict eval. Corresponds to a VarEnvironmentObject, where its var
931 // bindings lives.
932 //
933 // Eval
934 // A sloppy eval. This is an empty scope, used only in the frontend, to
935 // detect redeclaration errors. It has no Environment. Any `var`s declared
936 // in the eval code are bound on the nearest enclosing var environment.
937 //
938 class EvalScope : public Scope {
939 friend class Scope;
940 friend class AbstractBindingIter<JSAtom>;
941 friend class GCMarker;
942 friend class frontend::ScopeStencil;
943
944 public:
945 struct SlotInfo {
946 // Frame slots [0, nextFrameSlot) are live when this is the innermost
947 // scope.
948 uint32_t nextFrameSlot = 0;
949
950 // All bindings in an eval script are 'var' bindings. The implicit
951 // lexical scope around the eval is present regardless of strictness
952 // and is its own LexicalScope.
953 // `vars` includes top-level functions which is distinguished by a bit
954 // on the BindingName.
955 //
956 // vars - [0, length)
957 };
958
959 using RuntimeData = RuntimeScopeData<SlotInfo>;
960 using ParserData = ParserScopeData<SlotInfo>;
961
962 template <typename NameT>
963 using AbstractData =
964 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
965 RuntimeData, ParserData>;
966
967 private:
968 static EvalScope* createWithData(JSContext* cx, ScopeKind kind,
969 MutableHandle<UniquePtr<RuntimeData>> data,
970 HandleScope enclosing);
971
972 template <typename AtomT, typename ShapeT>
973 static bool prepareForScopeCreation(
974 JSContext* cx, ScopeKind scopeKind,
975 typename MaybeRootedScopeData<EvalScope, AtomT>::MutableHandleType data,
976 ShapeT envShape);
977
data()978 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
979
data()980 const RuntimeData& data() const {
981 return *static_cast<const RuntimeData*>(rawData());
982 }
983
984 public:
985 // Starting a scope, the nearest var scope that a direct eval can
986 // introduce vars on.
987 static Scope* nearestVarScopeForDirectEval(Scope* scope);
988
nextFrameSlot()989 uint32_t nextFrameSlot() const { return data().slotInfo.nextFrameSlot; }
990
strict()991 bool strict() const { return kind() == ScopeKind::StrictEval; }
992
hasBindings()993 bool hasBindings() const { return data().length > 0; }
994
isNonGlobal()995 bool isNonGlobal() const {
996 if (strict()) {
997 return true;
998 }
999 return !nearestVarScopeForDirectEval(enclosing())->is<GlobalScope>();
1000 }
1001 };
1002
1003 template <>
1004 inline bool Scope::is<EvalScope>() const {
1005 return kind_ == ScopeKind::Eval || kind_ == ScopeKind::StrictEval;
1006 }
1007
1008 //
1009 // Scope corresponding to the toplevel script in an ES module.
1010 //
1011 // Like GlobalScopes, these scopes contain both vars and lexical bindings, as
1012 // the treating of imports and exports requires putting them in one scope.
1013 //
1014 // Corresponds to a ModuleEnvironmentObject on the environment chain.
1015 //
1016 class ModuleScope : public Scope {
1017 friend class GCMarker;
1018 friend class AbstractBindingIter<JSAtom>;
1019 friend class Scope;
1020 friend class AbstractScopePtr;
1021 friend class frontend::ScopeStencil;
1022 static const ScopeKind classScopeKind_ = ScopeKind::Module;
1023
1024 public:
1025 struct SlotInfo {
1026 // Frame slots [0, nextFrameSlot) are live when this is the innermost
1027 // scope.
1028 uint32_t nextFrameSlot = 0;
1029
1030 // Bindings are sorted by kind.
1031 //
1032 // imports - [0, varStart)
1033 // vars - [varStart, letStart)
1034 // lets - [letStart, constStart)
1035 // consts - [constStart, length)
1036 uint32_t varStart = 0;
1037 uint32_t letStart = 0;
1038 uint32_t constStart = 0;
1039 };
1040
alignas(ScopeDataAlignBytes)1041 struct alignas(ScopeDataAlignBytes) RuntimeData
1042 : public AbstractBaseScopeData<JSAtom> {
1043 SlotInfo slotInfo;
1044 // The module of the scope.
1045 HeapPtr<ModuleObject*> module = {};
1046
1047 explicit RuntimeData(size_t length);
1048 RuntimeData() = delete;
1049
1050 void trace(JSTracer* trc);
1051 };
1052
1053 using ParserData = ParserScopeData<SlotInfo>;
1054
1055 template <typename NameT>
1056 using AbstractData =
1057 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
1058 RuntimeData, ParserData>;
1059
1060 private:
1061 static ModuleScope* createWithData(JSContext* cx,
1062 MutableHandle<UniquePtr<RuntimeData>> data,
1063 Handle<ModuleObject*> module,
1064 HandleScope enclosing);
1065 template <typename AtomT, typename ShapeT>
1066 static bool prepareForScopeCreation(
1067 JSContext* cx,
1068 typename MaybeRootedScopeData<ModuleScope, AtomT>::MutableHandleType data,
1069 HandleModuleObject module, ShapeT envShape);
1070
data()1071 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
1072
data()1073 const RuntimeData& data() const {
1074 return *static_cast<const RuntimeData*>(rawData());
1075 }
1076
1077 public:
nextFrameSlot()1078 uint32_t nextFrameSlot() const { return data().slotInfo.nextFrameSlot; }
1079
module()1080 ModuleObject* module() const { return data().module; }
initModule(ModuleObject * mod)1081 void initModule(ModuleObject* mod) { return data().module.init(mod); }
1082
1083 // Off-thread compilation needs to calculate environmentChainLength for
1084 // an emptyGlobalScope where the global may not be available.
1085 static const size_t EnclosingEnvironmentChainLength = 1;
1086 };
1087
1088 class WasmInstanceScope : public Scope {
1089 friend class AbstractBindingIter<JSAtom>;
1090 friend class Scope;
1091 friend class GCMarker;
1092 friend class AbstractScopePtr;
1093 static const ScopeKind classScopeKind_ = ScopeKind::WasmInstance;
1094
1095 public:
1096 struct SlotInfo {
1097 // Frame slots [0, nextFrameSlot) are live when this is the innermost
1098 // scope.
1099 uint32_t nextFrameSlot = 0;
1100
1101 // Bindings list the WASM memories and globals.
1102 //
1103 // memories - [0, globalsStart)
1104 // globals - [globalsStart, length)
1105 uint32_t globalsStart = 0;
1106 };
1107
alignas(ScopeDataAlignBytes)1108 struct alignas(ScopeDataAlignBytes) RuntimeData
1109 : public AbstractBaseScopeData<JSAtom> {
1110 SlotInfo slotInfo;
1111 // The wasm instance of the scope.
1112 HeapPtr<WasmInstanceObject*> instance = {};
1113
1114 explicit RuntimeData(size_t length);
1115 RuntimeData() = delete;
1116
1117 void trace(JSTracer* trc);
1118 };
1119
1120 using ParserData = ParserScopeData<SlotInfo>;
1121
1122 template <typename NameT>
1123 using AbstractData =
1124 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
1125 RuntimeData, ParserData>;
1126
1127 static WasmInstanceScope* create(JSContext* cx, WasmInstanceObject* instance);
1128
1129 private:
data()1130 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
1131
data()1132 const RuntimeData& data() const {
1133 return *static_cast<const RuntimeData*>(rawData());
1134 }
1135
1136 public:
instance()1137 WasmInstanceObject* instance() const { return data().instance; }
1138
memoriesStart()1139 uint32_t memoriesStart() const { return 0; }
1140
globalsStart()1141 uint32_t globalsStart() const { return data().slotInfo.globalsStart; }
1142
namesCount()1143 uint32_t namesCount() const { return data().length; }
1144 };
1145
1146 // Scope corresponding to the wasm function. A WasmFunctionScope is used by
1147 // Debugger only, and not for wasm execution.
1148 //
1149 class WasmFunctionScope : public Scope {
1150 friend class AbstractBindingIter<JSAtom>;
1151 friend class Scope;
1152 friend class GCMarker;
1153 friend class AbstractScopePtr;
1154 static const ScopeKind classScopeKind_ = ScopeKind::WasmFunction;
1155
1156 public:
1157 struct SlotInfo {
1158 // Frame slots [0, nextFrameSlot) are live when this is the innermost
1159 // scope.
1160 uint32_t nextFrameSlot = 0;
1161
1162 // Bindings are the local variable names.
1163 //
1164 // vars - [0, length)
1165 };
1166
1167 using RuntimeData = RuntimeScopeData<SlotInfo>;
1168 using ParserData = ParserScopeData<SlotInfo>;
1169
1170 template <typename NameT>
1171 using AbstractData =
1172 typename std::conditional_t<std::is_same<NameT, JSAtom>::value,
1173 RuntimeData, ParserData>;
1174
1175 static WasmFunctionScope* create(JSContext* cx, HandleScope enclosing,
1176 uint32_t funcIndex);
1177
1178 private:
data()1179 RuntimeData& data() { return *static_cast<RuntimeData*>(rawData()); }
1180
data()1181 const RuntimeData& data() const {
1182 return *static_cast<const RuntimeData*>(rawData());
1183 }
1184 };
1185
1186 template <typename F>
applyScopeDataTyped(F && f)1187 void Scope::applyScopeDataTyped(F&& f) {
1188 switch (kind()) {
1189 case ScopeKind::Function: {
1190 f(&as<FunctionScope>().data());
1191 break;
1192 case ScopeKind::FunctionBodyVar:
1193 f(&as<VarScope>().data());
1194 break;
1195 case ScopeKind::Lexical:
1196 case ScopeKind::SimpleCatch:
1197 case ScopeKind::Catch:
1198 case ScopeKind::NamedLambda:
1199 case ScopeKind::StrictNamedLambda:
1200 case ScopeKind::FunctionLexical:
1201 f(&as<LexicalScope>().data());
1202 break;
1203 case ScopeKind::ClassBody:
1204 f(&as<ClassBodyScope>().data());
1205 break;
1206 case ScopeKind::With:
1207 // With scopes do not have data.
1208 break;
1209 case ScopeKind::Eval:
1210 case ScopeKind::StrictEval:
1211 f(&as<EvalScope>().data());
1212 break;
1213 case ScopeKind::Global:
1214 case ScopeKind::NonSyntactic:
1215 f(&as<GlobalScope>().data());
1216 break;
1217 case ScopeKind::Module:
1218 f(&as<ModuleScope>().data());
1219 break;
1220 case ScopeKind::WasmInstance:
1221 f(&as<WasmInstanceScope>().data());
1222 break;
1223 case ScopeKind::WasmFunction:
1224 f(&as<WasmFunctionScope>().data());
1225 break;
1226 }
1227 }
1228 }
1229
1230 //
1231 // An iterator for a Scope's bindings. This is the source of truth for frame
1232 // and environment object layout.
1233 //
1234 // It may be placed in GC containers; for example:
1235 //
1236 // for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
1237 // use(bi);
1238 // SomeMayGCOperation();
1239 // use(bi);
1240 // }
1241 //
1242 template <typename NameT>
1243 class BaseAbstractBindingIter {
1244 protected:
1245 // Bindings are sorted by kind. Because different Scopes have differently
1246 // laid out {Runtime,Parser}Data for packing, BindingIter must handle all
1247 // binding kinds.
1248 //
1249 // Kind ranges:
1250 //
1251 // imports - [0, positionalFormalStart)
1252 // positional formals - [positionalFormalStart, nonPositionalFormalStart)
1253 // other formals - [nonPositionalParamStart, varStart)
1254 // vars - [varStart, letStart)
1255 // lets - [letStart, constStart)
1256 // consts - [constStart, syntheticStart)
1257 // synthetic - [syntheticStart, privateMethodStart)
1258 // private methods = [privateMethodStart, length)
1259 //
1260 // Access method when not closed over:
1261 //
1262 // imports - name
1263 // positional formals - argument slot
1264 // other formals - frame slot
1265 // vars - frame slot
1266 // lets - frame slot
1267 // consts - frame slot
1268 // synthetic - frame slot
1269 // private methods - frame slot
1270 //
1271 // Access method when closed over:
1272 //
1273 // imports - name
1274 // positional formals - environment slot or name
1275 // other formals - environment slot or name
1276 // vars - environment slot or name
1277 // lets - environment slot or name
1278 // consts - environment slot or name
1279 // synthetic - environment slot or name
1280 // private methods - environment slot or name
1281 MOZ_INIT_OUTSIDE_CTOR uint32_t positionalFormalStart_;
1282 MOZ_INIT_OUTSIDE_CTOR uint32_t nonPositionalFormalStart_;
1283 MOZ_INIT_OUTSIDE_CTOR uint32_t varStart_;
1284 MOZ_INIT_OUTSIDE_CTOR uint32_t letStart_;
1285 MOZ_INIT_OUTSIDE_CTOR uint32_t constStart_;
1286 MOZ_INIT_OUTSIDE_CTOR uint32_t syntheticStart_;
1287 MOZ_INIT_OUTSIDE_CTOR uint32_t privateMethodStart_;
1288 MOZ_INIT_OUTSIDE_CTOR uint32_t length_;
1289
1290 MOZ_INIT_OUTSIDE_CTOR uint32_t index_;
1291
1292 enum Flags : uint8_t {
1293 CannotHaveSlots = 0,
1294 CanHaveArgumentSlots = 1 << 0,
1295 CanHaveFrameSlots = 1 << 1,
1296 CanHaveEnvironmentSlots = 1 << 2,
1297
1298 // See comment in settle below.
1299 HasFormalParameterExprs = 1 << 3,
1300 IgnoreDestructuredFormalParameters = 1 << 4,
1301
1302 // Truly I hate named lambdas.
1303 IsNamedLambda = 1 << 5
1304 };
1305
1306 static const uint8_t CanHaveSlotsMask = 0x7;
1307
1308 MOZ_INIT_OUTSIDE_CTOR uint8_t flags_;
1309 MOZ_INIT_OUTSIDE_CTOR uint16_t argumentSlot_;
1310 MOZ_INIT_OUTSIDE_CTOR uint32_t frameSlot_;
1311 MOZ_INIT_OUTSIDE_CTOR uint32_t environmentSlot_;
1312
1313 MOZ_INIT_OUTSIDE_CTOR AbstractBindingName<NameT>* names_;
1314
init(uint32_t positionalFormalStart,uint32_t nonPositionalFormalStart,uint32_t varStart,uint32_t letStart,uint32_t constStart,uint32_t syntheticStart,uint32_t privateMethodStart,uint8_t flags,uint32_t firstFrameSlot,uint32_t firstEnvironmentSlot,mozilla::Span<AbstractBindingName<NameT>> names)1315 void init(uint32_t positionalFormalStart, uint32_t nonPositionalFormalStart,
1316 uint32_t varStart, uint32_t letStart, uint32_t constStart,
1317 uint32_t syntheticStart, uint32_t privateMethodStart, uint8_t flags,
1318 uint32_t firstFrameSlot, uint32_t firstEnvironmentSlot,
1319 mozilla::Span<AbstractBindingName<NameT>> names) {
1320 positionalFormalStart_ = positionalFormalStart;
1321 nonPositionalFormalStart_ = nonPositionalFormalStart;
1322 varStart_ = varStart;
1323 letStart_ = letStart;
1324 constStart_ = constStart;
1325 syntheticStart_ = syntheticStart;
1326 privateMethodStart_ = privateMethodStart;
1327 length_ = names.size();
1328
1329 index_ = 0;
1330 flags_ = flags;
1331 argumentSlot_ = 0;
1332 frameSlot_ = firstFrameSlot;
1333 environmentSlot_ = firstEnvironmentSlot;
1334 names_ = names.data();
1335
1336 settle();
1337 }
1338
1339 void init(LexicalScope::AbstractData<NameT>& data, uint32_t firstFrameSlot,
1340 uint8_t flags);
1341
1342 void init(ClassBodyScope::AbstractData<NameT>& data, uint32_t firstFrameSlot);
1343 void init(FunctionScope::AbstractData<NameT>& data, uint8_t flags);
1344
1345 void init(VarScope::AbstractData<NameT>& data, uint32_t firstFrameSlot);
1346 void init(GlobalScope::AbstractData<NameT>& data);
1347 void init(EvalScope::AbstractData<NameT>& data, bool strict);
1348 void init(ModuleScope::AbstractData<NameT>& data);
1349 void init(WasmInstanceScope::AbstractData<NameT>& data);
1350 void init(WasmFunctionScope::AbstractData<NameT>& data);
1351
hasFormalParameterExprs()1352 bool hasFormalParameterExprs() const {
1353 return flags_ & HasFormalParameterExprs;
1354 }
1355
ignoreDestructuredFormalParameters()1356 bool ignoreDestructuredFormalParameters() const {
1357 return flags_ & IgnoreDestructuredFormalParameters;
1358 }
1359
isNamedLambda()1360 bool isNamedLambda() const { return flags_ & IsNamedLambda; }
1361
increment()1362 void increment() {
1363 MOZ_ASSERT(!done());
1364 if (flags_ & CanHaveSlotsMask) {
1365 if (canHaveArgumentSlots()) {
1366 if (index_ < nonPositionalFormalStart_) {
1367 MOZ_ASSERT(index_ >= positionalFormalStart_);
1368 argumentSlot_++;
1369 }
1370 }
1371 if (closedOver()) {
1372 // Imports must not be given known slots. They are
1373 // indirect bindings.
1374 MOZ_ASSERT(kind() != BindingKind::Import);
1375 MOZ_ASSERT(canHaveEnvironmentSlots());
1376 environmentSlot_++;
1377 } else if (canHaveFrameSlots()) {
1378 // Usually positional formal parameters don't have frame
1379 // slots, except when there are parameter expressions, in
1380 // which case they act like lets.
1381 if (index_ >= nonPositionalFormalStart_ ||
1382 (hasFormalParameterExprs() && name())) {
1383 frameSlot_++;
1384 }
1385 }
1386 }
1387 index_++;
1388 }
1389
settle()1390 void settle() {
1391 if (ignoreDestructuredFormalParameters()) {
1392 while (!done() && !name()) {
1393 increment();
1394 }
1395 }
1396 }
1397
1398 BaseAbstractBindingIter() = default;
1399
1400 public:
BaseAbstractBindingIter(LexicalScope::AbstractData<NameT> & data,uint32_t firstFrameSlot,bool isNamedLambda)1401 BaseAbstractBindingIter(LexicalScope::AbstractData<NameT>& data,
1402 uint32_t firstFrameSlot, bool isNamedLambda) {
1403 init(data, firstFrameSlot, isNamedLambda ? IsNamedLambda : 0);
1404 }
1405
BaseAbstractBindingIter(ClassBodyScope::AbstractData<NameT> & data,uint32_t firstFrameSlot)1406 BaseAbstractBindingIter(ClassBodyScope::AbstractData<NameT>& data,
1407 uint32_t firstFrameSlot) {
1408 init(data, firstFrameSlot);
1409 }
1410
BaseAbstractBindingIter(FunctionScope::AbstractData<NameT> & data,bool hasParameterExprs)1411 BaseAbstractBindingIter(FunctionScope::AbstractData<NameT>& data,
1412 bool hasParameterExprs) {
1413 init(data, IgnoreDestructuredFormalParameters |
1414 (hasParameterExprs ? HasFormalParameterExprs : 0));
1415 }
1416
BaseAbstractBindingIter(VarScope::AbstractData<NameT> & data,uint32_t firstFrameSlot)1417 BaseAbstractBindingIter(VarScope::AbstractData<NameT>& data,
1418 uint32_t firstFrameSlot) {
1419 init(data, firstFrameSlot);
1420 }
1421
BaseAbstractBindingIter(GlobalScope::AbstractData<NameT> & data)1422 explicit BaseAbstractBindingIter(GlobalScope::AbstractData<NameT>& data) {
1423 init(data);
1424 }
1425
BaseAbstractBindingIter(ModuleScope::AbstractData<NameT> & data)1426 explicit BaseAbstractBindingIter(ModuleScope::AbstractData<NameT>& data) {
1427 init(data);
1428 }
1429
BaseAbstractBindingIter(WasmFunctionScope::AbstractData<NameT> & data)1430 explicit BaseAbstractBindingIter(
1431 WasmFunctionScope::AbstractData<NameT>& data) {
1432 init(data);
1433 }
1434
BaseAbstractBindingIter(EvalScope::AbstractData<NameT> & data,bool strict)1435 BaseAbstractBindingIter(EvalScope::AbstractData<NameT>& data, bool strict) {
1436 init(data, strict);
1437 }
1438
1439 MOZ_IMPLICIT BaseAbstractBindingIter(
1440 const BaseAbstractBindingIter<NameT>& bi) = default;
1441
done()1442 bool done() const { return index_ == length_; }
1443
1444 explicit operator bool() const { return !done(); }
1445
1446 void operator++(int) {
1447 increment();
1448 settle();
1449 }
1450
isLast()1451 bool isLast() const {
1452 MOZ_ASSERT(!done());
1453 return index_ + 1 == length_;
1454 }
1455
canHaveArgumentSlots()1456 bool canHaveArgumentSlots() const { return flags_ & CanHaveArgumentSlots; }
1457
canHaveFrameSlots()1458 bool canHaveFrameSlots() const { return flags_ & CanHaveFrameSlots; }
1459
canHaveEnvironmentSlots()1460 bool canHaveEnvironmentSlots() const {
1461 return flags_ & CanHaveEnvironmentSlots;
1462 }
1463
name()1464 typename AbstractBindingName<NameT>::NamePointerT name() const {
1465 MOZ_ASSERT(!done());
1466 return names_[index_].name();
1467 }
1468
closedOver()1469 bool closedOver() const {
1470 MOZ_ASSERT(!done());
1471 return names_[index_].closedOver();
1472 }
1473
location()1474 BindingLocation location() const {
1475 MOZ_ASSERT(!done());
1476 if (!(flags_ & CanHaveSlotsMask)) {
1477 return BindingLocation::Global();
1478 }
1479 if (index_ < positionalFormalStart_) {
1480 return BindingLocation::Import();
1481 }
1482 if (closedOver()) {
1483 MOZ_ASSERT(canHaveEnvironmentSlots());
1484 return BindingLocation::Environment(environmentSlot_);
1485 }
1486 if (index_ < nonPositionalFormalStart_ && canHaveArgumentSlots()) {
1487 return BindingLocation::Argument(argumentSlot_);
1488 }
1489 if (canHaveFrameSlots()) {
1490 return BindingLocation::Frame(frameSlot_);
1491 }
1492 MOZ_ASSERT(isNamedLambda());
1493 return BindingLocation::NamedLambdaCallee();
1494 }
1495
kind()1496 BindingKind kind() const {
1497 MOZ_ASSERT(!done());
1498 if (index_ < positionalFormalStart_) {
1499 return BindingKind::Import;
1500 }
1501 if (index_ < varStart_) {
1502 // When the parameter list has expressions, the parameters act
1503 // like lexical bindings and have TDZ.
1504 if (hasFormalParameterExprs()) {
1505 return BindingKind::Let;
1506 }
1507 return BindingKind::FormalParameter;
1508 }
1509 if (index_ < letStart_) {
1510 return BindingKind::Var;
1511 }
1512 if (index_ < constStart_) {
1513 return BindingKind::Let;
1514 }
1515 if (index_ < syntheticStart_) {
1516 return isNamedLambda() ? BindingKind::NamedLambdaCallee
1517 : BindingKind::Const;
1518 }
1519 if (index_ < privateMethodStart_) {
1520 return BindingKind::Synthetic;
1521 }
1522 return BindingKind::PrivateMethod;
1523 }
1524
nameLocation()1525 js::frontend::NameLocation nameLocation() const {
1526 using js::frontend::NameLocation;
1527
1528 BindingKind bindKind = kind();
1529 BindingLocation bl = location();
1530 switch (bl.kind()) {
1531 case BindingLocation::Kind::Global:
1532 return NameLocation::Global(bindKind);
1533 case BindingLocation::Kind::Argument:
1534 return NameLocation::ArgumentSlot(bl.argumentSlot());
1535 case BindingLocation::Kind::Frame:
1536 return NameLocation::FrameSlot(bindKind, bl.slot());
1537 case BindingLocation::Kind::Environment:
1538 return NameLocation::EnvironmentCoordinate(bindKind, 0, bl.slot());
1539 case BindingLocation::Kind::Import:
1540 return NameLocation::Import();
1541 case BindingLocation::Kind::NamedLambdaCallee:
1542 return NameLocation::NamedLambdaCallee();
1543 }
1544 MOZ_CRASH("Bad BindingKind");
1545 }
1546
isTopLevelFunction()1547 bool isTopLevelFunction() const {
1548 MOZ_ASSERT(!done());
1549 bool result = names_[index_].isTopLevelFunction();
1550 MOZ_ASSERT_IF(result, kind() == BindingKind::Var);
1551 return result;
1552 }
1553
hasArgumentSlot()1554 bool hasArgumentSlot() const {
1555 MOZ_ASSERT(!done());
1556 if (hasFormalParameterExprs()) {
1557 return false;
1558 }
1559 return index_ >= positionalFormalStart_ &&
1560 index_ < nonPositionalFormalStart_;
1561 }
1562
argumentSlot()1563 uint16_t argumentSlot() const {
1564 MOZ_ASSERT(canHaveArgumentSlots());
1565 return mozilla::AssertedCast<uint16_t>(index_);
1566 }
1567
nextFrameSlot()1568 uint32_t nextFrameSlot() const {
1569 MOZ_ASSERT(canHaveFrameSlots());
1570 return frameSlot_;
1571 }
1572
nextEnvironmentSlot()1573 uint32_t nextEnvironmentSlot() const {
1574 MOZ_ASSERT(canHaveEnvironmentSlots());
1575 return environmentSlot_;
1576 }
1577 };
1578
1579 template <typename NameT>
1580 class AbstractBindingIter;
1581
1582 template <>
1583 class AbstractBindingIter<JSAtom> : public BaseAbstractBindingIter<JSAtom> {
1584 using Base = BaseAbstractBindingIter<JSAtom>;
1585
1586 public:
1587 AbstractBindingIter(ScopeKind kind, BaseScopeData* data,
1588 uint32_t firstFrameSlot);
1589
1590 explicit AbstractBindingIter(Scope* scope);
1591 explicit AbstractBindingIter(JSScript* script);
1592
1593 using Base::Base;
1594
1595 void trace(JSTracer* trc);
1596 };
1597
1598 template <>
1599 class AbstractBindingIter<frontend::TaggedParserAtomIndex>
1600 : public BaseAbstractBindingIter<frontend::TaggedParserAtomIndex> {
1601 using Base = BaseAbstractBindingIter<frontend::TaggedParserAtomIndex>;
1602
1603 public:
1604 explicit AbstractBindingIter(const frontend::ScopeStencilRef& ref);
1605
1606 using Base::Base;
1607 };
1608
1609 void DumpBindings(JSContext* cx, Scope* scope);
1610 JSAtom* FrameSlotName(JSScript* script, jsbytecode* pc);
1611
1612 Shape* EmptyEnvironmentShape(JSContext* cx, const JSClass* cls,
1613 uint32_t numSlots, ObjectFlags objectFlags);
1614
1615 template <class T>
EmptyEnvironmentShape(JSContext * cx)1616 Shape* EmptyEnvironmentShape(JSContext* cx) {
1617 return EmptyEnvironmentShape(cx, &T::class_, T::RESERVED_SLOTS,
1618 T::OBJECT_FLAGS);
1619 }
1620
1621 //
1622 // A refinement BindingIter that only iterates over positional formal
1623 // parameters of a function.
1624 //
1625 class PositionalFormalParameterIter : public BindingIter {
settle()1626 void settle() {
1627 if (index_ >= nonPositionalFormalStart_) {
1628 index_ = length_;
1629 }
1630 }
1631
1632 public:
1633 explicit PositionalFormalParameterIter(Scope* scope);
1634 explicit PositionalFormalParameterIter(JSScript* script);
1635
1636 void operator++(int) {
1637 BindingIter::operator++(1);
1638 settle();
1639 }
1640
isDestructured()1641 bool isDestructured() const { return !name(); }
1642 };
1643
1644 //
1645 // Iterator for walking the scope chain.
1646 //
1647 // It may be placed in GC containers; for example:
1648 //
1649 // for (Rooted<ScopeIter> si(cx, ScopeIter(scope)); si; si++) {
1650 // use(si);
1651 // SomeMayGCOperation();
1652 // use(si);
1653 // }
1654 //
1655 class MOZ_STACK_CLASS ScopeIter {
1656 Scope* scope_;
1657
1658 public:
ScopeIter(Scope * scope)1659 explicit ScopeIter(Scope* scope) : scope_(scope) {}
1660
1661 explicit ScopeIter(JSScript* script);
1662
1663 explicit ScopeIter(const ScopeIter& si) = default;
1664
done()1665 bool done() const { return !scope_; }
1666
1667 explicit operator bool() const { return !done(); }
1668
1669 void operator++(int) {
1670 MOZ_ASSERT(!done());
1671 scope_ = scope_->enclosing();
1672 }
1673
scope()1674 Scope* scope() const {
1675 MOZ_ASSERT(!done());
1676 return scope_;
1677 }
1678
kind()1679 ScopeKind kind() const {
1680 MOZ_ASSERT(!done());
1681 return scope_->kind();
1682 }
1683
1684 // Returns the shape of the environment if it is known. It is possible to
1685 // hasSyntacticEnvironment and to have no known shape, e.g., eval.
environmentShape()1686 Shape* environmentShape() const { return scope()->environmentShape(); }
1687
1688 // Returns whether this scope has a syntactic environment (i.e., an
1689 // Environment that isn't a non-syntactic With or NonSyntacticVariables)
1690 // on the environment chain.
1691 bool hasSyntacticEnvironment() const;
1692
trace(JSTracer * trc)1693 void trace(JSTracer* trc) {
1694 if (scope_) {
1695 TraceRoot(trc, &scope_, "scope iter scope");
1696 }
1697 }
1698 };
1699
1700 //
1701 // Specializations of Rooted containers for the iterators.
1702 //
1703
1704 template <typename Wrapper>
1705 class WrappedPtrOperations<BindingIter, Wrapper> {
iter()1706 const BindingIter& iter() const {
1707 return static_cast<const Wrapper*>(this)->get();
1708 }
1709
1710 public:
done()1711 bool done() const { return iter().done(); }
1712 explicit operator bool() const { return !done(); }
isLast()1713 bool isLast() const { return iter().isLast(); }
canHaveArgumentSlots()1714 bool canHaveArgumentSlots() const { return iter().canHaveArgumentSlots(); }
canHaveFrameSlots()1715 bool canHaveFrameSlots() const { return iter().canHaveFrameSlots(); }
canHaveEnvironmentSlots()1716 bool canHaveEnvironmentSlots() const {
1717 return iter().canHaveEnvironmentSlots();
1718 }
name()1719 JSAtom* name() const { return iter().name(); }
closedOver()1720 bool closedOver() const { return iter().closedOver(); }
location()1721 BindingLocation location() const { return iter().location(); }
kind()1722 BindingKind kind() const { return iter().kind(); }
isTopLevelFunction()1723 bool isTopLevelFunction() const { return iter().isTopLevelFunction(); }
hasArgumentSlot()1724 bool hasArgumentSlot() const { return iter().hasArgumentSlot(); }
argumentSlot()1725 uint16_t argumentSlot() const { return iter().argumentSlot(); }
nextFrameSlot()1726 uint32_t nextFrameSlot() const { return iter().nextFrameSlot(); }
nextEnvironmentSlot()1727 uint32_t nextEnvironmentSlot() const { return iter().nextEnvironmentSlot(); }
1728 };
1729
1730 template <typename Wrapper>
1731 class MutableWrappedPtrOperations<BindingIter, Wrapper>
1732 : public WrappedPtrOperations<BindingIter, Wrapper> {
iter()1733 BindingIter& iter() { return static_cast<Wrapper*>(this)->get(); }
1734
1735 public:
1736 void operator++(int) { iter().operator++(1); }
1737 };
1738
1739 template <typename Wrapper>
1740 class WrappedPtrOperations<ScopeIter, Wrapper> {
iter()1741 const ScopeIter& iter() const {
1742 return static_cast<const Wrapper*>(this)->get();
1743 }
1744
1745 public:
done()1746 bool done() const { return iter().done(); }
1747 explicit operator bool() const { return !done(); }
scope()1748 Scope* scope() const { return iter().scope(); }
kind()1749 ScopeKind kind() const { return iter().kind(); }
environmentShape()1750 Shape* environmentShape() const { return iter().environmentShape(); }
hasSyntacticEnvironment()1751 bool hasSyntacticEnvironment() const {
1752 return iter().hasSyntacticEnvironment();
1753 }
1754 };
1755
1756 template <typename Wrapper>
1757 class MutableWrappedPtrOperations<ScopeIter, Wrapper>
1758 : public WrappedPtrOperations<ScopeIter, Wrapper> {
iter()1759 ScopeIter& iter() { return static_cast<Wrapper*>(this)->get(); }
1760
1761 public:
1762 void operator++(int) { iter().operator++(1); }
1763 };
1764
1765 Shape* CreateEnvironmentShape(JSContext* cx, BindingIter& bi,
1766 const JSClass* cls, uint32_t numSlots,
1767 ObjectFlags objectFlags);
1768
1769 Shape* CreateEnvironmentShape(
1770 JSContext* cx, frontend::CompilationAtomCache& atomCache,
1771 AbstractBindingIter<frontend::TaggedParserAtomIndex>& bi,
1772 const JSClass* cls, uint32_t numSlots, ObjectFlags objectFlags);
1773
1774 Shape* EmptyEnvironmentShape(JSContext* cx, const JSClass* cls,
1775 uint32_t numSlots, ObjectFlags objectFlags);
1776
GetOffsetOfParserScopeDataTrailingNames(ScopeKind kind)1777 static inline size_t GetOffsetOfParserScopeDataTrailingNames(ScopeKind kind) {
1778 switch (kind) {
1779 // FunctionScope
1780 case ScopeKind::Function:
1781 return GetOffsetOfScopeDataTrailingNames<FunctionScope::ParserData>();
1782
1783 // VarScope
1784 case ScopeKind::FunctionBodyVar:
1785 return GetOffsetOfScopeDataTrailingNames<VarScope::ParserData>();
1786
1787 // LexicalScope
1788 case ScopeKind::Lexical:
1789 case ScopeKind::SimpleCatch:
1790 case ScopeKind::Catch:
1791 case ScopeKind::NamedLambda:
1792 case ScopeKind::StrictNamedLambda:
1793 case ScopeKind::FunctionLexical:
1794 return GetOffsetOfScopeDataTrailingNames<LexicalScope::ParserData>();
1795
1796 // ClassBodyScope
1797 case ScopeKind::ClassBody:
1798 return GetOffsetOfScopeDataTrailingNames<ClassBodyScope::ParserData>();
1799
1800 // EvalScope
1801 case ScopeKind::Eval:
1802 case ScopeKind::StrictEval:
1803 return GetOffsetOfScopeDataTrailingNames<EvalScope::ParserData>();
1804
1805 // GlobalScope
1806 case ScopeKind::Global:
1807 case ScopeKind::NonSyntactic:
1808 return GetOffsetOfScopeDataTrailingNames<GlobalScope::ParserData>();
1809
1810 // ModuleScope
1811 case ScopeKind::Module:
1812 return GetOffsetOfScopeDataTrailingNames<ModuleScope::ParserData>();
1813
1814 // WasmInstanceScope
1815 case ScopeKind::WasmInstance:
1816 return GetOffsetOfScopeDataTrailingNames<WasmInstanceScope::ParserData>();
1817
1818 // WasmFunctionScope
1819 case ScopeKind::WasmFunction:
1820 return GetOffsetOfScopeDataTrailingNames<WasmFunctionScope::ParserData>();
1821
1822 // WithScope doesn't have ScopeData.
1823 case ScopeKind::With:
1824 default:
1825 MOZ_CRASH("Unexpected ScopeKind");
1826 }
1827
1828 return 0;
1829 }
1830
SizeOfParserScopeData(ScopeKind kind,uint32_t length)1831 inline size_t SizeOfParserScopeData(ScopeKind kind, uint32_t length) {
1832 return GetOffsetOfParserScopeDataTrailingNames(kind) +
1833 sizeof(AbstractBindingName<frontend::TaggedParserAtomIndex>) * length;
1834 }
1835
1836 inline mozilla::Span<AbstractBindingName<frontend::TaggedParserAtomIndex>>
GetParserScopeDataTrailingNames(ScopeKind kind,AbstractBaseScopeData<frontend::TaggedParserAtomIndex> * data)1837 GetParserScopeDataTrailingNames(
1838 ScopeKind kind,
1839 AbstractBaseScopeData<frontend::TaggedParserAtomIndex>* data) {
1840 return mozilla::Span(
1841 reinterpret_cast<AbstractBindingName<frontend::TaggedParserAtomIndex>*>(
1842 uintptr_t(data) + GetOffsetOfParserScopeDataTrailingNames(kind)),
1843 data->length);
1844 }
1845
1846 } // namespace js
1847
1848 namespace JS {
1849
1850 template <>
1851 struct GCPolicy<js::ScopeKind> : public IgnoreGCPolicy<js::ScopeKind> {};
1852
1853 template <typename T>
1854 struct ScopeDataGCPolicy : public NonGCPointerPolicy<T> {};
1855
1856 #define DEFINE_SCOPE_DATA_GCPOLICY(Data) \
1857 template <> \
1858 struct MapTypeToRootKind<Data*> { \
1859 static const RootKind kind = RootKind::Traceable; \
1860 }; \
1861 template <> \
1862 struct GCPolicy<Data*> : public ScopeDataGCPolicy<Data*> {}
1863
1864 DEFINE_SCOPE_DATA_GCPOLICY(js::LexicalScope::RuntimeData);
1865 DEFINE_SCOPE_DATA_GCPOLICY(js::ClassBodyScope::RuntimeData);
1866 DEFINE_SCOPE_DATA_GCPOLICY(js::FunctionScope::RuntimeData);
1867 DEFINE_SCOPE_DATA_GCPOLICY(js::VarScope::RuntimeData);
1868 DEFINE_SCOPE_DATA_GCPOLICY(js::GlobalScope::RuntimeData);
1869 DEFINE_SCOPE_DATA_GCPOLICY(js::EvalScope::RuntimeData);
1870 DEFINE_SCOPE_DATA_GCPOLICY(js::ModuleScope::RuntimeData);
1871 DEFINE_SCOPE_DATA_GCPOLICY(js::WasmFunctionScope::RuntimeData);
1872
1873 #undef DEFINE_SCOPE_DATA_GCPOLICY
1874
1875 namespace ubi {
1876
1877 template <>
1878 class Concrete<js::Scope> : TracerConcrete<js::Scope> {
1879 protected:
1880 explicit Concrete(js::Scope* ptr) : TracerConcrete<js::Scope>(ptr) {}
1881
1882 public:
1883 static void construct(void* storage, js::Scope* ptr) {
1884 new (storage) Concrete(ptr);
1885 }
1886
1887 CoarseType coarseType() const final { return CoarseType::Script; }
1888
1889 Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
1890
1891 const char16_t* typeName() const override { return concreteTypeName; }
1892 static const char16_t concreteTypeName[];
1893 };
1894
1895 } // namespace ubi
1896 } // namespace JS
1897
1898 #endif // vm_Scope_h
1899