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