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