tor-browser

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

JitScript.h (21957B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef jit_JitScript_h
      8 #define jit_JitScript_h
      9 
     10 #include "mozilla/Assertions.h"
     11 #include "mozilla/Atomics.h"
     12 #include "mozilla/Attributes.h"
     13 #include "mozilla/HashFunctions.h"
     14 #include "mozilla/LinkedList.h"
     15 #include "mozilla/Maybe.h"
     16 #include "mozilla/MemoryReporting.h"
     17 
     18 #include <stddef.h>
     19 #include <stdint.h>
     20 
     21 #include "jstypes.h"
     22 #include "NamespaceImports.h"
     23 
     24 #include "ds/LifoAlloc.h"
     25 #include "gc/Barrier.h"
     26 #include "jit/BaselineIC.h"
     27 #include "js/TypeDecls.h"
     28 #include "js/UniquePtr.h"
     29 #include "js/Vector.h"
     30 #include "util/TrailingArray.h"
     31 #include "vm/EnvironmentObject.h"
     32 
     33 class JS_PUBLIC_API JSScript;
     34 class JS_PUBLIC_API JSTracer;
     35 struct JS_PUBLIC_API JSContext;
     36 
     37 namespace JS {
     38 class Zone;
     39 }
     40 
     41 namespace js {
     42 
     43 class SystemAllocPolicy;
     44 
     45 namespace gc {
     46 class AllocSite;
     47 }
     48 
     49 namespace jit {
     50 
     51 class BaselineScript;
     52 class ICStubSpace;
     53 class InliningRoot;
     54 class IonScript;
     55 class JitScript;
     56 class JitZone;
     57 
     58 // Magic values indicating compilation has been disabled or the script
     59 // is already scheduled for background compilation.
     60 static constexpr uintptr_t DisabledScript = 0x1;
     61 static constexpr uintptr_t QueuedScript = 0x3;
     62 static constexpr uintptr_t CompilingScript = 0x5;
     63 
     64 static constexpr uint32_t SpecialScriptBit = 0x1;
     65 static_assert((DisabledScript & SpecialScriptBit) != 0);
     66 static_assert((QueuedScript & SpecialScriptBit) != 0);
     67 static_assert((CompilingScript & SpecialScriptBit) != 0);
     68 
     69 static BaselineScript* const BaselineDisabledScriptPtr =
     70    reinterpret_cast<BaselineScript*>(DisabledScript);
     71 static BaselineScript* const BaselineQueuedScriptPtr =
     72    reinterpret_cast<BaselineScript*>(QueuedScript);
     73 static BaselineScript* const BaselineCompilingScriptPtr =
     74    reinterpret_cast<BaselineScript*>(CompilingScript);
     75 
     76 static IonScript* const IonDisabledScriptPtr =
     77    reinterpret_cast<IonScript*>(DisabledScript);
     78 static IonScript* const IonCompilingScriptPtr =
     79    reinterpret_cast<IonScript*>(CompilingScript);
     80 
     81 /* [SMDOC] ICScript Lifetimes
     82 *
     83 * An ICScript owns an array of ICEntries, each of which owns a linked
     84 * list of ICStubs.
     85 *
     86 * A JitScript contains an embedded ICScript. If it has done any trial
     87 * inlining, it also owns an InliningRoot. The InliningRoot owns all
     88 * of the ICScripts that have been created for inlining into the
     89 * corresponding JitScript. This ties the lifetime of the inlined
     90 * ICScripts to the lifetime of the JitScript itself.
     91 *
     92 * We store pointers to ICScripts in two other places: on the stack in
     93 * BaselineFrame, and in IC stubs for CallInlinedFunction.
     94 *
     95 * The ICScript pointer in a BaselineFrame either points to the
     96 * ICScript embedded in the JitScript for that frame, or to an inlined
     97 * ICScript owned by a caller. In each case, there must be a frame on
     98 * the stack corresponding to the JitScript that owns the current
     99 * ICScript, which will keep the ICScript alive.
    100 *
    101 * Each ICStub is owned by an ICScript and, indirectly, a
    102 * JitScript. An ICStub that uses CallInlinedFunction contains an
    103 * ICScript for use by the callee. The ICStub and the callee ICScript
    104 * are always owned by the same JitScript, so the callee ICScript will
    105 * not be freed while the ICStub is alive.
    106 *
    107 * The lifetime of an ICScript is independent of the lifetimes of the
    108 * BaselineScript and IonScript/WarpScript to which it
    109 * corresponds. They can be destroyed and recreated, and the ICScript
    110 * will remain valid.
    111 *
    112 * When we discard JIT code, we mark ICScripts that are active on the stack as
    113 * active and then purge all of the inactive ICScripts. We also purge ICStubs,
    114 * including the CallInlinedFunction stub at the trial inining call site, and
    115 * reset the ICStates to allow trial inlining again later.
    116 *
    117 * If there's a BaselineFrame for an inlined ICScript, we'll preserve both this
    118 * ICScript and the IC chain for the call site in the caller's ICScript.
    119 * See ICScript::purgeStubs and ICScript::purgeInactiveICScripts.
    120 */
    121 
    122 class alignas(uintptr_t) ICScript final : public TrailingArray<ICScript> {
    123 public:
    124  ICScript(uint32_t warmUpCount, Offset fallbackStubsOffset, Offset endOffset,
    125           uint32_t depth, uint32_t bytecodeSize,
    126           InliningRoot* inliningRoot = nullptr)
    127      : inliningRoot_(inliningRoot),
    128        warmUpCount_(warmUpCount),
    129        fallbackStubsOffset_(fallbackStubsOffset),
    130        endOffset_(endOffset),
    131        depth_(depth),
    132        bytecodeSize_(bytecodeSize) {}
    133 
    134  ~ICScript();
    135 
    136  bool isInlined() const { return depth_ > 0; }
    137 
    138  void initICEntries(JSContext* cx, JSScript* script);
    139 
    140  ICEntry& icEntry(size_t index) {
    141    MOZ_ASSERT(index < numICEntries());
    142    return icEntries()[index];
    143  }
    144 
    145  ICFallbackStub* fallbackStub(size_t index) {
    146    MOZ_ASSERT(index < numICEntries());
    147    return fallbackStubs() + index;
    148  }
    149 
    150  ICEntry* icEntryForStub(const ICFallbackStub* stub) {
    151    size_t index = stub - fallbackStubs();
    152    MOZ_ASSERT(index < numICEntries());
    153    return &icEntry(index);
    154  }
    155  ICFallbackStub* fallbackStubForICEntry(const ICEntry* entry) {
    156    size_t index = entry - icEntries();
    157    MOZ_ASSERT(index < numICEntries());
    158    return fallbackStub(index);
    159  }
    160 
    161  InliningRoot* inliningRoot() const { return inliningRoot_; }
    162  uint32_t depth() const { return depth_; }
    163 
    164  uint32_t bytecodeSize() const { return bytecodeSize_; }
    165 
    166  void resetWarmUpCount(uint32_t count) { warmUpCount_ = count; }
    167 
    168  static constexpr size_t offsetOfFirstStub(uint32_t entryIndex) {
    169    return sizeof(ICScript) + entryIndex * sizeof(ICEntry) +
    170           ICEntry::offsetOfFirstStub();
    171  }
    172 
    173  static constexpr Offset offsetOfWarmUpCount() {
    174    return offsetof(ICScript, warmUpCount_);
    175  }
    176  static constexpr Offset offsetOfDepth() { return offsetof(ICScript, depth_); }
    177 
    178  static constexpr Offset offsetOfICEntries() { return sizeof(ICScript); }
    179  uint32_t numICEntries() const {
    180    return numElements<ICEntry>(icEntriesOffset(), fallbackStubsOffset());
    181  }
    182 
    183  static constexpr Offset offsetOfEnvAllocSite() {
    184    return offsetof(ICScript, envAllocSite_);
    185  }
    186 
    187  ICEntry* interpreterICEntryFromPCOffset(uint32_t pcOffset);
    188 
    189  ICEntry& icEntryFromPCOffset(uint32_t pcOffset);
    190 
    191  [[nodiscard]] bool addInlinedChild(JSContext* cx,
    192                                     js::UniquePtr<ICScript> child,
    193                                     uint32_t pcOffset);
    194  ICScript* findInlinedChild(uint32_t pcOffset);
    195  void removeInlinedChild(uint32_t pcOffset);
    196  bool hasInlinedChild(uint32_t pcOffset);
    197 
    198  void purgeStubs(Zone* zone, ICStubSpace& newStubSpace);
    199 
    200  void purgeInactiveICScripts();
    201 
    202  bool active() const { return active_; }
    203  void setActive() { active_ = true; }
    204  void resetActive() { active_ = false; }
    205 
    206  gc::AllocSite* getOrCreateAllocSite(JSScript* outerScript, uint32_t pcOffset);
    207 
    208  void ensureEnvAllocSite(JSScript* outerScript);
    209  gc::AllocSite* maybeEnvAllocSite() const { return envAllocSite_; }
    210 
    211  void prepareForDestruction(Zone* zone);
    212 
    213  void trace(JSTracer* trc);
    214  bool traceWeak(JSTracer* trc);
    215 
    216 #ifdef DEBUG
    217  mozilla::HashNumber hash(JSContext* cx);
    218 #endif
    219 
    220 private:
    221  class CallSite {
    222   public:
    223    CallSite(ICScript* callee, uint32_t pcOffset)
    224        : callee_(callee), pcOffset_(pcOffset) {}
    225    ICScript* callee_;
    226    uint32_t pcOffset_;
    227  };
    228 
    229  // If this ICScript was created for trial inlining or has another
    230  // ICScript inlined into it, a pointer to the root of the inlining
    231  // tree. Otherwise, nullptr.
    232  InliningRoot* inliningRoot_ = nullptr;
    233 
    234  // ICScripts that have been inlined into this ICScript.
    235  js::UniquePtr<Vector<CallSite>> inlinedChildren_;
    236 
    237  // List of allocation sites referred to by ICs in this script.
    238  static constexpr size_t AllocSiteChunkSize = 256;
    239  LifoAlloc allocSitesSpace_{AllocSiteChunkSize, js::BackgroundMallocArena};
    240  Vector<gc::AllocSite*, 0, SystemAllocPolicy> allocSites_;
    241 
    242  // Optional alloc site to use when allocating environment chain objects.
    243  gc::AllocSite* envAllocSite_ = nullptr;
    244 
    245  // Number of times this copy of the script has been called or has had
    246  // backedges taken.  Reset if the script's JIT code is forcibly discarded.
    247  // See also the ScriptWarmUpData class.
    248  mozilla::Atomic<uint32_t, mozilla::Relaxed> warmUpCount_ = {};
    249 
    250  // The offset of the ICFallbackStub array.
    251  Offset fallbackStubsOffset_;
    252 
    253  // The size of this allocation.
    254  Offset endOffset_;
    255 
    256  // The inlining depth of this ICScript. 0 for the inlining root.
    257  uint32_t depth_;
    258 
    259  // Bytecode size of the JSScript corresponding to this ICScript.
    260  uint32_t bytecodeSize_;
    261 
    262  // Flag set when discarding JIT code to indicate this script is on the stack
    263  // and should not be discarded.
    264  bool active_ = false;
    265 
    266  Offset icEntriesOffset() const { return offsetOfICEntries(); }
    267  Offset fallbackStubsOffset() const { return fallbackStubsOffset_; }
    268  Offset endOffset() const { return endOffset_; }
    269 
    270 public:
    271  ICEntry* icEntries() { return offsetToPointer<ICEntry>(icEntriesOffset()); }
    272 
    273 private:
    274  ICFallbackStub* fallbackStubs() {
    275    return offsetToPointer<ICFallbackStub>(fallbackStubsOffset());
    276  }
    277 
    278  JitScript* outerJitScript();
    279 
    280  friend class JitScript;
    281 };
    282 
    283 // [SMDOC] JitScript
    284 //
    285 // JitScript stores type inference data, Baseline ICs and other JIT-related data
    286 // for a script. Scripts with a JitScript can run in the Baseline Interpreter.
    287 //
    288 // IC Data
    289 // =======
    290 // All IC data for Baseline (Interpreter and JIT) is stored in an ICScript. Each
    291 // JitScript contains an ICScript as the last field. Additional free-standing
    292 // ICScripts may be created during trial inlining. Ion has its own IC chains
    293 // stored in IonScript.
    294 //
    295 // For each IC we store an ICEntry, which points to the first ICStub in the
    296 // chain, and an ICFallbackStub. Note that multiple stubs in the same zone can
    297 // share Baseline IC code. This works because the stub data is stored in the
    298 // ICStub instead of baked in in the stub code.
    299 //
    300 // Storing this separate from BaselineScript allows us to use the same ICs in
    301 // the Baseline Interpreter and Baseline JIT. It also simplifies debug mode OSR
    302 // because the JitScript can be reused when we have to recompile the
    303 // BaselineScript.
    304 //
    305 // An ICScript contains a list of IC entries and a list of fallback stubs.
    306 // There's one ICEntry and ICFallbackStub for each JOF_IC bytecode op.
    307 //
    308 // The ICScript also contains the warmUpCount for the script.
    309 //
    310 // Inlining Data
    311 // =============
    312 // JitScript also contains a list of Warp compilations inlining this script, for
    313 // invalidation.
    314 //
    315 // Memory Layout
    316 // =============
    317 // JitScript contains an ICScript as the last field. ICScript has trailing
    318 // (variable length) arrays for ICEntry and ICFallbackStub. The memory layout is
    319 // as follows:
    320 //
    321 //  Item                    | Offset
    322 //  ------------------------+------------------------
    323 //  JitScript               | 0
    324 //  -->ICScript  (field)    |
    325 //     ICEntry[]            | icEntriesOffset()
    326 //     ICFallbackStub[]     | fallbackStubsOffset()
    327 //
    328 // These offsets are also used to compute numICEntries.
    329 class alignas(uintptr_t) JitScript final
    330    : public mozilla::LinkedListElement<JitScript>,
    331      public TrailingArray<JitScript> {
    332  friend class ::JSScript;
    333 
    334  // Profile string used by the profiler for Baseline Interpreter frames.
    335  const char* profileString_ = nullptr;
    336 
    337  HeapPtr<JSScript*> owningScript_;
    338 
    339  // Baseline code for the script. Either nullptr, BaselineDisabledScriptPtr,
    340  // BaselineQueuedScriptPtr, BaselineCompilingScriptPtr,
    341  // or a valid BaselineScript*.
    342  GCStructPtr<BaselineScript*> baselineScript_;
    343 
    344  // Ion code for this script. Either nullptr, IonDisabledScriptPtr,
    345  // IonCompilingScriptPtr or a valid IonScript*.
    346  GCStructPtr<IonScript*> ionScript_;
    347 
    348  // For functions that need a CallObject and/or NamedLambdaObject, the template
    349  // objects used by the Baseline JIT and Ion. If the function needs both a
    350  // named lambda object and a call object, the named lambda object template is
    351  // linked via the call object's enclosing environment. This field is set the
    352  // first time the Baseline JIT compiles this script.
    353  mozilla::Maybe<HeapPtr<EnvironmentObject*>> templateEnv_;
    354 
    355  // The size of this allocation.
    356  Offset endOffset_ = 0;
    357 
    358  // Analysis data computed lazily the first time this script is compiled or
    359  // inlined by WarpBuilder.
    360  mozilla::Maybe<bool> usesEnvironmentChain_;
    361 
    362  struct Flags {
    363    // True if this script entered Ion via OSR at a loop header.
    364    bool hadIonOSR : 1;
    365    bool ranBytecodeAnalysis : 1;
    366  };
    367  Flags flags_ = {};  // Zero-initialize flags.
    368 
    369  js::UniquePtr<InliningRoot> inliningRoot_;
    370 
    371 #ifdef DEBUG
    372  // If the last warp compilation invalidated because of TranspiledCacheIR
    373  // bailouts, this is a hash of the ICScripts used in that compilation.
    374  // When recompiling, we assert that the hash has changed.
    375  mozilla::Maybe<mozilla::HashNumber> failedICHash_;
    376 
    377  // To avoid pathological cases, we skip the check if we have purged
    378  // stubs due to GC pressure.
    379  bool hasPurgedStubs_ = false;
    380 #endif
    381 
    382  // Value of the warmup counter when the last IC stub was attached,
    383  // used for Ion hints.
    384  uint32_t warmUpCountAtLastICStub_ = 0;
    385 
    386  ICScript icScript_;
    387  // End of fields.
    388 
    389  Offset endOffset() const { return endOffset_; }
    390 
    391 public:
    392  JitScript(JSScript* script, Offset fallbackStubsOffset, Offset endOffset,
    393            const char* profileString);
    394 
    395  ~JitScript();
    396 
    397  JSScript* owningScript() const { return owningScript_; }
    398 
    399  [[nodiscard]] bool ensureHasCachedBaselineJitData(JSContext* cx,
    400                                                    HandleScript script);
    401  [[nodiscard]] bool ensureHasCachedIonData(JSContext* cx, HandleScript script);
    402 
    403  void setHadIonOSR() { flags_.hadIonOSR = true; }
    404  bool hadIonOSR() const { return flags_.hadIonOSR; }
    405 
    406  void setRanBytecodeAnalysis() { flags_.ranBytecodeAnalysis = true; }
    407  bool ranBytecodeAnalysis() const { return flags_.ranBytecodeAnalysis; }
    408 
    409  uint32_t numICEntries() const { return icScript_.numICEntries(); }
    410 
    411 #ifdef DEBUG
    412  bool hasActiveICScript() const;
    413 #endif
    414  void resetAllActiveFlags();
    415 
    416  void ensureProfileString(JSContext* cx, JSScript* script);
    417  void ensureProfilerScriptSource(JSContext* cx, JSScript* script);
    418 
    419  const char* profileString() const {
    420    MOZ_ASSERT(profileString_);
    421    return profileString_;
    422  }
    423 
    424  static void Destroy(Zone* zone, JitScript* script);
    425 
    426  static constexpr Offset offsetOfICEntries() { return sizeof(JitScript); }
    427 
    428  static constexpr size_t offsetOfBaselineScript() {
    429    return offsetof(JitScript, baselineScript_);
    430  }
    431  static constexpr size_t offsetOfIonScript() {
    432    return offsetof(JitScript, ionScript_);
    433  }
    434  static constexpr size_t offsetOfICScript() {
    435    return offsetof(JitScript, icScript_);
    436  }
    437  static constexpr size_t offsetOfWarmUpCount() {
    438    return offsetOfICScript() + ICScript::offsetOfWarmUpCount();
    439  }
    440 
    441  uint32_t warmUpCount() const { return icScript_.warmUpCount_; }
    442  void incWarmUpCount() { icScript_.warmUpCount_++; }
    443  void resetWarmUpCount(uint32_t count);
    444 
    445  void prepareForDestruction(Zone* zone);
    446 
    447  void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t* data,
    448                              size_t* allocSites) const;
    449 
    450  ICEntry& icEntry(size_t index) { return icScript_.icEntry(index); }
    451 
    452  ICFallbackStub* fallbackStub(size_t index) {
    453    return icScript_.fallbackStub(index);
    454  }
    455 
    456  ICEntry* icEntryForStub(const ICFallbackStub* stub) {
    457    return icScript_.icEntryForStub(stub);
    458  }
    459  ICFallbackStub* fallbackStubForICEntry(const ICEntry* entry) {
    460    return icScript_.fallbackStubForICEntry(entry);
    461  }
    462 
    463  void trace(JSTracer* trc);
    464  void traceWeak(JSTracer* trc);
    465  void purgeStubs(JSScript* script, ICStubSpace& newStubSpace);
    466 
    467  void purgeInactiveICScripts();
    468 
    469  ICEntry& icEntryFromPCOffset(uint32_t pcOffset) {
    470    return icScript_.icEntryFromPCOffset(pcOffset);
    471  };
    472 
    473  size_t allocBytes() const { return endOffset(); }
    474 
    475  EnvironmentObject* templateEnvironment() const { return templateEnv_.ref(); }
    476 
    477  std::pair<CallObject*, NamedLambdaObject*> functionEnvironmentTemplates(
    478      JSFunction* fun) const;
    479 
    480  bool usesEnvironmentChain() const { return *usesEnvironmentChain_; }
    481 
    482  bool resetAllocSites(bool resetNurserySites, bool resetPretenuredSites);
    483  bool hasPretenuredAllocSites();
    484 
    485  void updateLastICStubCounter() { warmUpCountAtLastICStub_ = warmUpCount(); }
    486  uint32_t warmUpCountAtLastICStub() const { return warmUpCountAtLastICStub_; }
    487 
    488  bool hasEnvAllocSite() const { return icScript_.envAllocSite_; }
    489 
    490 private:
    491  // Methods to set baselineScript_ to a BaselineScript*, nullptr, or
    492  // BaselineDisabledScriptPtr.
    493  void setBaselineScriptImpl(JSScript* script, BaselineScript* baselineScript);
    494  void setBaselineScriptImpl(JS::GCContext* gcx, JSScript* script,
    495                             BaselineScript* baselineScript);
    496 
    497 public:
    498  // Methods for getting/setting/clearing a BaselineScript*.
    499  bool hasBaselineScript() const {
    500    bool res = baselineScript_ &&
    501               baselineScript_ != BaselineDisabledScriptPtr &&
    502               baselineScript_ != BaselineQueuedScriptPtr &&
    503               baselineScript_ != BaselineCompilingScriptPtr;
    504    MOZ_ASSERT_IF(!res, !hasIonScript());
    505    return res;
    506  }
    507  BaselineScript* baselineScript() const {
    508    MOZ_ASSERT(hasBaselineScript());
    509    return baselineScript_;
    510  }
    511  void setBaselineScript(JSScript* script, BaselineScript* baselineScript) {
    512    MOZ_ASSERT(!hasBaselineScript());
    513    setBaselineScriptImpl(script, baselineScript);
    514    MOZ_ASSERT(hasBaselineScript());
    515  }
    516  [[nodiscard]] BaselineScript* clearBaselineScript(JS::GCContext* gcx,
    517                                                    JSScript* script) {
    518    BaselineScript* baseline = baselineScript();
    519    setBaselineScriptImpl(gcx, script, nullptr);
    520    return baseline;
    521  }
    522  bool isBaselineQueued() const {
    523    return baselineScript_ == BaselineQueuedScriptPtr;
    524  }
    525  void clearIsBaselineQueued(JSScript* script) {
    526    MOZ_ASSERT(isBaselineQueued());
    527    setBaselineScriptImpl(script, nullptr);
    528  }
    529  bool isBaselineCompiling() const {
    530    return baselineScript_ == BaselineCompilingScriptPtr;
    531  }
    532  void setIsBaselineCompiling(JSScript* script) {
    533    MOZ_ASSERT(baselineScript_ == nullptr);
    534    setBaselineScriptImpl(script, BaselineCompilingScriptPtr);
    535  }
    536  void clearIsBaselineCompiling(JSScript* script) {
    537    MOZ_ASSERT(isBaselineCompiling());
    538    setBaselineScriptImpl(script, nullptr);
    539  }
    540 
    541 private:
    542  // Methods to set ionScript_ to an IonScript*, nullptr, or one of the special
    543  // Ion{Disabled,Compiling}ScriptPtr values.
    544  void setIonScriptImpl(JS::GCContext* gcx, JSScript* script,
    545                        IonScript* ionScript);
    546  void setIonScriptImpl(JSScript* script, IonScript* ionScript);
    547 
    548  // Helper that calls the passed function for the outer ICScript and for each
    549  // inlined ICScript.
    550  template <typename F>
    551  void forEachICScript(const F& f);
    552  template <typename F>
    553  void forEachICScript(const F& f) const;
    554 
    555 public:
    556  // Methods for getting/setting/clearing an IonScript*.
    557  bool hasIonScript() const {
    558    bool res = ionScript_ && ionScript_ != IonDisabledScriptPtr &&
    559               ionScript_ != IonCompilingScriptPtr;
    560    MOZ_ASSERT_IF(res, baselineScript_);
    561    return res;
    562  }
    563  IonScript* ionScript() const {
    564    MOZ_ASSERT(hasIonScript());
    565    return ionScript_;
    566  }
    567  void setIonScript(JSScript* script, IonScript* ionScript) {
    568    MOZ_ASSERT(!hasIonScript());
    569    setIonScriptImpl(script, ionScript);
    570    MOZ_ASSERT(hasIonScript());
    571  }
    572  [[nodiscard]] IonScript* clearIonScript(JS::GCContext* gcx,
    573                                          JSScript* script) {
    574    IonScript* ion = ionScript();
    575    setIonScriptImpl(gcx, script, nullptr);
    576    return ion;
    577  }
    578 
    579  // Methods for off-thread compilation.
    580  bool isIonCompilingOffThread() const {
    581    return ionScript_ == IonCompilingScriptPtr;
    582  }
    583  void setIsIonCompilingOffThread(JSScript* script) {
    584    MOZ_ASSERT(ionScript_ == nullptr);
    585    setIonScriptImpl(script, IonCompilingScriptPtr);
    586  }
    587  void clearIsIonCompilingOffThread(JSScript* script) {
    588    MOZ_ASSERT(isIonCompilingOffThread());
    589    setIonScriptImpl(script, nullptr);
    590  }
    591  ICScript* icScript() { return &icScript_; }
    592 
    593  bool hasInliningRoot() const { return !!inliningRoot_; }
    594  InliningRoot* inliningRoot() const { return inliningRoot_.get(); }
    595  InliningRoot* getOrCreateInliningRoot(JSContext* cx, JSScript* script);
    596 
    597  inline void notePurgedStubs() {
    598 #ifdef DEBUG
    599    failedICHash_.reset();
    600    hasPurgedStubs_ = true;
    601 #endif
    602  }
    603 
    604 #ifdef DEBUG
    605  bool hasPurgedStubs() const { return hasPurgedStubs_; }
    606  bool hasFailedICHash() const { return failedICHash_.isSome(); }
    607  mozilla::HashNumber getFailedICHash() { return failedICHash_.extract(); }
    608  void setFailedICHash(mozilla::HashNumber hash) {
    609    MOZ_ASSERT(failedICHash_.isNothing());
    610    if (!hasPurgedStubs_) {
    611      failedICHash_.emplace(hash);
    612    }
    613  }
    614 #endif
    615 
    616  inline void clearFailedICHash() {
    617 #ifdef DEBUG
    618    failedICHash_.reset();
    619 #endif
    620  }
    621 };
    622 
    623 // Ensures no JitScripts are purged in the current zone.
    624 class MOZ_RAII AutoKeepJitScripts {
    625  jit::JitZone* zone_;
    626  bool prev_;
    627 
    628  AutoKeepJitScripts(const AutoKeepJitScripts&) = delete;
    629  void operator=(const AutoKeepJitScripts&) = delete;
    630 
    631 public:
    632  explicit inline AutoKeepJitScripts(JSContext* cx);
    633  inline ~AutoKeepJitScripts();
    634 };
    635 
    636 // Mark ICScripts on the stack as active, so that they are not discarded
    637 // during GC, and copy active Baseline IC stubs to the new stub space.
    638 void MarkActiveICScriptsAndCopyStubs(Zone* zone, ICStubSpace& newStubSpace);
    639 
    640 #ifdef JS_STRUCTURED_SPEW
    641 void JitSpewBaselineICStats(JSScript* script, const char* dumpReason);
    642 #endif
    643 
    644 }  // namespace jit
    645 }  // namespace js
    646 
    647 #endif /* jit_JitScript_h */