tor-browser

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

CompilationStencil.h (99032B)


      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_CompilationStencil_h
      8 #define frontend_CompilationStencil_h
      9 
     10 #include "mozilla/AlreadyAddRefed.h"  // already_AddRefed
     11 #include "mozilla/Assertions.h"  // MOZ_ASSERT, MOZ_RELEASE_ASSERT, MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE
     12 #include "mozilla/Atomics.h"     // mozilla::Atomic
     13 #include "mozilla/Attributes.h"  // MOZ_RAII, MOZ_STACK_CLASS
     14 #include "mozilla/HashTable.h"   // mozilla::HashMap, mozilla::DefaultHasher
     15 #include "mozilla/Maybe.h"       // mozilla::Maybe
     16 #include "mozilla/MemoryReporting.h"  // mozilla::MallocSizeOf
     17 #include "mozilla/RefPtr.h"           // RefPtr
     18 #include "mozilla/Span.h"             // mozilla::Span
     19 #include "mozilla/Variant.h"          // mozilla::Variant
     20 
     21 #include <algorithm>    // std::swap
     22 #include <stddef.h>     // size_t
     23 #include <stdint.h>     // uint32_t, uintptr_t
     24 #include <type_traits>  // std::is_pointer_v
     25 #include <utility>      // std::forward, std::move
     26 
     27 #include "ds/LifoAlloc.h"                 // LifoAlloc, LifoAllocScope
     28 #include "frontend/FrontendContext.h"     // FrontendContext
     29 #include "frontend/FunctionSyntaxKind.h"  // FunctionSyntaxKind
     30 #include "frontend/NameAnalysisTypes.h"   // NameLocation
     31 #include "frontend/ParserAtom.h"  // ParserAtomsTable, ParserAtomIndex, TaggedParserAtomIndex, ParserAtomSpan
     32 #include "frontend/ScopeIndex.h"     // ScopeIndex
     33 #include "frontend/ScriptIndex.h"    // ScriptIndex
     34 #include "frontend/SharedContext.h"  // ThisBinding, InheritThis, Directives
     35 #include "frontend/Stencil.h"  // ScriptStencil, ScriptStencilExtra, ScopeStencil, RegExpStencil, BigIntStencil, ObjLiteralStencil, BaseParserScopeData, StencilModuleMetadata
     36 #include "frontend/TaggedParserAtomIndexHasher.h"  // TaggedParserAtomIndexHasher
     37 #include "frontend/UsedNameTracker.h"              // UsedNameTracker
     38 #include "js/AllocPolicy.h"    // SystemAllocPolicy, ReportOutOfMemory
     39 #include "js/GCVector.h"       // JS::GCVector
     40 #include "js/RefCounted.h"     // AtomicRefCounted
     41 #include "js/RootingAPI.h"     // JS::Handle
     42 #include "js/Transcoding.h"    // JS::TranscodeBuffer, JS::TranscodeRange
     43 #include "js/UniquePtr.h"      // js::UniquePtr
     44 #include "js/Vector.h"         // Vector
     45 #include "js/WasmModule.h"     // JS::WasmModule
     46 #include "vm/FunctionFlags.h"  // FunctionFlags
     47 #include "vm/GlobalObject.h"   // GlobalObject
     48 #include "vm/JSContext.h"      // JSContext
     49 #include "vm/JSFunction.h"     // JSFunction
     50 #include "vm/JSScript.h"       // BaseScript, ScriptSource, SourceExtent
     51 #include "vm/Realm.h"          // JSContext::global
     52 #include "vm/Scope.h"          // Scope, ModuleScope
     53 #include "vm/ScopeKind.h"      // ScopeKind
     54 #include "vm/SharedStencil.h"  // ImmutableScriptFlags, MemberInitializers, SharedImmutableScriptData, RO_IMMUTABLE_SCRIPT_FLAGS
     55 
     56 class JSAtom;
     57 class JSFunction;
     58 class JSObject;
     59 class JSString;
     60 class JSTracer;
     61 
     62 namespace JS {
     63 class JS_PUBLIC_API ReadOnlyCompileOptions;
     64 }
     65 
     66 namespace js {
     67 
     68 class AtomSet;
     69 class JSONPrinter;
     70 class ModuleObject;
     71 
     72 namespace frontend {
     73 
     74 struct InitialStencilAndDelazifications;
     75 struct CompilationInput;
     76 struct CompilationStencil;
     77 struct CompilationGCOutput;
     78 struct PreallocatedCompilationGCOutput;
     79 class ScriptStencilIterable;
     80 struct InputName;
     81 class ScopeBindingCache;
     82 struct ScriptStencilRef;
     83 
     84 // When delazifying modules' inner functions, the actual global scope is used.
     85 // However, when doing a delazification the global scope is not available. We
     86 // use this dummy type to be a placeholder to be used as part of the InputScope
     87 // variants to mimic what the Global scope would be used for.
     88 struct FakeStencilGlobalScope {};
     89 
     90 // Reference to a Scope within an InitialStencilAndDelazifications.
     91 struct ScopeStencilRef {
     92  const InitialStencilAndDelazifications& stencils_;
     93  // Index of the script in the initial stencil of stencils_, where the script
     94  // holds the scope.
     95  const ScriptIndex scriptIndex_;
     96  // Index of the scope in te CompilationStencil (either initial or the
     97  // delazification) pointed by the stencils_ and scriptIndex_.
     98  const ScopeIndex scopeIndex_;
     99 
    100  // Lookup the ScopeStencil referenced by this ScopeStencilRef.
    101  inline const ScopeStencil& scope() const;
    102  // Reference to the script which owns the scope pointed by this object.
    103  inline ScriptStencilRef script() const;
    104 
    105  // For a Function scope, return the ScriptExtra information from the initial
    106  // stencil.
    107  inline const ScriptStencilExtra& functionScriptExtra() const;
    108 
    109  // CompilationStencil (either initial or delazification) which contains the
    110  // scope data.
    111  inline const CompilationStencil* context() const;
    112 };
    113 
    114 // Wraps a scope for a CompilationInput. The scope is either as a GC pointer to
    115 // an instantiated scope, or as a reference to a CompilationStencil.
    116 //
    117 // Note: A scope reference may be nullptr/InvalidIndex if there is no such
    118 // scope, such as the enclosingScope at the end of a scope chain. See `isNull`
    119 // helper.
    120 class InputScope {
    121  using InputScopeStorage =
    122      mozilla::Variant<Scope*, ScopeStencilRef, FakeStencilGlobalScope>;
    123  InputScopeStorage scope_;
    124 
    125 public:
    126  // Create an InputScope given an instantiated scope.
    127  explicit InputScope(Scope* ptr) : scope_(ptr) {}
    128 
    129  // Create an InputScope for a global.
    130  explicit InputScope(FakeStencilGlobalScope global) : scope_(global) {}
    131 
    132  // Create an InputScope given a CompilationStencil and the ScopeIndex which is
    133  // an offset within the same CompilationStencil given as argument.
    134  InputScope(const InitialStencilAndDelazifications& stencils,
    135             ScriptIndex scriptIndex, ScopeIndex scopeIndex)
    136      : scope_(ScopeStencilRef{stencils, scriptIndex, scopeIndex}) {}
    137 
    138  // Returns the variant used by the InputScope. This can be useful for complex
    139  // cases where the following accessors are not enough.
    140  const InputScopeStorage& variant() const { return scope_; }
    141  InputScopeStorage& variant() { return scope_; }
    142 
    143  // This match function will unwrap the variant for each type, and will
    144  // specialize and call the Matcher given as argument with the type and value
    145  // of the stored pointer / reference.
    146  //
    147  // This is useful for cases where the code is literally identical despite
    148  // having different specializations. This is achiveable by relying on
    149  // function overloading when the usage differ between the 2 types.
    150  //
    151  // Example:
    152  //   inputScope.match([](auto& scope) {
    153  //     // scope is either a `Scope*` or a `ScopeStencilRef`.
    154  //     for (auto bi = InputBindingIter(scope); bi; bi++) {
    155  //       InputName name(scope, bi.name());
    156  //       // ...
    157  //     }
    158  //   });
    159  template <typename Matcher>
    160  decltype(auto) match(Matcher&& matcher) const& {
    161    return scope_.match(std::forward<Matcher>(matcher));
    162  }
    163  template <typename Matcher>
    164  decltype(auto) match(Matcher&& matcher) & {
    165    return scope_.match(std::forward<Matcher>(matcher));
    166  }
    167 
    168  bool isNull() const {
    169    return scope_.match(
    170        [](const Scope* ptr) { return !ptr; },
    171        [](const ScopeStencilRef& ref) { return !ref.scopeIndex_.isValid(); },
    172        [](const FakeStencilGlobalScope&) { return false; });
    173  }
    174 
    175  ScopeKind kind() const {
    176    return scope_.match(
    177        [](const Scope* ptr) { return ptr->kind(); },
    178        [](const ScopeStencilRef& ref) { return ref.scope().kind(); },
    179        [](const FakeStencilGlobalScope&) { return ScopeKind::Global; });
    180  };
    181  bool hasEnvironment() const {
    182    return scope_.match(
    183        [](const Scope* ptr) { return ptr->hasEnvironment(); },
    184        [](const ScopeStencilRef& ref) { return ref.scope().hasEnvironment(); },
    185        [](const FakeStencilGlobalScope&) {
    186          // See Scope::hasEnvironment
    187          return true;
    188        });
    189  };
    190  inline InputScope enclosing() const;
    191  bool hasOnChain(ScopeKind kind) const {
    192    return scope_.match([=](const Scope* ptr) { return ptr->hasOnChain(kind); },
    193                        [=](const ScopeStencilRef& ref) {
    194                          ScopeStencilRef it = ref;
    195                          while (true) {
    196                            const ScopeStencil& scope = it.scope();
    197                            if (scope.kind() == kind) {
    198                              return true;
    199                            }
    200                            if (scope.kind() == ScopeKind::Module &&
    201                                kind == ScopeKind::Global) {
    202                              return true;
    203                            }
    204                            if (!scope.hasEnclosing()) {
    205                              break;
    206                            }
    207                            new (&it)
    208                                ScopeStencilRef{ref.stencils_, ref.scriptIndex_,
    209                                                scope.enclosing()};
    210                          }
    211                          return false;
    212                        },
    213                        [=](const FakeStencilGlobalScope&) {
    214                          return kind == ScopeKind::Global;
    215                        });
    216  }
    217  uint32_t environmentChainLength() const {
    218    return scope_.match(
    219        [](const Scope* ptr) { return ptr->environmentChainLength(); },
    220        [](const ScopeStencilRef& ref) {
    221          uint32_t length = 0;
    222          ScopeStencilRef it = ref;
    223          while (true) {
    224            const ScopeStencil& scope = it.scope();
    225            if (scope.hasEnvironment() &&
    226                scope.kind() != ScopeKind::NonSyntactic) {
    227              length++;
    228            }
    229            if (scope.kind() == ScopeKind::Module) {
    230              // Stencil do not encode the Global scope, as it used to be
    231              // assumed to already exists. As moving delazification off-thread,
    232              // we need to materialize a fake-stencil version of the Global
    233              // Scope.
    234              MOZ_ASSERT(!scope.hasEnclosing());
    235              length += js::ModuleScope::EnclosingEnvironmentChainLength;
    236            }
    237            if (!scope.hasEnclosing()) {
    238              break;
    239            }
    240            new (&it) ScopeStencilRef{ref.stencils_, ref.scriptIndex_,
    241                                      scope.enclosing()};
    242          }
    243          return length;
    244        },
    245        [=](const FakeStencilGlobalScope&) {
    246          // Stencil-based delazification needs to calculate
    247          // environmentChainLength where the global is not available.
    248          //
    249          // The FakeStencilGlobalScope is used to represent what the global
    250          // would be if we had access to it while delazifying.
    251          return uint32_t(js::ModuleScope::EnclosingEnvironmentChainLength);
    252        });
    253  }
    254  void trace(JSTracer* trc);
    255  bool isStencil() const { return !scope_.is<Scope*>(); };
    256 
    257  // Various accessors which are valid only when the InputScope is a
    258  // FunctionScope. Some of these accessors are returning values associated with
    259  // the canonical function.
    260 private:
    261  inline FunctionFlags functionFlags() const;
    262  inline ImmutableScriptFlags immutableFlags() const;
    263 
    264 public:
    265  inline MemberInitializers getMemberInitializers() const;
    266  RO_IMMUTABLE_SCRIPT_FLAGS(immutableFlags())
    267  bool isArrow() const { return functionFlags().isArrow(); }
    268  bool allowSuperProperty() const {
    269    return functionFlags().allowSuperProperty();
    270  }
    271  bool isClassConstructor() const {
    272    return functionFlags().isClassConstructor();
    273  }
    274 };
    275 
    276 // Reference to a Script within an InitialStencilAndDelazifications.
    277 struct ScriptStencilRef {
    278  const InitialStencilAndDelazifications& stencils_;
    279  // Index of the script within the initial CompilationStencil of stencils_.
    280  const ScriptIndex scriptIndex_;
    281 
    282  // Returns a ScriptStencilRef corresponding to the top-level script, which is
    283  // the first script in the initial stencil.
    284  inline ScriptStencilRef topLevelScript() const;
    285 
    286  // Returns a ScriptStencilRef which corresponds to the enclosing script of the
    287  // current script.
    288  inline ScriptStencilRef enclosingScript() const;
    289 
    290  // scriptData about the current script, held by the enclosing (initial /
    291  // delazification) stencil.
    292  //
    293  // This function is used to get function flags known by the caller, and when
    294  // looking for scope index in the enclosing stencil.
    295  inline const ScriptStencil& scriptDataFromEnclosing() const;
    296 
    297  // scriptData about the current script, held by the initial stencil.
    298  //
    299  // This function is used to implement gcThingsFromInitial, and also query
    300  // whether this script is compiled as part of the initial stencil or not.
    301  inline const ScriptStencil& scriptDataFromInitial() const;
    302 
    303  // Returns whether the script is held by the initial stencil.
    304  inline bool isEagerlyCompiledInInitial() const;
    305 
    306  // scriptExtra about the current script, held by the initial stencil.
    307  inline const ScriptStencilExtra& scriptExtra() const;
    308 
    309  // gcThings about the current script, held by the initial stencil. Unless this
    310  // script is compiled as part of the top-level, it would most likely only
    311  // contain the list of inner functions.
    312  inline mozilla::Span<TaggedScriptThingIndex> gcThingsFromInitial() const;
    313 
    314  // Initial or delazification stencil which holds the the compilation result
    315  // for the current scriptIndex_.
    316  inline const CompilationStencil* context() const;
    317  inline const CompilationStencil* maybeContext() const;
    318 };
    319 
    320 // Wraps a script for a CompilationInput. The script is either as a BaseScript
    321 // pointer to an instantiated script, or as a reference to a CompilationStencil.
    322 class InputScript {
    323  using InputScriptStorage = mozilla::Variant<BaseScript*, ScriptStencilRef>;
    324  InputScriptStorage script_;
    325 
    326 public:
    327  // Create an InputScript given an instantiated BaseScript pointer.
    328  explicit InputScript(BaseScript* ptr) : script_(ptr) {}
    329 
    330  // Create an InputScript given a CompilationStencil and the ScriptIndex which
    331  // is an offset within the same CompilationStencil given as argument.
    332  InputScript(const InitialStencilAndDelazifications& stencils,
    333              ScriptIndex scriptIndex)
    334      : script_(ScriptStencilRef{stencils, scriptIndex}) {}
    335 
    336  const InputScriptStorage& raw() const { return script_; }
    337  InputScriptStorage& raw() { return script_; }
    338 
    339  SourceExtent extent() const {
    340    return script_.match(
    341        [](const BaseScript* ptr) { return ptr->extent(); },
    342        [](const ScriptStencilRef& ref) { return ref.scriptExtra().extent; });
    343  }
    344  ImmutableScriptFlags immutableFlags() const {
    345    return script_.match(
    346        [](const BaseScript* ptr) { return ptr->immutableFlags(); },
    347        [](const ScriptStencilRef& ref) {
    348          return ref.scriptExtra().immutableFlags;
    349        });
    350  }
    351  RO_IMMUTABLE_SCRIPT_FLAGS(immutableFlags())
    352  FunctionFlags functionFlags() const {
    353    return script_.match(
    354        [](const BaseScript* ptr) { return ptr->function()->flags(); },
    355        [](const ScriptStencilRef& ref) {
    356          auto& scriptData = ref.scriptDataFromEnclosing();
    357          return scriptData.functionFlags;
    358        });
    359  }
    360  bool hasPrivateScriptData() const {
    361    return script_.match(
    362        [](const BaseScript* ptr) { return ptr->hasPrivateScriptData(); },
    363        [](const ScriptStencilRef& ref) {
    364          // See BaseScript::CreateRawLazy.
    365          auto& scriptData = ref.scriptDataFromEnclosing();
    366          return scriptData.hasGCThings() ||
    367                 ref.scriptExtra().useMemberInitializers();
    368        });
    369  }
    370  InputScope enclosingScope() const {
    371    return script_.match(
    372        [](const BaseScript* ptr) {
    373          return InputScope(ptr->function()->enclosingScope());
    374        },
    375        [](const ScriptStencilRef& ref) {
    376          // The ScriptStencilRef only reference lazy Script, otherwise we
    377          // should fetch the enclosing scope using the bodyScope field of the
    378          // immutable data which is a reference to the vector of gc-things.
    379          auto enclosing = ref.enclosingScript();
    380          auto& scriptData = ref.scriptDataFromEnclosing();
    381          MOZ_RELEASE_ASSERT(!scriptData.hasSharedData());
    382          MOZ_ASSERT(scriptData.hasLazyFunctionEnclosingScopeIndex());
    383          auto scopeIndex = scriptData.lazyFunctionEnclosingScopeIndex();
    384          return InputScope(ref.stencils_, enclosing.scriptIndex_, scopeIndex);
    385        });
    386  }
    387  MemberInitializers getMemberInitializers() const {
    388    return script_.match(
    389        [](const BaseScript* ptr) { return ptr->getMemberInitializers(); },
    390        [](const ScriptStencilRef& ref) {
    391          return ref.scriptExtra().memberInitializers();
    392        });
    393  }
    394 
    395  InputName displayAtom() const;
    396  void trace(JSTracer* trc);
    397  bool isNull() const {
    398    return script_.match([](const BaseScript* ptr) { return !ptr; },
    399                         [](const ScriptStencilRef& ref) { return false; });
    400  }
    401  bool isStencil() const {
    402    return script_.match([](const BaseScript* ptr) { return false; },
    403                         [](const ScriptStencilRef&) { return true; });
    404  }
    405 
    406  ScriptSourceObject* sourceObject() const {
    407    return script_.match(
    408        [](const BaseScript* ptr) { return ptr->sourceObject(); },
    409        [](const ScriptStencilRef&) {
    410          return static_cast<ScriptSourceObject*>(nullptr);
    411        });
    412  }
    413 };
    414 
    415 // Iterator for walking the scope chain, this is identical to ScopeIter but
    416 // accept an InputScope instead of a Scope pointer.
    417 //
    418 // It may be placed in GC containers; for example:
    419 //
    420 //   for (Rooted<InputScopeIter> si(cx, InputScopeIter(scope)); si; si++) {
    421 //     use(si);
    422 //     SomeMayGCOperation();
    423 //     use(si);
    424 //   }
    425 //
    426 class MOZ_STACK_CLASS InputScopeIter {
    427  InputScope scope_;
    428 
    429 public:
    430  explicit InputScopeIter(const InputScope& scope) : scope_(scope) {}
    431 
    432  InputScope& scope() {
    433    MOZ_ASSERT(!done());
    434    return scope_;
    435  }
    436 
    437  const InputScope& scope() const {
    438    MOZ_ASSERT(!done());
    439    return scope_;
    440  }
    441 
    442  bool done() const { return scope_.isNull(); }
    443  explicit operator bool() const { return !done(); }
    444  void operator++(int) { scope_ = scope_.enclosing(); }
    445  ScopeKind kind() const { return scope_.kind(); }
    446 
    447  // Returns whether this scope has a syntactic environment (i.e., an
    448  // Environment that isn't a non-syntactic With or NonSyntacticVariables)
    449  // on the environment chain.
    450  bool hasSyntacticEnvironment() const {
    451    return scope_.hasEnvironment() && scope_.kind() != ScopeKind::NonSyntactic;
    452  }
    453 
    454  void trace(JSTracer* trc) { scope_.trace(trc); }
    455 };
    456 
    457 // Reference to a Binding Name within an existing CompilationStencil.
    458 // TaggedParserAtomIndex are in some cases indexes in the parserAtomData of the
    459 // CompilationStencil.
    460 struct NameStencilRef {
    461  const CompilationStencil& context_;
    462  const TaggedParserAtomIndex atomIndex_;
    463 };
    464 
    465 // Wraps a name for a CompilationInput. The name is either as a GC pointer to
    466 // a JSAtom, or a TaggedParserAtomIndex which might reference to a non-included.
    467 //
    468 // The constructor for this class are using an InputScope as argument. This
    469 // InputScope is made to fetch back the CompilationStencil associated with the
    470 // TaggedParserAtomIndex when using a Stencil as input.
    471 struct InputName {
    472  using InputNameStorage = mozilla::Variant<JSAtom*, NameStencilRef>;
    473  InputNameStorage variant_;
    474 
    475  InputName(Scope*, JSAtom* ptr) : variant_(ptr) {}
    476  InputName(const ScopeStencilRef& scope, TaggedParserAtomIndex index)
    477      : variant_(NameStencilRef{*scope.context(), index}) {}
    478  InputName(BaseScript*, JSAtom* ptr) : variant_(ptr) {}
    479  InputName(const ScriptStencilRef& script, TaggedParserAtomIndex index)
    480      : variant_(NameStencilRef{*script.context(), index}) {}
    481 
    482  // Dummy for empty global.
    483  InputName(const FakeStencilGlobalScope&, TaggedParserAtomIndex)
    484      : variant_(static_cast<JSAtom*>(nullptr)) {}
    485 
    486  // The InputName is either from an instantiated name, or from another
    487  // CompilationStencil. This method interns the current name in the parser atom
    488  // table of a CompilationState, which has a corresponding CompilationInput.
    489  TaggedParserAtomIndex internInto(FrontendContext* fc,
    490                                   ParserAtomsTable& parserAtoms,
    491                                   CompilationAtomCache& atomCache);
    492 
    493  // Compare an InputName, which is not yet interned, with `other` is either an
    494  // interned name or a well-known or static string.
    495  //
    496  // The `otherCached` argument should be a reference to a JSAtom*, initialized
    497  // to nullptr, which is used to cache the JSAtom representation of the `other`
    498  // argument if needed. If a different `other` parameter is provided, the
    499  // `otherCached` argument should be reset to nullptr.
    500  bool isEqualTo(FrontendContext* fc, ParserAtomsTable& parserAtoms,
    501                 CompilationAtomCache& atomCache, TaggedParserAtomIndex other,
    502                 JSAtom** otherCached) const;
    503 
    504  bool isNull() const {
    505    return variant_.match(
    506        [](JSAtom* ptr) { return !ptr; },
    507        [](const NameStencilRef& ref) { return !ref.atomIndex_; });
    508  }
    509 };
    510 
    511 // ScopeContext holds information derived from the scope and environment chains
    512 // to try to avoid the parser needing to traverse VM structures directly.
    513 struct ScopeContext {
    514  // Cache: Scope -> (JSAtom/TaggedParserAtomIndex -> NameLocation)
    515  //
    516  // This cache maps the scope to a hash table which can lookup a name of the
    517  // scope to the equivalent NameLocation.
    518  ScopeBindingCache* scopeCache = nullptr;
    519 
    520  // Generation number of the `scopeCache` collected before filling the cache
    521  // with enclosing scope information.
    522  //
    523  // The generation number, obtained from `scopeCache->getCurrentGeneration()`
    524  // is incremented each time the GC invalidate the content of the cache. The
    525  // `scopeCache` can only be used when the generation number collected before
    526  // filling the cache is identical to the generation number seen when querying
    527  // the cached content.
    528  size_t scopeCacheGen = 0;
    529 
    530  // Class field initializer info if we are nested within a class constructor.
    531  // We may be an combination of arrow and eval context within the constructor.
    532  mozilla::Maybe<MemberInitializers> memberInitializers = {};
    533 
    534  enum class EnclosingLexicalBindingKind {
    535    Let,
    536    Const,
    537    CatchParameter,
    538    Synthetic,
    539    PrivateMethod,
    540  };
    541 
    542  using EnclosingLexicalBindingCache =
    543      mozilla::HashMap<TaggedParserAtomIndex, EnclosingLexicalBindingKind,
    544                       TaggedParserAtomIndexHasher>;
    545 
    546  // Cache of enclosing lexical bindings.
    547  // Used only for eval.
    548  mozilla::Maybe<EnclosingLexicalBindingCache> enclosingLexicalBindingCache_;
    549 
    550  // A map of private names to NameLocations used to allow evals to
    551  // provide correct private name semantics (particularly around early
    552  // errors and private brand lookup).
    553  using EffectiveScopePrivateFieldCache =
    554      mozilla::HashMap<TaggedParserAtomIndex, NameLocation,
    555                       TaggedParserAtomIndexHasher>;
    556 
    557  // Cache of enclosing class's private fields.
    558  // Used only for eval.
    559  mozilla::Maybe<EffectiveScopePrivateFieldCache>
    560      effectiveScopePrivateFieldCache_;
    561 
    562 #ifdef DEBUG
    563  bool enclosingEnvironmentIsDebugProxy_ = false;
    564 #endif
    565 
    566  // How many hops required to navigate from 'enclosingScope' to effective
    567  // scope.
    568  uint32_t effectiveScopeHops = 0;
    569 
    570  uint32_t enclosingScopeEnvironmentChainLength = 0;
    571 
    572  // Eval and arrow scripts also inherit the "this" environment -- used by
    573  // `super` expressions -- from their enclosing script. We count the number of
    574  // environment hops needed to get from enclosing scope to the nearest
    575  // appropriate environment. This value is undefined if the script we are
    576  // compiling is not an eval or arrow-function.
    577  uint32_t enclosingThisEnvironmentHops = 0;
    578 
    579  // The kind of enclosing scope.
    580  ScopeKind enclosingScopeKind = ScopeKind::Global;
    581 
    582  // The type of binding required for `this` of the top level context, as
    583  // indicated by the enclosing scopes of this parse.
    584  //
    585  // NOTE: This is computed based on the effective scope (defined above).
    586  ThisBinding thisBinding = ThisBinding::Global;
    587 
    588  // Eval and arrow scripts inherit certain syntax allowances from their
    589  // enclosing scripts.
    590  bool allowNewTarget = false;
    591  bool allowSuperProperty = false;
    592  bool allowSuperCall = false;
    593  bool allowArguments = true;
    594 
    595  // Indicates there is a 'class' or 'with' scope on enclosing scope chain.
    596  bool inClass = false;
    597  bool inWith = false;
    598 
    599  // True if the enclosing scope is for FunctionScope of arrow function.
    600  bool enclosingScopeIsArrow = false;
    601 
    602  // True if the enclosing scope has environment.
    603  bool enclosingScopeHasEnvironment = false;
    604 
    605 #ifdef DEBUG
    606  // True if the enclosing scope has non-syntactic scope on chain.
    607  bool hasNonSyntacticScopeOnChain = false;
    608 
    609  // True if the enclosing scope has function scope where the function needs
    610  // home object.
    611  bool hasFunctionNeedsHomeObjectOnChain = false;
    612 #endif
    613 
    614  bool init(FrontendContext* fc, CompilationInput& input,
    615            ParserAtomsTable& parserAtoms, ScopeBindingCache* scopeCache,
    616            InheritThis inheritThis, JSObject* enclosingEnv);
    617 
    618  mozilla::Maybe<EnclosingLexicalBindingKind>
    619  lookupLexicalBindingInEnclosingScope(TaggedParserAtomIndex name);
    620 
    621  NameLocation searchInEnclosingScope(FrontendContext* fc,
    622                                      CompilationInput& input,
    623                                      ParserAtomsTable& parserAtoms,
    624                                      TaggedParserAtomIndex name);
    625 
    626  bool effectiveScopePrivateFieldCacheHas(TaggedParserAtomIndex name);
    627  mozilla::Maybe<NameLocation> getPrivateFieldLocation(
    628      TaggedParserAtomIndex name);
    629 
    630 private:
    631  void computeThisBinding(const InputScope& scope);
    632  void computeThisEnvironment(const InputScope& enclosingScope);
    633  void computeInScope(const InputScope& enclosingScope);
    634  void cacheEnclosingScope(const InputScope& enclosingScope);
    635  NameLocation searchInEnclosingScopeWithCache(FrontendContext* fc,
    636                                               CompilationInput& input,
    637                                               ParserAtomsTable& parserAtoms,
    638                                               TaggedParserAtomIndex name);
    639  NameLocation searchInEnclosingScopeNoCache(FrontendContext* fc,
    640                                             CompilationInput& input,
    641                                             ParserAtomsTable& parserAtoms,
    642                                             TaggedParserAtomIndex name);
    643 
    644  InputScope determineEffectiveScope(InputScope& scope, JSObject* environment);
    645 
    646  bool cachePrivateFieldsForEval(FrontendContext* fc, CompilationInput& input,
    647                                 JSObject* enclosingEnvironment,
    648                                 const InputScope& effectiveScope,
    649                                 ParserAtomsTable& parserAtoms);
    650 
    651  bool cacheEnclosingScopeBindingForEval(FrontendContext* fc,
    652                                         CompilationInput& input,
    653                                         ParserAtomsTable& parserAtoms);
    654 
    655  bool addToEnclosingLexicalBindingCache(FrontendContext* fc,
    656                                         ParserAtomsTable& parserAtoms,
    657                                         CompilationAtomCache& atomCache,
    658                                         InputName& name,
    659                                         EnclosingLexicalBindingKind kind);
    660 };
    661 
    662 struct CompilationAtomCache {
    663 public:
    664  using AtomCacheVector = JS::GCVector<JSString*, 0, js::SystemAllocPolicy>;
    665 
    666 private:
    667  // Atoms lowered into or converted from CompilationStencil.parserAtomData.
    668  //
    669  // This field is here instead of in CompilationGCOutput because atoms lowered
    670  // from JSAtom is part of input (enclosing scope bindings, lazy function name,
    671  // etc), and having 2 vectors in both input/output is error prone.
    672  AtomCacheVector atoms_;
    673 
    674 public:
    675  JSString* getExistingStringAt(ParserAtomIndex index) const;
    676  JSString* getExistingStringAt(JSContext* cx,
    677                                TaggedParserAtomIndex taggedIndex) const;
    678  JSString* getStringAt(ParserAtomIndex index) const;
    679 
    680  JSAtom* getExistingAtomAt(ParserAtomIndex index) const;
    681  JSAtom* getExistingAtomAt(JSContext* cx,
    682                            TaggedParserAtomIndex taggedIndex) const;
    683  JSAtom* getAtomAt(ParserAtomIndex index) const;
    684 
    685  bool hasAtomAt(ParserAtomIndex index) const;
    686  bool setAtomAt(FrontendContext* fc, ParserAtomIndex index, JSString* atom);
    687  bool allocate(FrontendContext* fc, size_t length);
    688 
    689  bool empty() const { return atoms_.empty(); }
    690  size_t size() const { return atoms_.length(); }
    691 
    692  void stealBuffer(AtomCacheVector& atoms);
    693  void releaseBuffer(AtomCacheVector& atoms);
    694 
    695  void trace(JSTracer* trc);
    696 
    697  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    698    return atoms_.sizeOfExcludingThis(mallocSizeOf);
    699  }
    700 };
    701 
    702 // Information associated with an extra binding provided to a global script.
    703 // See frontend::CompileGlobalScriptWithExtraBindings.
    704 struct ExtraBindingInfo {
    705  // UTF-8 encoded name of the binding.
    706  UniqueChars nameChars;
    707 
    708  TaggedParserAtomIndex nameIndex;
    709 
    710  // If the binding conflicts with global variable or global lexical variable,
    711  // the binding is shadowed.
    712  bool isShadowed = false;
    713 
    714  ExtraBindingInfo(UniqueChars&& nameChars, bool isShadowed)
    715      : nameChars(std::move(nameChars)), isShadowed(isShadowed) {}
    716 };
    717 
    718 using ExtraBindingInfoVector =
    719    js::Vector<ExtraBindingInfo, 0, js::SystemAllocPolicy>;
    720 
    721 // Input of the compilation, including source and enclosing context.
    722 struct CompilationInput {
    723  enum class CompilationTarget {
    724    Global,
    725    SelfHosting,
    726    StandaloneFunction,
    727    StandaloneFunctionInNonSyntacticScope,
    728    Eval,
    729    Module,
    730    Delazification,
    731  };
    732  CompilationTarget target = CompilationTarget::Global;
    733 
    734  const JS::ReadOnlyCompileOptions& options;
    735 
    736  CompilationAtomCache atomCache;
    737 
    738 private:
    739  InputScript lazy_ = InputScript(nullptr);
    740 
    741  // Extra bindings for the global script.
    742  ExtraBindingInfoVector* maybeExtraBindings_ = nullptr;
    743 
    744 public:
    745  RefPtr<ScriptSource> source;
    746 
    747  //  * If the target is Global, null.
    748  //  * If the target is SelfHosting, null. Instantiation code for self-hosting
    749  //    will ignore this and use the appropriate empty global scope instead.
    750  //  * If the target is StandaloneFunction, an empty global scope.
    751  //  * If the target is StandaloneFunctionInNonSyntacticScope, the non-null
    752  //    enclosing scope of the function
    753  //  * If the target is Eval, the non-null enclosing scope of the `eval`.
    754  //  * If the target is Module, null that means empty global scope
    755  //    (See EmitterScope::checkEnvironmentChainLength)
    756  //  * If the target is Delazification, the non-null enclosing scope of
    757  //    the function
    758  InputScope enclosingScope = InputScope(nullptr);
    759 
    760  explicit CompilationInput(const JS::ReadOnlyCompileOptions& options)
    761      : options(options) {}
    762 
    763 private:
    764  bool initScriptSource(FrontendContext* fc);
    765 
    766 public:
    767  bool initForGlobal(FrontendContext* fc) {
    768    target = CompilationTarget::Global;
    769    return initScriptSource(fc);
    770  }
    771 
    772  bool initForGlobalWithExtraBindings(
    773      FrontendContext* fc, ExtraBindingInfoVector* maybeExtraBindings) {
    774    MOZ_ASSERT(maybeExtraBindings);
    775    target = CompilationTarget::Global;
    776    maybeExtraBindings_ = maybeExtraBindings;
    777    return initScriptSource(fc);
    778  }
    779 
    780  bool initForSelfHostingGlobal(FrontendContext* fc) {
    781    target = CompilationTarget::SelfHosting;
    782    return initScriptSource(fc);
    783  }
    784 
    785  bool initForStandaloneFunction(JSContext* cx, FrontendContext* fc) {
    786    target = CompilationTarget::StandaloneFunction;
    787    if (!initScriptSource(fc)) {
    788      return false;
    789    }
    790    enclosingScope = InputScope(&cx->global()->emptyGlobalScope());
    791    return true;
    792  }
    793 
    794  bool initForStandaloneFunctionInNonSyntacticScope(
    795      FrontendContext* fc, JS::Handle<Scope*> functionEnclosingScope);
    796 
    797  bool initForEval(FrontendContext* fc, JS::Handle<Scope*> evalEnclosingScope) {
    798    target = CompilationTarget::Eval;
    799    if (!initScriptSource(fc)) {
    800      return false;
    801    }
    802    enclosingScope = InputScope(evalEnclosingScope);
    803    return true;
    804  }
    805 
    806  bool initForModule(FrontendContext* fc) {
    807    target = CompilationTarget::Module;
    808    if (!initScriptSource(fc)) {
    809      return false;
    810    }
    811    // The `enclosingScope` is the emptyGlobalScope.
    812    return true;
    813  }
    814 
    815  void initFromLazy(JSContext* cx, BaseScript* lazyScript, ScriptSource* ss) {
    816    MOZ_ASSERT(cx->compartment() == lazyScript->compartment());
    817 
    818    // We can only compile functions whose parents have previously been
    819    // compiled, because compilation requires full information about the
    820    // function's immediately enclosing scope.
    821    MOZ_ASSERT(lazyScript->isReadyForDelazification());
    822    target = CompilationTarget::Delazification;
    823    lazy_ = InputScript(lazyScript);
    824    source = ss;
    825    enclosingScope = lazy_.enclosingScope();
    826  }
    827 
    828  void initFromStencil(const InitialStencilAndDelazifications& stencils,
    829                       ScriptIndex scriptIndex, ScriptSource* ss) {
    830    target = CompilationTarget::Delazification;
    831    lazy_ = InputScript(stencils, scriptIndex);
    832    source = ss;
    833    enclosingScope = lazy_.enclosingScope();
    834  }
    835 
    836  // Returns true if enclosingScope field is provided to init* function,
    837  // instead of setting to empty global internally.
    838  bool hasNonDefaultEnclosingScope() const {
    839    return target == CompilationTarget::StandaloneFunctionInNonSyntacticScope ||
    840           target == CompilationTarget::Eval ||
    841           target == CompilationTarget::Delazification;
    842  }
    843 
    844  // Returns the enclosing scope provided to init* function.
    845  // nullptr otherwise.
    846  InputScope maybeNonDefaultEnclosingScope() const {
    847    if (hasNonDefaultEnclosingScope()) {
    848      return enclosingScope;
    849    }
    850    return InputScope(nullptr);
    851  }
    852 
    853  // The BaseScript* is needed when instantiating a lazy function.
    854  // See InstantiateTopLevel and FunctionsFromExistingLazy.
    855  InputScript lazyOuterScript() { return lazy_; }
    856  BaseScript* lazyOuterBaseScript() { return lazy_.raw().as<BaseScript*>(); }
    857 
    858  // The JSFunction* is needed when instantiating a lazy function.
    859  // See FunctionsFromExistingLazy.
    860  JSFunction* function() const {
    861    return lazy_.raw().as<BaseScript*>()->function();
    862  }
    863 
    864  // When compiling an inner function, we want to know the unique identifier
    865  // which identify a function. This is computed from the source extend.
    866  SourceExtent extent() const { return lazy_.extent(); }
    867 
    868  // See `BaseScript::immutableFlags_`.
    869  ImmutableScriptFlags immutableFlags() const { return lazy_.immutableFlags(); }
    870 
    871  RO_IMMUTABLE_SCRIPT_FLAGS(immutableFlags())
    872 
    873  FunctionFlags functionFlags() const { return lazy_.functionFlags(); }
    874 
    875  // When delazifying, return the kind of function which is defined.
    876  FunctionSyntaxKind functionSyntaxKind() const;
    877 
    878  bool hasPrivateScriptData() const {
    879    // This is equivalent to: ngcthings != 0 || useMemberInitializers()
    880    // See BaseScript::CreateRawLazy.
    881    return lazy_.hasPrivateScriptData();
    882  }
    883 
    884  // Whether this CompilationInput is parsing the top-level of a script, or
    885  // false if we are parsing an inner function.
    886  bool isInitialStencil() { return lazy_.isNull(); }
    887 
    888  // Whether this CompilationInput is parsing a specific function with already
    889  // pre-parsed contextual information.
    890  bool isDelazifying() { return target == CompilationTarget::Delazification; }
    891 
    892  bool hasExtraBindings() const { return !!maybeExtraBindings_; }
    893  ExtraBindingInfoVector& extraBindings() { return *maybeExtraBindings_; }
    894  const ExtraBindingInfoVector& extraBindings() const {
    895    return *maybeExtraBindings_;
    896  }
    897  bool internExtraBindings(FrontendContext* fc, ParserAtomsTable& parserAtoms);
    898 
    899  void trace(JSTracer* trc);
    900 
    901  // Size of dynamic data. Note that GC data is counted by GC and not here. We
    902  // also ignore ScriptSource which is a shared RefPtr.
    903  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    904    return atomCache.sizeOfExcludingThis(mallocSizeOf);
    905  }
    906  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
    907    return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
    908  }
    909 
    910 #if defined(DEBUG) || defined(JS_JITSPEW)
    911  void dump() const;
    912  void dump(js::JSONPrinter& json) const;
    913  void dumpFields(js::JSONPrinter& json) const;
    914 #endif
    915 };
    916 
    917 // When compiling a function which was previously Syntaxly Parsed, we generated
    918 // some information which made it possible to skip over some parsing phases,
    919 // such as computing closed over bindings as well as parsing inner functions.
    920 // This class contains all information which is generated by the SyntaxParse and
    921 // reused in the FullParse.
    922 class CompilationSyntaxParseCache {
    923  // When delazifying, we should prepare an array which contains all
    924  // stencil-like gc-things such that it can be used by the parser.
    925  //
    926  // When compiling from a Stencil, this will alias the existing Stencil.
    927  mozilla::Span<TaggedScriptThingIndex> cachedGCThings_;
    928 
    929  // When delazifying, we should perpare an array which contains all
    930  // stencil-like information about scripts, such that it can be used by the
    931  // parser.
    932  //
    933  // When compiling from a Stencil, these will alias the existing Stencil.
    934  mozilla::Span<ScriptStencil> cachedScriptData_;
    935  mozilla::Span<ScriptStencilExtra> cachedScriptExtra_;
    936 
    937  // When delazifying, we copy the atom, either from JSAtom, or from another
    938  // Stencil into TaggedParserAtomIndex which are valid in this current
    939  // CompilationState.
    940  mozilla::Span<TaggedParserAtomIndex> closedOverBindings_;
    941 
    942  // Atom of the function being compiled. This atom index is valid in the
    943  // current CompilationState.
    944  TaggedParserAtomIndex displayAtom_;
    945 
    946  // Stencil-like data about the function which is being compiled.
    947  ScriptStencilExtra funExtra_;
    948 
    949 #ifdef DEBUG
    950  // Whether any of these data should be considered or not.
    951  bool isInitialized = false;
    952 #endif
    953 
    954 public:
    955  // When doing a full-parse of an incomplete BaseScript*, we have to iterate
    956  // over functions and closed-over bindings, to avoid costly recursive decent
    957  // in inner functions. This function will clone the BaseScript* information to
    958  // make it available as a stencil-like data to the full-parser.
    959  mozilla::Span<TaggedParserAtomIndex> closedOverBindings() const {
    960    MOZ_ASSERT(isInitialized);
    961    return closedOverBindings_;
    962  }
    963  const ScriptStencil& scriptData(size_t functionIndex) const {
    964    return cachedScriptData_[scriptIndex(functionIndex)];
    965  }
    966  const ScriptStencilExtra& scriptExtra(size_t functionIndex) const {
    967    return cachedScriptExtra_[scriptIndex(functionIndex)];
    968  }
    969 
    970  // Return the name of the function being delazified, if any.
    971  TaggedParserAtomIndex displayAtom() const {
    972    MOZ_ASSERT(isInitialized);
    973    return displayAtom_;
    974  }
    975 
    976  // Return the extra information about the function being delazified, if any.
    977  const ScriptStencilExtra& funExtra() const {
    978    MOZ_ASSERT(isInitialized);
    979    return funExtra_;
    980  }
    981 
    982  // Initialize the SynaxParse cache given a LifoAlloc. The JSContext is only
    983  // used for reporting allocation errors.
    984  [[nodiscard]] bool init(FrontendContext* fc, LifoAlloc& alloc,
    985                          ParserAtomsTable& parseAtoms,
    986                          CompilationAtomCache& atomCache,
    987                          const InputScript& lazy);
    988 
    989 private:
    990  // Return the script index of a given inner function.
    991  //
    992  // WARNING: The ScriptIndex returned by this function corresponds to the index
    993  // in the cachedScriptExtra_ and cachedScriptData_ spans. With the
    994  // cachedGCThings_ span, these might be reference to an actual Stencil from
    995  // another compilation. Thus, the ScriptIndex returned by this function should
    996  // not be confused with any ScriptIndex from the CompilationState.
    997  ScriptIndex scriptIndex(size_t functionIndex) const {
    998    MOZ_ASSERT(isInitialized);
    999    auto taggedScriptIndex = cachedGCThings_[functionIndex];
   1000    MOZ_ASSERT(taggedScriptIndex.isFunction());
   1001    return taggedScriptIndex.toFunction();
   1002  }
   1003 
   1004  [[nodiscard]] bool copyFunctionInfo(FrontendContext* fc,
   1005                                      ParserAtomsTable& parseAtoms,
   1006                                      CompilationAtomCache& atomCache,
   1007                                      const InputScript& lazy);
   1008  [[nodiscard]] bool copyScriptInfo(FrontendContext* fc, LifoAlloc& alloc,
   1009                                    ParserAtomsTable& parseAtoms,
   1010                                    CompilationAtomCache& atomCache,
   1011                                    BaseScript* lazy);
   1012  [[nodiscard]] bool copyScriptInfo(FrontendContext* fc, LifoAlloc& alloc,
   1013                                    ParserAtomsTable& parseAtoms,
   1014                                    CompilationAtomCache& atomCache,
   1015                                    const ScriptStencilRef& lazy);
   1016  [[nodiscard]] bool copyClosedOverBindings(FrontendContext* fc,
   1017                                            LifoAlloc& alloc,
   1018                                            ParserAtomsTable& parseAtoms,
   1019                                            CompilationAtomCache& atomCache,
   1020                                            BaseScript* lazy);
   1021  [[nodiscard]] bool copyClosedOverBindings(FrontendContext* fc,
   1022                                            LifoAlloc& alloc,
   1023                                            ParserAtomsTable& parseAtoms,
   1024                                            CompilationAtomCache& atomCache,
   1025                                            const ScriptStencilRef& lazy);
   1026 };
   1027 
   1028 // AsmJS scripts are very rare on-average, so we use a HashMap to associate
   1029 // data with a ScriptStencil. The ScriptStencil has a flag to indicate if we
   1030 // need to even do this lookup.
   1031 using StencilAsmJSMap =
   1032    mozilla::HashMap<ScriptIndex, RefPtr<const JS::WasmModule>,
   1033                     mozilla::DefaultHasher<ScriptIndex>,
   1034                     js::SystemAllocPolicy>;
   1035 
   1036 struct StencilAsmJSContainer
   1037    : public js::AtomicRefCounted<StencilAsmJSContainer> {
   1038  StencilAsmJSMap moduleMap;
   1039 
   1040  StencilAsmJSContainer() = default;
   1041 
   1042  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   1043    return moduleMap.shallowSizeOfExcludingThis(mallocSizeOf);
   1044  }
   1045  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   1046    return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
   1047  }
   1048 };
   1049 
   1050 // Store shared data for non-lazy script.
   1051 struct SharedDataContainer {
   1052  // NOTE: While stored, we must hold a ref-count and care must be taken when
   1053  //       updating or clearing the pointer.
   1054  using SingleSharedDataPtr = SharedImmutableScriptData*;
   1055 
   1056  using SharedDataVector =
   1057      Vector<RefPtr<js::SharedImmutableScriptData>, 0, js::SystemAllocPolicy>;
   1058  using SharedDataVectorPtr = SharedDataVector*;
   1059 
   1060  using SharedDataMap =
   1061      mozilla::HashMap<ScriptIndex, RefPtr<js::SharedImmutableScriptData>,
   1062                       mozilla::DefaultHasher<ScriptIndex>,
   1063                       js::SystemAllocPolicy>;
   1064  using SharedDataMapPtr = SharedDataMap*;
   1065 
   1066 private:
   1067  enum {
   1068    SingleTag = 0,
   1069    VectorTag = 1,
   1070    MapTag = 2,
   1071    BorrowTag = 3,
   1072 
   1073    TagMask = 3,
   1074  };
   1075 
   1076  uintptr_t data_ = 0;
   1077 
   1078 public:
   1079  // Defaults to SingleSharedData.
   1080  SharedDataContainer() = default;
   1081 
   1082  SharedDataContainer(const SharedDataContainer&) = delete;
   1083  SharedDataContainer(SharedDataContainer&& other) noexcept {
   1084    std::swap(data_, other.data_);
   1085    MOZ_ASSERT(other.isEmpty());
   1086  }
   1087 
   1088  SharedDataContainer& operator=(const SharedDataContainer&) = delete;
   1089  SharedDataContainer& operator=(SharedDataContainer&& other) noexcept {
   1090    std::swap(data_, other.data_);
   1091    MOZ_ASSERT(other.isEmpty());
   1092    return *this;
   1093  }
   1094 
   1095  ~SharedDataContainer();
   1096 
   1097  [[nodiscard]] bool initVector(FrontendContext* fc);
   1098  [[nodiscard]] bool initMap(FrontendContext* fc);
   1099 
   1100 private:
   1101  [[nodiscard]] bool convertFromSingleToMap(FrontendContext* fc);
   1102 
   1103 public:
   1104  bool isEmpty() const { return (data_) == SingleTag; }
   1105  bool isSingle() const { return (data_ & TagMask) == SingleTag; }
   1106  bool isVector() const { return (data_ & TagMask) == VectorTag; }
   1107  bool isMap() const { return (data_ & TagMask) == MapTag; }
   1108  bool isBorrow() const { return (data_ & TagMask) == BorrowTag; }
   1109 
   1110  void setSingle(already_AddRefed<SharedImmutableScriptData>&& data) {
   1111    MOZ_ASSERT(isEmpty());
   1112    data_ = reinterpret_cast<uintptr_t>(data.take());
   1113    MOZ_ASSERT(isSingle());
   1114    MOZ_ASSERT(!isEmpty());
   1115  }
   1116 
   1117  void setBorrow(SharedDataContainer* sharedData) {
   1118    MOZ_ASSERT(isEmpty());
   1119    data_ = reinterpret_cast<uintptr_t>(sharedData) | BorrowTag;
   1120    MOZ_ASSERT(isBorrow());
   1121  }
   1122 
   1123  SingleSharedDataPtr asSingle() const {
   1124    MOZ_ASSERT(isSingle());
   1125    MOZ_ASSERT(!isEmpty());
   1126    static_assert(SingleTag == 0);
   1127    return reinterpret_cast<SingleSharedDataPtr>(data_);
   1128  }
   1129  SharedDataVectorPtr asVector() const {
   1130    MOZ_ASSERT(isVector());
   1131    return reinterpret_cast<SharedDataVectorPtr>(data_ & ~TagMask);
   1132  }
   1133  SharedDataMapPtr asMap() const {
   1134    MOZ_ASSERT(isMap());
   1135    return reinterpret_cast<SharedDataMapPtr>(data_ & ~TagMask);
   1136  }
   1137  SharedDataContainer* asBorrow() const {
   1138    MOZ_ASSERT(isBorrow());
   1139    return reinterpret_cast<SharedDataContainer*>(data_ & ~TagMask);
   1140  }
   1141 
   1142  [[nodiscard]] bool prepareStorageFor(FrontendContext* fc,
   1143                                       size_t nonLazyScriptCount,
   1144                                       size_t allScriptCount);
   1145  [[nodiscard]] bool cloneFrom(FrontendContext* fc,
   1146                               const SharedDataContainer& other);
   1147 
   1148  // Returns index-th script's shared data, or nullptr if it doesn't have.
   1149  js::SharedImmutableScriptData* get(ScriptIndex index) const;
   1150 
   1151  // Add data for index-th script and share it with VM.
   1152  [[nodiscard]] bool addAndShare(FrontendContext* fc, ScriptIndex index,
   1153                                 js::SharedImmutableScriptData* data);
   1154 
   1155  // Add data for index-th script without sharing it with VM.
   1156  // The data should already be shared with VM.
   1157  //
   1158  // The data is supposed to be added from delazification.
   1159  [[nodiscard]] bool addExtraWithoutShare(FrontendContext* fc,
   1160                                          ScriptIndex index,
   1161                                          js::SharedImmutableScriptData* data);
   1162 
   1163  // Dynamic memory associated with this container. Does not include the
   1164  // SharedImmutableScriptData since we are not the unique owner of it.
   1165  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   1166    if (isVector()) {
   1167      return asVector()->sizeOfIncludingThis(mallocSizeOf);
   1168    }
   1169    if (isMap()) {
   1170      return asMap()->shallowSizeOfIncludingThis(mallocSizeOf);
   1171    }
   1172    MOZ_ASSERT(isSingle() || isBorrow());
   1173    return 0;
   1174  }
   1175 
   1176 #if defined(DEBUG) || defined(JS_JITSPEW)
   1177  void dump() const;
   1178  void dump(js::JSONPrinter& json) const;
   1179  void dumpFields(js::JSONPrinter& json) const;
   1180 #endif
   1181 };
   1182 
   1183 struct ExtensibleCompilationStencil;
   1184 
   1185 // The top level struct of stencil specialized for non-extensible case.
   1186 // Used as the compilation output, and also XDR decode output.
   1187 //
   1188 // In XDR decode output case, the span and not-owning pointer fields point
   1189 // the internal LifoAlloc and the external XDR buffer.
   1190 //
   1191 // In BorrowingCompilationStencil usage, span and not-owning pointer fields
   1192 // point the ExtensibleCompilationStencil and its LifoAlloc.
   1193 //
   1194 // The dependent XDR buffer or ExtensibleCompilationStencil must be kept
   1195 // alive manually.
   1196 //
   1197 // See SMDOC in Stencil.h for more info.
   1198 struct CompilationStencil {
   1199  friend struct ExtensibleCompilationStencil;
   1200 
   1201  static constexpr ScriptIndex TopLevelIndex = ScriptIndex(0);
   1202 
   1203  static constexpr size_t LifoAllocChunkSize = 512;
   1204 
   1205  // The lifetime of this CompilationStencil may be managed by stack allocation,
   1206  // UniquePtr<T>, or RefPtr<T>. If a RefPtr is used, this ref-count will track
   1207  // the lifetime, otherwise it is ignored.
   1208  //
   1209  // NOTE: Internal code and public APIs use a mix of these different allocation
   1210  //       modes.
   1211  //
   1212  // See: JS::StencilAddRef/Release
   1213  mutable mozilla::Atomic<uintptr_t> refCount_{0};
   1214 
   1215 private:
   1216  // On-heap ExtensibleCompilationStencil that this CompilationStencil owns,
   1217  // and this CompilationStencil borrows each data from.
   1218  UniquePtr<ExtensibleCompilationStencil> ownedBorrowStencil;
   1219 
   1220 public:
   1221  enum class StorageType {
   1222    // Pointers and spans point LifoAlloc or owned buffer.
   1223    Owned,
   1224 
   1225    // Pointers and spans point external data, such as XDR buffer, or not-owned
   1226    // ExtensibleCompilationStencil (see BorrowingCompilationStencil).
   1227    Borrowed,
   1228 
   1229    // Pointers and spans point data owned by ownedBorrowStencil.
   1230    OwnedExtensible,
   1231  };
   1232  StorageType storageType = StorageType::Owned;
   1233 
   1234  // Value of CanLazilyParse(CompilationInput) on compilation.
   1235  // Used during instantiation, and also queried by
   1236  // InitialStencilAndDelazifications.
   1237  bool canLazilyParse = false;
   1238 
   1239  // If this stencil is a delazification, this identifies location of the
   1240  // function in the source text.
   1241  using FunctionKey = SourceExtent::FunctionKey;
   1242  FunctionKey functionKey = SourceExtent::NullFunctionKey;
   1243 
   1244  // This holds allocations that do not require destructors to be run but are
   1245  // live until the stencil is released.
   1246  LifoAlloc alloc;
   1247 
   1248  // The source text holder for the script. This may be an empty placeholder if
   1249  // the code will fully parsed and options indicate the source will never be
   1250  // needed again.
   1251  RefPtr<ScriptSource> source;
   1252 
   1253  // Stencil for all function and non-function scripts. The TopLevelIndex is
   1254  // reserved for the top-level script. This top-level may or may not be a
   1255  // function.
   1256  mozilla::Span<ScriptStencil> scriptData;
   1257 
   1258  // Immutable data computed during initial compilation and never updated during
   1259  // delazification.
   1260  mozilla::Span<ScriptStencilExtra> scriptExtra;
   1261 
   1262  mozilla::Span<TaggedScriptThingIndex> gcThingData;
   1263 
   1264  // scopeData and scopeNames have the same size, and i-th scopeNames contains
   1265  // the names for the bindings contained in the slot defined by i-th scopeData.
   1266  mozilla::Span<ScopeStencil> scopeData;
   1267  mozilla::Span<BaseParserScopeData*> scopeNames;
   1268 
   1269  // Hold onto the RegExpStencil, BigIntStencil, and ObjLiteralStencil that are
   1270  // allocated during parse to ensure correct destruction.
   1271  mozilla::Span<RegExpStencil> regExpData;
   1272  mozilla::Span<BigIntStencil> bigIntData;
   1273  mozilla::Span<ObjLiteralStencil> objLiteralData;
   1274 
   1275  // List of parser atoms for this compilation. This may contain nullptr entries
   1276  // when round-tripping with XDR if the atom was generated in original parse
   1277  // but not used by stencil.
   1278  ParserAtomSpan parserAtomData;
   1279 
   1280  // Variable sized container for bytecode and other immutable data. A valid
   1281  // stencil always contains at least an entry for `TopLevelIndex` script.
   1282  SharedDataContainer sharedData;
   1283 
   1284  // Module metadata if this is a module compile.
   1285  RefPtr<StencilModuleMetadata> moduleMetadata;
   1286 
   1287  // AsmJS modules generated by parsing. These scripts are never lazy and
   1288  // therefore only generated during initial parse.
   1289  //
   1290  // This is non-null if we have seen an asm.js directive, but doesn't imply
   1291  // that we successfully compiled an asm.js module. See the comment in
   1292  // FunctionBox::setUseAsm for more information.
   1293  RefPtr<StencilAsmJSContainer> asmJS;
   1294 
   1295  // End of fields.
   1296 
   1297  // Construct a CompilationStencil
   1298  explicit CompilationStencil(ScriptSource* source)
   1299      : alloc(LifoAllocChunkSize, js::BackgroundMallocArena), source(source) {}
   1300 
   1301  // Take the ownership of on-heap ExtensibleCompilationStencil and
   1302  // borrow from it.
   1303  explicit CompilationStencil(
   1304      UniquePtr<ExtensibleCompilationStencil>&& extensibleStencil);
   1305 
   1306  void AddRef();
   1307  void Release();
   1308 
   1309 protected:
   1310  void borrowFromExtensibleCompilationStencil(
   1311      ExtensibleCompilationStencil& extensibleStencil);
   1312 
   1313 #ifdef DEBUG
   1314  void assertBorrowingFromExtensibleCompilationStencil(
   1315      const ExtensibleCompilationStencil& extensibleStencil) const;
   1316 #endif
   1317 
   1318 public:
   1319  bool isInitialStencil() const {
   1320    return functionKey == SourceExtent::NullFunctionKey;
   1321  }
   1322 
   1323  [[nodiscard]] static bool instantiateStencilAfterPreparation(
   1324      JSContext* cx, CompilationInput& input, const CompilationStencil& stencil,
   1325      CompilationGCOutput& gcOutput);
   1326 
   1327  [[nodiscard]] static bool prepareForInstantiate(
   1328      FrontendContext* fc, CompilationAtomCache& atomCache,
   1329      const CompilationStencil& stencil, CompilationGCOutput& gcOutput);
   1330  [[nodiscard]] static bool prepareForInstantiate(
   1331      FrontendContext* fc, const CompilationStencil& stencil,
   1332      PreallocatedCompilationGCOutput& gcOutput);
   1333 
   1334  [[nodiscard]] static bool instantiateStencils(
   1335      JSContext* cx, CompilationInput& input, const CompilationStencil& stencil,
   1336      CompilationGCOutput& gcOutput);
   1337 
   1338  // Decode the special self-hosted stencil
   1339  [[nodiscard]] bool instantiateSelfHostedAtoms(
   1340      JSContext* cx, AtomSet& atomSet, CompilationAtomCache& atomCache) const;
   1341  [[nodiscard]] JSScript* instantiateSelfHostedTopLevelForRealm(
   1342      JSContext* cx, CompilationInput& input);
   1343  [[nodiscard]] JSFunction* instantiateSelfHostedLazyFunction(
   1344      JSContext* cx, CompilationAtomCache& atomCache, ScriptIndex index,
   1345      JS::Handle<JSAtom*> name);
   1346  [[nodiscard]] bool delazifySelfHostedFunction(JSContext* cx,
   1347                                                CompilationAtomCache& atomCache,
   1348                                                ScriptIndexRange range,
   1349                                                Handle<JSAtom*> name,
   1350                                                JS::Handle<JSFunction*> fun);
   1351 
   1352  // To avoid any misuses, make sure this is neither copyable or assignable.
   1353  CompilationStencil(const CompilationStencil&) = delete;
   1354  CompilationStencil(CompilationStencil&&) = delete;
   1355  CompilationStencil& operator=(const CompilationStencil&) = delete;
   1356  CompilationStencil& operator=(CompilationStencil&&) = delete;
   1357 #ifdef DEBUG
   1358  ~CompilationStencil() {
   1359    // We can mix UniquePtr<..> and RefPtr<..>. This asserts that a UniquePtr
   1360    // does not delete a reference-counted stencil.
   1361    MOZ_ASSERT(!refCount_);
   1362  }
   1363 #endif
   1364 
   1365  static inline ScriptStencilIterable functionScriptStencils(
   1366      const CompilationStencil& stencil, CompilationGCOutput& gcOutput);
   1367 
   1368  void setFunctionKey(BaseScript* lazy) {
   1369    functionKey = lazy->extent().toFunctionKey();
   1370  }
   1371 
   1372  inline size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
   1373  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   1374    return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
   1375  }
   1376 
   1377  const ParserAtomSpan& parserAtomsSpan() const { return parserAtomData; }
   1378 
   1379  bool isModule() const;
   1380 
   1381  // Whether this stencil has a function with an asm.js directive in it. The
   1382  // function may not have been compiled with asm.js if support was disabled or
   1383  // the asm.js module failed validation.
   1384  bool hasAsmJS() const;
   1385 
   1386  bool hasMultipleReference() const { return refCount_ > 1; }
   1387 
   1388  bool hasOwnedBorrow() const {
   1389    return storageType == StorageType::OwnedExtensible;
   1390  }
   1391 
   1392  ExtensibleCompilationStencil* takeOwnedBorrow() {
   1393    MOZ_ASSERT(!hasMultipleReference());
   1394    MOZ_ASSERT(hasOwnedBorrow());
   1395    return ownedBorrowStencil.release();
   1396  }
   1397 
   1398 #ifdef DEBUG
   1399  void assertNoExternalDependency() const;
   1400 #endif
   1401 
   1402 #if defined(DEBUG) || defined(JS_JITSPEW)
   1403  void dump() const;
   1404  void dump(js::JSONPrinter& json) const;
   1405  void dumpFields(js::JSONPrinter& json) const;
   1406 
   1407  void dumpAtom(TaggedParserAtomIndex index) const;
   1408 #endif
   1409 };
   1410 
   1411 // A Map from a function key to the ScriptIndex in the initial stencil.
   1412 class FunctionKeyToScriptIndexMap {
   1413  using FunctionKey = SourceExtent::FunctionKey;
   1414  mozilla::HashMap<FunctionKey, ScriptIndex,
   1415                   mozilla::DefaultHasher<FunctionKey>, js::SystemAllocPolicy>
   1416      map_;
   1417 
   1418  template <typename T>
   1419  [[nodiscard]] bool init(FrontendContext* fc, const T& scriptExtra,
   1420                          size_t scriptExtraSize);
   1421 
   1422 public:
   1423  FunctionKeyToScriptIndexMap() = default;
   1424 
   1425  [[nodiscard]] bool init(FrontendContext* fc,
   1426                          const CompilationStencil* initial);
   1427  [[nodiscard]] bool init(FrontendContext* fc,
   1428                          const ExtensibleCompilationStencil* initial);
   1429 
   1430  mozilla::Maybe<ScriptIndex> get(FunctionKey key) const;
   1431 
   1432  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
   1433  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   1434    return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
   1435  }
   1436 };
   1437 
   1438 // This structure represents a function script inside a function, using a pair
   1439 // of indices which points to the enclosing script and the possibly-local index
   1440 // inside the enclosing compilation stencil.
   1441 //
   1442 // The `enclosingIndexInInitial` represents both the function script index in
   1443 // `InitialStencilAndDelazifications::initial_` and the stencil index within
   1444 // `InitialStencilAndDelazifications::delazifications_`, unless it is 0, in
   1445 // which case it corresponds to the initial stencil.
   1446 //
   1447 // The `indexInEnclosing` represents the script index in the compilation stencil
   1448 // in which the enclosing script would be fully parsed, indexed by
   1449 // `enclosingIndexInInitial`, which can either be the initial stencil or a
   1450 // delazification stencil.
   1451 //
   1452 // This structure absorbs the `InitialStencilAndDelazifications` splitted
   1453 // representation of having multiple `CompilationStencil`. Among the differences
   1454 // we can note the followings special case:
   1455 //
   1456 // (a) When `enclosingIndexInInitial` points a function which is eagerly
   1457 //   compiled in the initial compilation, then the `indexInEnclosing` is also an
   1458 //   index in the initial compilation, which points an inner function inside the
   1459 //   enclosing function. Thus, `indexInEnclosing > enclosingIndexInInitial`.
   1460 //
   1461 // (b) When `enclosingIndexInInitial` points a function which is syntax-parsed
   1462 //   in the initial compilation, then the `indexInEnclosing` is an index in a
   1463 //   delazification compilation. Given that the index 0-th of a delazification
   1464 //   compilation is the delazified script. Thus, `indexInEnclosing > 0`, which
   1465 //   points an inner function inside the enclosing function.
   1466 //
   1467 // At the intersection of both cases, the followings should be held:
   1468 //
   1469 // - `indexInEnclosing != 0`: it cannot point neither of the top-level script,
   1470 // or
   1471 //   the enclosing function script itself.
   1472 struct ScriptIndexes {
   1473  // Index of an enclosing function script within the initial
   1474  // CompilationStencil. This is used also to retrieve the initial stencil or
   1475  // delazification stencil from `InitialStencilAndDelazifications`.
   1476  ScriptIndex enclosingIndexInInitial;
   1477 
   1478  // Index of a function script within the enclosing `CompilationStencil`. The
   1479  // enclosing `CompilationStencil` contains the fully-parsed content for the
   1480  // `enclosingIndexInInitial` function script. It can either be the initial
   1481  // compilation stencil or the delazitication.
   1482  ScriptIndex indexInEnclosing;
   1483 };
   1484 
   1485 struct RelativeIndexes {
   1486  // Number of tasks which are making use of the indexes_ vector.
   1487  ExclusiveData<size_t> consumers_;
   1488 
   1489  // The consumers_ lock must be held and should have at most a single consumer
   1490  // to write to this value. In the spirit, this should be an RWExclusiveData
   1491  // using the same lock as the consumers_, except that we do not want to hold
   1492  // the lock when we are in a section where the consumer value is positive.
   1493  Vector<ScriptIndexes, 0, js::SystemAllocPolicy> indexes_;
   1494 
   1495  RelativeIndexes() : consumers_(mutexid::StencilCache), indexes_() {}
   1496 
   1497  ScriptIndexes& operator[](size_t i) { return indexes_[i]; }
   1498  const ScriptIndexes& operator[](size_t i) const { return indexes_[i]; }
   1499 };
   1500 
   1501 // A class to Associate the initial stencil and the delazifications.
   1502 //
   1503 // This struct is initialized with the initial stencil, with an empty set of
   1504 // delazifications.
   1505 // The delazifications_ vector is fixed-size, pre-allocated for each script
   1506 // stencil, excluding the top-level script.
   1507 //
   1508 // The delazifications_ vector elements are initialized with nullptr, and
   1509 // monotonically populated with each delazification result.
   1510 // Only the first delazification for the given function is used.
   1511 //
   1512 // This struct is supposed to be read/write from multiple threads, and all
   1513 // operations, except init, are thread-safe.
   1514 struct InitialStencilAndDelazifications {
   1515 private:
   1516  using FunctionKey = SourceExtent::FunctionKey;
   1517 
   1518  // Shared reference to the initial stencil.
   1519  RefPtr<const CompilationStencil> initial_;
   1520 
   1521  // Exclusively owning pointers for delazifications.
   1522  //
   1523  // The i-th element is for ScriptIndex(i-1).
   1524  //
   1525  // If the initial stencil is known to be fully-parsed, this vector is
   1526  // 0-sized and unused.
   1527  Vector<mozilla::Atomic<CompilationStencil*>, 0, js::SystemAllocPolicy>
   1528      delazifications_;
   1529 
   1530  // A Map from a function key to the ScriptIndex in the initial stencil.
   1531  //
   1532  // If the initial stencil is known to be fully-parsed, this map is
   1533  // uninitialized and unused
   1534  FunctionKeyToScriptIndexMap functionKeyToInitialScriptIndex_;
   1535 
   1536  // Map an initial scriptIndex to its enclosing initial scriptIndex as well as
   1537  // its scriptIndex within the enclosing script stencil.
   1538  //
   1539  // This structure caches information which is only available after some
   1540  // computation in a stencil.
   1541  //
   1542  // For example, the following script:
   1543  // ```js
   1544  // function f1() {
   1545  //   function f2() {
   1546  //     function f3() {}
   1547  //     function f4() {}
   1548  //   }
   1549  //   function f5() {}
   1550  // }
   1551  // ```
   1552  //
   1553  // Would yield a vector such as:
   1554  //
   1555  // relativeIndexes_ = {
   1556  //   /* f1 */ { enclosingIndexInInitial: 0, indexInEnclosing: 1 },
   1557  //   /* f2 */ { enclosingIndexInInitial: 1, indexInEnclosing: 1 },
   1558  //   /* f3 */ { enclosingIndexInInitial: 2, indexInEnclosing: 1 },
   1559  //   /* f4 */ { enclosingIndexInInitial: 2, indexInEnclosing: 2 },
   1560  //   /* f5 */ { enclosingIndexInInitial: 1, indexInEnclosing: 2 },
   1561  // }
   1562  //
   1563  RelativeIndexes relativeIndexes_;
   1564 
   1565  mutable mozilla::Atomic<uintptr_t> refCount_{0};
   1566 
   1567 public:
   1568  class RelativeIndexesGuard {
   1569    friend struct InitialStencilAndDelazifications;
   1570    RefPtr<InitialStencilAndDelazifications> stencils_;
   1571 
   1572    explicit RelativeIndexesGuard(InitialStencilAndDelazifications* stencils)
   1573        : stencils_(stencils) {}
   1574 
   1575   public:
   1576    RelativeIndexesGuard() : stencils_(nullptr) {}
   1577 
   1578    RelativeIndexesGuard(RelativeIndexesGuard&& src)
   1579        : stencils_(std::move(src.stencils_)) {}
   1580 
   1581    ~RelativeIndexesGuard() {
   1582      if (stencils_) {
   1583        stencils_->decrementRelativeIndexesConsumer();
   1584        stencils_ = nullptr;
   1585      }
   1586    };
   1587    explicit operator bool() { return bool(stencils_); }
   1588  };
   1589 
   1590 private:
   1591  // Initialize relative indexes based on the initial's gcThings.
   1592  void decrementRelativeIndexesConsumer();
   1593  friend class RelativeIndexesGuard;
   1594 
   1595 public:
   1596  InitialStencilAndDelazifications() = default;
   1597  ~InitialStencilAndDelazifications();
   1598 
   1599  void AddRef();
   1600  void Release();
   1601 
   1602  [[nodiscard]] bool init(FrontendContext* fc,
   1603                          const CompilationStencil* initial);
   1604 
   1605  [[nodiscard]] RelativeIndexesGuard ensureRelativeIndexes(FrontendContext* fc);
   1606 
   1607  // Get the initial stencil.
   1608  // As long as this instance is initialized, this returns non-null pointer.
   1609  const CompilationStencil* getInitial() const;
   1610 
   1611  // Returns true if the initial stencil is compiled with
   1612  // CanLazilyParse(CompilationInput).
   1613  //
   1614  // If this returns false:
   1615  //   * the delazifications_ vector is not allocated
   1616  //   * the functionKeyToInitialScriptIndex_ is not initialized
   1617  //   * getDelazificationAt and storeDelazification shouldn't be called
   1618  //   * getMerged shouldn't be called, and getInitial should be used instead
   1619  bool canLazilyParse() const { return initial_->canLazilyParse; }
   1620 
   1621  // Return the delazification stencil if it's already populated.
   1622  // Returns nullptr otherwise.
   1623  //
   1624  // The functionIndex parameter is the index of the corresponding script
   1625  // stencil (0-indexed, with the index 0 being the top-level script).
   1626  //
   1627  // if the extent is used instead, it calculates functionIndex and returns
   1628  // the delazification stencil if the functionIndex is found and it's already
   1629  // populated.
   1630  // Returns nullptr otherwise.
   1631  const CompilationStencil* getDelazificationAt(size_t functionIndex) const;
   1632  const CompilationStencil* getDelazificationFor(
   1633      const SourceExtent& extent) const;
   1634 
   1635  // Return the ScriptIndex of a delazification stencil in the initial stencil.
   1636  // This index is retrieved using the SourceExtent.
   1637  ScriptIndex getScriptIndexFor(const CompilationStencil* delazification) const;
   1638 
   1639  // Return the script indexes to find the enclosing function script's index in
   1640  // the initial stencil as well as the ScriptIndex within the enclosing
   1641  // stencil.
   1642  const ScriptIndexes& getRelativeIndexesAt(ScriptIndex initialIndex) const;
   1643 
   1644  // Return the initial scriptIndex corresponding to the `enclosedInEnclosing`
   1645  // scriptIndex in the `CompilationStencil` indexed by `enclosingInInitial` in
   1646  // the `InitialStencilAndDelazifications`.
   1647  //
   1648  // Special cases:
   1649  //
   1650  // - For zero-values of `enclosedInEnclosing`, then the `enclosedInEnclosing`
   1651  //   index points at the first script of the `CompilationStencil` indexed by
   1652  //   `enclosingInInitial`. The 0-th script of any `CompilationStencil` is the
   1653  //   top-level or the function it-self. Thus `enclosingInInitial` is returned.
   1654  //
   1655  // - For cases where the script indexed by `enclosingInInitial` is compiled in
   1656  //   the initial stencil, then the index `enclosedInEnclosing` is already a
   1657  //   ScriptIndex in the initial CompilationStencil. Thus this function simply
   1658  //   return `enclosedInEnclosing`.
   1659  //
   1660  // Note:
   1661  //
   1662  // For non-zero values of `enclosedInEnclosing`, this function behaves as the
   1663  // reverse mapping of `getRelativeIndexesAt`.
   1664  ScriptIndex getInitialIndexFor(ScriptIndex enclosingInInitial,
   1665                                 ScriptIndex enclosedInEnclosing) const;
   1666 
   1667  // Try storing the delazification stencil.
   1668  //
   1669  // The `delazification` stencil should have only one ref count.
   1670  //
   1671  // If the function was not yet delazified and populated, the `delazification`
   1672  // is stored into the vector and the ownership is transferred to the vector,
   1673  // and the same `delazification`'s pointer is returned.
   1674  //
   1675  // If the function was already delazified and stored, the passed
   1676  // `delazification` is discared, and the already delazified stencil's pointer
   1677  // is returned.
   1678  //
   1679  // This function is infallible and never returns nullptr.
   1680  const CompilationStencil* storeDelazification(
   1681      RefPtr<CompilationStencil>&& delazification);
   1682 
   1683  // Create single CompilationStencil that reflects the initial stencil
   1684  // and the all delazifications.
   1685  //
   1686  // Returns nullptr if any error happens, and sets exception on the
   1687  // FrontendContext.
   1688  CompilationStencil* getMerged(FrontendContext* fc) const;
   1689 
   1690  // Whether this stencil has a function with an asm.js directive in it. The
   1691  // function may not have been compiled with asm.js if support was disabled or
   1692  // the asm.js module failed validation.
   1693  bool hasAsmJS() const;
   1694 
   1695  // Instantiate the initial stencil and all delazifications populated so far.
   1696  [[nodiscard]] static bool instantiateStencils(
   1697      JSContext* cx, CompilationInput& input,
   1698      InitialStencilAndDelazifications& stencils,
   1699      CompilationGCOutput& gcOutput);
   1700 
   1701  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
   1702  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   1703    return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
   1704  }
   1705 
   1706 #if defined(DEBUG) || defined(JS_JITSPEW)
   1707  void dump() const;
   1708  void dump(js::JSONPrinter& json) const;
   1709  void dumpFields(js::JSONPrinter& json) const;
   1710 #endif
   1711 };
   1712 
   1713 // The top level struct of stencil specialized for extensible case.
   1714 // Used as the temporary storage during compilation, an the compilation output.
   1715 //
   1716 // All not-owning pointer fields point the internal LifoAlloc.
   1717 //
   1718 // See CompilationStencil for each field's description.
   1719 //
   1720 // Also see SMDOC in Stencil.h for more info.
   1721 struct ExtensibleCompilationStencil {
   1722  bool canLazilyParse = false;
   1723 
   1724  using FunctionKey = SourceExtent::FunctionKey;
   1725 
   1726  FunctionKey functionKey = SourceExtent::NullFunctionKey;
   1727 
   1728  // Data pointed by other fields are allocated in this LifoAlloc,
   1729  // and moved to `CompilationStencil.alloc`.
   1730  LifoAlloc alloc;
   1731 
   1732  RefPtr<ScriptSource> source;
   1733 
   1734  // NOTE: We reserve a modest amount of inline storage in order to reduce
   1735  //       allocations in the most common delazification cases. These common
   1736  //       cases have one script and scope, as well as a handful of gcthings.
   1737  //       For complex pages this covers about 75% of delazifications.
   1738 
   1739  Vector<ScriptStencil, 1, js::SystemAllocPolicy> scriptData;
   1740  Vector<ScriptStencilExtra, 0, js::SystemAllocPolicy> scriptExtra;
   1741 
   1742  Vector<TaggedScriptThingIndex, 8, js::SystemAllocPolicy> gcThingData;
   1743 
   1744  Vector<ScopeStencil, 1, js::SystemAllocPolicy> scopeData;
   1745  Vector<BaseParserScopeData*, 1, js::SystemAllocPolicy> scopeNames;
   1746 
   1747  Vector<RegExpStencil, 0, js::SystemAllocPolicy> regExpData;
   1748  BigIntStencilVector bigIntData;
   1749  Vector<ObjLiteralStencil, 0, js::SystemAllocPolicy> objLiteralData;
   1750 
   1751  // Table of parser atoms for this compilation.
   1752  ParserAtomsTable parserAtoms;
   1753 
   1754  SharedDataContainer sharedData;
   1755 
   1756  RefPtr<StencilModuleMetadata> moduleMetadata;
   1757 
   1758  // AsmJS modules generated by parsing. These scripts are never lazy and
   1759  // therefore only generated during initial parse.
   1760  //
   1761  // This is non-null if we have seen an asm.js directive, but doesn't imply
   1762  // that we successfully compiled an asm.js module. See the comment in
   1763  // FunctionBox::setUseAsm for more information.
   1764  RefPtr<StencilAsmJSContainer> asmJS;
   1765 
   1766  explicit ExtensibleCompilationStencil(ScriptSource* source);
   1767 
   1768  explicit ExtensibleCompilationStencil(CompilationInput& input);
   1769  ExtensibleCompilationStencil(const JS::ReadOnlyCompileOptions& options,
   1770                               RefPtr<ScriptSource> source);
   1771 
   1772  ExtensibleCompilationStencil(ExtensibleCompilationStencil&& other) noexcept
   1773      : canLazilyParse(other.canLazilyParse),
   1774        functionKey(other.functionKey),
   1775        alloc(CompilationStencil::LifoAllocChunkSize,
   1776              js::BackgroundMallocArena),
   1777        source(std::move(other.source)),
   1778        scriptData(std::move(other.scriptData)),
   1779        scriptExtra(std::move(other.scriptExtra)),
   1780        gcThingData(std::move(other.gcThingData)),
   1781        scopeData(std::move(other.scopeData)),
   1782        scopeNames(std::move(other.scopeNames)),
   1783        regExpData(std::move(other.regExpData)),
   1784        bigIntData(std::move(other.bigIntData)),
   1785        objLiteralData(std::move(other.objLiteralData)),
   1786        parserAtoms(std::move(other.parserAtoms)),
   1787        sharedData(std::move(other.sharedData)),
   1788        moduleMetadata(std::move(other.moduleMetadata)),
   1789        asmJS(std::move(other.asmJS)) {
   1790    alloc.steal(&other.alloc);
   1791    parserAtoms.fixupAlloc(alloc);
   1792  }
   1793 
   1794  ExtensibleCompilationStencil& operator=(
   1795      ExtensibleCompilationStencil&& other) noexcept {
   1796    MOZ_ASSERT(alloc.isEmpty());
   1797 
   1798    canLazilyParse = other.canLazilyParse;
   1799    functionKey = other.functionKey;
   1800    source = std::move(other.source);
   1801    scriptData = std::move(other.scriptData);
   1802    scriptExtra = std::move(other.scriptExtra);
   1803    gcThingData = std::move(other.gcThingData);
   1804    scopeData = std::move(other.scopeData);
   1805    scopeNames = std::move(other.scopeNames);
   1806    regExpData = std::move(other.regExpData);
   1807    bigIntData = std::move(other.bigIntData);
   1808    objLiteralData = std::move(other.objLiteralData);
   1809    parserAtoms = std::move(other.parserAtoms);
   1810    sharedData = std::move(other.sharedData);
   1811    moduleMetadata = std::move(other.moduleMetadata);
   1812    asmJS = std::move(other.asmJS);
   1813 
   1814    alloc.steal(&other.alloc);
   1815    parserAtoms.fixupAlloc(alloc);
   1816 
   1817    return *this;
   1818  }
   1819 
   1820  void setFunctionKey(const SourceExtent& extent) {
   1821    functionKey = extent.toFunctionKey();
   1822  }
   1823 
   1824  bool isInitialStencil() const {
   1825    return functionKey == SourceExtent::NullFunctionKey;
   1826  }
   1827 
   1828  // Steal CompilationStencil content.
   1829  [[nodiscard]] bool steal(FrontendContext* fc,
   1830                           RefPtr<CompilationStencil>&& other);
   1831 
   1832  // Clone ExtensibleCompilationStencil content.
   1833  [[nodiscard]] bool cloneFrom(FrontendContext* fc,
   1834                               const CompilationStencil& other);
   1835  [[nodiscard]] bool cloneFrom(FrontendContext* fc,
   1836                               const ExtensibleCompilationStencil& other);
   1837 
   1838 private:
   1839  template <typename Stencil>
   1840  [[nodiscard]] bool cloneFromImpl(FrontendContext* fc, const Stencil& other);
   1841 
   1842 public:
   1843  const ParserAtomVector& parserAtomsSpan() const {
   1844    return parserAtoms.entries();
   1845  }
   1846 
   1847  bool isModule() const;
   1848 
   1849  // Whether this stencil has a function with an asm.js directive in it. The
   1850  // function may not have been compiled with asm.js if support was disabled or
   1851  // the asm.js module failed validation.
   1852  bool hasAsmJS() const;
   1853 
   1854  inline size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
   1855  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   1856    return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
   1857  }
   1858 
   1859 #ifdef DEBUG
   1860  void assertNoExternalDependency() const;
   1861 #endif
   1862 
   1863 #if defined(DEBUG) || defined(JS_JITSPEW)
   1864  void dump();
   1865  void dump(js::JSONPrinter& json);
   1866  void dumpFields(js::JSONPrinter& json);
   1867 
   1868  void dumpAtom(TaggedParserAtomIndex index);
   1869 #endif
   1870 };
   1871 
   1872 // The internal state of the compilation.
   1873 struct MOZ_RAII CompilationState : public ExtensibleCompilationStencil {
   1874  Directives directives;
   1875 
   1876  ScopeContext scopeContext;
   1877 
   1878  UsedNameTracker usedNames;
   1879 
   1880  // LifoAlloc scope used by Parser for allocating AST etc.
   1881  //
   1882  // NOTE: This is not used for ExtensibleCompilationStencil.alloc.
   1883  LifoAllocScope& parserAllocScope;
   1884 
   1885  CompilationInput& input;
   1886  CompilationSyntaxParseCache previousParseCache;
   1887 
   1888  // The number of functions that *will* have bytecode.
   1889  // This doesn't count top-level non-function script.
   1890  //
   1891  // This should be counted while parsing, and should be passed to
   1892  // SharedDataContainer.prepareStorageFor *before* start emitting bytecode.
   1893  size_t nonLazyFunctionCount = 0;
   1894 
   1895  // End of fields.
   1896 
   1897  CompilationState(FrontendContext* fc, LifoAllocScope& parserAllocScope,
   1898                   CompilationInput& input);
   1899 
   1900  bool init(FrontendContext* fc, ScopeBindingCache* scopeCache,
   1901            InheritThis inheritThis = InheritThis::No,
   1902            JSObject* enclosingEnv = nullptr) {
   1903    if (!scopeContext.init(fc, input, parserAtoms, scopeCache, inheritThis,
   1904                           enclosingEnv)) {
   1905      return false;
   1906    }
   1907 
   1908    // gcThings is later used by the full parser initialization.
   1909    if (input.isDelazifying()) {
   1910      InputScript lazy = input.lazyOuterScript();
   1911      auto& atomCache = input.atomCache;
   1912      if (!previousParseCache.init(fc, alloc, parserAtoms, atomCache, lazy)) {
   1913        return false;
   1914      }
   1915    }
   1916 
   1917    return true;
   1918  }
   1919 
   1920  // Track the state of key allocations and roll them back as parts of parsing
   1921  // get retried. This ensures iteration during stencil instantiation does not
   1922  // encounter discarded frontend state.
   1923  struct CompilationStatePosition {
   1924    // Temporarily share this token struct with CompilationState.
   1925    size_t scriptDataLength = 0;
   1926 
   1927    size_t asmJSCount = 0;
   1928  };
   1929 
   1930  bool prepareSharedDataStorage(FrontendContext* fc);
   1931 
   1932  CompilationStatePosition getPosition();
   1933  void rewind(const CompilationStatePosition& pos);
   1934 
   1935  // When parsing arrow function, parameter is parsed twice, and if there are
   1936  // functions inside parameter expression, stencils will be created for them.
   1937  //
   1938  // Those functions exist only for lazy parsing.
   1939  // Mark them "ghost", so that they don't affect other parts.
   1940  //
   1941  // See GHOST_FUNCTION in FunctionFlags.h for more details.
   1942  void markGhost(const CompilationStatePosition& pos);
   1943 
   1944  // Allocate space for `length` gcthings, and return the address of the
   1945  // first element to `cursor` to initialize on the caller.
   1946  bool allocateGCThingsUninitialized(FrontendContext* fc,
   1947                                     ScriptIndex scriptIndex, size_t length,
   1948                                     TaggedScriptThingIndex** cursor);
   1949 
   1950  bool appendScriptStencilAndData(FrontendContext* fc);
   1951 
   1952  bool appendGCThings(FrontendContext* fc, ScriptIndex scriptIndex,
   1953                      mozilla::Span<const TaggedScriptThingIndex> things);
   1954 };
   1955 
   1956 // A temporary CompilationStencil instance that borrows
   1957 // ExtensibleCompilationStencil data.
   1958 // Ensure that this instance does not outlive the ExtensibleCompilationStencil.
   1959 class MOZ_STACK_CLASS BorrowingCompilationStencil : public CompilationStencil {
   1960 public:
   1961  explicit BorrowingCompilationStencil(
   1962      ExtensibleCompilationStencil& extensibleStencil);
   1963 };
   1964 
   1965 // Size of dynamic data. Ignores Spans (unless their contents are in the
   1966 // LifoAlloc) and RefPtrs since we are not the unique owner.
   1967 inline size_t CompilationStencil::sizeOfExcludingThis(
   1968    mozilla::MallocSizeOf mallocSizeOf) const {
   1969  if (ownedBorrowStencil) {
   1970    return ownedBorrowStencil->sizeOfIncludingThis(mallocSizeOf);
   1971  }
   1972 
   1973  size_t moduleMetadataSize =
   1974      moduleMetadata ? moduleMetadata->sizeOfIncludingThis(mallocSizeOf) : 0;
   1975  size_t asmJSSize = asmJS ? asmJS->sizeOfIncludingThis(mallocSizeOf) : 0;
   1976 
   1977  return alloc.sizeOfExcludingThis(mallocSizeOf) +
   1978         sharedData.sizeOfExcludingThis(mallocSizeOf) + moduleMetadataSize +
   1979         asmJSSize;
   1980 }
   1981 
   1982 inline size_t ExtensibleCompilationStencil::sizeOfExcludingThis(
   1983    mozilla::MallocSizeOf mallocSizeOf) const {
   1984  size_t moduleMetadataSize =
   1985      moduleMetadata ? moduleMetadata->sizeOfIncludingThis(mallocSizeOf) : 0;
   1986  size_t asmJSSize = asmJS ? asmJS->sizeOfIncludingThis(mallocSizeOf) : 0;
   1987 
   1988  return alloc.sizeOfExcludingThis(mallocSizeOf) +
   1989         scriptData.sizeOfExcludingThis(mallocSizeOf) +
   1990         scriptExtra.sizeOfExcludingThis(mallocSizeOf) +
   1991         gcThingData.sizeOfExcludingThis(mallocSizeOf) +
   1992         scopeData.sizeOfExcludingThis(mallocSizeOf) +
   1993         scopeNames.sizeOfExcludingThis(mallocSizeOf) +
   1994         regExpData.sizeOfExcludingThis(mallocSizeOf) +
   1995         bigIntData.sizeOfExcludingThis(mallocSizeOf) +
   1996         objLiteralData.sizeOfExcludingThis(mallocSizeOf) +
   1997         parserAtoms.sizeOfExcludingThis(mallocSizeOf) +
   1998         sharedData.sizeOfExcludingThis(mallocSizeOf) + moduleMetadataSize +
   1999         asmJSSize;
   2000 }
   2001 
   2002 // A PreAllocateableGCArray is an array of GC thing pointers.
   2003 //
   2004 // The array's internal buffer can be allocated ahead of time, possibly off
   2005 // main thread.
   2006 template <typename T>
   2007 struct PreAllocateableGCArray {
   2008 private:
   2009  size_t length_ = 0;
   2010 
   2011  // Inline element for the case when length_ == 1.
   2012  T inlineElem_;
   2013 
   2014  // Heap-allocated elements for the case when length_ > 1;
   2015  T* elems_ = nullptr;
   2016 
   2017 public:
   2018  struct Preallocated {
   2019   private:
   2020    size_t length_ = 0;
   2021    uintptr_t* elems_ = nullptr;
   2022 
   2023    friend struct PreAllocateableGCArray<T>;
   2024 
   2025   public:
   2026    Preallocated() = default;
   2027    ~Preallocated();
   2028 
   2029    bool empty() const { return length_ == 0; }
   2030 
   2031    size_t length() const { return length_; }
   2032 
   2033   private:
   2034    bool isInline() const { return length_ == 1; }
   2035 
   2036   public:
   2037    bool allocate(size_t length);
   2038 
   2039    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   2040      return sizeof(uintptr_t) * length_;
   2041    }
   2042  };
   2043 
   2044  PreAllocateableGCArray() {
   2045    static_assert(std::is_pointer_v<T>,
   2046                  "PreAllocateableGCArray element must be a pointer");
   2047  }
   2048  ~PreAllocateableGCArray();
   2049 
   2050  bool empty() const { return length_ == 0; }
   2051 
   2052  size_t length() const { return length_; }
   2053 
   2054 private:
   2055  bool isInline() const { return length_ == 1; }
   2056 
   2057 public:
   2058  bool allocate(size_t length);
   2059  bool allocateWith(T init, size_t length);
   2060 
   2061  // Steal pre-allocated buffer.
   2062  void steal(Preallocated&& buffer);
   2063 
   2064  T& operator[](size_t index) {
   2065    MOZ_ASSERT(index < length_);
   2066 
   2067    if (isInline()) {
   2068      return inlineElem_;
   2069    }
   2070 
   2071    return elems_[index];
   2072  }
   2073  const T& operator[](size_t index) const {
   2074    MOZ_ASSERT(index < length_);
   2075 
   2076    if (isInline()) {
   2077      return inlineElem_;
   2078    }
   2079 
   2080    return elems_[index];
   2081  }
   2082 
   2083  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   2084    if (!elems_) {
   2085      return 0;
   2086    }
   2087 
   2088    return sizeof(T) * length_;
   2089  }
   2090 
   2091  void trace(JSTracer* trc);
   2092 };
   2093 
   2094 struct CompilationGCOutput;
   2095 
   2096 // Pre-allocated storage for CompilationGCOutput.
   2097 struct PreallocatedCompilationGCOutput {
   2098 private:
   2099  PreAllocateableGCArray<JSFunction*>::Preallocated functions;
   2100  PreAllocateableGCArray<js::Scope*>::Preallocated scopes;
   2101 
   2102  friend struct CompilationGCOutput;
   2103 
   2104 public:
   2105  PreallocatedCompilationGCOutput() = default;
   2106 
   2107  [[nodiscard]] bool allocate(FrontendContext* fc, size_t scriptDataLength,
   2108                              size_t scopeDataLength) {
   2109    if (!functions.allocate(scriptDataLength)) {
   2110      ReportOutOfMemory(fc);
   2111      return false;
   2112    }
   2113    if (!scopes.allocate(scopeDataLength)) {
   2114      ReportOutOfMemory(fc);
   2115      return false;
   2116    }
   2117    return true;
   2118  }
   2119 
   2120  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   2121    return functions.sizeOfExcludingThis(mallocSizeOf) +
   2122           scopes.sizeOfExcludingThis(mallocSizeOf);
   2123  }
   2124 };
   2125 
   2126 // The output of GC allocation from stencil.
   2127 struct CompilationGCOutput {
   2128  // The resulting outermost script for the compilation powered
   2129  // by this CompilationStencil.
   2130  JSScript* script = nullptr;
   2131 
   2132  // The resulting module object if there is one.
   2133  ModuleObject* module = nullptr;
   2134 
   2135  // An array to handle tracing of JSFunction* and Atoms within.
   2136  //
   2137  // If the top level script isn't a function, the item at TopLevelIndex is
   2138  // nullptr.
   2139  PreAllocateableGCArray<JSFunction*> functions;
   2140 
   2141  // References to scopes are controlled via AbstractScopePtr, which holds onto
   2142  // an index (and CompilationStencil reference).
   2143  PreAllocateableGCArray<js::Scope*> scopes;
   2144 
   2145  // The result ScriptSourceObject. This is unused in delazifying parses.
   2146  ScriptSourceObject* sourceObject = nullptr;
   2147 
   2148 private:
   2149  // If we are only instantiating part of a stencil, we can reduce allocations
   2150  // by setting a base index and allocating only the array elements we need.
   2151  // This applies to both the `functions` and `scopes` arrays. These fields are
   2152  // initialized by `ensureAllocatedWithBaseIndex` which also allocates the
   2153  // array appropriately.
   2154  //
   2155  // Note: These are only used for self-hosted delazification currently.
   2156  ScriptIndex functionsBaseIndex{};
   2157  ScopeIndex scopesBaseIndex{};
   2158 
   2159  // End of fields.
   2160 
   2161 public:
   2162  CompilationGCOutput() = default;
   2163 
   2164  // Helper to access the `functions` array. The NoBaseIndex version is used if
   2165  // the caller never uses a base index.
   2166  JSFunction*& getFunction(ScriptIndex index) {
   2167    return functions[index - functionsBaseIndex];
   2168  }
   2169  JSFunction*& getFunctionNoBaseIndex(ScriptIndex index) {
   2170    MOZ_ASSERT(!functionsBaseIndex);
   2171    return functions[index];
   2172  }
   2173 
   2174  // Helper accessors for the `scopes` array.
   2175  js::Scope*& getScope(ScopeIndex index) {
   2176    return scopes[index - scopesBaseIndex];
   2177  }
   2178  js::Scope*& getScopeNoBaseIndex(ScopeIndex index) {
   2179    MOZ_ASSERT(!scopesBaseIndex);
   2180    return scopes[index];
   2181  }
   2182  js::Scope* getScopeNoBaseIndex(ScopeIndex index) const {
   2183    MOZ_ASSERT(!scopesBaseIndex);
   2184    return scopes[index];
   2185  }
   2186 
   2187  // Allocate output arrays.
   2188  [[nodiscard]] bool ensureAllocated(FrontendContext* fc,
   2189                                     size_t scriptDataLength,
   2190                                     size_t scopeDataLength) {
   2191    if (functions.empty()) {
   2192      if (!functions.allocate(scriptDataLength)) {
   2193        ReportOutOfMemory(fc);
   2194        return false;
   2195      }
   2196    }
   2197    if (scopes.empty()) {
   2198      if (!scopes.allocate(scopeDataLength)) {
   2199        ReportOutOfMemory(fc);
   2200        return false;
   2201      }
   2202    }
   2203    return true;
   2204  }
   2205 
   2206  // Steal output arrays' buffer.
   2207  void steal(PreallocatedCompilationGCOutput&& pre) {
   2208    functions.steal(std::move(pre.functions));
   2209    scopes.steal(std::move(pre.scopes));
   2210  }
   2211 
   2212  // A variant of `ensureAllocated` that sets a base index for the function and
   2213  // scope arrays. This is used when instantiating only a subset of the stencil.
   2214  // Currently this only applies to self-hosted delazification. The ranges
   2215  // include the start index and exclude the limit index.
   2216  [[nodiscard]] bool ensureAllocatedWithBaseIndex(FrontendContext* fc,
   2217                                                  ScriptIndex scriptStart,
   2218                                                  ScriptIndex scriptLimit,
   2219                                                  ScopeIndex scopeStart,
   2220                                                  ScopeIndex scopeLimit) {
   2221    this->functionsBaseIndex = scriptStart;
   2222    this->scopesBaseIndex = scopeStart;
   2223 
   2224    return ensureAllocated(fc, scriptLimit - scriptStart,
   2225                           scopeLimit - scopeStart);
   2226  }
   2227 
   2228  // Size of dynamic data. Note that GC data is counted by GC and not here.
   2229  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
   2230    return functions.sizeOfExcludingThis(mallocSizeOf) +
   2231           scopes.sizeOfExcludingThis(mallocSizeOf);
   2232  }
   2233 
   2234  void trace(JSTracer* trc);
   2235 };
   2236 
   2237 // Iterator over functions that make up a CompilationStencil. This abstracts
   2238 // over the parallel arrays in stencil and gc-output that use the same index
   2239 // system.
   2240 class ScriptStencilIterable {
   2241 public:
   2242  class ScriptAndFunction {
   2243   public:
   2244    const ScriptStencil& script;
   2245    const ScriptStencilExtra* scriptExtra;
   2246    JSFunction* function;
   2247    ScriptIndex index;
   2248 
   2249    ScriptAndFunction() = delete;
   2250    ScriptAndFunction(const ScriptStencil& script,
   2251                      const ScriptStencilExtra* scriptExtra,
   2252                      JSFunction* function, ScriptIndex index)
   2253        : script(script),
   2254          scriptExtra(scriptExtra),
   2255          function(function),
   2256          index(index) {}
   2257  };
   2258 
   2259  class Iterator {
   2260    size_t index_ = 0;
   2261    const CompilationStencil& stencil_;
   2262    CompilationGCOutput& gcOutput_;
   2263 
   2264    Iterator(const CompilationStencil& stencil, CompilationGCOutput& gcOutput,
   2265             size_t index)
   2266        : index_(index), stencil_(stencil), gcOutput_(gcOutput) {
   2267      MOZ_ASSERT(index == stencil.scriptData.size());
   2268    }
   2269 
   2270   public:
   2271    explicit Iterator(const CompilationStencil& stencil,
   2272                      CompilationGCOutput& gcOutput)
   2273        : stencil_(stencil), gcOutput_(gcOutput) {
   2274      skipTopLevelNonFunction();
   2275    }
   2276 
   2277    Iterator operator++() {
   2278      next();
   2279      assertFunction();
   2280      return *this;
   2281    }
   2282 
   2283    void next() {
   2284      MOZ_ASSERT(index_ < stencil_.scriptData.size());
   2285      index_++;
   2286    }
   2287 
   2288    void assertFunction() {
   2289      if (index_ < stencil_.scriptData.size()) {
   2290        MOZ_ASSERT(stencil_.scriptData[index_].isFunction());
   2291      }
   2292    }
   2293 
   2294    void skipTopLevelNonFunction() {
   2295      MOZ_ASSERT(index_ == 0);
   2296      if (stencil_.scriptData.size()) {
   2297        if (!stencil_.scriptData[0].isFunction()) {
   2298          next();
   2299          assertFunction();
   2300        }
   2301      }
   2302    }
   2303 
   2304    bool operator!=(const Iterator& other) const {
   2305      return index_ != other.index_;
   2306    }
   2307 
   2308    ScriptAndFunction operator*() {
   2309      ScriptIndex index = ScriptIndex(index_);
   2310      const ScriptStencil& script = stencil_.scriptData[index];
   2311      const ScriptStencilExtra* scriptExtra = nullptr;
   2312      if (stencil_.isInitialStencil()) {
   2313        scriptExtra = &stencil_.scriptExtra[index];
   2314      }
   2315      return ScriptAndFunction(script, scriptExtra,
   2316                               gcOutput_.getFunctionNoBaseIndex(index), index);
   2317    }
   2318 
   2319    static Iterator end(const CompilationStencil& stencil,
   2320                        CompilationGCOutput& gcOutput) {
   2321      return Iterator(stencil, gcOutput, stencil.scriptData.size());
   2322    }
   2323  };
   2324 
   2325  const CompilationStencil& stencil_;
   2326  CompilationGCOutput& gcOutput_;
   2327 
   2328  explicit ScriptStencilIterable(const CompilationStencil& stencil,
   2329                                 CompilationGCOutput& gcOutput)
   2330      : stencil_(stencil), gcOutput_(gcOutput) {}
   2331 
   2332  Iterator begin() const { return Iterator(stencil_, gcOutput_); }
   2333 
   2334  Iterator end() const { return Iterator::end(stencil_, gcOutput_); }
   2335 };
   2336 
   2337 inline ScriptStencilIterable CompilationStencil::functionScriptStencils(
   2338    const CompilationStencil& stencil, CompilationGCOutput& gcOutput) {
   2339  return ScriptStencilIterable(stencil, gcOutput);
   2340 }
   2341 
   2342 // Merge CompilationStencil for delazification into initial
   2343 // ExtensibleCompilationStencil.
   2344 struct CompilationStencilMerger {
   2345 private:
   2346  using FunctionKey = SourceExtent::FunctionKey;
   2347 
   2348  // The stencil for the initial compilation.
   2349  // Delazifications are merged into this.
   2350  //
   2351  // If any failure happens during merge operation, this field is reset to
   2352  // nullptr.
   2353  UniquePtr<ExtensibleCompilationStencil> initial_;
   2354 
   2355  FunctionKeyToScriptIndexMap functionKeyToInitialScriptIndex_;
   2356 
   2357  ScriptIndex getInitialScriptIndexFor(
   2358      const CompilationStencil& delazification) const;
   2359 
   2360  // A map from delazification's ParserAtomIndex to
   2361  // initial's TaggedParserAtomIndex
   2362  using AtomIndexMap = Vector<TaggedParserAtomIndex, 0, js::SystemAllocPolicy>;
   2363 
   2364  [[nodiscard]] bool buildAtomIndexMap(FrontendContext* fc,
   2365                                       const CompilationStencil& delazification,
   2366                                       AtomIndexMap& atomIndexMap);
   2367 
   2368 public:
   2369  CompilationStencilMerger() = default;
   2370 
   2371  // Set the initial stencil and prepare for merging.
   2372  [[nodiscard]] bool setInitial(
   2373      FrontendContext* fc, UniquePtr<ExtensibleCompilationStencil>&& initial);
   2374 
   2375  // Merge the delazification stencil into the initial stencil.
   2376  [[nodiscard]] bool addDelazification(
   2377      FrontendContext* fc, const CompilationStencil& delazification);
   2378 
   2379  // Merge the delazification stencil into the initial stencil if the
   2380  // delazification stencil can be merged.
   2381  //
   2382  // If the delazification's enclosing function is not yet merged, this does
   2383  // do nothing.
   2384  [[nodiscard]] bool maybeAddDelazification(
   2385      FrontendContext* fc, const CompilationStencil& delazification);
   2386 
   2387  ExtensibleCompilationStencil& getResult() const { return *initial_; }
   2388  UniquePtr<ExtensibleCompilationStencil> takeResult() {
   2389    return std::move(initial_);
   2390  }
   2391 };
   2392 
   2393 ScriptStencilRef ScopeStencilRef::script() const {
   2394  return ScriptStencilRef{stencils_, scriptIndex_};
   2395 }
   2396 
   2397 const CompilationStencil* ScopeStencilRef::context() const {
   2398  return script().context();
   2399 }
   2400 
   2401 const ScopeStencil& ScopeStencilRef::scope() const {
   2402  return context()->scopeData[scopeIndex_];
   2403 }
   2404 
   2405 const ScriptStencilExtra& ScopeStencilRef::functionScriptExtra() const {
   2406  MOZ_ASSERT(scope().isFunction());
   2407  // Extract the `ScriptIndex` from the function's scope. This index is valid in
   2408  // the `CompilationStencil` which has the shared data for `scriptIndex_`.
   2409  ScriptIndex functionIndexInContext = scope().functionIndex();
   2410  // Convert the function's index to an index in the initial stencil.
   2411  ScriptIndex functionIndexInInitial =
   2412      stencils_.getInitialIndexFor(scriptIndex_, functionIndexInContext);
   2413  // Create a ScriptStencilRef from the function index in the initial stencil.
   2414  ScriptStencilRef function{stencils_, functionIndexInInitial};
   2415  return function.scriptExtra();
   2416 }
   2417 
   2418 InputScope InputScope::enclosing() const {
   2419  return scope_.match(
   2420      [](const Scope* ptr) {
   2421        // This may return a nullptr Scope pointer.
   2422        return InputScope(ptr->enclosing());
   2423      },
   2424      [](const ScopeStencilRef& ref) {
   2425        auto& scope = ref.scope();
   2426        if (scope.hasEnclosing()) {
   2427 #ifdef DEBUG
   2428          // Assert that checking for the same stencil is equivalent to
   2429          // checking for being encoded in the initial stencil.
   2430          if (ref.scriptIndex_ != 0) {
   2431            auto enclosingScript = ref.script().enclosingScript();
   2432            bool same = ref.context() == enclosingScript.context();
   2433            MOZ_ASSERT(same == ref.script().isEagerlyCompiledInInitial());
   2434          }
   2435 #endif
   2436 
   2437          // By default we are walking the scope within the same function.
   2438          ScriptIndex scriptIndex = ref.scriptIndex_;
   2439 
   2440          // `scope.enclosing()` and `scope` would have the same scriptIndex
   2441          // unless `scope` is the first scope of the script. In which case, the
   2442          // returned enclosing scope index should be returned with the
   2443          // enclosing script index.
   2444          //
   2445          // This can only happen in the initial stencil, as only the initial
   2446          // stencil can have multiple scripts compiled in the same stencil.
   2447          if (ref.script().isEagerlyCompiledInInitial()) {
   2448            auto gcThingsFromContext = ref.script().gcThingsFromInitial();
   2449            if (gcThingsFromContext[0].toScope() == ref.scopeIndex_) {
   2450              scriptIndex = ref.script().enclosingScript().scriptIndex_;
   2451            }
   2452          }
   2453 
   2454          return InputScope(ref.stencils_, scriptIndex, scope.enclosing());
   2455        }
   2456 
   2457        // By default the previous condition (scope.hasEnclosing()) should
   2458        // trigger, except when we are at the top-level of a delazification, in
   2459        // which case we have to find the enclosing script in the stencil of the
   2460        // enclosing script, to find the lazyFunctionEnclosingScopeIndex which
   2461        // is valid in the stencil of the enclosing script.
   2462        //
   2463        // Note, at one point the enclosing script would be the initial stencil.
   2464        if (!ref.script().isEagerlyCompiledInInitial()) {
   2465          auto enclosing = ref.script().enclosingScript();
   2466          auto& scriptData = ref.script().scriptDataFromEnclosing();
   2467          MOZ_ASSERT(scriptData.hasLazyFunctionEnclosingScopeIndex());
   2468          return InputScope(ref.stencils_, enclosing.scriptIndex_,
   2469                            scriptData.lazyFunctionEnclosingScopeIndex());
   2470        }
   2471 
   2472        // The global scope is not known by the Stencil, while parsing inner
   2473        // functions from Stencils where they are known at the execution using
   2474        // the GlobalScope.
   2475        if (ref.scope().kind() == ScopeKind::Module) {
   2476          return InputScope(FakeStencilGlobalScope{});
   2477        }
   2478        return InputScope(nullptr);
   2479      },
   2480      [](const FakeStencilGlobalScope&) { return InputScope(nullptr); });
   2481 }
   2482 
   2483 FunctionFlags InputScope::functionFlags() const {
   2484  return scope_.match(
   2485      [](const Scope* ptr) {
   2486        JSFunction* fun = ptr->as<FunctionScope>().canonicalFunction();
   2487        return fun->flags();
   2488      },
   2489      [](const ScopeStencilRef& ref) {
   2490        MOZ_ASSERT(ref.scope().isFunction());
   2491        ScriptIndex functionIndexInContext = ref.scope().functionIndex();
   2492        // Unlike InputScript::functionFlags(), which returns the functionFlags
   2493        // using the ScriptStencilRef::scriptDataFromEnclosing() function,
   2494        // ref.context() is already the CompilationStencil holding the
   2495        // information about the extracted function index. Using the same code
   2496        // as in InputScript::functionFlags() would yield an error for cases
   2497        // where the functionIndexInContext is 0, as we will look for the
   2498        // scriptData in the wrong CompilationStencil.
   2499        ScriptStencil& data = ref.context()->scriptData[functionIndexInContext];
   2500        return data.functionFlags;
   2501      },
   2502      [](const FakeStencilGlobalScope&) -> FunctionFlags {
   2503        MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No functionFlags on global.");
   2504      });
   2505 }
   2506 
   2507 ImmutableScriptFlags InputScope::immutableFlags() const {
   2508  return scope_.match(
   2509      [](const Scope* ptr) {
   2510        JSFunction* fun = ptr->as<FunctionScope>().canonicalFunction();
   2511        return fun->baseScript()->immutableFlags();
   2512      },
   2513      [](const ScopeStencilRef& ref) {
   2514        return ref.functionScriptExtra().immutableFlags;
   2515      },
   2516      [](const FakeStencilGlobalScope&) -> ImmutableScriptFlags {
   2517        MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No immutableFlags on global.");
   2518      });
   2519 }
   2520 
   2521 MemberInitializers InputScope::getMemberInitializers() const {
   2522  return scope_.match(
   2523      [](const Scope* ptr) {
   2524        JSFunction* fun = ptr->as<FunctionScope>().canonicalFunction();
   2525        return fun->baseScript()->getMemberInitializers();
   2526      },
   2527      [](const ScopeStencilRef& ref) {
   2528        return ref.functionScriptExtra().memberInitializers();
   2529      },
   2530      [](const FakeStencilGlobalScope&) -> MemberInitializers {
   2531        MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(
   2532            "No getMemberInitializers on global.");
   2533      });
   2534 }
   2535 
   2536 ScriptStencilRef ScriptStencilRef::topLevelScript() const {
   2537  return ScriptStencilRef{stencils_, ScriptIndex(0)};
   2538 }
   2539 
   2540 ScriptStencilRef ScriptStencilRef::enclosingScript() const {
   2541  auto indexes = stencils_.getRelativeIndexesAt(scriptIndex_);
   2542  ScriptStencilRef enclosing{stencils_, indexes.enclosingIndexInInitial};
   2543  return enclosing;
   2544 }
   2545 
   2546 const ScriptStencil& ScriptStencilRef::scriptDataFromInitial() const {
   2547  return stencils_.getInitial()->scriptData[scriptIndex_];
   2548 }
   2549 
   2550 bool ScriptStencilRef::isEagerlyCompiledInInitial() const {
   2551  return scriptDataFromInitial().hasSharedData();
   2552 }
   2553 
   2554 const ScriptStencil& ScriptStencilRef::scriptDataFromEnclosing() const {
   2555  // The script data is held by the enclosing script except for the top-level.
   2556  if (scriptIndex_ == 0) {
   2557    return stencils_.getInitial()->scriptData[0];
   2558  }
   2559  // Get the enclosing stencil.
   2560  auto indexes = stencils_.getRelativeIndexesAt(scriptIndex_);
   2561  ScriptStencilRef enclosing{stencils_, indexes.enclosingIndexInInitial};
   2562  return enclosing.context()->scriptData[indexes.indexInEnclosing];
   2563 }
   2564 
   2565 mozilla::Span<TaggedScriptThingIndex> ScriptStencilRef::gcThingsFromInitial()
   2566    const {
   2567  return scriptDataFromInitial().gcthings(*stencils_.getInitial());
   2568 }
   2569 
   2570 const ScriptStencilExtra& ScriptStencilRef::scriptExtra() const {
   2571  return stencils_.getInitial()->scriptExtra[scriptIndex_];
   2572 }
   2573 
   2574 const CompilationStencil* ScriptStencilRef::context() const {
   2575  // The initial stencil might contain more than the top-level script, in which
   2576  // case we should return the initial stencil when it contains the bytecode for
   2577  // the script at the given index.
   2578  if (isEagerlyCompiledInInitial()) {
   2579    return stencils_.getInitial();
   2580  }
   2581  const auto* delazification = stencils_.getDelazificationAt(scriptIndex_);
   2582  MOZ_ASSERT(delazification);
   2583  return delazification;
   2584 }
   2585 
   2586 const CompilationStencil* ScriptStencilRef::maybeContext() const {
   2587  // The initial stencil might contain more than the top-level script, in which
   2588  // case we should return the initial stencil when it contains the bytecode for
   2589  // the script at the given index.
   2590  if (isEagerlyCompiledInInitial()) {
   2591    return stencils_.getInitial();
   2592  }
   2593  return stencils_.getDelazificationAt(scriptIndex_);
   2594 }
   2595 
   2596 }  // namespace frontend
   2597 }  // namespace js
   2598 
   2599 namespace mozilla {
   2600 template <>
   2601 struct RefPtrTraits<js::frontend::CompilationStencil> {
   2602  static void AddRef(js::frontend::CompilationStencil* stencil) {
   2603    stencil->AddRef();
   2604  }
   2605  static void Release(js::frontend::CompilationStencil* stencil) {
   2606    stencil->Release();
   2607  }
   2608 };
   2609 }  // namespace mozilla
   2610 
   2611 #endif  // frontend_CompilationStencil_h