tor-browser

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

JSScript.h (85174B)


      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 /* JS script descriptor. */
      8 
      9 #ifndef vm_JSScript_h
     10 #define vm_JSScript_h
     11 
     12 #include "mozilla/Atomics.h"
     13 #include "mozilla/Maybe.h"
     14 #include "mozilla/MaybeOneOf.h"
     15 #include "mozilla/MemoryReporting.h"
     16 #include "mozilla/RefPtr.h"
     17 #include "mozilla/Span.h"
     18 
     19 #include "mozilla/UniquePtr.h"
     20 #include "mozilla/Utf8.h"
     21 #include "mozilla/Variant.h"
     22 
     23 #include <type_traits>  // std::is_same
     24 #include <utility>      // std::move
     25 
     26 #include "jstypes.h"
     27 
     28 #include "frontend/ScriptIndex.h"  // ScriptIndex
     29 #include "gc/Barrier.h"
     30 #include "js/ColumnNumber.h"  // JS::LimitedColumnNumberOneOrigin, JS::LimitedColumnNumberOneOrigin
     31 #include "js/CompileOptions.h"
     32 #include "js/Transcoding.h"
     33 #include "js/UbiNode.h"
     34 #include "js/UniquePtr.h"
     35 #include "js/Utility.h"
     36 #include "util/TrailingArray.h"
     37 #include "vm/BytecodeIterator.h"
     38 #include "vm/BytecodeLocation.h"
     39 #include "vm/BytecodeUtil.h"
     40 #include "vm/MutexIDs.h"  // mutexid
     41 #include "vm/NativeObject.h"
     42 #include "vm/SharedImmutableStringsCache.h"
     43 #include "vm/SharedStencil.h"  // js::GCThingIndex, js::SourceExtent, js::SharedImmutableScriptData, MemberInitializers
     44 #include "vm/StencilEnums.h"   // SourceRetrievable
     45 
     46 namespace JS {
     47 struct ScriptSourceInfo;
     48 template <typename UnitT>
     49 class SourceText;
     50 }  // namespace JS
     51 
     52 namespace js {
     53 
     54 class Compressor;
     55 class FrontendContext;
     56 class ScriptSource;
     57 
     58 class VarScope;
     59 class LexicalScope;
     60 
     61 class JS_PUBLIC_API Sprinter;
     62 
     63 namespace coverage {
     64 class LCovSource;
     65 }  // namespace coverage
     66 
     67 namespace gc {
     68 class AllocSite;
     69 }  // namespace gc
     70 
     71 namespace jit {
     72 class AutoKeepJitScripts;
     73 class BaselineScript;
     74 class IonScript;
     75 struct IonScriptCounts;
     76 class JitScript;
     77 }  // namespace jit
     78 
     79 class ModuleObject;
     80 class RegExpObject;
     81 class SourceCompressionTaskEntry;
     82 class Shape;
     83 class SrcNote;
     84 class DebugScript;
     85 
     86 namespace frontend {
     87 struct CompilationStencil;
     88 struct ExtensibleCompilationStencil;
     89 struct CompilationGCOutput;
     90 struct InitialStencilAndDelazifications;
     91 struct CompilationStencilMerger;
     92 class StencilXDR;
     93 }  // namespace frontend
     94 
     95 class ScriptCounts {
     96 public:
     97  using PCCountsVector = mozilla::Vector<PCCounts, 0, SystemAllocPolicy>;
     98 
     99  inline ScriptCounts();
    100  inline explicit ScriptCounts(PCCountsVector&& jumpTargets);
    101  inline ScriptCounts(ScriptCounts&& src);
    102  inline ~ScriptCounts();
    103 
    104  inline ScriptCounts& operator=(ScriptCounts&& src);
    105 
    106  // Return the counter used to count the number of visits. Returns null if
    107  // the element is not found.
    108  PCCounts* maybeGetPCCounts(size_t offset);
    109  const PCCounts* maybeGetPCCounts(size_t offset) const;
    110 
    111  // PCCounts are stored at jump-target offsets. This function looks for the
    112  // previous PCCount which is in the same basic block as the current offset.
    113  PCCounts* getImmediatePrecedingPCCounts(size_t offset);
    114 
    115  // Return the counter used to count the number of throws. Returns null if
    116  // the element is not found.
    117  const PCCounts* maybeGetThrowCounts(size_t offset) const;
    118 
    119  // Throw counts are stored at the location of each throwing
    120  // instruction. This function looks for the previous throw count.
    121  //
    122  // Note: if the offset of the returned count is higher than the offset of
    123  // the immediate preceding PCCount, then this throw happened in the same
    124  // basic block.
    125  const PCCounts* getImmediatePrecedingThrowCounts(size_t offset) const;
    126 
    127  // Return the counter used to count the number of throws. Allocate it if
    128  // none exists yet. Returns null if the allocation failed.
    129  PCCounts* getThrowCounts(size_t offset);
    130 
    131  size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
    132 
    133  bool traceWeak(JSTracer* trc) { return true; }
    134 
    135 private:
    136  friend class ::JSScript;
    137  friend struct ScriptAndCounts;
    138 
    139  // This sorted array is used to map an offset to the number of times a
    140  // branch got visited.
    141  PCCountsVector pcCounts_;
    142 
    143  // This sorted vector is used to map an offset to the number of times an
    144  // instruction throw.
    145  PCCountsVector throwCounts_;
    146 
    147  // Information about any Ion compilations for the script.
    148  jit::IonScriptCounts* ionCounts_;
    149 };
    150 
    151 // The key of these side-table hash maps are intentionally not traced GC
    152 // references to JSScript. Instead, we use bare pointers and manually fix up
    153 // when objects could have moved (see Zone::fixupScriptMapsAfterMovingGC) and
    154 // remove when the realm is destroyed (see Zone::clearScriptCounts and
    155 // Zone::clearScriptNames). They essentially behave as weak references, except
    156 // that the references are not cleared early by the GC. They must be non-strong
    157 // references because the tables are kept at the Zone level and otherwise the
    158 // table keys would keep scripts alive, thus keeping Realms alive, beyond their
    159 // expected lifetimes. However, We do not use actual weak references (e.g. as
    160 // used by WeakMap tables provided in gc/WeakMap.h) because they would be
    161 // collected before the calls to the JSScript::finalize function which are used
    162 // to aggregate code coverage results on the realm.
    163 //
    164 // Note carefully, however, that there is an exceptional case for which we *do*
    165 // want the JSScripts to be strong references (and thus traced): when the
    166 // --dump-bytecode command line option or the PCCount JSFriend API is used,
    167 // then the scripts for all counts must remain alive. See
    168 // Zone::traceScriptTableRoots() for more details.
    169 //
    170 // TODO: Clean this up by either aggregating coverage results in some other
    171 // way, or by tweaking sweep ordering.
    172 using UniqueScriptCounts = js::UniquePtr<ScriptCounts>;
    173 using ScriptCountsMap =
    174    GCRekeyableHashMap<HeapPtr<BaseScript*>, UniqueScriptCounts,
    175                       DefaultHasher<HeapPtr<BaseScript*>>, SystemAllocPolicy>;
    176 
    177 // The 'const char*' for the function name is a pointer within the LCovSource's
    178 // LifoAlloc and will be discarded at the same time.
    179 using ScriptLCovEntry = std::tuple<coverage::LCovSource*, const char*>;
    180 using ScriptLCovMap =
    181    GCRekeyableHashMap<HeapPtr<BaseScript*>, ScriptLCovEntry,
    182                       DefaultHasher<HeapPtr<BaseScript*>>, SystemAllocPolicy>;
    183 
    184 #ifdef MOZ_VTUNE
    185 using ScriptVTuneIdMap =
    186    GCRekeyableHashMap<HeapPtr<BaseScript*>, uint32_t,
    187                       DefaultHasher<HeapPtr<BaseScript*>>, SystemAllocPolicy>;
    188 #endif
    189 #ifdef JS_CACHEIR_SPEW
    190 using ScriptFinalWarmUpCountEntry = std::tuple<uint32_t, SharedImmutableString>;
    191 using ScriptFinalWarmUpCountMap =
    192    GCRekeyableHashMap<HeapPtr<BaseScript*>, ScriptFinalWarmUpCountEntry,
    193                       DefaultHasher<HeapPtr<BaseScript*>>, SystemAllocPolicy>;
    194 #endif
    195 
    196 struct ScriptSourceChunk {
    197  ScriptSource* ss = nullptr;
    198  uint32_t chunk = 0;
    199 
    200  ScriptSourceChunk() = default;
    201 
    202  ScriptSourceChunk(ScriptSource* ss, uint32_t chunk) : ss(ss), chunk(chunk) {
    203    MOZ_ASSERT(valid());
    204  }
    205 
    206  bool valid() const { return ss != nullptr; }
    207 
    208  bool operator==(const ScriptSourceChunk& other) const {
    209    return ss == other.ss && chunk == other.chunk;
    210  }
    211 };
    212 
    213 struct ScriptSourceChunkHasher {
    214  using Lookup = ScriptSourceChunk;
    215 
    216  static HashNumber hash(const ScriptSourceChunk& ssc) {
    217    return mozilla::AddToHash(DefaultHasher<ScriptSource*>::hash(ssc.ss),
    218                              ssc.chunk);
    219  }
    220  static bool match(const ScriptSourceChunk& c1, const ScriptSourceChunk& c2) {
    221    return c1 == c2;
    222  }
    223 };
    224 
    225 template <typename Unit>
    226 using EntryUnits = mozilla::UniquePtr<Unit[], JS::FreePolicy>;
    227 
    228 // The uncompressed source cache contains *either* UTF-8 source data *or*
    229 // UTF-16 source data.  ScriptSourceChunk implies a ScriptSource that
    230 // contains either UTF-8 data or UTF-16 data, so the nature of the key to
    231 // Map below indicates how each SourceData ought to be interpreted.
    232 using SourceData = mozilla::UniquePtr<void, JS::FreePolicy>;
    233 
    234 template <typename Unit>
    235 inline SourceData ToSourceData(EntryUnits<Unit> chars) {
    236  static_assert(std::is_same_v<SourceData::deleter_type,
    237                               typename EntryUnits<Unit>::deleter_type>,
    238                "EntryUnits and SourceData must share the same deleter "
    239                "type, that need not know the type of the data being freed, "
    240                "for the upcast below to be safe");
    241  return SourceData(chars.release());
    242 }
    243 
    244 class UncompressedSourceCache {
    245  using Map = HashMap<ScriptSourceChunk, SourceData, ScriptSourceChunkHasher,
    246                      SystemAllocPolicy>;
    247 
    248 public:
    249  // Hold an entry in the source data cache and prevent it from being purged on
    250  // GC.
    251  class AutoHoldEntry {
    252    UncompressedSourceCache* cache_ = nullptr;
    253    ScriptSourceChunk sourceChunk_ = {};
    254    SourceData data_ = nullptr;
    255 
    256   public:
    257    explicit AutoHoldEntry() = default;
    258 
    259    ~AutoHoldEntry() {
    260      if (cache_) {
    261        MOZ_ASSERT(sourceChunk_.valid());
    262        cache_->releaseEntry(*this);
    263      }
    264    }
    265 
    266    template <typename Unit>
    267    void holdUnits(EntryUnits<Unit> units) {
    268      MOZ_ASSERT(!cache_);
    269      MOZ_ASSERT(!sourceChunk_.valid());
    270      MOZ_ASSERT(!data_);
    271 
    272      data_ = ToSourceData(std::move(units));
    273    }
    274 
    275   private:
    276    void holdEntry(UncompressedSourceCache* cache,
    277                   const ScriptSourceChunk& sourceChunk) {
    278      // Initialise the holder for a specific cache and script source.
    279      // This will hold on to the cached source chars in the event that
    280      // the cache is purged.
    281      MOZ_ASSERT(!cache_);
    282      MOZ_ASSERT(!sourceChunk_.valid());
    283      MOZ_ASSERT(!data_);
    284 
    285      cache_ = cache;
    286      sourceChunk_ = sourceChunk;
    287    }
    288 
    289    void deferDelete(SourceData data) {
    290      // Take ownership of source chars now the cache is being purged. Remove
    291      // our reference to the ScriptSource which might soon be destroyed.
    292      MOZ_ASSERT(cache_);
    293      MOZ_ASSERT(sourceChunk_.valid());
    294      MOZ_ASSERT(!data_);
    295 
    296      cache_ = nullptr;
    297      sourceChunk_ = ScriptSourceChunk();
    298 
    299      data_ = std::move(data);
    300    }
    301 
    302    const ScriptSourceChunk& sourceChunk() const { return sourceChunk_; }
    303    friend class UncompressedSourceCache;
    304  };
    305 
    306 private:
    307  UniquePtr<Map> map_ = nullptr;
    308  AutoHoldEntry* holder_ = nullptr;
    309 
    310 public:
    311  UncompressedSourceCache() = default;
    312 
    313  template <typename Unit>
    314  const Unit* lookup(const ScriptSourceChunk& ssc, AutoHoldEntry& asp);
    315 
    316  bool put(const ScriptSourceChunk& ssc, SourceData data, AutoHoldEntry& asp);
    317 
    318  void purge();
    319 
    320  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
    321 
    322 private:
    323  void holdEntry(AutoHoldEntry& holder, const ScriptSourceChunk& ssc);
    324  void releaseEntry(AutoHoldEntry& holder);
    325 };
    326 
    327 template <typename Unit>
    328 struct SourceTypeTraits;
    329 
    330 template <>
    331 struct SourceTypeTraits<mozilla::Utf8Unit> {
    332  using CharT = char;
    333  using SharedImmutableString = js::SharedImmutableString;
    334 
    335  static const mozilla::Utf8Unit* units(const SharedImmutableString& string) {
    336    // Casting |char| data to |Utf8Unit| is safe because |Utf8Unit|
    337    // contains a |char|.  See the long comment in |Utf8Unit|'s definition.
    338    return reinterpret_cast<const mozilla::Utf8Unit*>(string.chars());
    339  }
    340 
    341  static char* toString(const mozilla::Utf8Unit* units) {
    342    auto asUnsigned =
    343        const_cast<unsigned char*>(mozilla::Utf8AsUnsignedChars(units));
    344    return reinterpret_cast<char*>(asUnsigned);
    345  }
    346 
    347  static UniqueChars toCacheable(EntryUnits<mozilla::Utf8Unit> str) {
    348    // The cache only stores strings of |char| or |char16_t|, and right now
    349    // it seems best not to gunk up the cache with |Utf8Unit| too.  So
    350    // cache |Utf8Unit| strings by interpreting them as |char| strings.
    351    char* chars = toString(str.release());
    352    return UniqueChars(chars);
    353  }
    354 };
    355 
    356 template <>
    357 struct SourceTypeTraits<char16_t> {
    358  using CharT = char16_t;
    359  using SharedImmutableString = js::SharedImmutableTwoByteString;
    360 
    361  static const char16_t* units(const SharedImmutableString& string) {
    362    return string.chars();
    363  }
    364 
    365  static char16_t* toString(const char16_t* units) {
    366    return const_cast<char16_t*>(units);
    367  }
    368 
    369  static UniqueTwoByteChars toCacheable(EntryUnits<char16_t> str) {
    370    return UniqueTwoByteChars(std::move(str));
    371  }
    372 };
    373 
    374 // Synchronously compress the source of |script|, for testing purposes.
    375 [[nodiscard]] extern bool SynchronouslyCompressSource(
    376    JSContext* cx, JS::Handle<BaseScript*> script);
    377 
    378 // Variant return type for ScriptSource::substringChars to support both UTF-8
    379 // and UTF-16.
    380 using SubstringCharsResult =
    381    mozilla::Variant<JS::UniqueChars, JS::UniqueTwoByteChars>;
    382 
    383 // [SMDOC] ScriptSource
    384 //
    385 // This class abstracts over the source we used to compile from. The current
    386 // representation may transition to different modes in order to save memory.
    387 // Abstractly the source may be one of UTF-8 or UTF-16. The data itself may be
    388 // unavailable, retrieveable-using-source-hook, compressed, or uncompressed. If
    389 // source is retrieved or decompressed for use, we may update the ScriptSource
    390 // to hold the result.
    391 class ScriptSource {
    392  // NOTE: While ScriptSources may be compressed off thread, they are only
    393  // modified by the main thread, and all members are always safe to access
    394  // on the main thread.
    395 
    396  friend class PendingSourceCompressionEntry;
    397  friend class SourceCompressionTaskEntry;
    398  friend bool SynchronouslyCompressSource(JSContext* cx,
    399                                          JS::Handle<BaseScript*> script);
    400 
    401  friend class frontend::StencilXDR;
    402 
    403 private:
    404  // Common base class of the templated variants of PinnedUnits<T>.
    405  class PinnedUnitsBase {
    406   protected:
    407    ScriptSource* source_;
    408 
    409    explicit PinnedUnitsBase(ScriptSource* source) : source_(source) {}
    410 
    411    void addReader();
    412 
    413    template <typename Unit>
    414    void removeReader();
    415  };
    416 
    417 public:
    418  // Any users that wish to manipulate the char buffer of the ScriptSource
    419  // needs to do so via PinnedUnits for GC safety. A GC may compress
    420  // ScriptSources. If the source were initially uncompressed, then any raw
    421  // pointers to the char buffer would now point to the freed, uncompressed
    422  // chars. This is analogous to Rooted.
    423  template <typename Unit>
    424  class PinnedUnits : public PinnedUnitsBase {
    425    const Unit* units_;
    426 
    427   public:
    428    // If maybeCx is nullptr, compressed sources will still be decompressed but
    429    // the result will not be cached. This allows off-main-thread use without
    430    // a JSContext.
    431    PinnedUnits(JSContext* maybeCx, ScriptSource* source,
    432                UncompressedSourceCache::AutoHoldEntry& holder, size_t begin,
    433                size_t len);
    434 
    435    ~PinnedUnits();
    436 
    437    const Unit* get() const { return units_; }
    438 
    439    const typename SourceTypeTraits<Unit>::CharT* asChars() const {
    440      return SourceTypeTraits<Unit>::toString(get());
    441    }
    442  };
    443 
    444  template <typename Unit>
    445  class PinnedUnitsIfUncompressed : public PinnedUnitsBase {
    446    const Unit* units_;
    447 
    448   public:
    449    PinnedUnitsIfUncompressed(ScriptSource* source, size_t begin, size_t len);
    450 
    451    ~PinnedUnitsIfUncompressed();
    452 
    453    const Unit* get() const { return units_; }
    454 
    455    const typename SourceTypeTraits<Unit>::CharT* asChars() const {
    456      return SourceTypeTraits<Unit>::toString(get());
    457    }
    458  };
    459 
    460 private:
    461  // Missing source text that isn't retrievable using the source hook.  (All
    462  // ScriptSources initially begin in this state.  Users that are compiling
    463  // source text will overwrite |data| to store a different state.)
    464  struct Missing {};
    465 
    466  // Source that can be retrieved using the registered source hook.  |Unit|
    467  // records the source type so that source-text coordinates in functions and
    468  // scripts that depend on this |ScriptSource| are correct.
    469  template <typename Unit>
    470  struct Retrievable {
    471    // The source hook and script URL required to retrieve source are stored
    472    // elsewhere, so nothing is needed here.  It'd be better hygiene to store
    473    // something source-hook-like in each |ScriptSource| that needs it, but that
    474    // requires reimagining a source-hook API that currently depends on source
    475    // hooks being uniquely-owned pointers...
    476  };
    477 
    478  // Uncompressed source text. Templates distinguish if we are interconvertable
    479  // to |Retrievable| or not.
    480  template <typename Unit>
    481  class UncompressedData {
    482    typename SourceTypeTraits<Unit>::SharedImmutableString string_;
    483 
    484   public:
    485    explicit UncompressedData(
    486        typename SourceTypeTraits<Unit>::SharedImmutableString str)
    487        : string_(std::move(str)) {}
    488 
    489    const Unit* units() const { return SourceTypeTraits<Unit>::units(string_); }
    490 
    491    size_t length() const { return string_.length(); }
    492  };
    493 
    494  template <typename Unit, SourceRetrievable CanRetrieve>
    495  class Uncompressed : public UncompressedData<Unit> {
    496    using Base = UncompressedData<Unit>;
    497 
    498   public:
    499    using Base::Base;
    500  };
    501 
    502  // Compressed source text. Templates distinguish if we are interconvertable
    503  // to |Retrievable| or not.
    504  template <typename Unit>
    505  struct CompressedData {
    506    // Single-byte compressed text, regardless whether the original text
    507    // was single-byte or two-byte.
    508    SharedImmutableString raw;
    509    size_t uncompressedLength;
    510 
    511    CompressedData(SharedImmutableString raw, size_t uncompressedLength)
    512        : raw(std::move(raw)), uncompressedLength(uncompressedLength) {}
    513  };
    514 
    515  template <typename Unit, SourceRetrievable CanRetrieve>
    516  struct Compressed : public CompressedData<Unit> {
    517    using Base = CompressedData<Unit>;
    518 
    519   public:
    520    using Base::Base;
    521  };
    522 
    523  // The set of currently allowed encoding modes.
    524  using SourceType =
    525      mozilla::Variant<Compressed<mozilla::Utf8Unit, SourceRetrievable::Yes>,
    526                       Uncompressed<mozilla::Utf8Unit, SourceRetrievable::Yes>,
    527                       Compressed<mozilla::Utf8Unit, SourceRetrievable::No>,
    528                       Uncompressed<mozilla::Utf8Unit, SourceRetrievable::No>,
    529                       Compressed<char16_t, SourceRetrievable::Yes>,
    530                       Uncompressed<char16_t, SourceRetrievable::Yes>,
    531                       Compressed<char16_t, SourceRetrievable::No>,
    532                       Uncompressed<char16_t, SourceRetrievable::No>,
    533                       Retrievable<mozilla::Utf8Unit>, Retrievable<char16_t>,
    534                       Missing>;
    535 
    536  //
    537  // Start of fields.
    538  //
    539 
    540  mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> refs = {};
    541 
    542  // An id for this source that is unique across the process. This can be used
    543  // to refer to this source from places that don't want to hold a strong
    544  // reference on the source itself.
    545  //
    546  // This is a 32 bit ID and could overflow, in which case the ID will not be
    547  // unique anymore.
    548  uint32_t id_ = 0;
    549 
    550  // Source data (as a mozilla::Variant).
    551  SourceType data = SourceType(Missing());
    552 
    553  // If the GC calls triggerConvertToCompressedSource with PinnedUnits present,
    554  // the last PinnedUnits instance will install the compressed chars upon
    555  // destruction.
    556  //
    557  // Retrievability isn't part of the type here because uncompressed->compressed
    558  // transitions must preserve existing retrievability.
    559  struct ReaderInstances {
    560    size_t count = 0;
    561    mozilla::MaybeOneOf<CompressedData<mozilla::Utf8Unit>,
    562                        CompressedData<char16_t>>
    563        pendingCompressed;
    564  };
    565  ExclusiveData<ReaderInstances> readers_;
    566 
    567  // The UTF-8 encoded filename of this script.
    568  SharedImmutableString filename_;
    569 
    570  // Hash of the script filename;
    571  HashNumber filenameHash_ = 0;
    572 
    573  // If this ScriptSource was generated by a code-introduction mechanism such
    574  // as |eval| or |new Function|, the debugger needs access to the "raw"
    575  // filename of the top-level script that contains the eval-ing code.  To
    576  // keep track of this, we must preserve the original outermost filename (of
    577  // the original introducer script), so that instead of a filename of
    578  // "foo.js line 30 > eval line 10 > Function", we can obtain the original
    579  // raw filename of "foo.js".
    580  //
    581  // In the case described above, this field will be set to to the original raw
    582  // UTF-8 encoded filename from above, otherwise it will be mozilla::Nothing.
    583  SharedImmutableString introducerFilename_;
    584 
    585  SharedImmutableTwoByteString displayURL_;
    586  SharedImmutableTwoByteString sourceMapURL_;
    587 
    588  // A string indicating how this source code was introduced into the system.
    589  // This is a constant, statically allocated C string, so does not need memory
    590  // management.
    591  //
    592  // TODO: Document the various additional introduction type constants.
    593  const char* introductionType_ = nullptr;
    594 
    595  // Bytecode offset in caller script that generated this code.  This is
    596  // present for eval-ed code, as well as "new Function(...)"-introduced
    597  // scripts.
    598  mozilla::Maybe<uint32_t> introductionOffset_;
    599 
    600  // If this source is for Function constructor, the position of ")" after
    601  // parameter list in the source.  This is used to get function body.
    602  // 0 for other cases.
    603  uint32_t parameterListEnd_ = 0;
    604 
    605  // Line number within the file where this source starts (1-origin).
    606  uint32_t startLine_ = 0;
    607  // Column number within the file where this source starts,
    608  // in UTF-16 code units.
    609  JS::LimitedColumnNumberOneOrigin startColumn_;
    610 
    611  // See: CompileOptions::mutedErrors.
    612  bool mutedErrors_ = false;
    613 
    614  // Carry the delazification mode per source.
    615  JS::DelazificationOption delazificationMode_ =
    616      JS::DelazificationOption::OnDemandOnly;
    617 
    618  // True if an associated SourceCompressionTask was ever created.
    619  bool hadCompressionTask_ = false;
    620 
    621  //
    622  // End of fields.
    623  //
    624 
    625  // How many ids have been handed out to sources.
    626  static mozilla::Atomic<uint32_t, mozilla::SequentiallyConsistent> idCount_;
    627 
    628  // Decompress and return the specified chunk of source code.
    629  // If maybeCx is nullptr, decompression still works but the uncompressed
    630  // result will not be cached. This allows off-main-thread callers to
    631  // decompress source without a JSContext, at the cost of potentially
    632  // decompressing the same chunk multiple times.
    633  template <typename Unit>
    634  const Unit* chunkUnits(JSContext* maybeCx,
    635                         UncompressedSourceCache::AutoHoldEntry& holder,
    636                         size_t chunk);
    637 
    638  // Return a string containing the chars starting at |begin| and ending at
    639  // |begin + len|.
    640  //
    641  // Warning: this is *not* GC-safe! Any chars to be handed out must use
    642  // PinnedUnits. See comment below.
    643  //
    644  // If maybeCx is nullptr, compressed sources will still be decompressed but
    645  // the result will not be cached. See chunkUnits comment above.
    646  template <typename Unit>
    647  const Unit* units(JSContext* maybeCx,
    648                    UncompressedSourceCache::AutoHoldEntry& asp, size_t begin,
    649                    size_t len);
    650 
    651  template <typename Unit>
    652  const Unit* uncompressedUnits(size_t begin, size_t len);
    653 
    654 public:
    655  // When creating a JSString* from TwoByte source characters, we don't try to
    656  // to deflate to Latin1 for longer strings, because this can be slow.
    657  static const size_t SourceDeflateLimit = 100;
    658 
    659  explicit ScriptSource()
    660      : id_(++idCount_), readers_(js::mutexid::SourceCompression) {}
    661  ~ScriptSource() { MOZ_ASSERT(refs == 0); }
    662 
    663  void AddRef() { refs++; }
    664  void Release() {
    665    MOZ_ASSERT(refs != 0);
    666    if (--refs == 0) {
    667      js_delete(this);
    668    }
    669  }
    670  [[nodiscard]] bool initFromOptions(FrontendContext* fc,
    671                                     const JS::ReadOnlyCompileOptions& options);
    672 
    673  /**
    674   * The minimum script length (in code units) necessary for a script to be
    675   * eligible to be compressed.
    676   */
    677  static constexpr size_t MinimumCompressibleLength = 256;
    678 
    679  SharedImmutableString getOrCreateStringZ(FrontendContext* fc,
    680                                           UniqueChars&& str);
    681  SharedImmutableTwoByteString getOrCreateStringZ(FrontendContext* fc,
    682                                                  UniqueTwoByteChars&& str);
    683 
    684 private:
    685  class LoadSourceMatcherBase;
    686  class LoadSourceMatcher;
    687  class SourcePropertiesGetter;
    688 
    689 public:
    690  // Attempt to load usable source for |ss| -- source text on which substring
    691  // operations and the like can be performed.  On success return true and set
    692  // |*loaded| to indicate whether usable source could be loaded; otherwise
    693  // return false.
    694  static bool loadSource(JSContext* cx, ScriptSource* ss, bool* loaded);
    695 
    696  // This is similar to loadSource, but it is designed to be used outside of the
    697  // main thread. This is done by removing the need of JSContext for the
    698  // Retrievable sources that require sourceHook. For retrievable cases, it
    699  // sets retrievable to true and sets the isUT16 depending on the encoding.
    700  //
    701  // *loaded indicates whether source text is available, *retrievable indicates
    702  // whether the source can be retrieved later via source hook.
    703  static void getSourceProperties(ScriptSource* ss, bool* hasSourceText,
    704                                  bool* retrievable);
    705 
    706  // Assign source data from |srcBuf| to this recently-created |ScriptSource|.
    707  template <typename Unit>
    708  [[nodiscard]] bool assignSource(FrontendContext* fc,
    709                                  const JS::ReadOnlyCompileOptions& options,
    710                                  JS::SourceText<Unit>& srcBuf);
    711 
    712  bool hasSourceText() const {
    713    return hasUncompressedSource() || hasCompressedSource();
    714  }
    715 
    716 private:
    717  template <typename Unit>
    718  struct UncompressedDataMatcher {
    719    template <SourceRetrievable CanRetrieve>
    720    const UncompressedData<Unit>* operator()(
    721        const Uncompressed<Unit, CanRetrieve>& u) {
    722      return &u;
    723    }
    724 
    725    template <typename T>
    726    const UncompressedData<Unit>* operator()(const T&) {
    727      MOZ_CRASH(
    728          "attempting to access uncompressed data in a ScriptSource not "
    729          "containing it");
    730      return nullptr;
    731    }
    732  };
    733 
    734 public:
    735  template <typename Unit>
    736  const UncompressedData<Unit>* uncompressedData() {
    737    return data.match(UncompressedDataMatcher<Unit>());
    738  }
    739 
    740 private:
    741  template <typename Unit>
    742  struct CompressedDataMatcher {
    743    template <SourceRetrievable CanRetrieve>
    744    const CompressedData<Unit>* operator()(
    745        const Compressed<Unit, CanRetrieve>& c) {
    746      return &c;
    747    }
    748 
    749    template <typename T>
    750    const CompressedData<Unit>* operator()(const T&) {
    751      MOZ_CRASH(
    752          "attempting to access compressed data in a ScriptSource not "
    753          "containing it");
    754      return nullptr;
    755    }
    756  };
    757 
    758 public:
    759  template <typename Unit>
    760  const CompressedData<Unit>* compressedData() {
    761    return data.match(CompressedDataMatcher<Unit>());
    762  }
    763 
    764 private:
    765  struct HasUncompressedSource {
    766    template <typename Unit, SourceRetrievable CanRetrieve>
    767    bool operator()(const Uncompressed<Unit, CanRetrieve>&) {
    768      return true;
    769    }
    770 
    771    template <typename Unit, SourceRetrievable CanRetrieve>
    772    bool operator()(const Compressed<Unit, CanRetrieve>&) {
    773      return false;
    774    }
    775 
    776    template <typename Unit>
    777    bool operator()(const Retrievable<Unit>&) {
    778      return false;
    779    }
    780 
    781    bool operator()(const Missing&) { return false; }
    782  };
    783 
    784 public:
    785  bool hasUncompressedSource() const {
    786    return data.match(HasUncompressedSource());
    787  }
    788 
    789 private:
    790  template <typename Unit>
    791  struct IsUncompressed {
    792    template <SourceRetrievable CanRetrieve>
    793    bool operator()(const Uncompressed<Unit, CanRetrieve>&) {
    794      return true;
    795    }
    796 
    797    template <typename T>
    798    bool operator()(const T&) {
    799      return false;
    800    }
    801  };
    802 
    803 public:
    804  template <typename Unit>
    805  bool isUncompressed() const {
    806    return data.match(IsUncompressed<Unit>());
    807  }
    808 
    809 private:
    810  struct HasCompressedSource {
    811    template <typename Unit, SourceRetrievable CanRetrieve>
    812    bool operator()(const Compressed<Unit, CanRetrieve>&) {
    813      return true;
    814    }
    815 
    816    template <typename T>
    817    bool operator()(const T&) {
    818      return false;
    819    }
    820  };
    821 
    822 public:
    823  bool hasCompressedSource() const { return data.match(HasCompressedSource()); }
    824 
    825 private:
    826  template <typename Unit>
    827  struct IsCompressed {
    828    template <SourceRetrievable CanRetrieve>
    829    bool operator()(const Compressed<Unit, CanRetrieve>&) {
    830      return true;
    831    }
    832 
    833    template <typename T>
    834    bool operator()(const T&) {
    835      return false;
    836    }
    837  };
    838 
    839 public:
    840  template <typename Unit>
    841  bool isCompressed() const {
    842    return data.match(IsCompressed<Unit>());
    843  }
    844 
    845 private:
    846  template <typename Unit>
    847  struct SourceTypeMatcher {
    848    template <template <typename C, SourceRetrievable R> class Data,
    849              SourceRetrievable CanRetrieve>
    850    bool operator()(const Data<Unit, CanRetrieve>&) {
    851      return true;
    852    }
    853 
    854    template <template <typename C, SourceRetrievable R> class Data,
    855              typename NotUnit, SourceRetrievable CanRetrieve>
    856    bool operator()(const Data<NotUnit, CanRetrieve>&) {
    857      return false;
    858    }
    859 
    860    bool operator()(const Retrievable<Unit>&) {
    861      MOZ_CRASH("source type only applies where actual text is available");
    862      return false;
    863    }
    864 
    865    template <typename NotUnit>
    866    bool operator()(const Retrievable<NotUnit>&) {
    867      return false;
    868    }
    869 
    870    bool operator()(const Missing&) {
    871      MOZ_CRASH("doesn't make sense to ask source type when missing");
    872      return false;
    873    }
    874  };
    875 
    876 public:
    877  template <typename Unit>
    878  bool hasSourceType() const {
    879    return data.match(SourceTypeMatcher<Unit>());
    880  }
    881 
    882 private:
    883  struct UncompressedLengthMatcher {
    884    template <typename Unit, SourceRetrievable CanRetrieve>
    885    size_t operator()(const Uncompressed<Unit, CanRetrieve>& u) {
    886      return u.length();
    887    }
    888 
    889    template <typename Unit, SourceRetrievable CanRetrieve>
    890    size_t operator()(const Compressed<Unit, CanRetrieve>& u) {
    891      return u.uncompressedLength;
    892    }
    893 
    894    template <typename Unit>
    895    size_t operator()(const Retrievable<Unit>&) {
    896      MOZ_CRASH("ScriptSource::length on a missing-but-retrievable source");
    897      return 0;
    898    }
    899 
    900    size_t operator()(const Missing& m) {
    901      MOZ_CRASH("ScriptSource::length on a missing source");
    902      return 0;
    903    }
    904  };
    905 
    906 public:
    907  size_t length() const {
    908    MOZ_ASSERT(hasSourceText());
    909    return data.match(UncompressedLengthMatcher());
    910  }
    911 
    912  JSLinearString* substring(JSContext* cx, size_t start, size_t stop);
    913  JSLinearString* substringDontDeflate(JSContext* cx, size_t start,
    914                                       size_t stop);
    915  // Get substring characters without creating a JSString. Returns a variant
    916  // containing either UniqueChars (UTF-8) or UniqueTwoByteChars (UTF-16).
    917  //
    918  // IMPORTANT: The returned buffer is NOT null-terminated. Callers must track
    919  // the length separately (stop - start). This is designed for consumers that
    920  // store length explicitly (e.g., ProfilerJSSourceData).
    921  //
    922  // Callers must handle empty sources before calling this (the function asserts
    923  // non-empty length). Returns nullptr only on allocation failures. Designed
    924  // for off-main-thread use where JSContext is not available for error
    925  // reporting.
    926  SubstringCharsResult substringChars(size_t start, size_t stop);
    927 
    928  [[nodiscard]] bool appendSubstring(JSContext* cx, js::StringBuilder& buf,
    929                                     size_t start, size_t stop);
    930 
    931  void setParameterListEnd(uint32_t parameterListEnd) {
    932    parameterListEnd_ = parameterListEnd;
    933  }
    934 
    935  bool isFunctionBody() const { return parameterListEnd_ != 0; }
    936  JSLinearString* functionBodyString(JSContext* cx);
    937 
    938  // Returns the function body substring. Unlike substringChars, this can return
    939  // an empty result (nullptr with *outLength == 0) for empty function bodies.
    940  // The caller doesn't need to check the length before calling.
    941  SubstringCharsResult functionBodyStringChars(size_t* outLength);
    942 
    943  // Returns true if this source should display only the function body.
    944  // In case of DOM event handler like <div onclick="foo()" the JS code is
    945  // wrapped into
    946  //   function onclick() {foo()}
    947  // We want to only return `foo()` here.
    948  // But only for event handlers, for `new Function("foo()")`, we want to
    949  // return:
    950  //   function anonymous() {foo()}
    951  bool shouldUnwrapEventHandlerBody() const {
    952    return hasIntroductionType() &&
    953           strcmp(introductionType(), "eventHandler") == 0 && isFunctionBody();
    954  }
    955 
    956  void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
    957                              JS::ScriptSourceInfo* info) const;
    958 
    959 private:
    960  // Overwrites |data| with the uncompressed data from |source|.
    961  //
    962  // This function asserts nothing about |data|.  Users should use assertions to
    963  // double-check their own understandings of the |data| state transition being
    964  // performed.
    965  template <typename ContextT, typename Unit>
    966  [[nodiscard]] bool setUncompressedSourceHelper(ContextT* cx,
    967                                                 EntryUnits<Unit>&& source,
    968                                                 size_t length,
    969                                                 SourceRetrievable retrievable);
    970 
    971 public:
    972  // Initialize a fresh |ScriptSource| with unretrievable, uncompressed source.
    973  template <typename Unit>
    974  [[nodiscard]] bool initializeUnretrievableUncompressedSource(
    975      FrontendContext* fc, EntryUnits<Unit>&& source, size_t length);
    976 
    977  // Set the retrieved source for a |ScriptSource| whose source was recorded as
    978  // missing but retrievable.
    979  template <typename Unit>
    980  [[nodiscard]] bool setRetrievedSource(JSContext* cx,
    981                                        EntryUnits<Unit>&& source,
    982                                        size_t length);
    983 
    984  [[nodiscard]] bool tryCompressOffThread(JSContext* cx);
    985 
    986  // Called by the SourceCompressionTask constructor to indicate such a task was
    987  // ever created.
    988  void noteSourceCompressionTask() { hadCompressionTask_ = true; }
    989 
    990  // *Trigger* the conversion of this ScriptSource from containing uncompressed
    991  // |Unit|-encoded source to containing compressed source.  Conversion may not
    992  // be complete when this function returns: it'll be delayed if there's ongoing
    993  // use of the uncompressed source via |PinnedUnits|, in which case conversion
    994  // won't occur until the outermost |PinnedUnits| is destroyed.
    995  //
    996  // Compressed source is in bytes, no matter that |Unit| might be |char16_t|.
    997  // |sourceLength| is the length in code units (not bytes) of the uncompressed
    998  // source.
    999  template <typename Unit>
   1000  void triggerConvertToCompressedSource(SharedImmutableString compressed,
   1001                                        size_t sourceLength);
   1002 
   1003  // Initialize a fresh ScriptSource as containing unretrievable compressed
   1004  // source of the indicated original encoding.
   1005  template <typename Unit>
   1006  [[nodiscard]] bool initializeWithUnretrievableCompressedSource(
   1007      FrontendContext* fc, UniqueChars&& raw, size_t rawLength,
   1008      size_t sourceLength);
   1009 
   1010 private:
   1011  void performTaskWork(SourceCompressionTaskEntry* task, Compressor& comp);
   1012 
   1013  struct TriggerConvertToCompressedSourceFromTask {
   1014    ScriptSource* const source_;
   1015    SharedImmutableString& compressed_;
   1016 
   1017    TriggerConvertToCompressedSourceFromTask(ScriptSource* source,
   1018                                             SharedImmutableString& compressed)
   1019        : source_(source), compressed_(compressed) {}
   1020 
   1021    template <typename Unit, SourceRetrievable CanRetrieve>
   1022    void operator()(const Uncompressed<Unit, CanRetrieve>&) {
   1023      source_->triggerConvertToCompressedSource<Unit>(std::move(compressed_),
   1024                                                      source_->length());
   1025    }
   1026 
   1027    template <typename Unit, SourceRetrievable CanRetrieve>
   1028    void operator()(const Compressed<Unit, CanRetrieve>&) {
   1029      MOZ_CRASH(
   1030          "can't set compressed source when source is already compressed -- "
   1031          "ScriptSource::tryCompressOffThread shouldn't have queued up this "
   1032          "task?");
   1033    }
   1034 
   1035    template <typename Unit>
   1036    void operator()(const Retrievable<Unit>&) {
   1037      MOZ_CRASH("shouldn't compressing unloaded-but-retrievable source");
   1038    }
   1039 
   1040    void operator()(const Missing&) {
   1041      MOZ_CRASH(
   1042          "doesn't make sense to set compressed source for missing source -- "
   1043          "ScriptSource::tryCompressOffThread shouldn't have queued up this "
   1044          "task?");
   1045    }
   1046  };
   1047 
   1048  template <typename Unit>
   1049  void convertToCompressedSource(SharedImmutableString compressed,
   1050                                 size_t uncompressedLength);
   1051 
   1052  template <typename Unit>
   1053  void performDelayedConvertToCompressedSource(
   1054      ExclusiveData<ReaderInstances>::Guard& g);
   1055 
   1056  void triggerConvertToCompressedSourceFromTask(
   1057      SharedImmutableString compressed);
   1058 
   1059 public:
   1060  HashNumber filenameHash() const { return filenameHash_; }
   1061  const char* filename() const {
   1062    return filename_ ? filename_.chars() : nullptr;
   1063  }
   1064  [[nodiscard]] bool setFilename(FrontendContext* fc, const char* filename);
   1065  [[nodiscard]] bool setFilename(FrontendContext* fc, UniqueChars&& filename);
   1066 
   1067  bool hasIntroducerFilename() const {
   1068    return introducerFilename_ ? true : false;
   1069  }
   1070  const char* introducerFilename() const {
   1071    return introducerFilename_ ? introducerFilename_.chars() : filename();
   1072  }
   1073  [[nodiscard]] bool setIntroducerFilename(FrontendContext* fc,
   1074                                           const char* filename);
   1075  [[nodiscard]] bool setIntroducerFilename(FrontendContext* fc,
   1076                                           UniqueChars&& filename);
   1077 
   1078  bool hasIntroductionType() const { return introductionType_; }
   1079  const char* introductionType() const {
   1080    MOZ_ASSERT(hasIntroductionType());
   1081    return introductionType_;
   1082  }
   1083 
   1084  uint32_t id() const { return id_; }
   1085 
   1086  // Display URLs
   1087  [[nodiscard]] bool setDisplayURL(FrontendContext* fc, const char16_t* url);
   1088  [[nodiscard]] bool setDisplayURL(FrontendContext* fc,
   1089                                   UniqueTwoByteChars&& url);
   1090  bool hasDisplayURL() const { return bool(displayURL_); }
   1091  const char16_t* displayURL() { return displayURL_.chars(); }
   1092 
   1093  // Source maps
   1094  [[nodiscard]] bool setSourceMapURL(FrontendContext* fc, const char16_t* url);
   1095  [[nodiscard]] bool setSourceMapURL(FrontendContext* fc,
   1096                                     UniqueTwoByteChars&& url);
   1097  bool hasSourceMapURL() const { return bool(sourceMapURL_); }
   1098  const char16_t* sourceMapURL() { return sourceMapURL_.chars(); }
   1099 
   1100  bool mutedErrors() const { return mutedErrors_; }
   1101 
   1102  uint32_t startLine() const { return startLine_; }
   1103  JS::LimitedColumnNumberOneOrigin startColumn() const { return startColumn_; }
   1104 
   1105  JS::DelazificationOption delazificationMode() const {
   1106    return delazificationMode_;
   1107  }
   1108 
   1109  bool hasIntroductionOffset() const { return introductionOffset_.isSome(); }
   1110  uint32_t introductionOffset() const { return introductionOffset_.value(); }
   1111  void setIntroductionOffset(uint32_t offset) {
   1112    MOZ_ASSERT(!hasIntroductionOffset());
   1113    MOZ_ASSERT(offset <= (uint32_t)INT32_MAX);
   1114    introductionOffset_.emplace(offset);
   1115  }
   1116 };
   1117 
   1118 // [SMDOC] ScriptSourceObject
   1119 //
   1120 // ScriptSourceObject stores the ScriptSource and GC pointers related to it.
   1121 class ScriptSourceObject : public NativeObject {
   1122  static const JSClassOps classOps_;
   1123 
   1124 public:
   1125  static const JSClass class_;
   1126 
   1127  static void finalize(JS::GCContext* gcx, JSObject* obj);
   1128 
   1129  static ScriptSourceObject* create(JSContext* cx, ScriptSource* source);
   1130 
   1131  // Initialize those properties of this ScriptSourceObject whose values
   1132  // are provided by |options|, re-wrapping as necessary.
   1133  static bool initFromOptions(JSContext* cx,
   1134                              JS::Handle<ScriptSourceObject*> source,
   1135                              const JS::InstantiateOptions& options);
   1136 
   1137  static bool initElementProperties(JSContext* cx,
   1138                                    JS::Handle<ScriptSourceObject*> source,
   1139                                    HandleString elementAttrName);
   1140 
   1141  bool hasSource() const { return !getReservedSlot(SOURCE_SLOT).isUndefined(); }
   1142  ScriptSource* source() const {
   1143    return static_cast<ScriptSource*>(getReservedSlot(SOURCE_SLOT).toPrivate());
   1144  }
   1145 
   1146  JSObject* unwrappedElement(JSContext* cx) const;
   1147 
   1148  const Value& unwrappedElementAttributeName() const {
   1149    MOZ_ASSERT(isInitialized());
   1150    const Value& v = getReservedSlot(ELEMENT_PROPERTY_SLOT);
   1151    MOZ_ASSERT(!v.isMagic());
   1152    return v;
   1153  }
   1154  BaseScript* unwrappedIntroductionScript() const {
   1155    MOZ_ASSERT(isInitialized());
   1156    Value value = getReservedSlot(INTRODUCTION_SCRIPT_SLOT);
   1157    if (value.isUndefined()) {
   1158      return nullptr;
   1159    }
   1160    return value.toGCThing()->as<BaseScript>();
   1161  }
   1162 
   1163  void setPrivate(JSRuntime* rt, const Value& value);
   1164  void clearPrivate(JSRuntime* rt);
   1165 
   1166  void setIntroductionScript(const Value& introductionScript) {
   1167    setReservedSlot(INTRODUCTION_SCRIPT_SLOT, introductionScript);
   1168  }
   1169 
   1170  Value getPrivate() const {
   1171    MOZ_ASSERT(isInitialized());
   1172    Value value = getReservedSlot(PRIVATE_SLOT);
   1173    return value;
   1174  }
   1175 
   1176 private:
   1177 #ifdef DEBUG
   1178  bool isInitialized() const {
   1179    Value element = getReservedSlot(ELEMENT_PROPERTY_SLOT);
   1180    if (element.isMagic(JS_GENERIC_MAGIC)) {
   1181      return false;
   1182    }
   1183    return !getReservedSlot(INTRODUCTION_SCRIPT_SLOT).isMagic(JS_GENERIC_MAGIC);
   1184  }
   1185 #endif
   1186 
   1187  enum {
   1188    PRIVATE_SLOT = 0,  // Must be first slot for JSCLASS_SLOT0_IS_NSISUPPORTS.
   1189    SOURCE_SLOT,
   1190    ELEMENT_PROPERTY_SLOT,
   1191    INTRODUCTION_SCRIPT_SLOT,
   1192    STENCILS_SLOT,
   1193    RESERVED_SLOTS
   1194  };
   1195 
   1196  // Delazification stencils can be aggregated in
   1197  // InitialStencilAndDelazification, this structure might be used for
   1198  // different purposes.
   1199  //  - Collecting: The goal is to aggregate all delazified functions in order
   1200  //    to aggregate them for serialization.
   1201  //  - Sharing: The goal is to use the InitialStencilAndDelazification as a way
   1202  //    to share multiple threads efforts towards parsing a Script Source
   1203  //    content.
   1204  //
   1205  // See setCollectingDelazifications and setSharingDelazifications for details.
   1206  static constexpr uintptr_t STENCILS_COLLECTING_DELAZIFICATIONS_FLAG = 0x1;
   1207  static constexpr uintptr_t STENCILS_SHARING_DELAZIFICATIONS_FLAG = 0x2;
   1208  static constexpr uintptr_t STENCILS_MASK = 0x3;
   1209 
   1210  void clearStencils();
   1211 
   1212  template <uintptr_t flag>
   1213  void setStencilsFlag();
   1214 
   1215  template <uintptr_t flag>
   1216  void unsetStencilsFlag();
   1217 
   1218  template <uintptr_t flag>
   1219  bool isStencilsFlagSet() const;
   1220 
   1221 public:
   1222  // Associate stencils to this ScriptSourceObject.
   1223  // The consumer should call setCollectingDelazifications or
   1224  // setSharingDelazifications after this.
   1225  void setStencils(
   1226      already_AddRefed<frontend::InitialStencilAndDelazifications> stencils);
   1227 
   1228  // Start collecting delazifications.
   1229  // This is a temporary state until unsetCollectingDelazifications is called,
   1230  // and this expects a pair of set/unset call.
   1231  //
   1232  // The caller should check isCollectingDelazifications before calling this.
   1233  void setCollectingDelazifications();
   1234 
   1235  // Clear the flag for collecting delazifications.
   1236  //
   1237  // If setSharingDelazifications wasn't called, this clears the association
   1238  // with the stencils.
   1239  void unsetCollectingDelazifications();
   1240 
   1241  // Returns true if setCollectingDelazifications was called and
   1242  // unsetCollectingDelazifications is not yet called.
   1243  bool isCollectingDelazifications() const;
   1244 
   1245  // Start sharing delazifications with others.
   1246  // This is a permanent state.
   1247  //
   1248  // The flag is orthogonal to setCollectingDelazifications.
   1249  void setSharingDelazifications();
   1250 
   1251  // Returns true if setSharingDelazifications was called.
   1252  bool isSharingDelazifications() const;
   1253 
   1254  // Return the associated stencils if any.
   1255  // Returns nullptr if stencils is not associated
   1256  frontend::InitialStencilAndDelazifications* maybeGetStencils();
   1257 };
   1258 
   1259 // ScriptWarmUpData represents a pointer-sized field in BaseScript that stores
   1260 // one of the following using low-bit tags:
   1261 //
   1262 // * The enclosing BaseScript. This is only used while this script is lazy and
   1263 //   its containing script is also lazy. This outer script must be compiled
   1264 //   before the current script can in order to correctly build the scope chain.
   1265 //
   1266 // * The enclosing Scope. This is only used while this script is lazy and its
   1267 //   containing script is compiled. This is the outer scope chain that will be
   1268 //   used to compile this scipt.
   1269 //
   1270 // * The script's warm-up count. This is only used until the script has a
   1271 //   JitScript. The Baseline Interpreter and JITs use the warm-up count stored
   1272 //   in JitScript.
   1273 //
   1274 // * A pointer to the JitScript, when the script is warm enough for the Baseline
   1275 //   Interpreter.
   1276 //
   1277 class ScriptWarmUpData {
   1278  uintptr_t data_ = ResetState();
   1279 
   1280 private:
   1281  static constexpr uintptr_t NumTagBits = 2;
   1282  static constexpr uint32_t MaxWarmUpCount = UINT32_MAX >> NumTagBits;
   1283 
   1284 public:
   1285  // Public only for the JITs.
   1286  static constexpr uintptr_t TagMask = (1 << NumTagBits) - 1;
   1287  static constexpr uintptr_t JitScriptTag = 0;
   1288  static constexpr uintptr_t EnclosingScriptTag = 1;
   1289  static constexpr uintptr_t EnclosingScopeTag = 2;
   1290  static constexpr uintptr_t WarmUpCountTag = 3;
   1291 
   1292 private:
   1293  // A gc-safe value to clear to.
   1294  constexpr uintptr_t ResetState() { return 0 | WarmUpCountTag; }
   1295 
   1296  template <uintptr_t Tag>
   1297  inline void setTaggedPtr(void* ptr) {
   1298    static_assert(Tag <= TagMask, "Tag must fit in TagMask");
   1299    MOZ_ASSERT((uintptr_t(ptr) & TagMask) == 0);
   1300    data_ = uintptr_t(ptr) | Tag;
   1301  }
   1302 
   1303  template <typename T, uintptr_t Tag>
   1304  inline T getTaggedPtr() const {
   1305    static_assert(Tag <= TagMask, "Tag must fit in TagMask");
   1306    MOZ_ASSERT((data_ & TagMask) == Tag);
   1307    return reinterpret_cast<T>(data_ & ~TagMask);
   1308  }
   1309 
   1310  void setWarmUpCount(uint32_t count) {
   1311    if (count > MaxWarmUpCount) {
   1312      count = MaxWarmUpCount;
   1313    }
   1314    data_ = (uintptr_t(count) << NumTagBits) | WarmUpCountTag;
   1315  }
   1316 
   1317 public:
   1318  void trace(JSTracer* trc);
   1319 
   1320  bool isEnclosingScript() const {
   1321    return (data_ & TagMask) == EnclosingScriptTag;
   1322  }
   1323  bool isEnclosingScope() const {
   1324    return (data_ & TagMask) == EnclosingScopeTag;
   1325  }
   1326  bool isWarmUpCount() const { return (data_ & TagMask) == WarmUpCountTag; }
   1327  bool isJitScript() const { return (data_ & TagMask) == JitScriptTag; }
   1328 
   1329  // NOTE: To change type safely, 'clear' the old tagged value and then 'init'
   1330  //       the new one. This will notify the GC appropriately.
   1331 
   1332  BaseScript* toEnclosingScript() const {
   1333    return getTaggedPtr<BaseScript*, EnclosingScriptTag>();
   1334  }
   1335  inline void initEnclosingScript(BaseScript* enclosingScript);
   1336  inline void clearEnclosingScript();
   1337 
   1338  Scope* toEnclosingScope() const {
   1339    return getTaggedPtr<Scope*, EnclosingScopeTag>();
   1340  }
   1341  inline void initEnclosingScope(Scope* enclosingScope);
   1342  inline void clearEnclosingScope();
   1343 
   1344  uint32_t toWarmUpCount() const {
   1345    MOZ_ASSERT(isWarmUpCount());
   1346    return data_ >> NumTagBits;
   1347  }
   1348  void resetWarmUpCount(uint32_t count) {
   1349    MOZ_ASSERT(isWarmUpCount());
   1350    setWarmUpCount(count);
   1351  }
   1352  void incWarmUpCount() {
   1353    MOZ_ASSERT(isWarmUpCount());
   1354    data_ += uintptr_t(1) << NumTagBits;
   1355  }
   1356 
   1357  jit::JitScript* toJitScript() const {
   1358    return getTaggedPtr<jit::JitScript*, JitScriptTag>();
   1359  }
   1360  void initJitScript(jit::JitScript* jitScript) {
   1361    MOZ_ASSERT(isWarmUpCount());
   1362    setTaggedPtr<JitScriptTag>(jitScript);
   1363  }
   1364  void clearJitScript() {
   1365    MOZ_ASSERT(isJitScript());
   1366    data_ = ResetState();
   1367  }
   1368 } JS_HAZ_GC_POINTER;
   1369 
   1370 static_assert(sizeof(ScriptWarmUpData) == sizeof(uintptr_t),
   1371              "JIT code depends on ScriptWarmUpData being pointer-sized");
   1372 
   1373 // [SMDOC] - JSScript data layout (unshared)
   1374 //
   1375 // PrivateScriptData stores variable-length data associated with a script.
   1376 // Abstractly a PrivateScriptData consists of the following:
   1377 //
   1378 //   * A non-empty array of GCCellPtr in gcthings()
   1379 //
   1380 // Accessing this array just requires calling the appropriate public
   1381 // Span-computing function.
   1382 //
   1383 // This class doesn't use the GC barrier wrapper classes. BaseScript::swapData
   1384 // performs a manual pre-write barrier when detaching PrivateScriptData from a
   1385 // script.
   1386 class alignas(uintptr_t) PrivateScriptData final
   1387    : public TrailingArray<PrivateScriptData> {
   1388 private:
   1389  uint32_t ngcthings = 0;
   1390 
   1391  // Note: This is only defined for scripts with an enclosing scope. This
   1392  // excludes lazy scripts with lazy parents.
   1393  js::MemberInitializers memberInitializers_ =
   1394      js::MemberInitializers::Invalid();
   1395 
   1396  // End of fields.
   1397 
   1398 private:
   1399  // Layout helpers
   1400  Offset gcThingsOffset() { return offsetOfGCThings(); }
   1401  Offset endOffset() const {
   1402    uintptr_t size = ngcthings * sizeof(JS::GCCellPtr);
   1403    return offsetOfGCThings() + size;
   1404  }
   1405 
   1406  // Initialize header and PackedSpans
   1407  explicit PrivateScriptData(uint32_t ngcthings);
   1408 
   1409 public:
   1410  static constexpr size_t offsetOfGCThings() {
   1411    return sizeof(PrivateScriptData);
   1412  }
   1413 
   1414  // Accessors for typed array spans.
   1415  mozilla::Span<JS::GCCellPtr> gcthings() {
   1416    Offset offset = offsetOfGCThings();
   1417    return mozilla::Span{offsetToPointer<JS::GCCellPtr>(offset), ngcthings};
   1418  }
   1419 
   1420  void setMemberInitializers(MemberInitializers memberInitializers) {
   1421    MOZ_ASSERT(memberInitializers_.valid == false,
   1422               "Only init MemberInitializers once");
   1423    memberInitializers_ = memberInitializers;
   1424  }
   1425  const MemberInitializers& getMemberInitializers() {
   1426    return memberInitializers_;
   1427  }
   1428 
   1429  // Allocate a new PrivateScriptData. Headers and GCCellPtrs are initialized.
   1430  static PrivateScriptData* new_(JSContext* cx, uint32_t ngcthings);
   1431 
   1432  static bool InitFromStencil(
   1433      JSContext* cx, js::HandleScript script,
   1434      const js::frontend::CompilationAtomCache& atomCache,
   1435      const js::frontend::CompilationStencil& stencil,
   1436      js::frontend::CompilationGCOutput& gcOutput,
   1437      const js::frontend::ScriptIndex scriptIndex);
   1438 
   1439  void trace(JSTracer* trc);
   1440 
   1441  size_t allocationSize() const;
   1442 
   1443  // PrivateScriptData has trailing data so isn't copyable or movable.
   1444  PrivateScriptData(const PrivateScriptData&) = delete;
   1445  PrivateScriptData& operator=(const PrivateScriptData&) = delete;
   1446 };
   1447 
   1448 // An entry in the runtime's pendingCompressions_ list for a single
   1449 // ScriptSource.
   1450 //
   1451 // It is not desirable to eagerly compress: if lazy functions that are tied to
   1452 // the ScriptSource were to be executed relatively soon after parsing, they
   1453 // would need to block on decompression, which hurts responsiveness.
   1454 //
   1455 // To this end, script sources are enqueued in a pending list by
   1456 // ScriptSource::tryCompressOffThread. When a major GC occurs, we allocate and
   1457 // submit SourceCompressionTasks for them. Currently, a script source is
   1458 // considered ready 2 major GCs after being enqueued.
   1459 class PendingSourceCompressionEntry {
   1460  // The major GC number of the runtime when the entry was enqueued.
   1461  uint64_t majorGCNumber_;
   1462 
   1463  // The source to be compressed.
   1464  RefPtr<ScriptSource> source_;
   1465 
   1466 public:
   1467  PendingSourceCompressionEntry(JSRuntime* rt, ScriptSource* source);
   1468 
   1469  ScriptSource* source() const { return source_.get(); }
   1470  uint64_t majorGCNumber() const { return majorGCNumber_; }
   1471  bool shouldCancel() const {
   1472    // If the refcount is exactly 1, then nothing else is holding on to the
   1473    // ScriptSource, so no reason to compress it and we should cancel the
   1474    // compression.
   1475    return source_->refs == 1;
   1476  }
   1477 };
   1478 
   1479 // [SMDOC] Script Representation (js::BaseScript)
   1480 //
   1481 // A "script" corresponds to a JavaScript function or a top-level (global, eval,
   1482 // module) body that will be executed using SpiderMonkey bytecode. Note that
   1483 // special forms such as asm.js do not use bytecode or the BaseScript type.
   1484 //
   1485 // BaseScript may be generated directly from the parser/emitter, or by cloning
   1486 // or deserializing another script. Cloning is typically used when a script is
   1487 // needed in multiple realms and we would like to avoid re-compiling.
   1488 //
   1489 // A single script may be shared by multiple JSFunctions in a realm when those
   1490 // function objects are used as closure. In this case, a single JSFunction is
   1491 // considered canonical (and often does not escape to script directly).
   1492 //
   1493 // A BaseScript may be in "lazy" form where the parser performs a syntax-only
   1494 // parse and saves minimal information. These lazy scripts must be recompiled
   1495 // from the source (generating bytecode) before they can execute in a process
   1496 // called "delazification". On GC memory pressure, a fully-compiled script may
   1497 // be converted back into lazy form by "relazification".
   1498 //
   1499 // A fully-initialized BaseScript can be identified with `hasBytecode()` and
   1500 // will have bytecode and set of GC-things such as scopes, inner-functions, and
   1501 // object/string literals. This is referred to as a "non-lazy" script.
   1502 //
   1503 // A lazy script has either an enclosing script or scope. Each script needs to
   1504 // know its enclosing scope in order to be fully compiled. If the parent is
   1505 // still lazy we track that script and will need to compile it first to know our
   1506 // own enclosing scope. This is because scope objects are not created until full
   1507 // compilation and bytecode generation.
   1508 //
   1509 //
   1510 // # Script Warm-Up #
   1511 //
   1512 // A script evolves its representation over time. As it becomes "hotter" we
   1513 // attach a stack of additional data-structures generated by the JITs to
   1514 // speed-up execution. This evolution may also be run in reverse, in order to
   1515 // reduce memory usage.
   1516 //
   1517 //              +-------------------------------------+
   1518 //              | ScriptSource                        |
   1519 //              |   Provides:   Source                |
   1520 //              |   Engine:     Parser                |
   1521 //              +-------------------------------------+
   1522 //                                v
   1523 //              +-----------------------------------------------+
   1524 //              | BaseScript                                    |
   1525 //              |   Provides:   SourceExtent/Bindings           |
   1526 //              |   Engine:     CompileLazyFunctionToStencil    |
   1527 //              |               /InstantiateStencilsForDelazify |
   1528 //              +-----------------------------------------------+
   1529 //                                v
   1530 //              +-------------------------------------+
   1531 //              | ImmutableScriptData                 |
   1532 //              |   Provides:   Bytecode              |
   1533 //              |   Engine:     Interpreter           |
   1534 //              +-------------------------------------+
   1535 //                                v
   1536 //              +-------------------------------------+
   1537 //              | JitScript                           |
   1538 //              |   Provides:   Inline Caches (ICs)   |
   1539 //              |   Engine:     BaselineInterpreter   |
   1540 //              +-------------------------------------+
   1541 //                                v
   1542 //              +-------------------------------------+
   1543 //              | BaselineScript                      |
   1544 //              |   Provides:   Native Code           |
   1545 //              |   Engine:     Baseline              |
   1546 //              +-------------------------------------+
   1547 //                                v
   1548 //              +-------------------------------------+
   1549 //              | IonScript                           |
   1550 //              |   Provides:   Optimized Native Code |
   1551 //              |   Engine:     IonMonkey             |
   1552 //              +-------------------------------------+
   1553 //
   1554 // NOTE: Scripts may be directly created with bytecode and skip the lazy script
   1555 //       form. This is always the case for top-level scripts.
   1556 class BaseScript : public gc::TenuredCellWithNonGCPointer<uint8_t> {
   1557  friend class js::gc::CellAllocator;
   1558 
   1559 public:
   1560  // Pointer to baseline->method()->raw(), ion->method()->raw(), a wasm jit
   1561  // entry, the JIT's EnterInterpreter stub, or the lazy link stub. Must be
   1562  // non-null (except on no-jit builds). This is stored in the cell header.
   1563  uint8_t* jitCodeRaw() const { return headerPtr(); }
   1564 
   1565 protected:
   1566  // Multi-purpose value that changes type as the script warms up from lazy form
   1567  // to interpreted-bytecode to JITs. See: ScriptWarmUpData type for more info.
   1568  ScriptWarmUpData warmUpData_ = {};
   1569 
   1570  // For function scripts this is the canonical function, otherwise nullptr.
   1571  const GCPtr<JSFunction*> function_ = {};
   1572 
   1573  // The ScriptSourceObject for this script. This is always same-compartment and
   1574  // same-realm with this script.
   1575  const GCPtr<ScriptSourceObject*> sourceObject_ = {};
   1576 
   1577  // Position of the function in the source buffer. Both in terms of line/column
   1578  // and code-unit offset.
   1579  const SourceExtent extent_ = {};
   1580 
   1581  // Immutable flags are a combination of parser options and bytecode
   1582  // characteristics. These flags are preserved when serializing or copying this
   1583  // script.
   1584  const ImmutableScriptFlags immutableFlags_ = {};
   1585 
   1586  // Mutable flags store transient information used by subsystems such as the
   1587  // debugger and the JITs. These flags are *not* preserved when serializing or
   1588  // cloning since they are based on runtime state.
   1589  MutableScriptFlags mutableFlags_ = {};
   1590 
   1591  // Variable-length data owned by this script. This stores one of:
   1592  //    - GC pointers that bytecode references.
   1593  //    - Inner-functions and bindings generated by syntax parse.
   1594  //    - Nullptr, if no bytecode or inner functions.
   1595  // This is updated as script is delazified and relazified.
   1596  GCStructPtr<PrivateScriptData*> data_;
   1597 
   1598  // Shareable script data. This includes runtime-wide atom pointers, bytecode,
   1599  // and various script note structures. If the script is currently lazy, this
   1600  // will be nullptr.
   1601  RefPtr<js::SharedImmutableScriptData> sharedData_ = {};
   1602 
   1603  // End of fields.
   1604 
   1605  BaseScript(uint8_t* stubEntry, JSFunction* function,
   1606             ScriptSourceObject* sourceObject, const SourceExtent& extent,
   1607             uint32_t immutableFlags);
   1608 
   1609  void setJitCodeRaw(uint8_t* code) { setHeaderPtr(code); }
   1610 
   1611 public:
   1612  static BaseScript* New(JSContext* cx, JS::Handle<JSFunction*> function,
   1613                         JS::Handle<js::ScriptSourceObject*> sourceObject,
   1614                         const js::SourceExtent& extent,
   1615                         uint32_t immutableFlags);
   1616 
   1617  // Create a lazy BaseScript without initializing any gc-things.
   1618  static BaseScript* CreateRawLazy(JSContext* cx, uint32_t ngcthings,
   1619                                   HandleFunction fun,
   1620                                   JS::Handle<ScriptSourceObject*> sourceObject,
   1621                                   const SourceExtent& extent,
   1622                                   uint32_t immutableFlags);
   1623 
   1624  bool isUsingInterpreterTrampoline(JSRuntime* rt) const;
   1625 
   1626  // Canonical function for the script, if it has a function. For top-level
   1627  // scripts this is nullptr.
   1628  JSFunction* function() const { return function_; }
   1629 
   1630  JS::Realm* realm() const { return sourceObject()->realm(); }
   1631  JS::Compartment* compartment() const { return sourceObject()->compartment(); }
   1632  JS::Compartment* maybeCompartment() const { return compartment(); }
   1633  inline JSPrincipals* principals() const;
   1634 
   1635  ScriptSourceObject* sourceObject() const { return sourceObject_; }
   1636  ScriptSource* scriptSource() const { return sourceObject()->source(); }
   1637  ScriptSource* maybeForwardedScriptSource() const;
   1638 
   1639  bool mutedErrors() const { return scriptSource()->mutedErrors(); }
   1640 
   1641  const char* filename() const { return scriptSource()->filename(); }
   1642  HashNumber filenameHash() const { return scriptSource()->filenameHash(); }
   1643  const char* maybeForwardedFilename() const {
   1644    return maybeForwardedScriptSource()->filename();
   1645  }
   1646 
   1647  uint32_t sourceStart() const { return extent_.sourceStart; }
   1648  uint32_t sourceEnd() const { return extent_.sourceEnd; }
   1649  uint32_t sourceLength() const {
   1650    return extent_.sourceEnd - extent_.sourceStart;
   1651  }
   1652  uint32_t toStringStart() const { return extent_.toStringStart; }
   1653  uint32_t toStringEnd() const { return extent_.toStringEnd; }
   1654  SourceExtent extent() const { return extent_; }
   1655 
   1656  [[nodiscard]] bool appendSourceDataForToString(JSContext* cx,
   1657                                                 js::StringBuilder& buf);
   1658 
   1659  // Line number (1-origin)
   1660  uint32_t lineno() const { return extent_.lineno; }
   1661  // Column number in UTF-16 code units
   1662  JS::LimitedColumnNumberOneOrigin column() const { return extent_.column; }
   1663 
   1664  JS::DelazificationOption delazificationMode() const {
   1665    return scriptSource()->delazificationMode();
   1666  }
   1667 
   1668 public:
   1669  ImmutableScriptFlags immutableFlags() const { return immutableFlags_; }
   1670  RO_IMMUTABLE_SCRIPT_FLAGS(immutableFlags_)
   1671  RW_MUTABLE_SCRIPT_FLAGS(mutableFlags_)
   1672 
   1673  bool hasEnclosingScript() const { return warmUpData_.isEnclosingScript(); }
   1674  BaseScript* enclosingScript() const {
   1675    return warmUpData_.toEnclosingScript();
   1676  }
   1677  void setEnclosingScript(BaseScript* enclosingScript);
   1678 
   1679  // Returns true is the script has an enclosing scope but no bytecode. It is
   1680  // ready for delazification.
   1681  // NOTE: The enclosing script must have been successfully compiled at some
   1682  // point for the enclosing scope to exist. That script may have since been
   1683  // GC'd, but we kept the scope live so we can still compile ourselves.
   1684  bool isReadyForDelazification() const {
   1685    return warmUpData_.isEnclosingScope();
   1686  }
   1687 
   1688  Scope* enclosingScope() const;
   1689  void setEnclosingScope(Scope* enclosingScope);
   1690  Scope* releaseEnclosingScope();
   1691 
   1692  bool hasJitScript() const { return warmUpData_.isJitScript(); }
   1693  jit::JitScript* jitScript() const {
   1694    MOZ_ASSERT(hasJitScript());
   1695    return warmUpData_.toJitScript();
   1696  }
   1697  jit::JitScript* maybeJitScript() const {
   1698    return hasJitScript() ? jitScript() : nullptr;
   1699  }
   1700 
   1701  inline bool hasBaselineScript() const;
   1702  inline bool hasIonScript() const;
   1703 
   1704  bool hasPrivateScriptData() const { return data_ != nullptr; }
   1705 
   1706  // Update data_ pointer while also informing GC MemoryUse tracking.
   1707  void swapData(UniquePtr<PrivateScriptData>& other);
   1708 
   1709  mozilla::Span<const JS::GCCellPtr> gcthings() const {
   1710    return data_ ? data_->gcthings() : mozilla::Span<JS::GCCellPtr>();
   1711  }
   1712 
   1713  // NOTE: This is only used to initialize a fresh script.
   1714  mozilla::Span<JS::GCCellPtr> gcthingsForInit() {
   1715    MOZ_ASSERT(!hasBytecode());
   1716    return data_ ? data_->gcthings() : mozilla::Span<JS::GCCellPtr>();
   1717  }
   1718 
   1719  void setMemberInitializers(MemberInitializers memberInitializers) {
   1720    MOZ_ASSERT(useMemberInitializers());
   1721    MOZ_ASSERT(data_);
   1722    data_->setMemberInitializers(memberInitializers);
   1723  }
   1724  const MemberInitializers& getMemberInitializers() const {
   1725    MOZ_ASSERT(data_);
   1726    return data_->getMemberInitializers();
   1727  }
   1728 
   1729  SharedImmutableScriptData* sharedData() const { return sharedData_; }
   1730  void initSharedData(SharedImmutableScriptData* data) {
   1731    MOZ_ASSERT(sharedData_ == nullptr);
   1732    sharedData_ = data;
   1733  }
   1734  void freeSharedData() { sharedData_ = nullptr; }
   1735 
   1736  // NOTE: Script only has bytecode if JSScript::fullyInitFromStencil completes
   1737  // successfully.
   1738  bool hasBytecode() const {
   1739    if (sharedData_) {
   1740      MOZ_ASSERT(data_);
   1741      MOZ_ASSERT(warmUpData_.isWarmUpCount() || warmUpData_.isJitScript());
   1742      return true;
   1743    }
   1744    return false;
   1745  }
   1746 
   1747 public:
   1748  static const JS::TraceKind TraceKind = JS::TraceKind::Script;
   1749 
   1750  void traceChildren(JSTracer* trc);
   1751  void finalize(JS::GCContext* gcx);
   1752 
   1753  size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
   1754    return mallocSizeOf(data_);
   1755  }
   1756 
   1757  inline JSScript* asJSScript();
   1758 
   1759  // JIT accessors
   1760  static constexpr size_t offsetOfJitCodeRaw() { return offsetOfHeaderPtr(); }
   1761  static constexpr size_t offsetOfPrivateData() {
   1762    return offsetof(BaseScript, data_);
   1763  }
   1764  static constexpr size_t offsetOfSharedData() {
   1765    return offsetof(BaseScript, sharedData_);
   1766  }
   1767  static size_t offsetOfImmutableFlags() {
   1768    static_assert(sizeof(ImmutableScriptFlags) == sizeof(uint32_t));
   1769    return offsetof(BaseScript, immutableFlags_);
   1770  }
   1771  static constexpr size_t offsetOfMutableFlags() {
   1772    static_assert(sizeof(MutableScriptFlags) == sizeof(uint32_t));
   1773    return offsetof(BaseScript, mutableFlags_);
   1774  }
   1775  static constexpr size_t offsetOfWarmUpData() {
   1776    return offsetof(BaseScript, warmUpData_);
   1777  }
   1778 
   1779 #if defined(DEBUG) || defined(JS_JITSPEW)
   1780  void dumpStringContent(js::GenericPrinter& out) const;
   1781 #endif
   1782 };
   1783 
   1784 extern void SweepScriptData(JSRuntime* rt);
   1785 
   1786 } /* namespace js */
   1787 
   1788 class JSScript : public js::BaseScript {
   1789 private:
   1790  friend bool js::PrivateScriptData::InitFromStencil(
   1791      JSContext* cx, js::HandleScript script,
   1792      const js::frontend::CompilationAtomCache& atomCache,
   1793      const js::frontend::CompilationStencil& stencil,
   1794      js::frontend::CompilationGCOutput& gcOutput,
   1795      const js::frontend::ScriptIndex scriptIndex);
   1796 
   1797 private:
   1798  using js::BaseScript::BaseScript;
   1799 
   1800 public:
   1801  static JSScript* Create(JSContext* cx, JS::Handle<JSFunction*> function,
   1802                          JS::Handle<js::ScriptSourceObject*> sourceObject,
   1803                          const js::SourceExtent& extent,
   1804                          js::ImmutableScriptFlags flags);
   1805 
   1806  // NOTE: This should only be used while delazifying.
   1807  static JSScript* CastFromLazy(js::BaseScript* lazy) {
   1808    return static_cast<JSScript*>(lazy);
   1809  }
   1810 
   1811  // NOTE: If you use createPrivateScriptData directly instead of via
   1812  // fullyInitFromStencil, you are responsible for notifying the debugger
   1813  // after successfully creating the script.
   1814  static bool createPrivateScriptData(JSContext* cx,
   1815                                      JS::Handle<JSScript*> script,
   1816                                      uint32_t ngcthings);
   1817 
   1818 public:
   1819  static bool fullyInitFromStencil(
   1820      JSContext* cx, const js::frontend::CompilationAtomCache& atomCache,
   1821      const js::frontend::CompilationStencil& stencil,
   1822      js::frontend::CompilationGCOutput& gcOutput, js::HandleScript script,
   1823      const js::frontend::ScriptIndex scriptIndex);
   1824 
   1825  // Allocate a JSScript and initialize it with bytecode. This consumes
   1826  // allocations within the stencil.
   1827  static JSScript* fromStencil(JSContext* cx,
   1828                               js::frontend::CompilationAtomCache& atomCache,
   1829                               const js::frontend::CompilationStencil& stencil,
   1830                               js::frontend::CompilationGCOutput& gcOutput,
   1831                               js::frontend::ScriptIndex scriptIndex);
   1832 
   1833 #ifdef DEBUG
   1834 private:
   1835  // Assert that jump targets are within the code array of the script.
   1836  void assertValidJumpTargets() const;
   1837 #endif
   1838 
   1839 public:
   1840  js::ImmutableScriptData* immutableScriptData() const {
   1841    return sharedData_->get();
   1842  }
   1843 
   1844  // Script bytecode is immutable after creation.
   1845  jsbytecode* code() const {
   1846    if (!sharedData_) {
   1847      return nullptr;
   1848    }
   1849    return immutableScriptData()->code();
   1850  }
   1851 
   1852  bool hasForceInterpreterOp() const {
   1853    // JSOp::ForceInterpreter, if present, must be the first op.
   1854    MOZ_ASSERT(length() >= 1);
   1855    return JSOp(*code()) == JSOp::ForceInterpreter;
   1856  }
   1857 
   1858  js::AllBytecodesIterable allLocations() {
   1859    return js::AllBytecodesIterable(this);
   1860  }
   1861 
   1862  js::BytecodeLocation location() { return js::BytecodeLocation(this, code()); }
   1863 
   1864  size_t length() const {
   1865    MOZ_ASSERT(sharedData_);
   1866    return immutableScriptData()->codeLength();
   1867  }
   1868 
   1869  jsbytecode* codeEnd() const { return code() + length(); }
   1870 
   1871  jsbytecode* lastPC() const {
   1872    jsbytecode* pc = codeEnd() - js::JSOpLength_RetRval;
   1873    MOZ_ASSERT(JSOp(*pc) == JSOp::RetRval || JSOp(*pc) == JSOp::Return);
   1874    return pc;
   1875  }
   1876 
   1877  // Note: ArgBytes is optional, but if specified then containsPC will also
   1878  //       check that the opcode arguments are in bounds.
   1879  template <size_t ArgBytes = 0>
   1880  bool containsPC(const jsbytecode* pc) const {
   1881    MOZ_ASSERT_IF(ArgBytes,
   1882                  js::GetBytecodeLength(pc) == sizeof(jsbytecode) + ArgBytes);
   1883    const jsbytecode* lastByte = pc + ArgBytes;
   1884    return pc >= code() && lastByte < codeEnd();
   1885  }
   1886  template <typename ArgType>
   1887  bool containsPC(const jsbytecode* pc) const {
   1888    return containsPC<sizeof(ArgType)>(pc);
   1889  }
   1890 
   1891  bool contains(const js::BytecodeLocation& loc) const {
   1892    return containsPC(loc.toRawBytecode());
   1893  }
   1894 
   1895  size_t pcToOffset(const jsbytecode* pc) const {
   1896    MOZ_ASSERT(containsPC(pc));
   1897    return size_t(pc - code());
   1898  }
   1899 
   1900  jsbytecode* offsetToPC(size_t offset) const {
   1901    MOZ_ASSERT(offset < length());
   1902    return code() + offset;
   1903  }
   1904 
   1905  size_t mainOffset() const { return immutableScriptData()->mainOffset; }
   1906 
   1907  // The fixed part of a stack frame is comprised of vars (in function and
   1908  // module code) and block-scoped locals (in all kinds of code).
   1909  size_t nfixed() const { return immutableScriptData()->nfixed; }
   1910 
   1911  // Number of fixed slots reserved for slots that are always live. Only
   1912  // nonzero for function or module code.
   1913  size_t numAlwaysLiveFixedSlots() const;
   1914 
   1915  // Calculate the number of fixed slots that are live at a particular bytecode.
   1916  size_t calculateLiveFixed(jsbytecode* pc);
   1917 
   1918  size_t nslots() const { return immutableScriptData()->nslots; }
   1919 
   1920  unsigned numArgs() const;
   1921 
   1922  inline js::Shape* initialEnvironmentShape() const;
   1923 
   1924  bool functionHasParameterExprs() const;
   1925 
   1926  bool functionAllowsParameterRedeclaration() const {
   1927    // Parameter redeclaration is only allowed for non-strict functions with
   1928    // simple parameter lists, which are neither arrow nor method functions. We
   1929    // don't have a flag at hand to test the function kind, but we can still
   1930    // test if the function is non-strict and has a simple parameter list by
   1931    // checking |hasMappedArgsObj()|. (Mapped arguments objects are only
   1932    // created for non-strict functions with simple parameter lists.)
   1933    return hasMappedArgsObj();
   1934  }
   1935 
   1936  size_t numICEntries() const { return immutableScriptData()->numICEntries; }
   1937 
   1938  size_t funLength() const { return immutableScriptData()->funLength; }
   1939 
   1940  void cacheForEval() {
   1941    MOZ_ASSERT(isForEval());
   1942    // IsEvalCacheCandidate will make sure that there's nothing in this
   1943    // script that would prevent reexecution even if isRunOnce is
   1944    // true.  So just pretend like we never ran this script.
   1945    clearFlag(MutableFlags::HasRunOnce);
   1946  }
   1947 
   1948  /*
   1949   * Arguments access (via JSOp::*Arg* opcodes) must access the canonical
   1950   * location for the argument. If an arguments object exists AND it's mapped
   1951   * ('arguments' aliases formals), then all access must go through the
   1952   * arguments object. Otherwise, the local slot is the canonical location for
   1953   * the arguments. Note: if a formal is aliased through the scope chain, then
   1954   * script->formalIsAliased and JSOp::*Arg* opcodes won't be emitted at all.
   1955   */
   1956  bool argsObjAliasesFormals() const {
   1957    return needsArgsObj() && hasMappedArgsObj();
   1958  }
   1959 
   1960  void updateJitCodeRaw(JSRuntime* rt);
   1961 
   1962  bool isModule() const;
   1963  js::ModuleObject* module() const;
   1964 
   1965  bool isGlobalCode() const;
   1966 
   1967  // Returns true if the script may read formal arguments on the stack
   1968  // directly, via lazy arguments or a rest parameter.
   1969  bool mayReadFrameArgsDirectly();
   1970 
   1971  static JSLinearString* sourceData(JSContext* cx, JS::HandleScript script);
   1972 
   1973 #ifdef MOZ_VTUNE
   1974  // Unique Method ID passed to the VTune profiler. Allows attribution of
   1975  // different jitcode to the same source script.
   1976  uint32_t vtuneMethodID();
   1977 #endif
   1978 
   1979 public:
   1980  /* Return whether this is a 'direct eval' script in a function scope. */
   1981  bool isDirectEvalInFunction() const;
   1982 
   1983  /*
   1984   * Return whether this script is a top-level script.
   1985   *
   1986   * If we evaluate some code which contains a syntax error, then we might
   1987   * produce a JSScript which has no associated bytecode. Testing with
   1988   * |code()| filters out this kind of scripts.
   1989   *
   1990   * If this script has a function associated to it, then it is not the
   1991   * top-level of a file.
   1992   */
   1993  bool isTopLevel() { return code() && !isFunction(); }
   1994 
   1995  /* Ensure the script has a JitScript. */
   1996  inline bool ensureHasJitScript(JSContext* cx, js::jit::AutoKeepJitScripts&);
   1997 
   1998  void maybeReleaseJitScript(JS::GCContext* gcx);
   1999  void releaseJitScript(JS::GCContext* gcx);
   2000  void releaseJitScriptOnFinalize(JS::GCContext* gcx);
   2001 
   2002  inline js::jit::BaselineScript* baselineScript() const;
   2003  inline js::jit::IonScript* ionScript() const;
   2004 
   2005  inline bool isIonCompilingOffThread() const;
   2006  inline bool canIonCompile() const;
   2007  inline void disableIon();
   2008 
   2009  inline bool isBaselineCompilingOffThread() const;
   2010  inline bool canBaselineCompile() const;
   2011  inline void disableBaselineCompile();
   2012 
   2013  inline js::GlobalObject& global() const;
   2014  inline bool hasGlobal(const js::GlobalObject* global) const;
   2015  js::GlobalObject& uninlinedGlobal() const;
   2016 
   2017  js::GCThingIndex bodyScopeIndex() const {
   2018    return immutableScriptData()->bodyScopeIndex;
   2019  }
   2020 
   2021  js::Scope* bodyScope() const { return getScope(bodyScopeIndex()); }
   2022 
   2023  js::Scope* outermostScope() const {
   2024    // The body scope may not be the outermost scope in the script when
   2025    // the decl env scope is present.
   2026    return getScope(js::GCThingIndex::outermostScopeIndex());
   2027  }
   2028 
   2029  bool functionHasExtraBodyVarScope() const {
   2030    bool res = BaseScript::functionHasExtraBodyVarScope();
   2031    MOZ_ASSERT_IF(res, functionHasParameterExprs());
   2032    return res;
   2033  }
   2034 
   2035  js::VarScope* functionExtraBodyVarScope() const;
   2036 
   2037  bool needsBodyEnvironment() const;
   2038 
   2039  inline js::LexicalScope* maybeNamedLambdaScope() const;
   2040 
   2041  // Drop script data and reset warmUpData to reference enclosing scope.
   2042  void relazify(JSRuntime* rt);
   2043 
   2044 private:
   2045  bool createJitScript(JSContext* cx);
   2046 
   2047  bool shareScriptData(JSContext* cx);
   2048 
   2049 public:
   2050  inline uint32_t getWarmUpCount() const;
   2051  inline void incWarmUpCounter();
   2052  inline void resetWarmUpCounterForGC();
   2053 
   2054  inline void updateLastICStubCounter();
   2055  inline uint32_t warmUpCountAtLastICStub() const;
   2056 
   2057  void resetWarmUpCounterToDelayIonCompilation();
   2058 
   2059  unsigned getWarmUpResetCount() const {
   2060    constexpr uint32_t MASK = uint32_t(MutableFlags::WarmupResets_MASK);
   2061    return mutableFlags_ & MASK;
   2062  }
   2063  void incWarmUpResetCounter() {
   2064    constexpr uint32_t MASK = uint32_t(MutableFlags::WarmupResets_MASK);
   2065    uint32_t newCount = getWarmUpResetCount() + 1;
   2066    if (newCount <= MASK) {
   2067      mutableFlags_ &= ~MASK;
   2068      mutableFlags_ |= newCount;
   2069    }
   2070  }
   2071  void resetWarmUpResetCounter() {
   2072    constexpr uint32_t MASK = uint32_t(MutableFlags::WarmupResets_MASK);
   2073    mutableFlags_ &= ~MASK;
   2074  }
   2075 
   2076 public:
   2077  bool initScriptCounts(JSContext* cx);
   2078  js::ScriptCounts& getScriptCounts();
   2079  js::PCCounts* maybeGetPCCounts(jsbytecode* pc);
   2080  const js::PCCounts* maybeGetThrowCounts(jsbytecode* pc);
   2081  js::PCCounts* getThrowCounts(jsbytecode* pc);
   2082  uint64_t getHitCount(jsbytecode* pc);
   2083  void addIonCounts(js::jit::IonScriptCounts* ionCounts);
   2084  js::jit::IonScriptCounts* getIonCounts();
   2085  void releaseScriptCounts(js::ScriptCounts* counts);
   2086  void destroyScriptCounts();
   2087  void resetScriptCounts();
   2088 
   2089  jsbytecode* main() const { return code() + mainOffset(); }
   2090 
   2091  js::BytecodeLocation mainLocation() const {
   2092    return js::BytecodeLocation(this, main());
   2093  }
   2094 
   2095  js::BytecodeLocation endLocation() const {
   2096    return js::BytecodeLocation(this, codeEnd());
   2097  }
   2098 
   2099  js::BytecodeLocation offsetToLocation(uint32_t offset) const {
   2100    return js::BytecodeLocation(this, offsetToPC(offset));
   2101  }
   2102 
   2103  void addSizeOfJitScript(mozilla::MallocSizeOf mallocSizeOf,
   2104                          size_t* sizeOfJitScript,
   2105                          size_t* sizeOfAllocSites) const;
   2106 
   2107  mozilla::Span<const js::TryNote> trynotes() const {
   2108    return immutableScriptData()->tryNotes();
   2109  }
   2110 
   2111  mozilla::Span<const js::ScopeNote> scopeNotes() const {
   2112    return immutableScriptData()->scopeNotes();
   2113  }
   2114 
   2115  mozilla::Span<const uint32_t> resumeOffsets() const {
   2116    return immutableScriptData()->resumeOffsets();
   2117  }
   2118 
   2119  uint32_t tableSwitchCaseOffset(jsbytecode* pc, uint32_t caseIndex) const {
   2120    MOZ_ASSERT(containsPC(pc));
   2121    MOZ_ASSERT(JSOp(*pc) == JSOp::TableSwitch);
   2122    uint32_t firstResumeIndex = GET_RESUMEINDEX(pc + 3 * JUMP_OFFSET_LEN);
   2123    return resumeOffsets()[firstResumeIndex + caseIndex];
   2124  }
   2125  jsbytecode* tableSwitchCasePC(jsbytecode* pc, uint32_t caseIndex) const {
   2126    return offsetToPC(tableSwitchCaseOffset(pc, caseIndex));
   2127  }
   2128 
   2129  bool hasLoops();
   2130 
   2131  uint32_t numNotes() const {
   2132    MOZ_ASSERT(sharedData_);
   2133    return immutableScriptData()->noteLength();
   2134  }
   2135  js::SrcNote* notes() const {
   2136    MOZ_ASSERT(sharedData_);
   2137    return immutableScriptData()->notes();
   2138  }
   2139  js::SrcNote* notesEnd() const {
   2140    MOZ_ASSERT(sharedData_);
   2141    return immutableScriptData()->notes() + numNotes();
   2142  }
   2143 
   2144  JSString* getString(js::GCThingIndex index) const {
   2145    return &gcthings()[index].as<JSString>();
   2146  }
   2147 
   2148  JSString* getString(jsbytecode* pc) const {
   2149    MOZ_ASSERT(containsPC<js::GCThingIndex>(pc));
   2150    MOZ_ASSERT(js::JOF_OPTYPE((JSOp)*pc) == JOF_STRING);
   2151    return getString(GET_GCTHING_INDEX(pc));
   2152  }
   2153 
   2154  bool atomizeString(JSContext* cx, jsbytecode* pc) {
   2155    MOZ_ASSERT(containsPC<js::GCThingIndex>(pc));
   2156    MOZ_ASSERT(js::JOF_OPTYPE((JSOp)*pc) == JOF_STRING);
   2157    js::GCThingIndex index = GET_GCTHING_INDEX(pc);
   2158    JSString* str = getString(index);
   2159    if (str->isAtom()) {
   2160      return true;
   2161    }
   2162    JSAtom* atom = js::AtomizeString(cx, str);
   2163    if (!atom) {
   2164      return false;
   2165    }
   2166    js::gc::CellPtrPreWriteBarrier(data_->gcthings()[index]);
   2167    data_->gcthings()[index] = JS::GCCellPtr(atom);
   2168    return true;
   2169  }
   2170 
   2171  JSAtom* getAtom(js::GCThingIndex index) const {
   2172    return &gcthings()[index].as<JSString>().asAtom();
   2173  }
   2174 
   2175  JSAtom* getAtom(jsbytecode* pc) const {
   2176    MOZ_ASSERT(containsPC<js::GCThingIndex>(pc));
   2177    MOZ_ASSERT(js::JOF_OPTYPE((JSOp)*pc) == JOF_ATOM);
   2178    return getAtom(GET_GCTHING_INDEX(pc));
   2179  }
   2180 
   2181  js::PropertyName* getName(js::GCThingIndex index) {
   2182    return getAtom(index)->asPropertyName();
   2183  }
   2184 
   2185  js::PropertyName* getName(jsbytecode* pc) const {
   2186    return getAtom(pc)->asPropertyName();
   2187  }
   2188 
   2189  JSObject* getObject(js::GCThingIndex index) const {
   2190    MOZ_ASSERT(gcthings()[index].asCell()->isTenured());
   2191    return &gcthings()[index].as<JSObject>();
   2192  }
   2193 
   2194  JSObject* getObject(const jsbytecode* pc) const {
   2195    MOZ_ASSERT(containsPC<js::GCThingIndex>(pc));
   2196    return getObject(GET_GCTHING_INDEX(pc));
   2197  }
   2198 
   2199  js::SharedShape* getShape(js::GCThingIndex index) const {
   2200    return &gcthings()[index].as<js::Shape>().asShared();
   2201  }
   2202 
   2203  js::SharedShape* getShape(const jsbytecode* pc) const {
   2204    MOZ_ASSERT(containsPC<js::GCThingIndex>(pc));
   2205    return getShape(GET_GCTHING_INDEX(pc));
   2206  }
   2207 
   2208  js::Scope* getScope(js::GCThingIndex index) const {
   2209    return &gcthings()[index].as<js::Scope>();
   2210  }
   2211 
   2212  js::Scope* getScope(jsbytecode* pc) const {
   2213    // This method is used to get a scope directly using a JSOp with an
   2214    // index. To search through ScopeNotes to look for a Scope using pc,
   2215    // use lookupScope.
   2216    MOZ_ASSERT(containsPC<js::GCThingIndex>(pc));
   2217    MOZ_ASSERT(js::JOF_OPTYPE(JSOp(*pc)) == JOF_SCOPE,
   2218               "Did you mean to use lookupScope(pc)?");
   2219    return getScope(GET_GCTHING_INDEX(pc));
   2220  }
   2221 
   2222  inline JSFunction* getFunction(js::GCThingIndex index) const;
   2223  inline JSFunction* getFunction(jsbytecode* pc) const;
   2224 
   2225  inline js::RegExpObject* getRegExp(js::GCThingIndex index) const;
   2226  inline js::RegExpObject* getRegExp(jsbytecode* pc) const;
   2227 
   2228  js::BigInt* getBigInt(js::GCThingIndex index) const {
   2229    MOZ_ASSERT(gcthings()[index].asCell()->isTenured());
   2230    return &gcthings()[index].as<js::BigInt>();
   2231  }
   2232 
   2233  js::BigInt* getBigInt(jsbytecode* pc) const {
   2234    MOZ_ASSERT(containsPC<js::GCThingIndex>(pc));
   2235    MOZ_ASSERT(js::JOF_OPTYPE(JSOp(*pc)) == JOF_BIGINT);
   2236    return getBigInt(GET_GCTHING_INDEX(pc));
   2237  }
   2238 
   2239  // The following 3 functions find the static scope just before the
   2240  // execution of the instruction pointed to by pc.
   2241 
   2242  js::Scope* lookupScope(const jsbytecode* pc) const;
   2243 
   2244  js::Scope* innermostScope(const jsbytecode* pc) const;
   2245  js::Scope* innermostScope() const { return innermostScope(main()); }
   2246 
   2247  /*
   2248   * The isEmpty method tells whether this script has code that computes any
   2249   * result (not return value, result AKA normal completion value) other than
   2250   * JSVAL_VOID, or any other effects.
   2251   */
   2252  bool isEmpty() const {
   2253    if (length() > 3) {
   2254      return false;
   2255    }
   2256 
   2257    jsbytecode* pc = code();
   2258    if (noScriptRval() && JSOp(*pc) == JSOp::False) {
   2259      ++pc;
   2260    }
   2261    return JSOp(*pc) == JSOp::RetRval;
   2262  }
   2263 
   2264  bool formalIsAliased(unsigned argSlot);
   2265  bool anyFormalIsForwarded();
   2266  bool formalLivesInArgumentsObject(unsigned argSlot);
   2267 
   2268  // See comment above 'debugMode' in Realm.h for explanation of
   2269  // invariants of debuggee compartments, scripts, and frames.
   2270  inline bool isDebuggee() const;
   2271 
   2272  // A helper class to prevent relazification of the given function's script
   2273  // while it's holding on to it.  This class automatically roots the script.
   2274  class AutoDelazify;
   2275  friend class AutoDelazify;
   2276 
   2277  class AutoDelazify {
   2278    JS::RootedScript script_;
   2279    JSContext* cx_;
   2280    bool oldAllowRelazify_ = false;
   2281 
   2282   public:
   2283    explicit AutoDelazify(JSContext* cx, JS::HandleFunction fun = nullptr)
   2284        : script_(cx), cx_(cx) {
   2285      holdScript(fun);
   2286    }
   2287 
   2288    ~AutoDelazify() { dropScript(); }
   2289 
   2290    void operator=(JS::HandleFunction fun) {
   2291      dropScript();
   2292      holdScript(fun);
   2293    }
   2294 
   2295    operator JS::HandleScript() const { return script_; }
   2296    explicit operator bool() const { return script_; }
   2297 
   2298   private:
   2299    void holdScript(JS::HandleFunction fun);
   2300    void dropScript();
   2301  };
   2302 
   2303 #if defined(DEBUG) || defined(JS_JITSPEW)
   2304 public:
   2305  struct DumpOptions {
   2306    bool recursive = false;
   2307    bool runtimeData = false;
   2308  };
   2309 
   2310  void dump(JSContext* cx);
   2311  void dumpRecursive(JSContext* cx);
   2312 
   2313  static bool dump(JSContext* cx, JS::Handle<JSScript*> script,
   2314                   DumpOptions& options, js::StringPrinter* sp);
   2315  static bool dumpSrcNotes(JSContext* cx, JS::Handle<JSScript*> script,
   2316                           js::GenericPrinter* sp);
   2317  static bool dumpTryNotes(JSContext* cx, JS::Handle<JSScript*> script,
   2318                           js::GenericPrinter* sp);
   2319  static bool dumpScopeNotes(JSContext* cx, JS::Handle<JSScript*> script,
   2320                             js::GenericPrinter* sp);
   2321  static bool dumpGCThings(JSContext* cx, JS::Handle<JSScript*> script,
   2322                           js::GenericPrinter* sp);
   2323 #endif
   2324 };
   2325 
   2326 namespace js {
   2327 
   2328 struct ScriptAndCounts {
   2329  /* This structure is stored and marked from the JSRuntime. */
   2330  JSScript* script;
   2331  ScriptCounts scriptCounts;
   2332 
   2333  inline explicit ScriptAndCounts(JSScript* script);
   2334  inline ScriptAndCounts(ScriptAndCounts&& sac);
   2335 
   2336  const PCCounts* maybeGetPCCounts(jsbytecode* pc) const {
   2337    return scriptCounts.maybeGetPCCounts(script->pcToOffset(pc));
   2338  }
   2339  const PCCounts* maybeGetThrowCounts(jsbytecode* pc) const {
   2340    return scriptCounts.maybeGetThrowCounts(script->pcToOffset(pc));
   2341  }
   2342 
   2343  jit::IonScriptCounts* getIonCounts() const { return scriptCounts.ionCounts_; }
   2344 
   2345  void trace(JSTracer* trc) {
   2346    TraceRoot(trc, &script, "ScriptAndCounts::script");
   2347  }
   2348 };
   2349 
   2350 extern JS::UniqueChars FormatIntroducedFilename(const char* filename,
   2351                                                uint32_t lineno,
   2352                                                const char* introducer);
   2353 
   2354 extern jsbytecode* LineNumberToPC(JSScript* script, unsigned lineno);
   2355 
   2356 extern JS_PUBLIC_API unsigned GetScriptLineExtent(
   2357    JSScript* script, JS::LimitedColumnNumberOneOrigin* columnp = nullptr);
   2358 
   2359 #ifdef JS_CACHEIR_SPEW
   2360 void maybeUpdateWarmUpCount(JSScript* script);
   2361 void maybeSpewScriptFinalWarmUpCount(JSScript* script);
   2362 #endif
   2363 
   2364 } /* namespace js */
   2365 
   2366 namespace js {
   2367 
   2368 extern unsigned PCToLineNumber(
   2369    JSScript* script, jsbytecode* pc,
   2370    JS::LimitedColumnNumberOneOrigin* columnp = nullptr);
   2371 
   2372 extern unsigned PCToLineNumber(
   2373    unsigned startLine, JS::LimitedColumnNumberOneOrigin startCol,
   2374    SrcNote* notes, SrcNote* notesEnd, jsbytecode* code, jsbytecode* pc,
   2375    JS::LimitedColumnNumberOneOrigin* columnp = nullptr);
   2376 
   2377 /*
   2378 * This function returns the file and line number of the script currently
   2379 * executing on cx. If there is no current script executing on cx (e.g., a
   2380 * native called directly through JSAPI (e.g., by setTimeout)), nullptr and 0
   2381 * are returned as the file and line.
   2382 */
   2383 extern void DescribeScriptedCallerForCompilation(
   2384    JSContext* cx, MutableHandleScript maybeScript, const char** file,
   2385    uint32_t* linenop, uint32_t* pcOffset, bool* mutedErrors);
   2386 
   2387 /*
   2388 * Like DescribeScriptedCallerForCompilation, but this function avoids looking
   2389 * up the script/pc and the full linear scan to compute line number.
   2390 */
   2391 extern void DescribeScriptedCallerForDirectEval(
   2392    JSContext* cx, HandleScript script, jsbytecode* pc, const char** file,
   2393    uint32_t* linenop, uint32_t* pcOffset, bool* mutedErrors);
   2394 
   2395 bool CheckCompileOptionsMatch(const JS::ReadOnlyCompileOptions& options,
   2396                              js::ImmutableScriptFlags flags);
   2397 
   2398 void FillImmutableFlagsFromCompileOptionsForTopLevel(
   2399    const JS::ReadOnlyCompileOptions& options, js::ImmutableScriptFlags& flags);
   2400 
   2401 void FillImmutableFlagsFromCompileOptionsForFunction(
   2402    const JS::ReadOnlyCompileOptions& options, js::ImmutableScriptFlags& flags);
   2403 
   2404 } /* namespace js */
   2405 
   2406 namespace JS {
   2407 
   2408 template <>
   2409 struct GCPolicy<js::ScriptLCovEntry>
   2410    : public IgnoreGCPolicy<js::ScriptLCovEntry> {};
   2411 
   2412 #ifdef JS_CACHEIR_SPEW
   2413 template <>
   2414 struct GCPolicy<js::ScriptFinalWarmUpCountEntry>
   2415    : public IgnoreGCPolicy<js::ScriptFinalWarmUpCountEntry> {};
   2416 #endif
   2417 
   2418 namespace ubi {
   2419 
   2420 template <>
   2421 class Concrete<JSScript> : public Concrete<js::BaseScript> {};
   2422 
   2423 }  // namespace ubi
   2424 }  // namespace JS
   2425 
   2426 #endif /* vm_JSScript_h */