tor-browser

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

BaselineCodeGen.h (20478B)


      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_BaselineCodeGen_h
      8 #define jit_BaselineCodeGen_h
      9 
     10 #include "jit/BaselineFrameInfo.h"
     11 #include "jit/BytecodeAnalysis.h"
     12 #include "jit/CompileWrappers.h"
     13 #include "jit/FixedList.h"
     14 #include "jit/MacroAssembler.h"
     15 #include "jit/PerfSpewer.h"
     16 
     17 namespace js {
     18 
     19 class NamedLambdaObject;
     20 
     21 namespace jit {
     22 
     23 class BaselineSnapshot;
     24 
     25 enum class ScriptGCThingType {
     26  Atom,
     27  String,
     28  RegExp,
     29  Object,
     30  Function,
     31  Scope,
     32  BigInt
     33 };
     34 
     35 // Base class for BaselineCompiler and BaselineInterpreterGenerator. The Handler
     36 // template is a class storing fields/methods that are interpreter or compiler
     37 // specific. This can be combined with template specialization of methods in
     38 // this class to specialize behavior.
     39 template <typename Handler>
     40 class BaselineCodeGen {
     41 protected:
     42  Handler handler;
     43 
     44  CompileRuntime* runtime;
     45  MacroAssembler& masm;
     46 
     47  typename Handler::FrameInfoT& frame;
     48 
     49  // Shared epilogue code to return to the caller.
     50  NonAssertingLabel return_;
     51 
     52  NonAssertingLabel postBarrierSlot_;
     53 
     54  // Prologue code where we resume for Ion prologue bailouts.
     55  NonAssertingLabel bailoutPrologue_;
     56 
     57  CodeOffset profilerEnterFrameToggleOffset_;
     58  CodeOffset profilerExitFrameToggleOffset_;
     59 
     60  // Early Ion bailouts will enter at this address. This is after frame
     61  // construction and before environment chain is initialized.
     62  CodeOffset bailoutPrologueOffset_;
     63 
     64  // Baseline Interpreter can enter Baseline Compiler code at this address. This
     65  // is right after the warm-up counter check in the prologue.
     66  CodeOffset warmUpCheckPrologueOffset_;
     67 
     68  uint32_t pushedBeforeCall_ = 0;
     69 #ifdef DEBUG
     70  bool inCall_ = false;
     71 #endif
     72 
     73  template <typename... HandlerArgs>
     74  explicit BaselineCodeGen(TempAllocator& alloc, MacroAssembler& masmArg,
     75                           CompileRuntime* runtimeArg, HandlerArgs&&... args);
     76 
     77  template <typename T>
     78  void pushArg(const T& t) {
     79    masm.Push(t);
     80  }
     81 
     82  // Pushes the current script as argument for a VM function.
     83  void pushScriptArg();
     84 
     85  // Pushes the bytecode pc as argument for a VM function.
     86  void pushBytecodePCArg();
     87 
     88  // Pushes a name/object/scope associated with the current bytecode op (and
     89  // stored in the script) as argument for a VM function.
     90  void loadScriptGCThing(ScriptGCThingType type, Register dest,
     91                         Register scratch);
     92  void loadScriptGCThingInternal(ScriptGCThingType type, Register dest,
     93                                 Register scratch);
     94  void pushScriptGCThingArg(ScriptGCThingType type, Register scratch1,
     95                            Register scratch2);
     96  void pushScriptNameArg(Register scratch1, Register scratch2);
     97 
     98  // Pushes a bytecode operand as argument for a VM function.
     99  void pushUint8BytecodeOperandArg(Register scratch);
    100  void pushUint16BytecodeOperandArg(Register scratch);
    101 
    102  void loadInt32LengthBytecodeOperand(Register dest);
    103  void loadNumFormalArguments(Register dest);
    104 
    105  // Loads the current JSScript* in dest.
    106  void loadScript(Register dest);
    107  // Loads the current JitScript* in dest
    108  void loadJitScript(Register dest);
    109 
    110  void saveInterpreterPCReg();
    111  void restoreInterpreterPCReg();
    112 
    113  // Subtracts |script->nslots() * sizeof(Value)| from reg.
    114  void subtractScriptSlotsSize(Register reg, Register scratch);
    115 
    116  // Loads the resume entries of the current BaselineScript* in dest
    117  void loadBaselineScriptResumeEntries(Register dest, Register scratch);
    118 
    119  // Jump to the script's resume entry indicated by resumeIndex.
    120  void jumpToResumeEntry(Register resumeIndex, Register scratch1,
    121                         Register scratch2);
    122 
    123  // Load the global's lexical environment.
    124  void loadGlobalLexicalEnvironment(Register dest);
    125  void pushGlobalLexicalEnvironmentValue(ValueOperand scratch);
    126 
    127  // Load the |this|-value from the global's lexical environment.
    128  void loadGlobalThisValue(ValueOperand dest);
    129 
    130  // Computes the frame size. See BaselineFrame::debugFrameSize_.
    131  void computeFrameSize(Register dest);
    132 
    133  void prepareVMCall();
    134 
    135  void storeFrameSizeAndPushDescriptor(uint32_t argSize, Register scratch);
    136 
    137  enum class CallVMPhase { BeforePushingLocals, AfterPushingLocals };
    138  bool callVMInternal(VMFunctionId id, RetAddrEntry::Kind kind,
    139                      CallVMPhase phase);
    140 
    141  template <typename Fn, Fn fn>
    142  bool callVM(RetAddrEntry::Kind kind = RetAddrEntry::Kind::CallVM,
    143              CallVMPhase phase = CallVMPhase::AfterPushingLocals);
    144 
    145  template <typename Fn, Fn fn>
    146  bool callVMNonOp(CallVMPhase phase = CallVMPhase::AfterPushingLocals) {
    147    return callVM<Fn, fn>(RetAddrEntry::Kind::NonOpCallVM, phase);
    148  }
    149 
    150  template <typename T>
    151  void emitGuardedCallPreBarrierAnyZone(const T& address, MIRType type,
    152                                        Register scratch) {
    153    MOZ_ASSERT_IF(handler.realmIndependentJitcode(), !masm.maybeRealm());
    154    masm.guardedCallPreBarrierAnyZone(address, type, scratch);
    155  }
    156 
    157  // ifDebuggee should be a function emitting code for when the script is a
    158  // debuggee script. ifNotDebuggee (if present) is called to emit code for
    159  // non-debuggee scripts.
    160  template <typename F1, typename F2>
    161  [[nodiscard]] bool emitDebugInstrumentation(
    162      const F1& ifDebuggee, const mozilla::Maybe<F2>& ifNotDebuggee);
    163  template <typename F>
    164  [[nodiscard]] bool emitDebugInstrumentation(const F& ifDebuggee) {
    165    return emitDebugInstrumentation(ifDebuggee, mozilla::Maybe<F>());
    166  }
    167 
    168  bool emitSuspend(JSOp op);
    169 
    170  [[nodiscard]] bool emitAfterYieldDebugInstrumentation(Register scratch);
    171  [[nodiscard]] bool emitDebugAfterYield();
    172 
    173  // ifSet should be a function emitting code for when the script has |flag|
    174  // set. ifNotSet emits code for when the flag isn't set.
    175  template <typename F1, typename F2>
    176  [[nodiscard]] bool emitTestScriptFlag(JSScript::ImmutableFlags flag,
    177                                        const F1& ifSet, const F2& ifNotSet,
    178                                        Register scratch);
    179 
    180  // If |script->hasFlag(flag) == value|, execute the code emitted by |emit|.
    181  template <typename F>
    182  [[nodiscard]] bool emitTestScriptFlag(JSScript::ImmutableFlags flag,
    183                                        bool value, const F& emit,
    184                                        Register scratch);
    185  template <typename F>
    186  [[nodiscard]] bool emitTestScriptFlag(JSScript::MutableFlags flag, bool value,
    187                                        const F& emit, Register scratch);
    188 
    189  [[nodiscard]] bool emitEnterGeneratorCode(Register script,
    190                                            Register resumeIndex,
    191                                            Register scratch);
    192 
    193  void emitInterpJumpToResumeEntry(Register script, Register resumeIndex,
    194                                   Register scratch);
    195  void emitJumpToInterpretOpLabel();
    196 
    197  [[nodiscard]] bool emitCheckThis(ValueOperand val, bool reinit = false);
    198  void emitLoadReturnValue(ValueOperand val);
    199  void emitGetAliasedVar(ValueOperand dest);
    200  [[nodiscard]] bool emitGetAliasedDebugVar(ValueOperand dest);
    201 
    202  [[nodiscard]] bool emitNextIC();
    203  [[nodiscard]] bool emitInterruptCheck();
    204  [[nodiscard]] bool emitWarmUpCounterIncrement();
    205 
    206  [[nodiscard]] bool emitTrialInliningCheck(Register count, Register icScript,
    207                                            Register scratch);
    208 
    209 #define EMIT_OP(op, ...) bool emit_##op();
    210  FOR_EACH_OPCODE(EMIT_OP)
    211 #undef EMIT_OP
    212 
    213  // JSOp::Pos, JSOp::Neg, JSOp::BitNot, JSOp::Inc, JSOp::Dec, JSOp::ToNumeric.
    214  [[nodiscard]] bool emitUnaryArith();
    215 
    216  // JSOp::BitXor, JSOp::Lsh, JSOp::Add etc.
    217  [[nodiscard]] bool emitBinaryArith();
    218 
    219  // Handles JSOp::Lt, JSOp::Gt, and friends
    220  [[nodiscard]] bool emitCompare();
    221 
    222  [[nodiscard]] bool emitConstantStrictEq(JSOp op);
    223 
    224  // Handles JSOp::NewObject and JSOp::NewInit.
    225  [[nodiscard]] bool emitNewObject();
    226 
    227  // For a JOF_JUMP op, jumps to the op's jump target.
    228  void emitJump();
    229 
    230  // For a JOF_JUMP op, jumps to the op's jump target depending on the Value
    231  // in |val|.
    232  void emitTestBooleanTruthy(bool branchIfTrue, ValueOperand val);
    233 
    234  // Converts |val| to an index in the jump table and stores this in |dest|
    235  // or branches to the default pc if not int32 or out-of-range.
    236  void emitGetTableSwitchIndex(ValueOperand val, Register dest,
    237                               Register scratch1, Register scratch2);
    238 
    239  // Jumps to the target of a table switch based on |key| and the
    240  // firstResumeIndex stored in JSOp::TableSwitch.
    241  void emitTableSwitchJump(Register key, Register scratch1, Register scratch2);
    242 
    243  [[nodiscard]] bool emitReturn();
    244 
    245  [[nodiscard]] bool emitTest(bool branchIfTrue);
    246  [[nodiscard]] bool emitAndOr(bool branchIfTrue);
    247  [[nodiscard]] bool emitCoalesce();
    248 
    249  [[nodiscard]] bool emitCall(JSOp op);
    250  [[nodiscard]] bool emitSpreadCall(JSOp op);
    251 
    252  [[nodiscard]] bool emitDelElem(bool strict);
    253  [[nodiscard]] bool emitDelProp(bool strict);
    254  [[nodiscard]] bool emitSetElemSuper(bool strict);
    255  [[nodiscard]] bool emitSetPropSuper(bool strict);
    256 
    257  // Try to bake in the result of BindUnqualifiedGName instead of using an IC.
    258  // Return true if we managed to optimize the op.
    259  bool tryOptimizeBindUnqualifiedGlobalName();
    260 
    261  [[nodiscard]] bool emitInitPropGetterSetter();
    262  [[nodiscard]] bool emitInitElemGetterSetter();
    263 
    264  [[nodiscard]] bool emitFormalArgAccess(JSOp op);
    265 
    266  [[nodiscard]] bool emitUninitializedLexicalCheck(const ValueOperand& val);
    267 
    268  [[nodiscard]] bool emitIsMagicValue();
    269 
    270  void getEnvironmentCoordinateObject(Register reg);
    271  Address getEnvironmentCoordinateAddressFromObject(Register objReg,
    272                                                    Register reg);
    273  Address getEnvironmentCoordinateAddress(Register reg);
    274 
    275  [[nodiscard]] bool emitPrologue();
    276  [[nodiscard]] bool emitEpilogue();
    277  [[nodiscard]] bool emitStackCheck();
    278  [[nodiscard]] bool emitDebugPrologue();
    279  [[nodiscard]] bool emitDebugEpilogue();
    280 
    281  [[nodiscard]] bool initEnvironmentChain();
    282 
    283  [[nodiscard]] bool emitHandleCodeCoverageAtPrologue();
    284 
    285  void emitInitFrameFields(Register nonFunctionEnv);
    286  [[nodiscard]] bool emitIsDebuggeeCheck();
    287  void emitInitializeLocals();
    288 
    289  void emitProfilerEnterFrame();
    290  void emitProfilerExitFrame();
    291 
    292  void emitOutOfLinePostBarrierSlot();
    293 };
    294 
    295 using RetAddrEntryVector = js::Vector<RetAddrEntry, 16, SystemAllocPolicy>;
    296 using AllocSiteIndexVector = js::Vector<uint32_t, 16, SystemAllocPolicy>;
    297 
    298 // Interface used by BaselineCodeGen for BaselineCompiler.
    299 class BaselineCompilerHandler {
    300  CompilerFrameInfo frame_;
    301  TempAllocator& alloc_;
    302  BytecodeAnalysis analysis_;
    303 #ifdef DEBUG
    304  const MacroAssembler& masm_;
    305 #endif
    306  FixedList<Label> labels_;
    307  RetAddrEntryVector retAddrEntries_;
    308  AllocSiteIndexVector allocSiteIndices_;
    309 
    310  // Native code offsets for OSR at JSOp::LoopHead ops.
    311  using OSREntryVector =
    312      Vector<BaselineScript::OSREntry, 16, SystemAllocPolicy>;
    313  OSREntryVector osrEntries_;
    314 
    315  JSScript* script_;
    316  jsbytecode* pc_;
    317 
    318  size_t nargs_;
    319 
    320  JSObject* globalLexicalEnvironment_;
    321  JSObject* globalThis_;
    322 
    323  CallObject* callObjectTemplate_;
    324  NamedLambdaObject* namedLambdaTemplate_;
    325 
    326  // Index of the current ICEntry in the script's JitScript.
    327  uint32_t icEntryIndex_;
    328 
    329  uint32_t baseWarmUpThreshold_;
    330 
    331  bool compileDebugInstrumentation_;
    332  bool ionCompileable_;
    333 
    334  bool compilingOffThread_ = false;
    335 
    336  bool needsEnvAllocSite_ = false;
    337 
    338 public:
    339  using FrameInfoT = CompilerFrameInfo;
    340 
    341  BaselineCompilerHandler(MacroAssembler& masm, TempAllocator& alloc,
    342                          BaselineSnapshot* snapshot);
    343 
    344  [[nodiscard]] bool init();
    345 
    346  CompilerFrameInfo& frame() { return frame_; }
    347 
    348  jsbytecode* pc() const { return pc_; }
    349  jsbytecode* maybePC() const { return pc_; }
    350 
    351  void moveToNextPC() { pc_ += GetBytecodeLength(pc_); }
    352  Label* labelOf(jsbytecode* pc) { return &labels_[script_->pcToOffset(pc)]; }
    353 
    354  bool isDefinitelyLastOp() const { return pc_ == script_->lastPC(); }
    355 
    356  bool shouldEmitDebugEpilogueAtReturnOp() const {
    357    // The JIT uses the return address -> pc mapping and bakes in the pc
    358    // argument so the DebugEpilogue call needs to be part of the returning
    359    // bytecode op for this to work.
    360    return true;
    361  }
    362 
    363  JSScript* script() const { return script_; }
    364  JSScript* maybeScript() const { return script_; }
    365 
    366  size_t nargs() const {
    367    MOZ_ASSERT(isFunction());
    368    return nargs_;
    369  }
    370  CallObject* callObjectTemplate() const { return callObjectTemplate_; }
    371  NamedLambdaObject* namedLambdaTemplate() const {
    372    return namedLambdaTemplate_;
    373  }
    374 
    375  bool isFunction() const { return !!script_->function(); }
    376 
    377  ModuleObject* module() const { return script_->module(); }
    378 
    379  bool compileDebugInstrumentation() const {
    380    return compileDebugInstrumentation_;
    381  }
    382 
    383  bool maybeIonCompileable() const { return ionCompileable_; }
    384  void setIonCompileable(bool value) { ionCompileable_ = value; }
    385 
    386  uint32_t icEntryIndex() const { return icEntryIndex_; }
    387  void moveToNextICEntry() { icEntryIndex_++; }
    388 
    389  BytecodeAnalysis& analysis() { return analysis_; }
    390 
    391  RetAddrEntryVector& retAddrEntries() { return retAddrEntries_; }
    392  OSREntryVector& osrEntries() { return osrEntries_; }
    393 
    394  [[nodiscard]] bool recordCallRetAddr(RetAddrEntry::Kind kind,
    395                                       uint32_t retOffset);
    396 
    397  // If a script has more |nslots| than this the stack check must account
    398  // for these slots explicitly.
    399  bool mustIncludeSlotsInStackCheck() const {
    400    static constexpr size_t NumSlotsLimit = 128;
    401    return script()->nslots() > NumSlotsLimit;
    402  }
    403 
    404  bool canHaveFixedSlots() const { return script()->nfixed() != 0; }
    405 
    406  JSObject* maybeGlobalLexicalEnvironment() const {
    407    return globalLexicalEnvironment_;
    408  }
    409  JSObject* globalThis() const { return globalThis_; }
    410 
    411  uint32_t baseWarmUpThreshold() const { return baseWarmUpThreshold_; }
    412 
    413  void maybeDisableIon();
    414 
    415  [[nodiscard]] bool addAllocSiteIndex(uint32_t entryIndex) {
    416    return allocSiteIndices_.append(entryIndex);
    417  }
    418  void createAllocSites();
    419 
    420  bool compilingOffThread() const { return compilingOffThread_; }
    421  void setCompilingOffThread() { compilingOffThread_ = true; }
    422 
    423  bool addEnvAllocSite() {
    424    needsEnvAllocSite_ = true;
    425    return true;
    426  }
    427 
    428  bool realmIndependentJitcode() const {
    429    return JS::Prefs::experimental_self_hosted_cache() &&
    430           script()->selfHosted();
    431  }
    432 };
    433 
    434 using BaselineCompilerCodeGen = BaselineCodeGen<BaselineCompilerHandler>;
    435 
    436 class BaselineCompiler final : private BaselineCompilerCodeGen {
    437  // Native code offsets for bytecode ops in the script's resume offsets list.
    438  ResumeOffsetEntryVector resumeOffsetEntries_;
    439 
    440  // Native code offsets for debug traps if the script is compiled with debug
    441  // instrumentation.
    442  using DebugTrapEntryVector =
    443      Vector<BaselineScript::DebugTrapEntry, 0, SystemAllocPolicy>;
    444  DebugTrapEntryVector debugTrapEntries_;
    445 
    446  CodeOffset profilerPushToggleOffset_;
    447 
    448  BaselinePerfSpewer perfSpewer_;
    449 
    450 public:
    451  BaselineCompiler(TempAllocator& alloc, CompileRuntime* runtime,
    452                   MacroAssembler& masm, BaselineSnapshot* snapshot);
    453  [[nodiscard]] bool init();
    454 
    455  static bool PrepareToCompile(JSContext* cx, Handle<JSScript*> script,
    456                               bool compileDebugInstrumentation);
    457 
    458  MethodStatus compile(JSContext* cx);
    459  MethodStatus compileOffThread();
    460 
    461  bool finishCompile(JSContext* cx);
    462 
    463  bool compileDebugInstrumentation() const {
    464    return handler.compileDebugInstrumentation();
    465  }
    466 
    467 private:
    468  bool compileImpl();
    469 
    470  bool emitBody();
    471 
    472  [[nodiscard]] bool emitDebugTrap();
    473 };
    474 
    475 // Interface used by BaselineCodeGen for BaselineInterpreterGenerator.
    476 class BaselineInterpreterHandler {
    477  InterpreterFrameInfo frame_;
    478 
    479  // Entry point to start interpreting a bytecode op. No registers are live. PC
    480  // is loaded from the frame.
    481  NonAssertingLabel interpretOp_;
    482 
    483  // Like interpretOp_ but at this point the PC is expected to be in
    484  // InterpreterPCReg.
    485  NonAssertingLabel interpretOpWithPCReg_;
    486 
    487  // Offsets of toggled jumps for debugger instrumentation.
    488  using CodeOffsetVector = Vector<uint32_t, 0, SystemAllocPolicy>;
    489  CodeOffsetVector debugInstrumentationOffsets_;
    490 
    491  // Offsets of toggled jumps for code coverage instrumentation.
    492  CodeOffsetVector codeCoverageOffsets_;
    493  NonAssertingLabel codeCoverageAtPrologueLabel_;
    494  NonAssertingLabel codeCoverageAtPCLabel_;
    495 
    496  // Offsets of IC calls for IsIonInlinableOp ops, for Ion bailouts.
    497  BaselineInterpreter::ICReturnOffsetVector icReturnOffsets_;
    498 
    499  // Offsets of some callVMs for BaselineDebugModeOSR.
    500  BaselineInterpreter::CallVMOffsets callVMOffsets_;
    501 
    502  // The current JSOp we are emitting interpreter code for.
    503  mozilla::Maybe<JSOp> currentOp_;
    504 
    505 public:
    506  using FrameInfoT = InterpreterFrameInfo;
    507 
    508  explicit BaselineInterpreterHandler(MacroAssembler& masm);
    509 
    510  InterpreterFrameInfo& frame() { return frame_; }
    511 
    512  Label* interpretOpLabel() { return &interpretOp_; }
    513  Label* interpretOpWithPCRegLabel() { return &interpretOpWithPCReg_; }
    514 
    515  Label* codeCoverageAtPrologueLabel() { return &codeCoverageAtPrologueLabel_; }
    516  Label* codeCoverageAtPCLabel() { return &codeCoverageAtPCLabel_; }
    517 
    518  CodeOffsetVector& debugInstrumentationOffsets() {
    519    return debugInstrumentationOffsets_;
    520  }
    521  CodeOffsetVector& codeCoverageOffsets() { return codeCoverageOffsets_; }
    522 
    523  BaselineInterpreter::ICReturnOffsetVector& icReturnOffsets() {
    524    return icReturnOffsets_;
    525  }
    526 
    527  void setCurrentOp(JSOp op) { currentOp_.emplace(op); }
    528  void resetCurrentOp() { currentOp_.reset(); }
    529  mozilla::Maybe<JSOp> currentOp() const { return currentOp_; }
    530 
    531  // Interpreter doesn't know the script and pc statically.
    532  jsbytecode* maybePC() const { return nullptr; }
    533  bool isDefinitelyLastOp() const { return false; }
    534  JSScript* maybeScript() const { return nullptr; }
    535 
    536  bool shouldEmitDebugEpilogueAtReturnOp() const {
    537    // The interpreter doesn't use the return address -> pc mapping and doesn't
    538    // bake in bytecode PCs so it can emit a shared DebugEpilogue call instead
    539    // of duplicating it for every return op.
    540    return false;
    541  }
    542 
    543  [[nodiscard]] bool addDebugInstrumentationOffset(CodeOffset offset);
    544 
    545  const BaselineInterpreter::CallVMOffsets& callVMOffsets() const {
    546    return callVMOffsets_;
    547  }
    548 
    549  [[nodiscard]] bool recordCallRetAddr(RetAddrEntry::Kind kind,
    550                                       uint32_t retOffset);
    551 
    552  bool maybeIonCompileable() const { return true; }
    553 
    554  // The interpreter doesn't know the number of slots statically so we always
    555  // include them.
    556  bool mustIncludeSlotsInStackCheck() const { return true; }
    557 
    558  bool canHaveFixedSlots() const { return true; }
    559  JSObject* maybeGlobalLexicalEnvironment() const { return nullptr; }
    560 
    561  bool addEnvAllocSite() { return false; }  // Not supported.
    562 
    563  bool realmIndependentJitcode() const { return true; }
    564 };
    565 
    566 using BaselineInterpreterCodeGen = BaselineCodeGen<BaselineInterpreterHandler>;
    567 
    568 class BaselineInterpreterGenerator final : private BaselineInterpreterCodeGen {
    569  // Offsets of patchable call instructions for debugger breakpoints/stepping.
    570  Vector<uint32_t, 0, SystemAllocPolicy> debugTrapOffsets_;
    571 
    572  // Offsets of move instructions for tableswitch base address.
    573  Vector<CodeOffset, 0, SystemAllocPolicy> tableLabels_;
    574 
    575  // Offset of the first tableswitch entry.
    576  uint32_t tableOffset_ = 0;
    577 
    578  // Offset of the code to start interpreting a bytecode op.
    579  uint32_t interpretOpOffset_ = 0;
    580 
    581  // Like interpretOpOffset_ but skips the debug trap for the current op.
    582  uint32_t interpretOpNoDebugTrapOffset_ = 0;
    583 
    584  // Offset of the jump (tail call) to the debug trap handler trampoline code.
    585  // When the debugger is enabled, NOPs are patched to calls to this location.
    586  uint32_t debugTrapHandlerOffset_ = 0;
    587 
    588  BaselineInterpreterPerfSpewer perfSpewer_;
    589 
    590 public:
    591  explicit BaselineInterpreterGenerator(JSContext* cx, TempAllocator& alloc,
    592                                        MacroAssembler& masm);
    593 
    594  [[nodiscard]] bool generate(JSContext* cx, BaselineInterpreter& interpreter);
    595 
    596 private:
    597  [[nodiscard]] bool emitInterpreterLoop();
    598  [[nodiscard]] bool emitDebugTrap();
    599 
    600  void emitOutOfLineCodeCoverageInstrumentation();
    601 };
    602 
    603 }  // namespace jit
    604 }  // namespace js
    605 
    606 #endif /* jit_BaselineCodeGen_h */