tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */