Stencil.h (46222B)
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 frontend_Stencil_h 8 #define frontend_Stencil_h 9 10 #include "mozilla/Assertions.h" // MOZ_ASSERT 11 #include "mozilla/Maybe.h" // mozilla::{Maybe, Nothing} 12 #include "mozilla/MemoryReporting.h" // mozilla::MallocSizeOf 13 #include "mozilla/Span.h" // mozilla::Span 14 #include "mozilla/Variant.h" // mozilla::Variant 15 16 #include <stddef.h> // size_t 17 #include <stdint.h> // char16_t, uint8_t, uint16_t, uint32_t 18 19 #include "frontend/AbstractScopePtr.h" // AbstractScopePtr, ScopeIndex 20 #include "frontend/ObjLiteral.h" // ObjLiteralStencil 21 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex 22 #include "frontend/ScriptIndex.h" // ScriptIndex 23 #include "frontend/TaggedParserAtomIndexHasher.h" // frontend::TaggedParserAtomIndexHasher 24 #include "frontend/TypedIndex.h" // TypedIndex 25 #include "js/AllocPolicy.h" // SystemAllocPolicy 26 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin 27 #include "js/RefCounted.h" // AtomicRefCounted 28 #include "js/RegExpFlags.h" // JS::RegExpFlags 29 #include "js/RootingAPI.h" // Handle 30 #include "js/TypeDecls.h" // JSContext 31 #include "js/UniquePtr.h" // js::UniquePtr 32 #include "js/Utility.h" // UniqueTwoByteChars 33 #include "js/Vector.h" // js::Vector 34 #include "vm/FunctionFlags.h" // FunctionFlags 35 #include "vm/Scope.h" // Scope, BaseScopeData, FunctionScope, LexicalScope, VarScope, GlobalScope, EvalScope, ModuleScope 36 #include "vm/ScopeKind.h" // ScopeKind 37 #include "vm/SharedStencil.h" // ImmutableScriptFlags, GCThingIndex, js::SharedImmutableScriptData, MemberInitializers, SourceExtent 38 39 namespace js { 40 41 class LifoAlloc; 42 class JSONPrinter; 43 class RegExpObject; 44 45 namespace frontend { 46 47 struct CompilationInput; 48 struct CompilationStencil; 49 struct CompilationAtomCache; 50 struct CompilationGCOutput; 51 struct CompilationStencilMerger; 52 class RegExpStencil; 53 class BigIntStencil; 54 class StencilXDR; 55 56 using BaseParserScopeData = AbstractBaseScopeData<TaggedParserAtomIndex>; 57 using ParserBindingName = AbstractBindingName<TaggedParserAtomIndex>; 58 59 template <typename Scope> 60 using ParserScopeSlotInfo = typename Scope::SlotInfo; 61 using ParserGlobalScopeSlotInfo = ParserScopeSlotInfo<GlobalScope>; 62 using ParserEvalScopeSlotInfo = ParserScopeSlotInfo<EvalScope>; 63 using ParserLexicalScopeSlotInfo = ParserScopeSlotInfo<LexicalScope>; 64 using ParserClassBodyScopeSlotInfo = ParserScopeSlotInfo<ClassBodyScope>; 65 using ParserFunctionScopeSlotInfo = ParserScopeSlotInfo<FunctionScope>; 66 using ParserModuleScopeSlotInfo = ParserScopeSlotInfo<ModuleScope>; 67 using ParserVarScopeSlotInfo = ParserScopeSlotInfo<VarScope>; 68 69 using ParserBindingIter = AbstractBindingIter<TaggedParserAtomIndex>; 70 using ParserPositionalFormalParameterIter = 71 AbstractPositionalFormalParameterIter<TaggedParserAtomIndex>; 72 73 // [SMDOC] Script Stencil (Frontend Representation) 74 // 75 // Stencils are the set of data structures capturing the result of parsing and 76 // bytecode emission. The Stencil format is a precursor format that is then used 77 // to allocate the corresponding scripts on the GC heap that will be used for 78 // execution. By decoupling from the GC and other runtime systems, robust 79 // caching and speculation systems can be built that are more thread-agnostic 80 // and flexible. 81 // 82 // See: https://bugzil.la/stencil 83 // 84 // There are numerous data structures that make up the Stencil format. The 85 // structures are designed for fast serialization to and from disk by preferring 86 // indices over pointers and vectors instead of graphs to allow bulk operations. 87 // 88 // 89 // ParserAtom 90 // ---------- 91 // Our parser relies on atomized strings as part of its normal operations and so 92 // a `ParserAtom` type exists that mirrors the `JSAtom` type but does not 93 // involve the garbage collector. This is possible because the lifetime of these 94 // ParserAtoms is the lifetime of the Stencil that makes use of them and we do 95 // not need finer grained collection. 96 // 97 // 98 // ScriptStencil 99 // ------------- 100 // The key structures generated by parsing are instances of `ScriptStencil`. 101 // There is a `ScriptStencil` for the top-level script and for each inner 102 // function. It contains information needed to create the `JSFunction` (if it is 103 // a function) and the `BaseScript` (if not asm.js) and may or may not have 104 // bytecode. Each `ScriptStencil` may also reference the following Stencil types 105 // (similar to the `BaseScript::gcthings()` list): 106 // 107 // * ParserAtom 108 // * ScopeStencil 109 // * RegExpStencil 110 // * BigIntStencil 111 // * ObjLiteralStencil 112 // * StencilModuleMetadata 113 // 114 // 115 // CompilationStencil / ExtensibleCompilationStencil 116 // ------------------------------------------------- 117 // Parsing a single JavaScript file may generate a tree of `ScriptStencil` that 118 // we then package up into the `ExtensibleCompilationStencil` type or 119 // `CompilationStencil`. They contain a series of vectors/spans segregated by 120 // data type for fast processing (a.k.a Data Oriented Design). 121 // 122 // `ExtensibleCompilationStencil` is mutable type used during parsing, and 123 // can be allocated either on stack or heap. 124 // `ExtensibleCompilationStencil` holds vectors of stencils. 125 // 126 // `CompilationStencil` is immutable type used for caching the compilation 127 // result, and is allocated on heap with refcount. 128 // `CompilationStencil` holds spans of stencils, and it can point either 129 // owned data or borrowed data. 130 // The borrowed data can be from other `ExtensibleCompilationStencil` or 131 // from serialized stencil (XDR) on memory or mmap. 132 // 133 // Delazifying a function will generate its bytecode but some fields remain 134 // unchanged from the initial lazy parse. 135 // When we delazify a function that was lazily parsed, we generate a new 136 // Stencil at the point too. These delazifications can be merged into the 137 // Stencil of the initial parse by using `CompilationStencilMerger`. 138 // 139 // Conversion from ExtensibleCompilationStencil to CompilationStencil 140 // ------------------------------------------------------------------ 141 // There are multiple ways to convert from `ExtensibleCompilationStencil` to 142 // `CompilationStencil`: 143 // 144 // 1. Temporarily borrow `ExtensibleCompilationStencil` content and call 145 // function that takes `CompilationStencil` reference, and keep using the 146 // `ExtensibleCompilationStencil` after that: 147 // 148 // ExtensibleCompilationStencil extensible = ...; 149 // { 150 // BorrowingCompilationStencil stencil(extensible); 151 // // Use `stencil reference. 152 // } 153 // 154 // 2. Take the ownership of an on-heap ExtensibleCompilationStencil. This makes 155 // the `CompilationStencil` self-contained and it's useful for caching: 156 // 157 // UniquePtr<ExtensibleCompilationStencil> extensible = ...; 158 // CompilationStencil stencil(std::move(extensible)); 159 // 160 // Conversion from CompilationStencil to ExtensibleCompilationStencil 161 // ------------------------------------------------------------------ 162 // In the same way, there are multiple ways to convert from 163 // `CompilationStencil` to `ExtensibleCompilationStencil`: 164 // 165 // 1. Take the ownership of `CompilationStencil`'s underlying data, Only when 166 // stencil owns the data and the refcount is 1: 167 // 168 // RefPtr<CompilationStencil> stencil = ...; 169 // ExtensibleCompilationStencil extensible(...); 170 // // NOTE: This is equivalent to cloneFrom below if `stencil` has refcount 171 // // more than 2, or it doesn't own the data. 172 // extensible.steal(fc, std::move(stencil)); 173 // 174 // 2. Clone the underlying data. This is slow but safe operation: 175 // 176 // CompilationStencil stencil = ...; 177 // ExtensibleCompilationStencil extensible(...); 178 // extensible.cloneFrom(fc, stencil); 179 // 180 // 3. Take the ownership back from the `CompilationStencil` which is created by 181 // taking the ownership of an on-heap `ExtensibleCompilationStencil`: 182 // 183 // CompilationStencil stencil = ...; 184 // ExtensibleCompilationStencil* extensible = stencil.takeOwnedBorrow(); 185 // 186 // CompilationGCOutput 187 // ------------------- 188 // When a Stencil is instantiated the equivalent script objects are allocated on 189 // the GC heap and their pointers are collected into the `CompilationGCOutput` 190 // structure. This is only used temporarily during instantiation. 191 // 192 // 193 // CompilationState 194 // ---------------- 195 // This is another temporary structure used by the parser while the Stencil is 196 // being generated. Once the `CompilationStencil` is complete, this can be 197 // released. 198 199 // Typed indices for the different stencil elements in the compilation result. 200 using RegExpIndex = TypedIndex<RegExpStencil>; 201 using BigIntIndex = TypedIndex<BigIntStencil>; 202 using ObjLiteralIndex = TypedIndex<ObjLiteralStencil>; 203 204 // Index into {ExtensibleCompilationStencil,CompilationStencil}.gcThingData. 205 class CompilationGCThingType {}; 206 using CompilationGCThingIndex = TypedIndex<CompilationGCThingType>; 207 208 // A syntax-checked regular expression string. 209 class RegExpStencil { 210 friend class StencilXDR; 211 212 TaggedParserAtomIndex atom_; 213 // Use uint32_t to make this struct fully-packed. 214 uint32_t flags_; 215 216 friend struct CompilationStencilMerger; 217 218 public: 219 RegExpStencil() = default; 220 221 RegExpStencil(TaggedParserAtomIndex atom, JS::RegExpFlags flags) 222 : atom_(atom), flags_(flags.value()) {} 223 224 JS::RegExpFlags flags() const { return JS::RegExpFlags(flags_); } 225 226 RegExpObject* createRegExp(JSContext* cx, 227 const CompilationAtomCache& atomCache) const; 228 229 // This is used by `Reflect.parse` when we need the RegExpObject but are not 230 // doing a complete instantiation of the CompilationStencil. 231 RegExpObject* createRegExpAndEnsureAtom( 232 JSContext* cx, FrontendContext* fc, ParserAtomsTable& parserAtoms, 233 CompilationAtomCache& atomCache) const; 234 235 #if defined(DEBUG) || defined(JS_JITSPEW) 236 void dump() const; 237 void dump(JSONPrinter& json, const CompilationStencil* stencil) const; 238 void dumpFields(JSONPrinter& json, const CompilationStencil* stencil) const; 239 #endif 240 }; 241 242 // This owns a set of characters guaranteed to parse into a BigInt via 243 // ParseBigIntLiteral. Used to avoid allocating the BigInt on the 244 // GC heap during parsing. 245 class BigIntStencil { 246 friend class StencilXDR; 247 248 // Source of the BigInt literal. 249 // It's not null-terminated, and also trailing 'n' suffix is not included. 250 // 251 // Int64-sized BigInt values are directly stored inline as int64_t. 252 mozilla::Variant<mozilla::Span<char16_t>, int64_t> bigInt_{int64_t{}}; 253 254 // Methods used by XDR. 255 mozilla::Span<char16_t>& source() { 256 if (bigInt_.is<int64_t>()) { 257 bigInt_ = mozilla::AsVariant(mozilla::Span<char16_t>{}); 258 } 259 return bigInt_.as<mozilla::Span<char16_t>>(); 260 } 261 const mozilla::Span<char16_t>& source() const { 262 return bigInt_.as<mozilla::Span<char16_t>>(); 263 } 264 265 [[nodiscard]] bool initFromChars(FrontendContext* fc, LifoAlloc& alloc, 266 mozilla::Span<const char16_t> buf); 267 268 public: 269 BigIntStencil() = default; 270 271 [[nodiscard]] bool init(FrontendContext* fc, LifoAlloc& alloc, 272 mozilla::Span<const char16_t> buf); 273 274 [[nodiscard]] bool init(FrontendContext* fc, LifoAlloc& alloc, 275 const BigIntStencil& other); 276 277 BigInt* createBigInt(JSContext* cx) const; 278 279 // Methods used by constant-folding. 280 bool isZero() const; 281 bool inplaceNegate(); 282 bool inplaceBitNot(); 283 284 #ifdef DEBUG 285 bool isContainedIn(const LifoAlloc& alloc) const; 286 #endif 287 288 #if defined(DEBUG) || defined(JS_JITSPEW) 289 void dump() const; 290 void dump(JSONPrinter& json) const; 291 void dumpCharsNoQuote(GenericPrinter& out) const; 292 #endif 293 }; 294 295 using BigIntStencilVector = Vector<BigIntStencil, 0, js::SystemAllocPolicy>; 296 297 class ScopeStencil { 298 friend class StencilXDR; 299 friend struct ScopeStencilRef; 300 friend class InputScope; 301 friend class AbstractBindingIter<frontend::TaggedParserAtomIndex>; 302 friend struct CompilationStencil; 303 friend struct CompilationStencilMerger; 304 305 // The enclosing scope. Valid only if HasEnclosing flag is set. 306 // compilation applies. 307 ScopeIndex enclosing_; 308 309 // First frame slot to use, or LOCALNO_LIMIT if none are allowed. 310 uint32_t firstFrameSlot_ = UINT32_MAX; 311 312 // The number of environment shape's slots. Valid only if 313 // HasEnvironmentShape flag is set. 314 uint32_t numEnvironmentSlots_; 315 316 // Canonical function if this is a FunctionScope. Valid only if 317 // kind_ is ScopeKind::Function. 318 ScriptIndex functionIndex_; 319 320 // The kind determines the corresponding BaseParserScopeData. 321 ScopeKind kind_{UINT8_MAX}; 322 323 // True if this scope has enclosing scope stencil. Otherwise, the enclosing 324 // scope will be read from CompilationInput while instantiating. Self-hosting 325 // is a special case and will use `emptyGlobalScope` when there is no 326 // enclosing scope stencil. 327 static constexpr uint8_t HasEnclosing = 1 << 0; 328 329 // If true, an environment Shape must be created. The shape itself may 330 // have no slots if the environment may be extensible later. 331 static constexpr uint8_t HasEnvironmentShape = 1 << 1; 332 333 // True if this is a FunctionScope for an arrow function. 334 static constexpr uint8_t IsArrow = 1 << 2; 335 336 uint8_t flags_ = 0; 337 338 // To make this struct packed, add explicit field for padding. 339 uint16_t padding_ = 0; 340 341 public: 342 // For XDR only. 343 ScopeStencil() = default; 344 345 ScopeStencil(ScopeKind kind, mozilla::Maybe<ScopeIndex> enclosing, 346 uint32_t firstFrameSlot, 347 mozilla::Maybe<uint32_t> numEnvironmentSlots, 348 mozilla::Maybe<ScriptIndex> functionIndex = mozilla::Nothing(), 349 bool isArrow = false) 350 : enclosing_(enclosing.valueOr(ScopeIndex(0))), 351 firstFrameSlot_(firstFrameSlot), 352 numEnvironmentSlots_(numEnvironmentSlots.valueOr(0)), 353 functionIndex_(functionIndex.valueOr(ScriptIndex(0))), 354 kind_(kind), 355 flags_((enclosing.isSome() ? HasEnclosing : 0) | 356 (numEnvironmentSlots.isSome() ? HasEnvironmentShape : 0) | 357 (isArrow ? IsArrow : 0)) { 358 MOZ_ASSERT((kind == ScopeKind::Function) == functionIndex.isSome()); 359 // Silence -Wunused-private-field warnings. 360 (void)padding_; 361 } 362 363 private: 364 // Create ScopeStencil with `args`, and append ScopeStencil and `data` to 365 // `compilationState`, and return the index of them as `indexOut`. 366 template <typename... Args> 367 static bool appendScopeStencilAndData(FrontendContext* fc, 368 CompilationState& compilationState, 369 BaseParserScopeData* data, 370 ScopeIndex* indexOut, Args&&... args); 371 372 public: 373 static bool createForFunctionScope( 374 FrontendContext* fc, CompilationState& compilationState, 375 FunctionScope::ParserData* dataArg, bool hasParameterExprs, 376 bool needsEnvironment, ScriptIndex functionIndex, bool isArrow, 377 mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index); 378 379 static bool createForLexicalScope( 380 FrontendContext* fc, CompilationState& compilationState, ScopeKind kind, 381 LexicalScope::ParserData* dataArg, uint32_t firstFrameSlot, 382 mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index); 383 384 static bool createForClassBodyScope( 385 FrontendContext* fc, CompilationState& compilationState, ScopeKind kind, 386 ClassBodyScope::ParserData* dataArg, uint32_t firstFrameSlot, 387 mozilla::Maybe<ScopeIndex> enclosing, ScopeIndex* index); 388 389 static bool createForVarScope(FrontendContext* fc, 390 CompilationState& compilationState, 391 ScopeKind kind, VarScope::ParserData* dataArg, 392 uint32_t firstFrameSlot, bool needsEnvironment, 393 mozilla::Maybe<ScopeIndex> enclosing, 394 ScopeIndex* index); 395 396 static bool createForGlobalScope(FrontendContext* fc, 397 CompilationState& compilationState, 398 ScopeKind kind, 399 GlobalScope::ParserData* dataArg, 400 ScopeIndex* index); 401 402 static bool createForEvalScope(FrontendContext* fc, 403 CompilationState& compilationState, 404 ScopeKind kind, EvalScope::ParserData* dataArg, 405 mozilla::Maybe<ScopeIndex> enclosing, 406 ScopeIndex* index); 407 408 static bool createForModuleScope(FrontendContext* fc, 409 CompilationState& compilationState, 410 ModuleScope::ParserData* dataArg, 411 mozilla::Maybe<ScopeIndex> enclosing, 412 ScopeIndex* index); 413 414 static bool createForWithScope(FrontendContext* fc, 415 CompilationState& compilationState, 416 mozilla::Maybe<ScopeIndex> enclosing, 417 ScopeIndex* index); 418 419 AbstractScopePtr enclosing(CompilationState& compilationState) const; 420 js::Scope* enclosingExistingScope(const CompilationInput& input, 421 const CompilationGCOutput& gcOutput) const; 422 423 private: 424 bool hasEnclosing() const { return flags_ & HasEnclosing; } 425 426 ScopeIndex enclosing() const { 427 MOZ_ASSERT(hasEnclosing()); 428 return enclosing_; 429 } 430 431 uint32_t firstFrameSlot() const { return firstFrameSlot_; } 432 433 bool hasEnvironmentShape() const { return flags_ & HasEnvironmentShape; } 434 435 uint32_t numEnvironmentSlots() const { 436 MOZ_ASSERT(hasEnvironmentShape()); 437 return numEnvironmentSlots_; 438 } 439 440 bool isFunction() const { return kind_ == ScopeKind::Function; } 441 442 ScriptIndex functionIndex() const { return functionIndex_; } 443 444 public: 445 ScopeKind kind() const { return kind_; } 446 447 bool hasEnvironment() const { 448 // Check if scope kind alone means we have an env shape, and 449 // otherwise check if we have one created. 450 return Scope::hasEnvironment(kind(), hasEnvironmentShape()); 451 } 452 453 bool isArrow() const { return flags_ & IsArrow; } 454 455 Scope* createScope(JSContext* cx, CompilationInput& input, 456 CompilationGCOutput& gcOutput, 457 BaseParserScopeData* baseScopeData) const; 458 Scope* createScope(JSContext* cx, CompilationAtomCache& atomCache, 459 Handle<Scope*> enclosingScope, 460 BaseParserScopeData* baseScopeData) const; 461 462 #if defined(DEBUG) || defined(JS_JITSPEW) 463 void dump() const; 464 void dump(JSONPrinter& json, const BaseParserScopeData* baseScopeData, 465 const CompilationStencil* stencil) const; 466 void dumpFields(JSONPrinter& json, const BaseParserScopeData* baseScopeData, 467 const CompilationStencil* stencil) const; 468 #endif 469 470 private: 471 // Transfer ownership into a new UniquePtr. 472 template <typename SpecificScopeType> 473 typename SpecificScopeType::RuntimeData* createSpecificScopeData( 474 JSContext* cx, CompilationAtomCache& atomCache, 475 BaseParserScopeData* baseData) const; 476 477 template <typename SpecificEnvironmentType> 478 [[nodiscard]] bool createSpecificShape( 479 JSContext* cx, ScopeKind kind, BaseScopeData* scopeData, 480 MutableHandle<SharedShape*> shape) const; 481 482 template <typename SpecificScopeType, typename SpecificEnvironmentType> 483 Scope* createSpecificScope(JSContext* cx, CompilationAtomCache& atomCache, 484 Handle<Scope*> enclosingScope, 485 BaseParserScopeData* baseData) const; 486 487 template <typename ScopeT> 488 static constexpr bool matchScopeKind(ScopeKind kind) { 489 switch (kind) { 490 case ScopeKind::Function: { 491 return std::is_same_v<ScopeT, FunctionScope>; 492 } 493 case ScopeKind::Lexical: 494 case ScopeKind::SimpleCatch: 495 case ScopeKind::Catch: 496 case ScopeKind::NamedLambda: 497 case ScopeKind::StrictNamedLambda: 498 case ScopeKind::FunctionLexical: { 499 return std::is_same_v<ScopeT, LexicalScope>; 500 } 501 case ScopeKind::ClassBody: { 502 return std::is_same_v<ScopeT, ClassBodyScope>; 503 } 504 case ScopeKind::FunctionBodyVar: { 505 return std::is_same_v<ScopeT, VarScope>; 506 } 507 case ScopeKind::Global: 508 case ScopeKind::NonSyntactic: { 509 return std::is_same_v<ScopeT, GlobalScope>; 510 } 511 case ScopeKind::Eval: 512 case ScopeKind::StrictEval: { 513 return std::is_same_v<ScopeT, EvalScope>; 514 } 515 case ScopeKind::Module: { 516 return std::is_same_v<ScopeT, ModuleScope>; 517 } 518 case ScopeKind::With: { 519 return std::is_same_v<ScopeT, WithScope>; 520 } 521 case ScopeKind::WasmFunction: 522 case ScopeKind::WasmInstance: { 523 return false; 524 } 525 } 526 return false; 527 } 528 }; 529 530 class StencilModuleImportAttribute { 531 public: 532 TaggedParserAtomIndex key; 533 TaggedParserAtomIndex value; 534 535 StencilModuleImportAttribute() = default; 536 StencilModuleImportAttribute(TaggedParserAtomIndex key, 537 TaggedParserAtomIndex value) 538 : key(key), value(value) {} 539 540 bool operator!=(const StencilModuleImportAttribute& rhs) const { 541 return key != rhs.key || value != rhs.value; 542 } 543 544 bool operator==(const StencilModuleImportAttribute& rhs) const { 545 return !(*this != rhs); 546 } 547 }; 548 549 class StencilModuleRequest { 550 public: 551 TaggedParserAtomIndex specifier; 552 TaggedParserAtomIndex firstUnsupportedAttributeKey; 553 554 using ImportAttributeVector = 555 Vector<StencilModuleImportAttribute, 0, js::SystemAllocPolicy>; 556 ImportAttributeVector attributes; 557 558 // For XDR only. 559 StencilModuleRequest() = default; 560 561 explicit StencilModuleRequest(TaggedParserAtomIndex specifier) 562 : specifier(specifier) { 563 MOZ_ASSERT(specifier); 564 } 565 566 StencilModuleRequest(const StencilModuleRequest& other) 567 : specifier(other.specifier), 568 firstUnsupportedAttributeKey(other.firstUnsupportedAttributeKey) { 569 AutoEnterOOMUnsafeRegion oomUnsafe; 570 if (!attributes.appendAll(other.attributes)) { 571 oomUnsafe.crash("StencilModuleRequest::StencilModuleRequest"); 572 } 573 } 574 575 StencilModuleRequest(StencilModuleRequest&& other) noexcept 576 : specifier(other.specifier), 577 firstUnsupportedAttributeKey(other.firstUnsupportedAttributeKey), 578 attributes(std::move(other.attributes)) {} 579 580 StencilModuleRequest& operator=(StencilModuleRequest& other) { 581 specifier = other.specifier; 582 firstUnsupportedAttributeKey = other.firstUnsupportedAttributeKey; 583 attributes = std::move(other.attributes); 584 return *this; 585 } 586 587 StencilModuleRequest& operator=(StencilModuleRequest&& other) noexcept { 588 specifier = other.specifier; 589 firstUnsupportedAttributeKey = other.firstUnsupportedAttributeKey; 590 attributes = std::move(other.attributes); 591 return *this; 592 } 593 594 bool operator==(const StencilModuleRequest& other) const { 595 size_t attrLen = attributes.length(); 596 if (specifier != other.specifier || 597 firstUnsupportedAttributeKey != other.firstUnsupportedAttributeKey || 598 attrLen != other.attributes.length()) { 599 return false; 600 } 601 602 for (size_t i = 0; i < attrLen; i++) { 603 if (attributes[i] != other.attributes[i]) { 604 return false; 605 } 606 } 607 608 return true; 609 } 610 611 bool operator!=(const StencilModuleRequest& other) const { 612 return !(*this == other); 613 } 614 }; 615 616 struct StencilModuleRequestHasher { 617 using Key = js::frontend::StencilModuleRequest; 618 using Lookup = Key; 619 620 static HashNumber hash(const Lookup& l) { 621 HashNumber hash = 0; 622 size_t attrLen = l.attributes.length(); 623 for (size_t i = 0; i < attrLen; i++) { 624 hash = mozilla::AddToHash( 625 hash, TaggedParserAtomIndexHasher::hash(l.attributes[i].key), 626 TaggedParserAtomIndexHasher::hash(l.attributes[i].value)); 627 } 628 return mozilla::AddToHash(hash, 629 TaggedParserAtomIndexHasher::hash(l.specifier)); 630 } 631 632 static bool match(const Key& k, const Lookup& l) { return k == l; } 633 }; 634 635 class MaybeModuleRequestIndex { 636 static constexpr uint32_t NOTHING = UINT32_MAX; 637 638 uint32_t bits = NOTHING; 639 640 public: 641 MaybeModuleRequestIndex() = default; 642 explicit MaybeModuleRequestIndex(uint32_t index) : bits(index) { 643 MOZ_ASSERT(isSome()); 644 } 645 646 MaybeModuleRequestIndex(const MaybeModuleRequestIndex& other) = default; 647 MaybeModuleRequestIndex& operator=(const MaybeModuleRequestIndex& other) = 648 default; 649 650 bool isNothing() const { return bits == NOTHING; } 651 bool isSome() const { return !isNothing(); } 652 explicit operator bool() const { return isSome(); } 653 654 uint32_t value() const { 655 MOZ_ASSERT(isSome()); 656 return bits; 657 } 658 659 uint32_t* operator&() { return &bits; } 660 }; 661 662 // Common type for ImportEntry / ExportEntry / ModuleRequest within frontend. We 663 // use a shared stencil class type to simplify serialization. 664 // 665 // https://tc39.es/ecma262/#importentry-record 666 // https://tc39.es/ecma262/#exportentry-record 667 // 668 // Note: We subdivide the spec's ExportEntry into ExportAs / ExportFrom forms 669 // for readability. 670 class StencilModuleEntry { 671 public: 672 // clang-format off 673 // 674 // | RequestedModule | ImportEntry | ImportNamespaceEntry | ExportAs | ExportFrom | ExportNamespaceFrom | ExportBatchFrom | 675 // |----------------------------------------------------------------------------------------------------------------------| 676 // moduleRequest | required | required | required | null | required | required | required | 677 // localName | null | required | required | required | null | null | null | 678 // importName | null | required | null | null | required | null | null | 679 // exportName | null | null | null | required | required | required | null | 680 // 681 // clang-format on 682 MaybeModuleRequestIndex moduleRequest; 683 TaggedParserAtomIndex localName; 684 TaggedParserAtomIndex importName; 685 TaggedParserAtomIndex exportName; 686 687 // Location used for error messages. If this is for a module request entry 688 // then it is the module specifier string, otherwise the import/export spec 689 // that failed. Exports may not fill these fields if an error cannot be 690 // generated such as `export let x;`. 691 692 // Line number (1-origin). 693 uint32_t lineno = 0; 694 695 // Column number in UTF-16 code units. 696 JS::ColumnNumberOneOrigin column; 697 698 private: 699 StencilModuleEntry(uint32_t lineno, JS::ColumnNumberOneOrigin column) 700 : lineno(lineno), column(column) {} 701 702 public: 703 // For XDR only. 704 StencilModuleEntry() = default; 705 706 StencilModuleEntry(const StencilModuleEntry& other) 707 : moduleRequest(other.moduleRequest), 708 localName(other.localName), 709 importName(other.importName), 710 exportName(other.exportName), 711 lineno(other.lineno), 712 column(other.column) {} 713 714 StencilModuleEntry(StencilModuleEntry&& other) noexcept 715 : moduleRequest(other.moduleRequest), 716 localName(other.localName), 717 importName(other.importName), 718 exportName(other.exportName), 719 lineno(other.lineno), 720 column(other.column) {} 721 722 StencilModuleEntry& operator=(StencilModuleEntry& other) { 723 moduleRequest = other.moduleRequest; 724 localName = other.localName; 725 importName = other.importName; 726 exportName = other.exportName; 727 lineno = other.lineno; 728 column = other.column; 729 return *this; 730 } 731 732 StencilModuleEntry& operator=(StencilModuleEntry&& other) noexcept { 733 moduleRequest = other.moduleRequest; 734 localName = other.localName; 735 importName = other.importName; 736 exportName = other.exportName; 737 lineno = other.lineno; 738 column = other.column; 739 return *this; 740 } 741 742 static StencilModuleEntry requestedModule( 743 MaybeModuleRequestIndex moduleRequest, uint32_t lineno, 744 JS::ColumnNumberOneOrigin column) { 745 MOZ_ASSERT(moduleRequest.isSome()); 746 StencilModuleEntry entry(lineno, column); 747 entry.moduleRequest = moduleRequest; 748 return entry; 749 } 750 751 static StencilModuleEntry importEntry(MaybeModuleRequestIndex moduleRequest, 752 TaggedParserAtomIndex localName, 753 TaggedParserAtomIndex importName, 754 uint32_t lineno, 755 JS::ColumnNumberOneOrigin column) { 756 MOZ_ASSERT(moduleRequest.isSome()); 757 MOZ_ASSERT(localName && importName); 758 StencilModuleEntry entry(lineno, column); 759 entry.moduleRequest = moduleRequest; 760 entry.localName = localName; 761 entry.importName = importName; 762 return entry; 763 } 764 765 static StencilModuleEntry importNamespaceEntry( 766 MaybeModuleRequestIndex moduleRequest, TaggedParserAtomIndex localName, 767 uint32_t lineno, JS::ColumnNumberOneOrigin column) { 768 MOZ_ASSERT(moduleRequest.isSome()); 769 MOZ_ASSERT(localName); 770 StencilModuleEntry entry(lineno, column); 771 entry.moduleRequest = moduleRequest; 772 entry.localName = localName; 773 return entry; 774 } 775 776 static StencilModuleEntry exportAsEntry(TaggedParserAtomIndex localName, 777 TaggedParserAtomIndex exportName, 778 uint32_t lineno, 779 JS::ColumnNumberOneOrigin column) { 780 MOZ_ASSERT(localName && exportName); 781 StencilModuleEntry entry(lineno, column); 782 entry.localName = localName; 783 entry.exportName = exportName; 784 return entry; 785 } 786 787 static StencilModuleEntry exportFromEntry( 788 MaybeModuleRequestIndex moduleRequest, TaggedParserAtomIndex importName, 789 TaggedParserAtomIndex exportName, uint32_t lineno, 790 JS::ColumnNumberOneOrigin column) { 791 MOZ_ASSERT(moduleRequest.isSome()); 792 MOZ_ASSERT(importName && exportName); 793 StencilModuleEntry entry(lineno, column); 794 entry.moduleRequest = moduleRequest; 795 entry.importName = importName; 796 entry.exportName = exportName; 797 return entry; 798 } 799 800 static StencilModuleEntry exportNamespaceFromEntry( 801 MaybeModuleRequestIndex moduleRequest, TaggedParserAtomIndex exportName, 802 uint32_t lineno, JS::ColumnNumberOneOrigin column) { 803 MOZ_ASSERT(moduleRequest.isSome()); 804 MOZ_ASSERT(exportName); 805 StencilModuleEntry entry(lineno, column); 806 entry.moduleRequest = MaybeModuleRequestIndex(moduleRequest); 807 entry.exportName = exportName; 808 return entry; 809 } 810 811 static StencilModuleEntry exportBatchFromEntry( 812 MaybeModuleRequestIndex moduleRequest, uint32_t lineno, 813 JS::ColumnNumberOneOrigin column) { 814 MOZ_ASSERT(moduleRequest.isSome()); 815 StencilModuleEntry entry(lineno, column); 816 entry.moduleRequest = MaybeModuleRequestIndex(moduleRequest); 817 return entry; 818 } 819 }; 820 821 // Metadata generated by parsing module scripts, including import/export tables. 822 class StencilModuleMetadata 823 : public js::AtomicRefCounted<StencilModuleMetadata> { 824 public: 825 using RequestVector = Vector<StencilModuleRequest, 0, js::SystemAllocPolicy>; 826 using EntryVector = Vector<StencilModuleEntry, 0, js::SystemAllocPolicy>; 827 828 RequestVector moduleRequests; 829 EntryVector requestedModules; 830 EntryVector importEntries; 831 EntryVector localExportEntries; 832 EntryVector indirectExportEntries; 833 EntryVector starExportEntries; 834 FunctionDeclarationVector functionDecls; 835 // Set to true if the module has a top-level await keyword. 836 bool isAsync = false; 837 838 StencilModuleMetadata() = default; 839 840 bool initModule(JSContext* cx, FrontendContext* fc, 841 CompilationAtomCache& atomCache, 842 JS::Handle<ModuleObject*> module) const; 843 844 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { 845 return mallocSizeOf(this) + 846 requestedModules.sizeOfExcludingThis(mallocSizeOf) + 847 importEntries.sizeOfExcludingThis(mallocSizeOf) + 848 localExportEntries.sizeOfExcludingThis(mallocSizeOf) + 849 indirectExportEntries.sizeOfExcludingThis(mallocSizeOf) + 850 starExportEntries.sizeOfExcludingThis(mallocSizeOf) + 851 functionDecls.sizeOfExcludingThis(mallocSizeOf); 852 } 853 854 #if defined(DEBUG) || defined(JS_JITSPEW) 855 void dump() const; 856 void dump(JSONPrinter& json, const CompilationStencil* stencil) const; 857 void dumpFields(JSONPrinter& json, const CompilationStencil* stencil) const; 858 #endif 859 860 private: 861 bool createModuleRequestObjects( 862 JSContext* cx, CompilationAtomCache& atomCache, 863 MutableHandle<ModuleRequestVector> output) const; 864 bool createRequestedModules( 865 JSContext* cx, CompilationAtomCache& atomCache, 866 Handle<ModuleRequestVector> moduleRequests, 867 MutableHandle<RequestedModuleVector> output) const; 868 bool createImportEntries(JSContext* cx, CompilationAtomCache& atomCache, 869 Handle<ModuleRequestVector> moduleRequests, 870 MutableHandle<ImportEntryVector> output) const; 871 bool createExportEntries(JSContext* cx, CompilationAtomCache& atomCache, 872 Handle<ModuleRequestVector> moduleRequests, 873 const EntryVector& input, 874 MutableHandle<ExportEntryVector> output) const; 875 ModuleRequestObject* createModuleRequestObject( 876 JSContext* cx, CompilationAtomCache& atomCache, 877 const StencilModuleRequest& request) const; 878 }; 879 880 // As an alternative to a ScopeIndex (which references a ScopeStencil), we may 881 // instead refer to an existing scope from GlobalObject::emptyGlobalScope(). 882 // 883 // NOTE: This is only used for the self-hosting global. 884 class EmptyGlobalScopeType {}; 885 886 // Things pointed by this index all end up being baked into GC things as part 887 // of stencil instantiation. 888 // 889 // 0x0000_0000 Null 890 // 0x1YYY_YYYY 28-bit ParserAtom 891 // 0x2YYY_YYYY Well-known/static atom (See TaggedParserAtomIndex) 892 // 0x3YYY_YYYY 28-bit BigInt 893 // 0x4YYY_YYYY 28-bit ObjLiteral 894 // 0x5YYY_YYYY 28-bit RegExp 895 // 0x6YYY_YYYY 28-bit Scope 896 // 0x7YYY_YYYY 28-bit Function 897 // 0x8000_0000 EmptyGlobalScope 898 class TaggedScriptThingIndex { 899 uint32_t data_; 900 901 static constexpr size_t IndexBit = TaggedParserAtomIndex::IndexBit; 902 static constexpr size_t IndexMask = TaggedParserAtomIndex::IndexMask; 903 904 static constexpr size_t TagShift = TaggedParserAtomIndex::TagShift; 905 static constexpr size_t TagBit = TaggedParserAtomIndex::TagBit; 906 static constexpr size_t TagMask = TaggedParserAtomIndex::TagMask; 907 908 public: 909 enum class Kind : uint32_t { 910 Null = uint32_t(TaggedParserAtomIndex::Kind::Null), 911 ParserAtomIndex = uint32_t(TaggedParserAtomIndex::Kind::ParserAtomIndex), 912 WellKnown = uint32_t(TaggedParserAtomIndex::Kind::WellKnown), 913 BigInt, 914 ObjLiteral, 915 RegExp, 916 Scope, 917 Function, 918 EmptyGlobalScope, 919 }; 920 921 private: 922 static constexpr uint32_t NullTag = uint32_t(Kind::Null) << TagShift; 923 static_assert(NullTag == TaggedParserAtomIndex::NullTag); 924 static constexpr uint32_t ParserAtomIndexTag = uint32_t(Kind::ParserAtomIndex) 925 << TagShift; 926 static_assert(ParserAtomIndexTag == 927 TaggedParserAtomIndex::ParserAtomIndexTag); 928 static constexpr uint32_t WellKnownTag = uint32_t(Kind::WellKnown) 929 << TagShift; 930 static_assert(WellKnownTag == TaggedParserAtomIndex::WellKnownTag); 931 932 static constexpr uint32_t BigIntTag = uint32_t(Kind::BigInt) << TagShift; 933 static constexpr uint32_t ObjLiteralTag = uint32_t(Kind::ObjLiteral) 934 << TagShift; 935 static constexpr uint32_t RegExpTag = uint32_t(Kind::RegExp) << TagShift; 936 static constexpr uint32_t ScopeTag = uint32_t(Kind::Scope) << TagShift; 937 static constexpr uint32_t FunctionTag = uint32_t(Kind::Function) << TagShift; 938 static constexpr uint32_t EmptyGlobalScopeTag = 939 uint32_t(Kind::EmptyGlobalScope) << TagShift; 940 941 public: 942 static constexpr uint32_t IndexLimit = Bit(IndexBit); 943 944 TaggedScriptThingIndex() : data_(NullTag) {} 945 946 explicit TaggedScriptThingIndex(TaggedParserAtomIndex index) 947 : data_(index.rawData()) {} 948 explicit TaggedScriptThingIndex(BigIntIndex index) 949 : data_(uint32_t(index) | BigIntTag) { 950 MOZ_ASSERT(uint32_t(index) < IndexLimit); 951 } 952 explicit TaggedScriptThingIndex(ObjLiteralIndex index) 953 : data_(uint32_t(index) | ObjLiteralTag) { 954 MOZ_ASSERT(uint32_t(index) < IndexLimit); 955 } 956 explicit TaggedScriptThingIndex(RegExpIndex index) 957 : data_(uint32_t(index) | RegExpTag) { 958 MOZ_ASSERT(uint32_t(index) < IndexLimit); 959 } 960 explicit TaggedScriptThingIndex(ScopeIndex index) 961 : data_(uint32_t(index) | ScopeTag) { 962 MOZ_ASSERT(uint32_t(index) < IndexLimit); 963 } 964 explicit TaggedScriptThingIndex(ScriptIndex index) 965 : data_(uint32_t(index) | FunctionTag) { 966 MOZ_ASSERT(uint32_t(index) < IndexLimit); 967 } 968 explicit TaggedScriptThingIndex(EmptyGlobalScopeType t) 969 : data_(EmptyGlobalScopeTag) {} 970 971 bool isAtom() const { 972 return (data_ & TagMask) == ParserAtomIndexTag || 973 (data_ & TagMask) == WellKnownTag; 974 } 975 bool isNull() const { 976 bool result = !data_; 977 MOZ_ASSERT_IF(result, (data_ & TagMask) == NullTag); 978 return result; 979 } 980 bool isBigInt() const { return (data_ & TagMask) == BigIntTag; } 981 bool isObjLiteral() const { return (data_ & TagMask) == ObjLiteralTag; } 982 bool isRegExp() const { return (data_ & TagMask) == RegExpTag; } 983 bool isScope() const { return (data_ & TagMask) == ScopeTag; } 984 bool isFunction() const { return (data_ & TagMask) == FunctionTag; } 985 bool isEmptyGlobalScope() const { 986 return (data_ & TagMask) == EmptyGlobalScopeTag; 987 } 988 989 TaggedParserAtomIndex toAtom() const { 990 MOZ_ASSERT(isAtom()); 991 return TaggedParserAtomIndex::fromRaw(data_); 992 } 993 BigIntIndex toBigInt() const { return BigIntIndex(data_ & IndexMask); } 994 ObjLiteralIndex toObjLiteral() const { 995 return ObjLiteralIndex(data_ & IndexMask); 996 } 997 RegExpIndex toRegExp() const { return RegExpIndex(data_ & IndexMask); } 998 ScopeIndex toScope() const { return ScopeIndex(data_ & IndexMask); } 999 ScriptIndex toFunction() const { return ScriptIndex(data_ & IndexMask); } 1000 1001 TaggedParserAtomIndex toAtomOrNull() const { 1002 MOZ_ASSERT(isAtom() || isNull()); 1003 return TaggedParserAtomIndex::fromRaw(data_); 1004 } 1005 1006 uint32_t* rawDataRef() { return &data_; } 1007 uint32_t rawData() const { return data_; } 1008 1009 Kind tag() const { return Kind((data_ & TagMask) >> TagShift); } 1010 1011 bool operator==(const TaggedScriptThingIndex& rhs) const { 1012 return data_ == rhs.data_; 1013 } 1014 }; 1015 1016 // Data generated by frontend that will be used to create a js::BaseScript. 1017 class ScriptStencil { 1018 friend struct CompilationStencilMerger; 1019 1020 public: 1021 // Fields for BaseScript. 1022 // Used by: 1023 // * Global script 1024 // * Eval 1025 // * Module 1026 // * non-lazy Function (except asm.js module) 1027 // * lazy Function (cannot be asm.js module) 1028 1029 // GCThings are stored into 1030 // {ExtensibleCompilationStencil,CompilationStencil}.gcThingData, 1031 // in [gcThingsOffset, gcThingsOffset + gcThingsLength) range. 1032 CompilationGCThingIndex gcThingsOffset; 1033 uint32_t gcThingsLength = 0; 1034 1035 // Fields for JSFunction. 1036 // Used by: 1037 // * non-lazy Function 1038 // * lazy Function 1039 // * asm.js module 1040 1041 // The explicit or implicit name of the function. The FunctionFlags indicate 1042 // the kind of name. 1043 TaggedParserAtomIndex functionAtom; 1044 1045 // If this ScriptStencil refers to a lazy child of the function being 1046 // compiled, this field holds the child's immediately enclosing scope's index. 1047 // Once compilation succeeds, we will store the scope pointed by this in the 1048 // child's BaseScript. (Debugger may become confused if lazy scripts refer to 1049 // partially initialized enclosing scopes, so we must avoid storing the 1050 // scope in the BaseScript until compilation has completed 1051 // successfully.) 1052 // 1053 // OR 1054 // 1055 // This may be used for self-hosting canonical name (TaggedParserAtomIndex). 1056 TaggedScriptThingIndex enclosingScopeOrCanonicalName; 1057 1058 // See: `FunctionFlags`. 1059 FunctionFlags functionFlags = {}; 1060 1061 // This is set by the BytecodeEmitter of the enclosing script when a reference 1062 // to this function is generated. 1063 static constexpr uint16_t WasEmittedByEnclosingScriptFlag = 1 << 0; 1064 1065 // If this is for the root of delazification, this represents 1066 // MutableScriptFlagsEnum::AllowRelazify value of the script *after* 1067 // delazification. 1068 // False otherwise. 1069 static constexpr uint16_t AllowRelazifyFlag = 1 << 1; 1070 1071 // Set if this is non-lazy script and shared data is created. 1072 // The shared data is stored into CompilationStencil.sharedData. 1073 static constexpr uint16_t HasSharedDataFlag = 1 << 2; 1074 1075 // True if this script is lazy function and has enclosing scope. In that 1076 // case, `enclosingScopeOrCanonicalName` will hold the ScopeIndex. 1077 static constexpr uint16_t HasLazyFunctionEnclosingScopeIndexFlag = 1 << 3; 1078 1079 // True if this script is a self-hosted function with a canonical name 1080 // explicitly set. In that case, `enclosingScopeOrCanonicalName` will hold the 1081 // TaggedParserAtomIndex. 1082 static constexpr uint16_t HasSelfHostedCanonicalName = 1 << 4; 1083 1084 uint16_t flags_ = 0; 1085 1086 // End of fields. 1087 1088 ScriptStencil() = default; 1089 1090 bool isFunction() const { 1091 bool result = functionFlags.toRaw() != 0x0000; 1092 MOZ_ASSERT_IF( 1093 result, functionFlags.isAsmJSNative() || functionFlags.hasBaseScript()); 1094 return result; 1095 } 1096 1097 bool hasGCThings() const { return gcThingsLength; } 1098 1099 mozilla::Span<TaggedScriptThingIndex> gcthings( 1100 const CompilationStencil& stencil) const; 1101 1102 bool wasEmittedByEnclosingScript() const { 1103 return flags_ & WasEmittedByEnclosingScriptFlag; 1104 } 1105 1106 void setWasEmittedByEnclosingScript() { 1107 flags_ |= WasEmittedByEnclosingScriptFlag; 1108 } 1109 1110 bool allowRelazify() const { return flags_ & AllowRelazifyFlag; } 1111 1112 void setAllowRelazify() { flags_ |= AllowRelazifyFlag; } 1113 1114 bool isGhost() const { return functionFlags.isGhost(); } 1115 void setIsGhost() { functionFlags.setIsGhost(); } 1116 1117 bool hasSharedData() const { return flags_ & HasSharedDataFlag; } 1118 1119 void setHasSharedData() { flags_ |= HasSharedDataFlag; } 1120 1121 bool hasLazyFunctionEnclosingScopeIndex() const { 1122 return flags_ & HasLazyFunctionEnclosingScopeIndexFlag; 1123 } 1124 1125 bool hasSelfHostedCanonicalName() const { 1126 return flags_ & HasSelfHostedCanonicalName; 1127 } 1128 1129 private: 1130 void setHasLazyFunctionEnclosingScopeIndex() { 1131 flags_ |= HasLazyFunctionEnclosingScopeIndexFlag; 1132 } 1133 1134 void setHasSelfHostedCanonicalName() { flags_ |= HasSelfHostedCanonicalName; } 1135 1136 public: 1137 void setLazyFunctionEnclosingScopeIndex(ScopeIndex index) { 1138 MOZ_ASSERT(enclosingScopeOrCanonicalName.isNull()); 1139 enclosingScopeOrCanonicalName = TaggedScriptThingIndex(index); 1140 setHasLazyFunctionEnclosingScopeIndex(); 1141 } 1142 1143 void resetHasLazyFunctionEnclosingScopeIndexAfterStencilMerge() { 1144 flags_ &= ~HasLazyFunctionEnclosingScopeIndexFlag; 1145 enclosingScopeOrCanonicalName = TaggedScriptThingIndex(); 1146 } 1147 1148 ScopeIndex lazyFunctionEnclosingScopeIndex() const { 1149 MOZ_ASSERT(hasLazyFunctionEnclosingScopeIndex()); 1150 return enclosingScopeOrCanonicalName.toScope(); 1151 } 1152 1153 void setSelfHostedCanonicalName(TaggedParserAtomIndex name) { 1154 MOZ_ASSERT(enclosingScopeOrCanonicalName.isNull()); 1155 enclosingScopeOrCanonicalName = TaggedScriptThingIndex(name); 1156 setHasSelfHostedCanonicalName(); 1157 } 1158 1159 TaggedParserAtomIndex selfHostedCanonicalName() const { 1160 MOZ_ASSERT(hasSelfHostedCanonicalName()); 1161 return enclosingScopeOrCanonicalName.toAtom(); 1162 } 1163 1164 #if defined(DEBUG) || defined(JS_JITSPEW) 1165 void dump() const; 1166 void dump(JSONPrinter& json, const CompilationStencil* stencil) const; 1167 void dumpFields(JSONPrinter& json, const CompilationStencil* stencil) const; 1168 #endif 1169 }; 1170 1171 // In addition to ScriptStencil, data generated only while initial-parsing. 1172 class ScriptStencilExtra { 1173 public: 1174 // See `BaseScript::immutableFlags_`. 1175 ImmutableScriptFlags immutableFlags; 1176 1177 // The location of this script in the source. 1178 SourceExtent extent; 1179 1180 // See `PrivateScriptData::memberInitializers_`. 1181 // This data only valid when `UseMemberInitializers` script flag is true. 1182 uint32_t memberInitializers_ = 0; 1183 1184 // See `JSFunction::nargs_`. 1185 uint16_t nargs = 0; 1186 1187 // To make this struct packed, add explicit field for padding. 1188 uint16_t padding_ = 0; 1189 1190 ScriptStencilExtra() = default; 1191 1192 RO_IMMUTABLE_SCRIPT_FLAGS(immutableFlags) 1193 1194 void setMemberInitializers(MemberInitializers member) { 1195 MOZ_ASSERT(useMemberInitializers()); 1196 memberInitializers_ = member.serialize(); 1197 } 1198 1199 MemberInitializers memberInitializers() const { 1200 MOZ_ASSERT(useMemberInitializers()); 1201 return MemberInitializers::deserialize(memberInitializers_); 1202 } 1203 1204 #if defined(DEBUG) || defined(JS_JITSPEW) 1205 void dump() const; 1206 void dump(JSONPrinter& json) const; 1207 void dumpFields(JSONPrinter& json) const; 1208 #endif 1209 }; 1210 1211 #if defined(DEBUG) || defined(JS_JITSPEW) 1212 void DumpTaggedParserAtomIndex(js::JSONPrinter& json, 1213 TaggedParserAtomIndex taggedIndex, 1214 const CompilationStencil* stencil); 1215 1216 void DumpTaggedParserAtomIndexNoQuote(GenericPrinter& out, 1217 TaggedParserAtomIndex taggedIndex, 1218 const CompilationStencil* stencil); 1219 #endif 1220 1221 } /* namespace frontend */ 1222 1223 #if defined(DEBUG) || defined(JS_JITSPEW) 1224 void DumpImmutableScriptFlags(js::JSONPrinter& json, 1225 ImmutableScriptFlags immutableFlags); 1226 void DumpFunctionFlagsItems(js::JSONPrinter& json, FunctionFlags functionFlags); 1227 #endif 1228 1229 } /* namespace js */ 1230 1231 #endif /* frontend_Stencil_h */