tor-browser

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

Simulator-mips64.cpp (127528B)


      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 // Copyright 2011 the V8 project authors. All rights reserved.
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 //       notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 //       copyright notice, this list of conditions and the following
     12 //       disclaimer in the documentation and/or other materials provided
     13 //       with the distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 //       contributors may be used to endorse or promote products derived
     16 //       from this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 #include "jit/mips64/Simulator-mips64.h"
     31 
     32 #include "mozilla/Casting.h"
     33 #include "mozilla/IntegerPrintfMacros.h"
     34 
     35 #include <float.h>
     36 #include <limits>
     37 
     38 #include "jit/AtomicOperations.h"
     39 #include "jit/mips64/Assembler-mips64.h"
     40 #include "js/Conversions.h"
     41 #include "js/UniquePtr.h"
     42 #include "js/Utility.h"
     43 #include "threading/LockGuard.h"
     44 #include "vm/JSContext.h"
     45 #include "vm/Runtime.h"
     46 #include "wasm/WasmInstance.h"
     47 #include "wasm/WasmSignalHandlers.h"
     48 
     49 #define I8(v) static_cast<int8_t>(v)
     50 #define I16(v) static_cast<int16_t>(v)
     51 #define U16(v) static_cast<uint16_t>(v)
     52 #define I32(v) static_cast<int32_t>(v)
     53 #define U32(v) static_cast<uint32_t>(v)
     54 #define I64(v) static_cast<int64_t>(v)
     55 #define U64(v) static_cast<uint64_t>(v)
     56 #define I128(v) static_cast<__int128_t>(v)
     57 #define U128(v) static_cast<__uint128_t>(v)
     58 
     59 #define I32_CHECK(v)                   \
     60  ({                                   \
     61    MOZ_ASSERT(I64(I32(v)) == I64(v)); \
     62    I32((v));                          \
     63  })
     64 
     65 namespace js {
     66 namespace jit {
     67 
     68 static const Instr kCallRedirInstr =
     69    op_special | MAX_BREAK_CODE << FunctionBits | ff_break;
     70 
     71 // Utils functions.
     72 static uint32_t GetFCSRConditionBit(uint32_t cc) {
     73  if (cc == 0) {
     74    return 23;
     75  }
     76  return 24 + cc;
     77 }
     78 
     79 // -----------------------------------------------------------------------------
     80 // MIPS assembly various constants.
     81 
     82 class SimInstruction {
     83 public:
     84  enum {
     85    kInstrSize = 4,
     86    // On MIPS PC cannot actually be directly accessed. We behave as if PC was
     87    // always the value of the current instruction being executed.
     88    kPCReadOffset = 0
     89  };
     90 
     91  // Get the raw instruction bits.
     92  inline Instr instructionBits() const {
     93    return *reinterpret_cast<const Instr*>(this);
     94  }
     95 
     96  // Set the raw instruction bits to value.
     97  inline void setInstructionBits(Instr value) {
     98    *reinterpret_cast<Instr*>(this) = value;
     99  }
    100 
    101  // Read one particular bit out of the instruction bits.
    102  inline int bit(int nr) const { return (instructionBits() >> nr) & 1; }
    103 
    104  // Read a bit field out of the instruction bits.
    105  inline int bits(int hi, int lo) const {
    106    return (instructionBits() >> lo) & ((2 << (hi - lo)) - 1);
    107  }
    108 
    109  // Instruction type.
    110  enum Type { kRegisterType, kImmediateType, kJumpType, kUnsupported = -1 };
    111 
    112  // Get the encoding type of the instruction.
    113  Type instructionType() const;
    114 
    115  // Accessors for the different named fields used in the MIPS encoding.
    116  inline OpcodeField opcodeValue() const {
    117    return static_cast<OpcodeField>(
    118        bits(OpcodeShift + OpcodeBits - 1, OpcodeShift));
    119  }
    120 
    121  inline int rsValue() const {
    122    MOZ_ASSERT(instructionType() == kRegisterType ||
    123               instructionType() == kImmediateType);
    124    return bits(RSShift + RSBits - 1, RSShift);
    125  }
    126 
    127  inline int rtValue() const {
    128    MOZ_ASSERT(instructionType() == kRegisterType ||
    129               instructionType() == kImmediateType);
    130    return bits(RTShift + RTBits - 1, RTShift);
    131  }
    132 
    133  inline int rdValue() const {
    134    MOZ_ASSERT(instructionType() == kRegisterType);
    135    return bits(RDShift + RDBits - 1, RDShift);
    136  }
    137 
    138  inline int saValue() const {
    139    MOZ_ASSERT(instructionType() == kRegisterType);
    140    return bits(SAShift + SABits - 1, SAShift);
    141  }
    142 
    143  inline int functionValue() const {
    144    MOZ_ASSERT(instructionType() == kRegisterType ||
    145               instructionType() == kImmediateType);
    146    return bits(FunctionShift + FunctionBits - 1, FunctionShift);
    147  }
    148 
    149  inline int fdValue() const { return bits(FDShift + FDBits - 1, FDShift); }
    150 
    151  inline int fsValue() const { return bits(FSShift + FSBits - 1, FSShift); }
    152 
    153  inline int ftValue() const { return bits(FTShift + FTBits - 1, FTShift); }
    154 
    155  inline int frValue() const { return bits(FRShift + FRBits - 1, FRShift); }
    156 
    157  // Float Compare condition code instruction bits.
    158  inline int fcccValue() const {
    159    return bits(FCccShift + FCccBits - 1, FCccShift);
    160  }
    161 
    162  // Float Branch condition code instruction bits.
    163  inline int fbccValue() const {
    164    return bits(FBccShift + FBccBits - 1, FBccShift);
    165  }
    166 
    167  // Float Branch true/false instruction bit.
    168  inline int fbtrueValue() const {
    169    return bits(FBtrueShift + FBtrueBits - 1, FBtrueShift);
    170  }
    171 
    172  // Return the fields at their original place in the instruction encoding.
    173  inline OpcodeField opcodeFieldRaw() const {
    174    return static_cast<OpcodeField>(instructionBits() & OpcodeMask);
    175  }
    176 
    177  inline int rsFieldRaw() const {
    178    MOZ_ASSERT(instructionType() == kRegisterType ||
    179               instructionType() == kImmediateType);
    180    return instructionBits() & RSMask;
    181  }
    182 
    183  // Same as above function, but safe to call within instructionType().
    184  inline int rsFieldRawNoAssert() const { return instructionBits() & RSMask; }
    185 
    186  inline int rtFieldRaw() const {
    187    MOZ_ASSERT(instructionType() == kRegisterType ||
    188               instructionType() == kImmediateType);
    189    return instructionBits() & RTMask;
    190  }
    191 
    192  inline int rdFieldRaw() const {
    193    MOZ_ASSERT(instructionType() == kRegisterType);
    194    return instructionBits() & RDMask;
    195  }
    196 
    197  inline int saFieldRaw() const {
    198    MOZ_ASSERT(instructionType() == kRegisterType);
    199    return instructionBits() & SAMask;
    200  }
    201 
    202  inline int functionFieldRaw() const {
    203    return instructionBits() & FunctionMask;
    204  }
    205 
    206  // Get the secondary field according to the opcode.
    207  inline int secondaryValue() const {
    208    OpcodeField op = opcodeFieldRaw();
    209    switch (op) {
    210      case op_special:
    211      case op_special2:
    212        return functionValue();
    213      case op_cop1:
    214        return rsValue();
    215      case op_regimm:
    216        return rtValue();
    217      default:
    218        return ff_null;
    219    }
    220  }
    221 
    222  inline int32_t imm16Value() const {
    223    MOZ_ASSERT(instructionType() == kImmediateType);
    224    return bits(Imm16Shift + Imm16Bits - 1, Imm16Shift);
    225  }
    226 
    227  inline int32_t imm26Value() const {
    228    MOZ_ASSERT(instructionType() == kJumpType);
    229    return bits(Imm26Shift + Imm26Bits - 1, Imm26Shift);
    230  }
    231 
    232  // Say if the instruction should not be used in a branch delay slot.
    233  bool isForbiddenInBranchDelay() const;
    234  // Say if the instruction 'links'. e.g. jal, bal.
    235  bool isLinkingInstruction() const;
    236  // Say if the instruction is a debugger break/trap.
    237  bool isTrap() const;
    238 
    239 private:
    240  SimInstruction() = delete;
    241  SimInstruction(const SimInstruction& other) = delete;
    242  void operator=(const SimInstruction& other) = delete;
    243 };
    244 
    245 bool SimInstruction::isForbiddenInBranchDelay() const {
    246  const int op = opcodeFieldRaw();
    247  switch (op) {
    248    case op_j:
    249    case op_jal:
    250    case op_beq:
    251    case op_bne:
    252    case op_blez:
    253    case op_bgtz:
    254    case op_beql:
    255    case op_bnel:
    256    case op_blezl:
    257    case op_bgtzl:
    258      return true;
    259    case op_regimm:
    260      switch (rtFieldRaw()) {
    261        case rt_bltz:
    262        case rt_bgez:
    263        case rt_bltzal:
    264        case rt_bgezal:
    265          return true;
    266        default:
    267          return false;
    268      };
    269      break;
    270    case op_special:
    271      switch (functionFieldRaw()) {
    272        case ff_jr:
    273        case ff_jalr:
    274          return true;
    275        default:
    276          return false;
    277      };
    278      break;
    279    default:
    280      return false;
    281  };
    282 }
    283 
    284 bool SimInstruction::isLinkingInstruction() const {
    285  const int op = opcodeFieldRaw();
    286  switch (op) {
    287    case op_jal:
    288      return true;
    289    case op_regimm:
    290      switch (rtFieldRaw()) {
    291        case rt_bgezal:
    292        case rt_bltzal:
    293          return true;
    294        default:
    295          return false;
    296      };
    297    case op_special:
    298      switch (functionFieldRaw()) {
    299        case ff_jalr:
    300          return true;
    301        default:
    302          return false;
    303      };
    304    default:
    305      return false;
    306  };
    307 }
    308 
    309 bool SimInstruction::isTrap() const {
    310  if (opcodeFieldRaw() != op_special) {
    311    return false;
    312  } else {
    313    switch (functionFieldRaw()) {
    314      case ff_break:
    315        return instructionBits() != kCallRedirInstr;
    316      case ff_tge:
    317      case ff_tgeu:
    318      case ff_tlt:
    319      case ff_tltu:
    320      case ff_teq:
    321      case ff_tne:
    322        return bits(15, 6) != kWasmTrapCode;
    323      default:
    324        return false;
    325    };
    326  }
    327 }
    328 
    329 SimInstruction::Type SimInstruction::instructionType() const {
    330  switch (opcodeFieldRaw()) {
    331    case op_special:
    332      switch (functionFieldRaw()) {
    333        case ff_jr:
    334        case ff_jalr:
    335        case ff_sync:
    336        case ff_break:
    337        case ff_sll:
    338        case ff_dsll:
    339        case ff_dsll32:
    340        case ff_srl:
    341        case ff_dsrl:
    342        case ff_dsrl32:
    343        case ff_sra:
    344        case ff_dsra:
    345        case ff_dsra32:
    346        case ff_sllv:
    347        case ff_dsllv:
    348        case ff_srlv:
    349        case ff_dsrlv:
    350        case ff_srav:
    351        case ff_dsrav:
    352        case ff_mfhi:
    353        case ff_mflo:
    354        case ff_mult:
    355        case ff_dmult:
    356        case ff_multu:
    357        case ff_dmultu:
    358        case ff_div:
    359        case ff_ddiv:
    360        case ff_divu:
    361        case ff_ddivu:
    362        case ff_add:
    363        case ff_dadd:
    364        case ff_addu:
    365        case ff_daddu:
    366        case ff_sub:
    367        case ff_dsub:
    368        case ff_subu:
    369        case ff_dsubu:
    370        case ff_and:
    371        case ff_or:
    372        case ff_xor:
    373        case ff_nor:
    374        case ff_slt:
    375        case ff_sltu:
    376        case ff_tge:
    377        case ff_tgeu:
    378        case ff_tlt:
    379        case ff_tltu:
    380        case ff_teq:
    381        case ff_tne:
    382        case ff_movz:
    383        case ff_movn:
    384        case ff_movci:
    385          return kRegisterType;
    386        default:
    387          return kUnsupported;
    388      };
    389      break;
    390    case op_special2:
    391      switch (functionFieldRaw()) {
    392        case ff_mul:
    393        case ff_clz:
    394        case ff_dclz:
    395          return kRegisterType;
    396        default:
    397          return kUnsupported;
    398      };
    399      break;
    400    case op_special3:
    401      switch (functionFieldRaw()) {
    402        case ff_ins:
    403        case ff_dins:
    404        case ff_dinsm:
    405        case ff_dinsu:
    406        case ff_ext:
    407        case ff_dext:
    408        case ff_dextm:
    409        case ff_dextu:
    410        case ff_bshfl:
    411        case ff_dbshfl:
    412          return kRegisterType;
    413        default:
    414          return kUnsupported;
    415      };
    416      break;
    417    case op_cop1:  // Coprocessor instructions.
    418      switch (rsFieldRawNoAssert()) {
    419        case rs_bc1:  // Branch on coprocessor condition.
    420          return kImmediateType;
    421        default:
    422          return kRegisterType;
    423      };
    424      break;
    425    case op_cop1x:
    426      return kRegisterType;
    427      // 16 bits Immediate type instructions. e.g.: addi dest, src, imm16.
    428    case op_regimm:
    429    case op_beq:
    430    case op_bne:
    431    case op_blez:
    432    case op_bgtz:
    433    case op_addi:
    434    case op_daddi:
    435    case op_addiu:
    436    case op_daddiu:
    437    case op_slti:
    438    case op_sltiu:
    439    case op_andi:
    440    case op_ori:
    441    case op_xori:
    442    case op_lui:
    443    case op_beql:
    444    case op_bnel:
    445    case op_blezl:
    446    case op_bgtzl:
    447    case op_lb:
    448    case op_lbu:
    449    case op_lh:
    450    case op_lhu:
    451    case op_lw:
    452    case op_lwu:
    453    case op_lwl:
    454    case op_lwr:
    455    case op_ll:
    456    case op_lld:
    457    case op_ld:
    458    case op_ldl:
    459    case op_ldr:
    460    case op_sb:
    461    case op_sh:
    462    case op_sw:
    463    case op_swl:
    464    case op_swr:
    465    case op_sc:
    466    case op_scd:
    467    case op_sd:
    468    case op_sdl:
    469    case op_sdr:
    470    case op_lwc1:
    471    case op_ldc1:
    472    case op_swc1:
    473    case op_sdc1:
    474      return kImmediateType;
    475      // 26 bits immediate type instructions. e.g.: j imm26.
    476    case op_j:
    477    case op_jal:
    478      return kJumpType;
    479    default:
    480      return kUnsupported;
    481  };
    482  return kUnsupported;
    483 }
    484 
    485 // C/C++ argument slots size.
    486 const int kCArgSlotCount = 0;
    487 const int kCArgsSlotsSize = kCArgSlotCount * sizeof(uintptr_t);
    488 const int kBranchReturnOffset = 2 * SimInstruction::kInstrSize;
    489 
    490 class CachePage {
    491 public:
    492  static const int LINE_VALID = 0;
    493  static const int LINE_INVALID = 1;
    494 
    495  static const int kPageShift = 12;
    496  static const int kPageSize = 1 << kPageShift;
    497  static const int kPageMask = kPageSize - 1;
    498  static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
    499  static const int kLineLength = 1 << kLineShift;
    500  static const int kLineMask = kLineLength - 1;
    501 
    502  CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
    503 
    504  char* validityByte(int offset) {
    505    return &validity_map_[offset >> kLineShift];
    506  }
    507 
    508  char* cachedData(int offset) { return &data_[offset]; }
    509 
    510 private:
    511  char data_[kPageSize];  // The cached data.
    512  static const int kValidityMapSize = kPageSize >> kLineShift;
    513  char validity_map_[kValidityMapSize];  // One byte per line.
    514 };
    515 
    516 // Protects the icache() and redirection() properties of the
    517 // Simulator.
    518 class AutoLockSimulatorCache : public LockGuard<Mutex> {
    519  using Base = LockGuard<Mutex>;
    520 
    521 public:
    522  explicit AutoLockSimulatorCache()
    523      : Base(SimulatorProcess::singleton_->cacheLock_) {}
    524 };
    525 
    526 mozilla::Atomic<size_t, mozilla::ReleaseAcquire>
    527    SimulatorProcess::ICacheCheckingDisableCount(
    528        1);  // Checking is disabled by default.
    529 SimulatorProcess* SimulatorProcess::singleton_ = nullptr;
    530 
    531 int64_t Simulator::StopSimAt = -1;
    532 
    533 Simulator* Simulator::Create() {
    534  auto sim = MakeUnique<Simulator>();
    535  if (!sim) {
    536    return nullptr;
    537  }
    538 
    539  if (!sim->init()) {
    540    return nullptr;
    541  }
    542 
    543  int64_t stopAt;
    544  char* stopAtStr = getenv("MIPS_SIM_STOP_AT");
    545  if (stopAtStr && sscanf(stopAtStr, "%" PRIi64, &stopAt) == 1) {
    546    fprintf(stderr, "\nStopping simulation at icount %" PRIi64 "\n", stopAt);
    547    Simulator::StopSimAt = stopAt;
    548  }
    549 
    550  return sim.release();
    551 }
    552 
    553 void Simulator::Destroy(Simulator* sim) { js_delete(sim); }
    554 
    555 // The MipsDebugger class is used by the simulator while debugging simulated
    556 // code.
    557 class MipsDebugger {
    558 public:
    559  explicit MipsDebugger(Simulator* sim) : sim_(sim) {}
    560 
    561  void stop(SimInstruction* instr);
    562  void debug();
    563  // Print all registers with a nice formatting.
    564  void printAllRegs();
    565  void printAllRegsIncludingFPU();
    566 
    567 private:
    568  // We set the breakpoint code to 0xfffff to easily recognize it.
    569  static const Instr kBreakpointInstr =
    570      static_cast<uint32_t>(op_special) | ff_break | 0xfffff << 6;
    571  static const Instr kNopInstr = static_cast<uint32_t>(op_special) | ff_sll;
    572 
    573  Simulator* sim_;
    574 
    575  int64_t getRegisterValue(int regnum);
    576  int64_t getFPURegisterValueLong(int regnum);
    577  float getFPURegisterValueFloat(int regnum);
    578  double getFPURegisterValueDouble(int regnum);
    579  bool getValue(const char* desc, int64_t* value);
    580 
    581  // Set or delete a breakpoint. Returns true if successful.
    582  bool setBreakpoint(SimInstruction* breakpc);
    583  bool deleteBreakpoint(SimInstruction* breakpc);
    584 
    585  // Undo and redo all breakpoints. This is needed to bracket disassembly and
    586  // execution to skip past breakpoints when run from the debugger.
    587  void undoBreakpoints();
    588  void redoBreakpoints();
    589 };
    590 
    591 static void UNSUPPORTED() {
    592  printf("Unsupported instruction.\n");
    593  MOZ_CRASH();
    594 }
    595 
    596 void MipsDebugger::stop(SimInstruction* instr) {
    597  // Get the stop code.
    598  uint32_t code = instr->bits(25, 6);
    599  // Retrieve the encoded address, which comes just after this stop.
    600  char* msg =
    601      *reinterpret_cast<char**>(sim_->get_pc() + SimInstruction::kInstrSize);
    602  // Update this stop description.
    603  if (!sim_->watchedStops_[code].desc_) {
    604    sim_->watchedStops_[code].desc_ = msg;
    605  }
    606  // Print the stop message and code if it is not the default code.
    607  if (code != kMaxStopCode) {
    608    printf("Simulator hit stop %u: %s\n", code, msg);
    609  } else {
    610    printf("Simulator hit %s\n", msg);
    611  }
    612  sim_->set_pc(sim_->get_pc() + 2 * SimInstruction::kInstrSize);
    613  debug();
    614 }
    615 
    616 int64_t MipsDebugger::getRegisterValue(int regnum) {
    617  if (regnum == kPCRegister) {
    618    return sim_->get_pc();
    619  }
    620  return sim_->getRegister(regnum);
    621 }
    622 
    623 int64_t MipsDebugger::getFPURegisterValueLong(int regnum) {
    624  return sim_->getFpuRegister(regnum);
    625 }
    626 
    627 float MipsDebugger::getFPURegisterValueFloat(int regnum) {
    628  return sim_->getFpuRegisterFloat(regnum);
    629 }
    630 
    631 double MipsDebugger::getFPURegisterValueDouble(int regnum) {
    632  return sim_->getFpuRegisterDouble(regnum);
    633 }
    634 
    635 bool MipsDebugger::getValue(const char* desc, int64_t* value) {
    636  Register reg = Register::FromName(desc);
    637  if (reg != InvalidReg) {
    638    *value = getRegisterValue(reg.code());
    639    return true;
    640  }
    641 
    642  if (strncmp(desc, "0x", 2) == 0) {
    643    return sscanf(desc, "%" PRIu64, reinterpret_cast<uint64_t*>(value)) == 1;
    644  }
    645  return sscanf(desc, "%" PRIi64, value) == 1;
    646 }
    647 
    648 bool MipsDebugger::setBreakpoint(SimInstruction* breakpc) {
    649  // Check if a breakpoint can be set. If not return without any side-effects.
    650  if (sim_->break_pc_ != nullptr) {
    651    return false;
    652  }
    653 
    654  // Set the breakpoint.
    655  sim_->break_pc_ = breakpc;
    656  sim_->break_instr_ = breakpc->instructionBits();
    657  // Not setting the breakpoint instruction in the code itself. It will be set
    658  // when the debugger shell continues.
    659  return true;
    660 }
    661 
    662 bool MipsDebugger::deleteBreakpoint(SimInstruction* breakpc) {
    663  if (sim_->break_pc_ != nullptr) {
    664    sim_->break_pc_->setInstructionBits(sim_->break_instr_);
    665  }
    666 
    667  sim_->break_pc_ = nullptr;
    668  sim_->break_instr_ = 0;
    669  return true;
    670 }
    671 
    672 void MipsDebugger::undoBreakpoints() {
    673  if (sim_->break_pc_) {
    674    sim_->break_pc_->setInstructionBits(sim_->break_instr_);
    675  }
    676 }
    677 
    678 void MipsDebugger::redoBreakpoints() {
    679  if (sim_->break_pc_) {
    680    sim_->break_pc_->setInstructionBits(kBreakpointInstr);
    681  }
    682 }
    683 
    684 void MipsDebugger::printAllRegs() {
    685  int64_t value;
    686  for (uint32_t i = 0; i < Registers::Total; i++) {
    687    value = getRegisterValue(i);
    688    printf("%3s: 0x%016" PRIx64 " %20" PRIi64 "   ", Registers::GetName(i),
    689           value, value);
    690 
    691    if (i % 2) {
    692      printf("\n");
    693    }
    694  }
    695  printf("\n");
    696 
    697  value = getRegisterValue(Simulator::LO);
    698  printf(" LO: 0x%016" PRIx64 " %20" PRIi64 "   ", value, value);
    699  value = getRegisterValue(Simulator::HI);
    700  printf(" HI: 0x%016" PRIx64 " %20" PRIi64 "\n", value, value);
    701  value = getRegisterValue(Simulator::pc);
    702  printf(" pc: 0x%016" PRIx64 "\n", value);
    703 }
    704 
    705 void MipsDebugger::printAllRegsIncludingFPU() {
    706  printAllRegs();
    707 
    708  printf("\n\n");
    709  // f0, f1, f2, ... f31.
    710  for (uint32_t i = 0; i < FloatRegisters::TotalPhys; i++) {
    711    printf("%3s: 0x%016" PRIi64 "\tflt: %-8.4g\tdbl: %-16.4g\n",
    712           FloatRegisters::GetName(i), getFPURegisterValueLong(i),
    713           getFPURegisterValueFloat(i), getFPURegisterValueDouble(i));
    714  }
    715 }
    716 
    717 static char* ReadLine(const char* prompt) {
    718  UniqueChars result;
    719  char lineBuf[256];
    720  int offset = 0;
    721  bool keepGoing = true;
    722  fprintf(stdout, "%s", prompt);
    723  fflush(stdout);
    724  while (keepGoing) {
    725    if (fgets(lineBuf, sizeof(lineBuf), stdin) == nullptr) {
    726      // fgets got an error. Just give up.
    727      return nullptr;
    728    }
    729    int len = strlen(lineBuf);
    730    if (len > 0 && lineBuf[len - 1] == '\n') {
    731      // Since we read a new line we are done reading the line. This
    732      // will exit the loop after copying this buffer into the result.
    733      keepGoing = false;
    734    }
    735    if (!result) {
    736      // Allocate the initial result and make room for the terminating '\0'
    737      result.reset(js_pod_malloc<char>(len + 1));
    738      if (!result) {
    739        return nullptr;
    740      }
    741    } else {
    742      // Allocate a new result with enough room for the new addition.
    743      int new_len = offset + len + 1;
    744      char* new_result = js_pod_malloc<char>(new_len);
    745      if (!new_result) {
    746        return nullptr;
    747      }
    748      // Copy the existing input into the new array and set the new
    749      // array as the result.
    750      memcpy(new_result, result.get(), offset * sizeof(char));
    751      result.reset(new_result);
    752    }
    753    // Copy the newly read line into the result.
    754    memcpy(result.get() + offset, lineBuf, len * sizeof(char));
    755    offset += len;
    756  }
    757 
    758  MOZ_ASSERT(result);
    759  result[offset] = '\0';
    760  return result.release();
    761 }
    762 
    763 static void DisassembleInstruction(uint64_t pc) {
    764  uint8_t* bytes = reinterpret_cast<uint8_t*>(pc);
    765  char hexbytes[256];
    766  sprintf(hexbytes, "0x%x 0x%x 0x%x 0x%x", bytes[0], bytes[1], bytes[2],
    767          bytes[3]);
    768  char llvmcmd[1024];
    769  sprintf(llvmcmd,
    770          "bash -c \"echo -n '%p'; echo '%s' | "
    771          "llvm-mc -disassemble -arch=mips64el -mcpu=mips64r2 | "
    772          "grep -v pure_instructions | grep -v .text\"",
    773          static_cast<void*>(bytes), hexbytes);
    774  if (system(llvmcmd)) {
    775    printf("Cannot disassemble instruction.\n");
    776  }
    777 }
    778 
    779 void MipsDebugger::debug() {
    780  intptr_t lastPC = -1;
    781  bool done = false;
    782 
    783 #define COMMAND_SIZE 63
    784 #define ARG_SIZE 255
    785 
    786 #define STR(a) #a
    787 #define XSTR(a) STR(a)
    788 
    789  char cmd[COMMAND_SIZE + 1];
    790  char arg1[ARG_SIZE + 1];
    791  char arg2[ARG_SIZE + 1];
    792  char* argv[3] = {cmd, arg1, arg2};
    793 
    794  // Make sure to have a proper terminating character if reaching the limit.
    795  cmd[COMMAND_SIZE] = 0;
    796  arg1[ARG_SIZE] = 0;
    797  arg2[ARG_SIZE] = 0;
    798 
    799  // Undo all set breakpoints while running in the debugger shell. This will
    800  // make them invisible to all commands.
    801  undoBreakpoints();
    802 
    803  while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
    804    if (lastPC != sim_->get_pc()) {
    805      DisassembleInstruction(sim_->get_pc());
    806      lastPC = sim_->get_pc();
    807    }
    808    char* line = ReadLine("sim> ");
    809    if (line == nullptr) {
    810      break;
    811    } else {
    812      char* last_input = sim_->lastDebuggerInput();
    813      if (strcmp(line, "\n") == 0 && last_input != nullptr) {
    814        line = last_input;
    815      } else {
    816        // Ownership is transferred to sim_;
    817        sim_->setLastDebuggerInput(line);
    818      }
    819      // Use sscanf to parse the individual parts of the command line. At the
    820      // moment no command expects more than two parameters.
    821      int argc = sscanf(line,
    822                              "%" XSTR(COMMAND_SIZE) "s "
    823                              "%" XSTR(ARG_SIZE) "s "
    824                              "%" XSTR(ARG_SIZE) "s",
    825                              cmd, arg1, arg2);
    826      if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
    827        SimInstruction* instr =
    828            reinterpret_cast<SimInstruction*>(sim_->get_pc());
    829        if (!instr->isTrap()) {
    830          sim_->instructionDecode(
    831              reinterpret_cast<SimInstruction*>(sim_->get_pc()));
    832        } else {
    833          // Allow si to jump over generated breakpoints.
    834          printf("/!\\ Jumping over generated breakpoint.\n");
    835          sim_->set_pc(sim_->get_pc() + SimInstruction::kInstrSize);
    836        }
    837      } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
    838        // Execute the one instruction we broke at with breakpoints disabled.
    839        sim_->instructionDecode(
    840            reinterpret_cast<SimInstruction*>(sim_->get_pc()));
    841        // Leave the debugger shell.
    842        done = true;
    843      } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
    844        if (argc == 2) {
    845          int64_t value;
    846          if (strcmp(arg1, "all") == 0) {
    847            printAllRegs();
    848          } else if (strcmp(arg1, "allf") == 0) {
    849            printAllRegsIncludingFPU();
    850          } else {
    851            Register reg = Register::FromName(arg1);
    852            FloatRegisters::Encoding fReg = FloatRegisters::FromName(arg1);
    853            if (reg != InvalidReg) {
    854              value = getRegisterValue(reg.code());
    855              printf("%s: 0x%016" PRIi64 " %20" PRIi64 " \n", arg1, value,
    856                     value);
    857            } else if (fReg != FloatRegisters::Invalid) {
    858              printf("%3s: 0x%016" PRIi64 "\tflt: %-8.4g\tdbl: %-16.4g\n",
    859                     FloatRegisters::GetName(fReg),
    860                     getFPURegisterValueLong(fReg),
    861                     getFPURegisterValueFloat(fReg),
    862                     getFPURegisterValueDouble(fReg));
    863            } else {
    864              printf("%s unrecognized\n", arg1);
    865            }
    866          }
    867        } else {
    868          printf("print <register> or print <fpu register> single\n");
    869        }
    870      } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
    871        int64_t* cur = nullptr;
    872        int64_t* end = nullptr;
    873        int next_arg = 1;
    874 
    875        if (strcmp(cmd, "stack") == 0) {
    876          cur = reinterpret_cast<int64_t*>(sim_->getRegister(Simulator::sp));
    877        } else {  // Command "mem".
    878          int64_t value;
    879          if (!getValue(arg1, &value)) {
    880            printf("%s unrecognized\n", arg1);
    881            continue;
    882          }
    883          cur = reinterpret_cast<int64_t*>(value);
    884          next_arg++;
    885        }
    886 
    887        int64_t words;
    888        if (argc == next_arg) {
    889          words = 10;
    890        } else {
    891          if (!getValue(argv[next_arg], &words)) {
    892            words = 10;
    893          }
    894        }
    895        end = cur + words;
    896 
    897        while (cur < end) {
    898          printf("  %p:  0x%016" PRIx64 " %20" PRIi64, cur, *cur, *cur);
    899          printf("\n");
    900          cur++;
    901        }
    902 
    903      } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0) ||
    904                 (strcmp(cmd, "di") == 0)) {
    905        uint8_t* cur = nullptr;
    906        uint8_t* end = nullptr;
    907 
    908        if (argc == 1) {
    909          cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
    910          end = cur + (10 * SimInstruction::kInstrSize);
    911        } else if (argc == 2) {
    912          Register reg = Register::FromName(arg1);
    913          if (reg != InvalidReg || strncmp(arg1, "0x", 2) == 0) {
    914            // The argument is an address or a register name.
    915            int64_t value;
    916            if (getValue(arg1, &value)) {
    917              cur = reinterpret_cast<uint8_t*>(value);
    918              // Disassemble 10 instructions at <arg1>.
    919              end = cur + (10 * SimInstruction::kInstrSize);
    920            }
    921          } else {
    922            // The argument is the number of instructions.
    923            int64_t value;
    924            if (getValue(arg1, &value)) {
    925              cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
    926              // Disassemble <arg1> instructions.
    927              end = cur + (value * SimInstruction::kInstrSize);
    928            }
    929          }
    930        } else {
    931          int64_t value1;
    932          int64_t value2;
    933          if (getValue(arg1, &value1) && getValue(arg2, &value2)) {
    934            cur = reinterpret_cast<uint8_t*>(value1);
    935            end = cur + (value2 * SimInstruction::kInstrSize);
    936          }
    937        }
    938 
    939        while (cur < end) {
    940          DisassembleInstruction(uint64_t(cur));
    941          cur += SimInstruction::kInstrSize;
    942        }
    943      } else if (strcmp(cmd, "gdb") == 0) {
    944        printf("relinquishing control to gdb\n");
    945 #if defined(__x86_64__)
    946        asm("int $3");
    947 #elif defined(__aarch64__)
    948        // see masm.breakpoint for arm64
    949        asm("brk #0xf000");
    950 #endif
    951        printf("regaining control from gdb\n");
    952      } else if (strcmp(cmd, "break") == 0) {
    953        if (argc == 2) {
    954          int64_t value;
    955          if (getValue(arg1, &value)) {
    956            if (!setBreakpoint(reinterpret_cast<SimInstruction*>(value))) {
    957              printf("setting breakpoint failed\n");
    958            }
    959          } else {
    960            printf("%s unrecognized\n", arg1);
    961          }
    962        } else {
    963          printf("break <address>\n");
    964        }
    965      } else if (strcmp(cmd, "del") == 0) {
    966        if (!deleteBreakpoint(nullptr)) {
    967          printf("deleting breakpoint failed\n");
    968        }
    969      } else if (strcmp(cmd, "flags") == 0) {
    970        printf("No flags on MIPS !\n");
    971      } else if (strcmp(cmd, "stop") == 0) {
    972        int64_t value;
    973        intptr_t stop_pc = sim_->get_pc() - 2 * SimInstruction::kInstrSize;
    974        SimInstruction* stop_instr = reinterpret_cast<SimInstruction*>(stop_pc);
    975        SimInstruction* msg_address = reinterpret_cast<SimInstruction*>(
    976            stop_pc + SimInstruction::kInstrSize);
    977        if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
    978          // Remove the current stop.
    979          if (sim_->isStopInstruction(stop_instr)) {
    980            stop_instr->setInstructionBits(kNopInstr);
    981            msg_address->setInstructionBits(kNopInstr);
    982          } else {
    983            printf("Not at debugger stop.\n");
    984          }
    985        } else if (argc == 3) {
    986          // Print information about all/the specified breakpoint(s).
    987          if (strcmp(arg1, "info") == 0) {
    988            if (strcmp(arg2, "all") == 0) {
    989              printf("Stop information:\n");
    990              for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
    991                   i++) {
    992                sim_->printStopInfo(i);
    993              }
    994            } else if (getValue(arg2, &value)) {
    995              sim_->printStopInfo(value);
    996            } else {
    997              printf("Unrecognized argument.\n");
    998            }
    999          } else if (strcmp(arg1, "enable") == 0) {
   1000            // Enable all/the specified breakpoint(s).
   1001            if (strcmp(arg2, "all") == 0) {
   1002              for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
   1003                   i++) {
   1004                sim_->enableStop(i);
   1005              }
   1006            } else if (getValue(arg2, &value)) {
   1007              sim_->enableStop(value);
   1008            } else {
   1009              printf("Unrecognized argument.\n");
   1010            }
   1011          } else if (strcmp(arg1, "disable") == 0) {
   1012            // Disable all/the specified breakpoint(s).
   1013            if (strcmp(arg2, "all") == 0) {
   1014              for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
   1015                   i++) {
   1016                sim_->disableStop(i);
   1017              }
   1018            } else if (getValue(arg2, &value)) {
   1019              sim_->disableStop(value);
   1020            } else {
   1021              printf("Unrecognized argument.\n");
   1022            }
   1023          }
   1024        } else {
   1025          printf("Wrong usage. Use help command for more information.\n");
   1026        }
   1027      } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
   1028        printf("cont\n");
   1029        printf("  continue execution (alias 'c')\n");
   1030        printf("stepi\n");
   1031        printf("  step one instruction (alias 'si')\n");
   1032        printf("print <register>\n");
   1033        printf("  print register content (alias 'p')\n");
   1034        printf("  use register name 'all' to print all registers\n");
   1035        printf("printobject <register>\n");
   1036        printf("  print an object from a register (alias 'po')\n");
   1037        printf("stack [<words>]\n");
   1038        printf("  dump stack content, default dump 10 words)\n");
   1039        printf("mem <address> [<words>]\n");
   1040        printf("  dump memory content, default dump 10 words)\n");
   1041        printf("flags\n");
   1042        printf("  print flags\n");
   1043        printf("disasm [<instructions>]\n");
   1044        printf("disasm [<address/register>]\n");
   1045        printf("disasm [[<address/register>] <instructions>]\n");
   1046        printf("  disassemble code, default is 10 instructions\n");
   1047        printf("  from pc (alias 'di')\n");
   1048        printf("gdb\n");
   1049        printf("  enter gdb\n");
   1050        printf("break <address>\n");
   1051        printf("  set a break point on the address\n");
   1052        printf("del\n");
   1053        printf("  delete the breakpoint\n");
   1054        printf("stop feature:\n");
   1055        printf("  Description:\n");
   1056        printf("    Stops are debug instructions inserted by\n");
   1057        printf("    the Assembler::stop() function.\n");
   1058        printf("    When hitting a stop, the Simulator will\n");
   1059        printf("    stop and and give control to the Debugger.\n");
   1060        printf("    All stop codes are watched:\n");
   1061        printf("    - They can be enabled / disabled: the Simulator\n");
   1062        printf("       will / won't stop when hitting them.\n");
   1063        printf("    - The Simulator keeps track of how many times they \n");
   1064        printf("      are met. (See the info command.) Going over a\n");
   1065        printf("      disabled stop still increases its counter. \n");
   1066        printf("  Commands:\n");
   1067        printf("    stop info all/<code> : print infos about number <code>\n");
   1068        printf("      or all stop(s).\n");
   1069        printf("    stop enable/disable all/<code> : enables / disables\n");
   1070        printf("      all or number <code> stop(s)\n");
   1071        printf("    stop unstop\n");
   1072        printf("      ignore the stop instruction at the current location\n");
   1073        printf("      from now on\n");
   1074      } else {
   1075        printf("Unknown command: %s\n", cmd);
   1076      }
   1077    }
   1078  }
   1079 
   1080  // Add all the breakpoints back to stop execution and enter the debugger
   1081  // shell when hit.
   1082  redoBreakpoints();
   1083 
   1084 #undef COMMAND_SIZE
   1085 #undef ARG_SIZE
   1086 
   1087 #undef STR
   1088 #undef XSTR
   1089 }
   1090 
   1091 static bool AllOnOnePage(uintptr_t start, int size) {
   1092  intptr_t start_page = (start & ~CachePage::kPageMask);
   1093  intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
   1094  return start_page == end_page;
   1095 }
   1096 
   1097 void Simulator::setLastDebuggerInput(char* input) {
   1098  js_free(lastDebuggerInput_);
   1099  lastDebuggerInput_ = input;
   1100 }
   1101 
   1102 static CachePage* GetCachePageLocked(SimulatorProcess::ICacheMap& i_cache,
   1103                                     void* page) {
   1104  SimulatorProcess::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
   1105  if (p) {
   1106    return p->value();
   1107  }
   1108  AutoEnterOOMUnsafeRegion oomUnsafe;
   1109  CachePage* new_page = js_new<CachePage>();
   1110  if (!new_page || !i_cache.add(p, page, new_page)) {
   1111    oomUnsafe.crash("Simulator CachePage");
   1112  }
   1113  return new_page;
   1114 }
   1115 
   1116 // Flush from start up to and not including start + size.
   1117 static void FlushOnePageLocked(SimulatorProcess::ICacheMap& i_cache,
   1118                               intptr_t start, int size) {
   1119  MOZ_ASSERT(size <= CachePage::kPageSize);
   1120  MOZ_ASSERT(AllOnOnePage(start, size - 1));
   1121  MOZ_ASSERT((start & CachePage::kLineMask) == 0);
   1122  MOZ_ASSERT((size & CachePage::kLineMask) == 0);
   1123  void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
   1124  int offset = (start & CachePage::kPageMask);
   1125  CachePage* cache_page = GetCachePageLocked(i_cache, page);
   1126  char* valid_bytemap = cache_page->validityByte(offset);
   1127  memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
   1128 }
   1129 
   1130 static void FlushICacheLocked(SimulatorProcess::ICacheMap& i_cache,
   1131                              void* start_addr, size_t size) {
   1132  intptr_t start = reinterpret_cast<intptr_t>(start_addr);
   1133  int intra_line = (start & CachePage::kLineMask);
   1134  start -= intra_line;
   1135  size += intra_line;
   1136  size = ((size - 1) | CachePage::kLineMask) + 1;
   1137  int offset = (start & CachePage::kPageMask);
   1138  while (!AllOnOnePage(start, size - 1)) {
   1139    int bytes_to_flush = CachePage::kPageSize - offset;
   1140    FlushOnePageLocked(i_cache, start, bytes_to_flush);
   1141    start += bytes_to_flush;
   1142    size -= bytes_to_flush;
   1143    MOZ_ASSERT((start & CachePage::kPageMask) == 0);
   1144    offset = 0;
   1145  }
   1146  if (size != 0) {
   1147    FlushOnePageLocked(i_cache, start, size);
   1148  }
   1149 }
   1150 
   1151 /* static */
   1152 void SimulatorProcess::checkICacheLocked(SimInstruction* instr) {
   1153  intptr_t address = reinterpret_cast<intptr_t>(instr);
   1154  void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
   1155  void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
   1156  int offset = (address & CachePage::kPageMask);
   1157  CachePage* cache_page = GetCachePageLocked(icache(), page);
   1158  char* cache_valid_byte = cache_page->validityByte(offset);
   1159  bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
   1160  char* cached_line = cache_page->cachedData(offset & ~CachePage::kLineMask);
   1161 
   1162  if (cache_hit) {
   1163 #ifdef DEBUG
   1164    // Check that the data in memory matches the contents of the I-cache.
   1165    int cmpret =
   1166        memcmp(reinterpret_cast<void*>(instr), cache_page->cachedData(offset),
   1167               SimInstruction::kInstrSize);
   1168    MOZ_ASSERT(cmpret == 0);
   1169 #endif
   1170  } else {
   1171    // Cache miss.  Load memory into the cache.
   1172    memcpy(cached_line, line, CachePage::kLineLength);
   1173    *cache_valid_byte = CachePage::LINE_VALID;
   1174  }
   1175 }
   1176 
   1177 HashNumber SimulatorProcess::ICacheHasher::hash(const Lookup& l) {
   1178  return U32(reinterpret_cast<uintptr_t>(l)) >> 2;
   1179 }
   1180 
   1181 bool SimulatorProcess::ICacheHasher::match(const Key& k, const Lookup& l) {
   1182  MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0);
   1183  MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0);
   1184  return k == l;
   1185 }
   1186 
   1187 /* static */
   1188 void SimulatorProcess::FlushICache(void* start_addr, size_t size) {
   1189  if (!ICacheCheckingDisableCount) {
   1190    AutoLockSimulatorCache als;
   1191    js::jit::FlushICacheLocked(icache(), start_addr, size);
   1192  }
   1193 }
   1194 
   1195 Simulator::Simulator() {
   1196  // Set up simulator support first. Some of this information is needed to
   1197  // setup the architecture state.
   1198 
   1199  // Note, allocation and anything that depends on allocated memory is
   1200  // deferred until init(), in order to handle OOM properly.
   1201 
   1202  stack_ = nullptr;
   1203  stackLimit_ = 0;
   1204  pc_modified_ = false;
   1205  icount_ = 0;
   1206  break_count_ = 0;
   1207  break_pc_ = nullptr;
   1208  break_instr_ = 0;
   1209  single_stepping_ = false;
   1210  single_step_callback_ = nullptr;
   1211  single_step_callback_arg_ = nullptr;
   1212 
   1213  // Set up architecture state.
   1214  // All registers are initialized to zero to start with.
   1215  for (int i = 0; i < Register::kNumSimuRegisters; i++) {
   1216    registers_[i] = 0;
   1217  }
   1218  for (int i = 0; i < Simulator::FPURegister::kNumFPURegisters; i++) {
   1219    FPUregisters_[i] = 0;
   1220  }
   1221  FCSR_ = 0;
   1222  LLBit_ = false;
   1223  LLAddr_ = 0;
   1224  lastLLValue_ = 0;
   1225 
   1226  // The ra and pc are initialized to a known bad value that will cause an
   1227  // access violation if the simulator ever tries to execute it.
   1228  registers_[pc] = bad_ra;
   1229  registers_[ra] = bad_ra;
   1230 
   1231  for (int i = 0; i < kNumExceptions; i++) {
   1232    exceptions[i] = 0;
   1233  }
   1234 
   1235  lastDebuggerInput_ = nullptr;
   1236 }
   1237 
   1238 bool Simulator::init() {
   1239  // Allocate 2MB for the stack. Note that we will only use 1MB, see below.
   1240  static const size_t stackSize = 2 * 1024 * 1024;
   1241  stack_ = js_pod_malloc<char>(stackSize);
   1242  if (!stack_) {
   1243    return false;
   1244  }
   1245 
   1246  // Leave a safety margin of 1MB to prevent overrunning the stack when
   1247  // pushing values (total stack size is 2MB).
   1248  stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
   1249 
   1250  // The sp is initialized to point to the bottom (high address) of the
   1251  // allocated stack area. To be safe in potential stack underflows we leave
   1252  // some buffer below.
   1253  registers_[sp] = reinterpret_cast<int64_t>(stack_) + stackSize - 64;
   1254 
   1255  return true;
   1256 }
   1257 
   1258 // When the generated code calls an external reference we need to catch that in
   1259 // the simulator.  The external reference will be a function compiled for the
   1260 // host architecture.  We need to call that function instead of trying to
   1261 // execute it with the simulator.  We do that by redirecting the external
   1262 // reference to a swi (software-interrupt) instruction that is handled by
   1263 // the simulator.  We write the original destination of the jump just at a known
   1264 // offset from the swi instruction so the simulator knows what to call.
   1265 class Redirection {
   1266  friend class SimulatorProcess;
   1267 
   1268  // sim's lock must already be held.
   1269  Redirection(void* nativeFunction, ABIFunctionType type)
   1270      : nativeFunction_(nativeFunction),
   1271        swiInstruction_(kCallRedirInstr),
   1272        type_(type),
   1273        next_(nullptr) {
   1274    next_ = SimulatorProcess::redirection();
   1275    if (!SimulatorProcess::ICacheCheckingDisableCount) {
   1276      FlushICacheLocked(SimulatorProcess::icache(), addressOfSwiInstruction(),
   1277                        SimInstruction::kInstrSize);
   1278    }
   1279    SimulatorProcess::setRedirection(this);
   1280  }
   1281 
   1282 public:
   1283  void* addressOfSwiInstruction() { return &swiInstruction_; }
   1284  void* nativeFunction() const { return nativeFunction_; }
   1285  ABIFunctionType type() const { return type_; }
   1286 
   1287  static Redirection* Get(void* nativeFunction, ABIFunctionType type) {
   1288    AutoLockSimulatorCache als;
   1289 
   1290    Redirection* current = SimulatorProcess::redirection();
   1291    for (; current != nullptr; current = current->next_) {
   1292      if (current->nativeFunction_ == nativeFunction) {
   1293        MOZ_ASSERT(current->type() == type);
   1294        return current;
   1295      }
   1296    }
   1297 
   1298    // Note: we can't use js_new here because the constructor is private.
   1299    AutoEnterOOMUnsafeRegion oomUnsafe;
   1300    Redirection* redir = js_pod_malloc<Redirection>(1);
   1301    if (!redir) {
   1302      oomUnsafe.crash("Simulator redirection");
   1303    }
   1304    new (redir) Redirection(nativeFunction, type);
   1305    return redir;
   1306  }
   1307 
   1308  static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) {
   1309    uint8_t* addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction);
   1310    uint8_t* addrOfRedirection =
   1311        addrOfSwi - offsetof(Redirection, swiInstruction_);
   1312    return reinterpret_cast<Redirection*>(addrOfRedirection);
   1313  }
   1314 
   1315 private:
   1316  void* nativeFunction_;
   1317  uint32_t swiInstruction_;
   1318  ABIFunctionType type_;
   1319  Redirection* next_;
   1320 };
   1321 
   1322 Simulator::~Simulator() { js_free(stack_); }
   1323 
   1324 SimulatorProcess::SimulatorProcess()
   1325    : cacheLock_(mutexid::SimulatorCacheLock), redirection_(nullptr) {
   1326  if (getenv("MIPS_SIM_ICACHE_CHECKS")) {
   1327    ICacheCheckingDisableCount = 0;
   1328  }
   1329 }
   1330 
   1331 SimulatorProcess::~SimulatorProcess() {
   1332  Redirection* r = redirection_;
   1333  while (r) {
   1334    Redirection* next = r->next_;
   1335    js_delete(r);
   1336    r = next;
   1337  }
   1338 }
   1339 
   1340 /* static */
   1341 void* Simulator::RedirectNativeFunction(void* nativeFunction,
   1342                                        ABIFunctionType type) {
   1343  Redirection* redirection = Redirection::Get(nativeFunction, type);
   1344  return redirection->addressOfSwiInstruction();
   1345 }
   1346 
   1347 // Get the active Simulator for the current thread.
   1348 Simulator* Simulator::Current() {
   1349  JSContext* cx = TlsContext.get();
   1350  MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
   1351  return cx->simulator();
   1352 }
   1353 
   1354 // Sets the register in the architecture state. It will also deal with updating
   1355 // Simulator internal state for special registers such as PC.
   1356 void Simulator::setRegister(int reg, int64_t value) {
   1357  MOZ_ASSERT((reg >= 0) && (reg < Register::kNumSimuRegisters));
   1358  if (reg == pc) {
   1359    pc_modified_ = true;
   1360  }
   1361 
   1362  // Zero register always holds 0.
   1363  registers_[reg] = (reg == 0) ? 0 : value;
   1364 }
   1365 
   1366 void Simulator::setFpuRegister(int fpureg, int64_t value) {
   1367  MOZ_ASSERT((fpureg >= 0) &&
   1368             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1369  FPUregisters_[fpureg] = value;
   1370 }
   1371 
   1372 void Simulator::setFpuRegisterLo(int fpureg, int32_t value) {
   1373  MOZ_ASSERT((fpureg >= 0) &&
   1374             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1375  *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]) = value;
   1376 }
   1377 
   1378 void Simulator::setFpuRegisterHi(int fpureg, int32_t value) {
   1379  MOZ_ASSERT((fpureg >= 0) &&
   1380             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1381  *((mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg])) + 1) = value;
   1382 }
   1383 
   1384 void Simulator::setFpuRegisterFloat(int fpureg, float value) {
   1385  MOZ_ASSERT((fpureg >= 0) &&
   1386             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1387  *mozilla::BitwiseCast<float*>(&FPUregisters_[fpureg]) = value;
   1388 }
   1389 
   1390 void Simulator::setFpuRegisterDouble(int fpureg, double value) {
   1391  MOZ_ASSERT((fpureg >= 0) &&
   1392             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1393  *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]) = value;
   1394 }
   1395 
   1396 // Get the register from the architecture state. This function does handle
   1397 // the special case of accessing the PC register.
   1398 int64_t Simulator::getRegister(int reg) const {
   1399  MOZ_ASSERT((reg >= 0) && (reg < Register::kNumSimuRegisters));
   1400  if (reg == 0) {
   1401    return 0;
   1402  }
   1403  return registers_[reg] + ((reg == pc) ? SimInstruction::kPCReadOffset : 0);
   1404 }
   1405 
   1406 int64_t Simulator::getFpuRegister(int fpureg) const {
   1407  MOZ_ASSERT((fpureg >= 0) &&
   1408             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1409  return FPUregisters_[fpureg];
   1410 }
   1411 
   1412 int32_t Simulator::getFpuRegisterLo(int fpureg) const {
   1413  MOZ_ASSERT((fpureg >= 0) &&
   1414             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1415  return *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]);
   1416 }
   1417 
   1418 int32_t Simulator::getFpuRegisterHi(int fpureg) const {
   1419  MOZ_ASSERT((fpureg >= 0) &&
   1420             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1421  return *((mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg])) + 1);
   1422 }
   1423 
   1424 float Simulator::getFpuRegisterFloat(int fpureg) const {
   1425  MOZ_ASSERT((fpureg >= 0) &&
   1426             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1427  return *mozilla::BitwiseCast<float*>(&FPUregisters_[fpureg]);
   1428 }
   1429 
   1430 double Simulator::getFpuRegisterDouble(int fpureg) const {
   1431  MOZ_ASSERT((fpureg >= 0) &&
   1432             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1433  return *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]);
   1434 }
   1435 
   1436 void Simulator::setCallResultDouble(double result) {
   1437  setFpuRegisterDouble(f0, result);
   1438 }
   1439 
   1440 void Simulator::setCallResultFloat(float result) {
   1441  setFpuRegisterFloat(f0, result);
   1442 }
   1443 
   1444 void Simulator::setCallResult(int64_t res) { setRegister(v0, res); }
   1445 #ifdef XP_DARWIN
   1446 // add a dedicated setCallResult for intptr_t on Darwin
   1447 void Simulator::setCallResult(intptr_t res) { setRegister(v0, I64(res)); }
   1448 #endif
   1449 void Simulator::setCallResult(__int128_t res) {
   1450  setRegister(v0, I64(res));
   1451  setRegister(v1, I64(res >> 64));
   1452 }
   1453 
   1454 // Helper functions for setting and testing the FCSR register's bits.
   1455 void Simulator::setFCSRBit(uint32_t cc, bool value) {
   1456  if (value) {
   1457    FCSR_ |= (1 << cc);
   1458  } else {
   1459    FCSR_ &= ~(1 << cc);
   1460  }
   1461 }
   1462 
   1463 bool Simulator::testFCSRBit(uint32_t cc) { return FCSR_ & (1 << cc); }
   1464 
   1465 // Sets the rounding error codes in FCSR based on the result of the rounding.
   1466 // Returns true if the operation was invalid.
   1467 template <typename T>
   1468 bool Simulator::setFCSRRoundError(double original, double rounded) {
   1469  bool ret = false;
   1470 
   1471  setFCSRBit(kFCSRInexactCauseBit, false);
   1472  setFCSRBit(kFCSRUnderflowCauseBit, false);
   1473  setFCSRBit(kFCSROverflowCauseBit, false);
   1474  setFCSRBit(kFCSRInvalidOpCauseBit, false);
   1475 
   1476  if (!std::isfinite(original) || !std::isfinite(rounded)) {
   1477    setFCSRBit(kFCSRInvalidOpFlagBit, true);
   1478    setFCSRBit(kFCSRInvalidOpCauseBit, true);
   1479    ret = true;
   1480  }
   1481 
   1482  if (original != rounded) {
   1483    setFCSRBit(kFCSRInexactFlagBit, true);
   1484    setFCSRBit(kFCSRInexactCauseBit, true);
   1485  }
   1486 
   1487  if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
   1488    setFCSRBit(kFCSRUnderflowFlagBit, true);
   1489    setFCSRBit(kFCSRUnderflowCauseBit, true);
   1490    ret = true;
   1491  }
   1492 
   1493  if ((long double)rounded > (long double)std::numeric_limits<T>::max() ||
   1494      (long double)rounded < (long double)std::numeric_limits<T>::min()) {
   1495    setFCSRBit(kFCSROverflowFlagBit, true);
   1496    setFCSRBit(kFCSROverflowCauseBit, true);
   1497    // The reference is not really clear but it seems this is required:
   1498    setFCSRBit(kFCSRInvalidOpFlagBit, true);
   1499    setFCSRBit(kFCSRInvalidOpCauseBit, true);
   1500    ret = true;
   1501  }
   1502 
   1503  return ret;
   1504 }
   1505 
   1506 // Raw access to the PC register.
   1507 void Simulator::set_pc(int64_t value) {
   1508  pc_modified_ = true;
   1509  registers_[pc] = value;
   1510 }
   1511 
   1512 bool Simulator::has_bad_pc() const {
   1513  return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
   1514 }
   1515 
   1516 // Raw access to the PC register without the special adjustment when reading.
   1517 int64_t Simulator::get_pc() const { return registers_[pc]; }
   1518 
   1519 JS::ProfilingFrameIterator::RegisterState Simulator::registerState() {
   1520  wasm::RegisterState state;
   1521  state.pc = (void*)get_pc();
   1522  state.fp = (void*)getRegister(fp);
   1523  state.sp = (void*)getRegister(sp);
   1524  state.lr = (void*)getRegister(ra);
   1525  return state;
   1526 }
   1527 
   1528 static bool AllowUnaligned() {
   1529  static bool hasReadFlag = false;
   1530  static bool unalignedAllowedFlag = false;
   1531  if (!hasReadFlag) {
   1532    unalignedAllowedFlag = !!getenv("MIPS_UNALIGNED");
   1533    hasReadFlag = true;
   1534  }
   1535  return unalignedAllowedFlag;
   1536 }
   1537 
   1538 // MIPS memory instructions (except lw(d)l/r , sw(d)l/r) trap on unaligned
   1539 // memory access enabling the OS to handle them via trap-and-emulate. Note that
   1540 // simulator runs have the runtime system running directly on the host system
   1541 // and only generated code is executed in the simulator. Since the host is
   1542 // typically IA32 it will not trap on unaligned memory access. We assume that
   1543 // that executing correct generated code will not produce unaligned memory
   1544 // access, so we explicitly check for address alignment and trap. Note that
   1545 // trapping does not occur when executing wasm code, which requires that
   1546 // unaligned memory access provides correct result.
   1547 
   1548 uint8_t Simulator::readBU(uint64_t addr, SimInstruction* instr) {
   1549  if (handleWasmSegFault(addr, 1)) {
   1550    return 0xff;
   1551  }
   1552 
   1553  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
   1554  return *ptr;
   1555 }
   1556 
   1557 int8_t Simulator::readB(uint64_t addr, SimInstruction* instr) {
   1558  if (handleWasmSegFault(addr, 1)) {
   1559    return -1;
   1560  }
   1561 
   1562  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
   1563  return *ptr;
   1564 }
   1565 
   1566 void Simulator::writeB(uint64_t addr, uint8_t value, SimInstruction* instr) {
   1567  if (handleWasmSegFault(addr, 1)) {
   1568    return;
   1569  }
   1570 
   1571  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
   1572  *ptr = value;
   1573 }
   1574 
   1575 void Simulator::writeB(uint64_t addr, int8_t value, SimInstruction* instr) {
   1576  if (handleWasmSegFault(addr, 1)) {
   1577    return;
   1578  }
   1579 
   1580  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
   1581  *ptr = value;
   1582 }
   1583 
   1584 uint16_t Simulator::readHU(uint64_t addr, SimInstruction* instr) {
   1585  if (handleWasmSegFault(addr, 2)) {
   1586    return 0xffff;
   1587  }
   1588 
   1589  if (AllowUnaligned() || (addr & 1) == 0 ||
   1590      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1591    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
   1592    return *ptr;
   1593  }
   1594  printf("Unaligned unsigned halfword read at 0x%016" PRIx64
   1595         ", pc=0x%016" PRIxPTR "\n",
   1596         addr, reinterpret_cast<intptr_t>(instr));
   1597  MOZ_CRASH();
   1598  return 0;
   1599 }
   1600 
   1601 int16_t Simulator::readH(uint64_t addr, SimInstruction* instr) {
   1602  if (handleWasmSegFault(addr, 2)) {
   1603    return -1;
   1604  }
   1605 
   1606  if (AllowUnaligned() || (addr & 1) == 0 ||
   1607      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1608    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
   1609    return *ptr;
   1610  }
   1611  printf("Unaligned signed halfword read at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR
   1612         "\n",
   1613         addr, reinterpret_cast<intptr_t>(instr));
   1614  MOZ_CRASH();
   1615  return 0;
   1616 }
   1617 
   1618 void Simulator::writeH(uint64_t addr, uint16_t value, SimInstruction* instr) {
   1619  if (handleWasmSegFault(addr, 2)) {
   1620    return;
   1621  }
   1622 
   1623  if (AllowUnaligned() || (addr & 1) == 0 ||
   1624      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1625    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
   1626    LLBit_ = false;
   1627    *ptr = value;
   1628    return;
   1629  }
   1630  printf("Unaligned unsigned halfword write at 0x%016" PRIx64
   1631         ", pc=0x%016" PRIxPTR "\n",
   1632         addr, reinterpret_cast<intptr_t>(instr));
   1633  MOZ_CRASH();
   1634 }
   1635 
   1636 void Simulator::writeH(uint64_t addr, int16_t value, SimInstruction* instr) {
   1637  if (handleWasmSegFault(addr, 2)) {
   1638    return;
   1639  }
   1640 
   1641  if (AllowUnaligned() || (addr & 1) == 0 ||
   1642      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1643    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
   1644    LLBit_ = false;
   1645    *ptr = value;
   1646    return;
   1647  }
   1648  printf("Unaligned halfword write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n",
   1649         addr, reinterpret_cast<intptr_t>(instr));
   1650  MOZ_CRASH();
   1651 }
   1652 
   1653 uint32_t Simulator::readWU(uint64_t addr, SimInstruction* instr) {
   1654  if (handleWasmSegFault(addr, 4)) {
   1655    return -1;
   1656  }
   1657 
   1658  if (AllowUnaligned() || (addr & 3) == 0 ||
   1659      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1660    uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
   1661    return *ptr;
   1662  }
   1663  printf("Unaligned read at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   1664         reinterpret_cast<intptr_t>(instr));
   1665  MOZ_CRASH();
   1666  return 0;
   1667 }
   1668 
   1669 int32_t Simulator::readW(uint64_t addr, SimInstruction* instr) {
   1670  if (handleWasmSegFault(addr, 4)) {
   1671    return -1;
   1672  }
   1673 
   1674  if (AllowUnaligned() || (addr & 3) == 0 ||
   1675      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1676    int32_t* ptr = reinterpret_cast<int32_t*>(addr);
   1677    return *ptr;
   1678  }
   1679  printf("Unaligned read at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   1680         reinterpret_cast<intptr_t>(instr));
   1681  MOZ_CRASH();
   1682  return 0;
   1683 }
   1684 
   1685 void Simulator::writeW(uint64_t addr, uint32_t value, SimInstruction* instr) {
   1686  if (handleWasmSegFault(addr, 4)) {
   1687    return;
   1688  }
   1689 
   1690  if (AllowUnaligned() || (addr & 3) == 0 ||
   1691      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1692    uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
   1693    LLBit_ = false;
   1694    *ptr = value;
   1695    return;
   1696  }
   1697  printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   1698         reinterpret_cast<intptr_t>(instr));
   1699  MOZ_CRASH();
   1700 }
   1701 
   1702 void Simulator::writeW(uint64_t addr, int32_t value, SimInstruction* instr) {
   1703  if (handleWasmSegFault(addr, 4)) {
   1704    return;
   1705  }
   1706 
   1707  if (AllowUnaligned() || (addr & 3) == 0 ||
   1708      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1709    int32_t* ptr = reinterpret_cast<int32_t*>(addr);
   1710    LLBit_ = false;
   1711    *ptr = value;
   1712    return;
   1713  }
   1714  printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   1715         reinterpret_cast<intptr_t>(instr));
   1716  MOZ_CRASH();
   1717 }
   1718 
   1719 int64_t Simulator::readDW(uint64_t addr, SimInstruction* instr) {
   1720  if (handleWasmSegFault(addr, 8)) {
   1721    return -1;
   1722  }
   1723 
   1724  if (AllowUnaligned() || (addr & kPointerAlignmentMask) == 0 ||
   1725      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1726    intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
   1727    return *ptr;
   1728  }
   1729  printf("Unaligned read at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   1730         reinterpret_cast<intptr_t>(instr));
   1731  MOZ_CRASH();
   1732  return 0;
   1733 }
   1734 
   1735 void Simulator::writeDW(uint64_t addr, int64_t value, SimInstruction* instr) {
   1736  if (handleWasmSegFault(addr, 8)) {
   1737    return;
   1738  }
   1739 
   1740  if (AllowUnaligned() || (addr & kPointerAlignmentMask) == 0 ||
   1741      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1742    int64_t* ptr = reinterpret_cast<int64_t*>(addr);
   1743    LLBit_ = false;
   1744    *ptr = value;
   1745    return;
   1746  }
   1747  printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   1748         reinterpret_cast<intptr_t>(instr));
   1749  MOZ_CRASH();
   1750 }
   1751 
   1752 double Simulator::readD(uint64_t addr, SimInstruction* instr) {
   1753  if (handleWasmSegFault(addr, 8)) {
   1754    return NAN;
   1755  }
   1756 
   1757  if (AllowUnaligned() || (addr & kDoubleAlignmentMask) == 0 ||
   1758      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1759    double* ptr = reinterpret_cast<double*>(addr);
   1760    return *ptr;
   1761  }
   1762  printf("Unaligned (double) read at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n",
   1763         addr, reinterpret_cast<intptr_t>(instr));
   1764  MOZ_CRASH();
   1765  return 0;
   1766 }
   1767 
   1768 void Simulator::writeD(uint64_t addr, double value, SimInstruction* instr) {
   1769  if (handleWasmSegFault(addr, 8)) {
   1770    return;
   1771  }
   1772 
   1773  if (AllowUnaligned() || (addr & kDoubleAlignmentMask) == 0 ||
   1774      wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) {
   1775    double* ptr = reinterpret_cast<double*>(addr);
   1776    LLBit_ = false;
   1777    *ptr = value;
   1778    return;
   1779  }
   1780  printf("Unaligned (double) write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n",
   1781         addr, reinterpret_cast<intptr_t>(instr));
   1782  MOZ_CRASH();
   1783 }
   1784 
   1785 int Simulator::loadLinkedW(uint64_t addr, SimInstruction* instr) {
   1786  if ((addr & 3) == 0) {
   1787    if (handleWasmSegFault(addr, 4)) {
   1788      return -1;
   1789    }
   1790 
   1791    volatile int32_t* ptr = reinterpret_cast<volatile int32_t*>(addr);
   1792    int32_t value = *ptr;
   1793    lastLLValue_ = value;
   1794    LLAddr_ = addr;
   1795    // Note that any memory write or "external" interrupt should reset this
   1796    // value to false.
   1797    LLBit_ = true;
   1798    return value;
   1799  }
   1800  printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   1801         reinterpret_cast<intptr_t>(instr));
   1802  MOZ_CRASH();
   1803  return 0;
   1804 }
   1805 
   1806 int Simulator::storeConditionalW(uint64_t addr, int value,
   1807                                 SimInstruction* instr) {
   1808  // Correct behavior in this case, as defined by architecture, is to just
   1809  // return 0, but there is no point at allowing that. It is certainly an
   1810  // indicator of a bug.
   1811  if (addr != LLAddr_) {
   1812    printf("SC to bad address: 0x%016" PRIx64 ", pc=0x%016" PRIxPTR
   1813           ", expected: 0x%016" PRIxPTR "\n",
   1814           addr, reinterpret_cast<intptr_t>(instr), LLAddr_);
   1815    MOZ_CRASH();
   1816  }
   1817 
   1818  if ((addr & 3) == 0) {
   1819    SharedMem<int32_t*> ptr =
   1820        SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr));
   1821 
   1822    if (!LLBit_) {
   1823      return 0;
   1824    }
   1825 
   1826    LLBit_ = false;
   1827    LLAddr_ = 0;
   1828    int32_t expected = int32_t(lastLLValue_);
   1829    int32_t old =
   1830        AtomicOperations::compareExchangeSeqCst(ptr, expected, int32_t(value));
   1831    return (old == expected) ? 1 : 0;
   1832  }
   1833  printf("Unaligned SC at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   1834         reinterpret_cast<intptr_t>(instr));
   1835  MOZ_CRASH();
   1836  return 0;
   1837 }
   1838 
   1839 int64_t Simulator::loadLinkedD(uint64_t addr, SimInstruction* instr) {
   1840  if ((addr & kPointerAlignmentMask) == 0) {
   1841    if (handleWasmSegFault(addr, 8)) {
   1842      return -1;
   1843    }
   1844 
   1845    volatile int64_t* ptr = reinterpret_cast<volatile int64_t*>(addr);
   1846    int64_t value = *ptr;
   1847    lastLLValue_ = value;
   1848    LLAddr_ = addr;
   1849    // Note that any memory write or "external" interrupt should reset this
   1850    // value to false.
   1851    LLBit_ = true;
   1852    return value;
   1853  }
   1854  printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   1855         reinterpret_cast<intptr_t>(instr));
   1856  MOZ_CRASH();
   1857  return 0;
   1858 }
   1859 
   1860 int Simulator::storeConditionalD(uint64_t addr, int64_t value,
   1861                                 SimInstruction* instr) {
   1862  // Correct behavior in this case, as defined by architecture, is to just
   1863  // return 0, but there is no point at allowing that. It is certainly an
   1864  // indicator of a bug.
   1865  if (addr != LLAddr_) {
   1866    printf("SC to bad address: 0x%016" PRIx64 ", pc=0x%016" PRIxPTR
   1867           ", expected: 0x%016" PRIxPTR "\n",
   1868           addr, reinterpret_cast<intptr_t>(instr), LLAddr_);
   1869    MOZ_CRASH();
   1870  }
   1871 
   1872  if ((addr & kPointerAlignmentMask) == 0) {
   1873    SharedMem<int64_t*> ptr =
   1874        SharedMem<int64_t*>::shared(reinterpret_cast<int64_t*>(addr));
   1875 
   1876    if (!LLBit_) {
   1877      return 0;
   1878    }
   1879 
   1880    LLBit_ = false;
   1881    LLAddr_ = 0;
   1882    int64_t expected = lastLLValue_;
   1883    int64_t old =
   1884        AtomicOperations::compareExchangeSeqCst(ptr, expected, int64_t(value));
   1885    return (old == expected) ? 1 : 0;
   1886  }
   1887  printf("Unaligned SC at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   1888         reinterpret_cast<intptr_t>(instr));
   1889  MOZ_CRASH();
   1890  return 0;
   1891 }
   1892 
   1893 uintptr_t Simulator::stackLimit() const { return stackLimit_; }
   1894 
   1895 uintptr_t* Simulator::addressOfStackLimit() { return &stackLimit_; }
   1896 
   1897 bool Simulator::overRecursed(uintptr_t newsp) const {
   1898  if (newsp == 0) {
   1899    newsp = getRegister(sp);
   1900  }
   1901  return newsp <= stackLimit();
   1902 }
   1903 
   1904 bool Simulator::overRecursedWithExtra(uint32_t extra) const {
   1905  uintptr_t newsp = getRegister(sp) - extra;
   1906  return newsp <= stackLimit();
   1907 }
   1908 
   1909 // Unsupported instructions use format to print an error and stop execution.
   1910 void Simulator::format(SimInstruction* instr, const char* format) {
   1911  printf("Simulator found unsupported instruction:\n 0x%016lx: %s\n",
   1912         reinterpret_cast<intptr_t>(instr), format);
   1913  MOZ_CRASH();
   1914 }
   1915 
   1916 // Note: With the code below we assume that all runtime calls return a 64 bits
   1917 // result. If they don't, the v1 result register contains a bogus value, which
   1918 // is fine because it is caller-saved.
   1919 ABI_FUNCTION_TYPE_SIM_PROTOTYPES
   1920 
   1921 // Software interrupt instructions are used by the simulator to call into C++.
   1922 void Simulator::softwareInterrupt(SimInstruction* instr) {
   1923  int32_t func = instr->functionFieldRaw();
   1924  uint32_t code = (func == ff_break) ? instr->bits(25, 6) : -1;
   1925 
   1926  // We first check if we met a call_rt_redirected.
   1927  if (instr->instructionBits() == kCallRedirInstr) {
   1928    Redirection* redirection = Redirection::FromSwiInstruction(instr);
   1929    uintptr_t nativeFn =
   1930        reinterpret_cast<uintptr_t>(redirection->nativeFunction());
   1931 
   1932    // Get the SP for reading stack arguments
   1933    int64_t* sp_ = reinterpret_cast<int64_t*>(getRegister(sp));
   1934 
   1935    // Store argument register values in local variables for ease of use below.
   1936    int64_t a0_ = getRegister(a0);
   1937    int64_t a1_ = getRegister(a1);
   1938    int64_t a2_ = getRegister(a2);
   1939    int64_t a3_ = getRegister(a3);
   1940    int64_t a4_ = getRegister(a4);
   1941    int64_t a5_ = getRegister(a5);
   1942    int64_t a6_ = getRegister(a6);
   1943    int64_t a7_ = getRegister(a7);
   1944    float f12_s = getFpuRegisterFloat(f12);
   1945    float f13_s = getFpuRegisterFloat(f13);
   1946    float f14_s = getFpuRegisterFloat(f14);
   1947    float f15_s = getFpuRegisterFloat(f15);
   1948    float f16_s = getFpuRegisterFloat(f16);
   1949    float f17_s = getFpuRegisterFloat(f17);
   1950    float f18_s = getFpuRegisterFloat(f18);
   1951    double f12_d = getFpuRegisterDouble(f12);
   1952    double f13_d = getFpuRegisterDouble(f13);
   1953    double f14_d = getFpuRegisterDouble(f14);
   1954    double f15_d = getFpuRegisterDouble(f15);
   1955 
   1956    // This is dodgy but it works because the C entry stubs are never moved.
   1957    // See comment in codegen-arm.cc and bug 1242173.
   1958    int64_t saved_ra = getRegister(ra);
   1959 
   1960    bool stack_aligned = (getRegister(sp) & (ABIStackAlignment - 1)) == 0;
   1961    if (!stack_aligned) {
   1962      fprintf(stderr, "Runtime call with unaligned stack!\n");
   1963      MOZ_CRASH();
   1964    }
   1965 
   1966    if (single_stepping_) {
   1967      single_step_callback_(single_step_callback_arg_, this, nullptr);
   1968    }
   1969 
   1970    switch (redirection->type()) {
   1971      ABI_FUNCTION_TYPE_MIPS64_SIM_DISPATCH
   1972 
   1973      default:
   1974        MOZ_CRASH("Unknown function type.");
   1975    }
   1976 
   1977    if (single_stepping_) {
   1978      single_step_callback_(single_step_callback_arg_, this, nullptr);
   1979    }
   1980 
   1981    setRegister(ra, saved_ra);
   1982    set_pc(getRegister(ra));
   1983  } else if (func == ff_break && code <= kMaxStopCode) {
   1984    if (isWatchpoint(code)) {
   1985      printWatchpoint(code);
   1986    } else {
   1987      increaseStopCounter(code);
   1988      handleStop(code, instr);
   1989    }
   1990  } else {
   1991    switch (func) {
   1992      case ff_tge:
   1993      case ff_tgeu:
   1994      case ff_tlt:
   1995      case ff_tltu:
   1996      case ff_teq:
   1997      case ff_tne:
   1998        if (instr->bits(15, 6) == kWasmTrapCode) {
   1999          uint8_t* newPC;
   2000          if (wasm::HandleIllegalInstruction(registerState(), &newPC)) {
   2001            set_pc(int64_t(newPC));
   2002            return;
   2003          }
   2004        }
   2005    };
   2006    // All remaining break_ codes, and all traps are handled here.
   2007    MipsDebugger dbg(this);
   2008    dbg.debug();
   2009  }
   2010 }
   2011 
   2012 // Stop helper functions.
   2013 bool Simulator::isWatchpoint(uint32_t code) {
   2014  return (code <= kMaxWatchpointCode);
   2015 }
   2016 
   2017 void Simulator::printWatchpoint(uint32_t code) {
   2018  MipsDebugger dbg(this);
   2019  ++break_count_;
   2020  printf("\n---- break %d marker: %20" PRIi64 "  (instr count: %20" PRIi64
   2021         ") ----\n",
   2022         code, break_count_, icount_);
   2023  dbg.printAllRegs();  // Print registers and continue running.
   2024 }
   2025 
   2026 void Simulator::handleStop(uint32_t code, SimInstruction* instr) {
   2027  // Stop if it is enabled, otherwise go on jumping over the stop
   2028  // and the message address.
   2029  if (isEnabledStop(code)) {
   2030    MipsDebugger dbg(this);
   2031    dbg.stop(instr);
   2032  } else {
   2033    set_pc(get_pc() + 2 * SimInstruction::kInstrSize);
   2034  }
   2035 }
   2036 
   2037 bool Simulator::isStopInstruction(SimInstruction* instr) {
   2038  int32_t func = instr->functionFieldRaw();
   2039  uint32_t code = U32(instr->bits(25, 6));
   2040  return (func == ff_break) && code > kMaxWatchpointCode &&
   2041         code <= kMaxStopCode;
   2042 }
   2043 
   2044 bool Simulator::isEnabledStop(uint32_t code) {
   2045  MOZ_ASSERT(code <= kMaxStopCode);
   2046  MOZ_ASSERT(code > kMaxWatchpointCode);
   2047  return !(watchedStops_[code].count_ & kStopDisabledBit);
   2048 }
   2049 
   2050 void Simulator::enableStop(uint32_t code) {
   2051  if (!isEnabledStop(code)) {
   2052    watchedStops_[code].count_ &= ~kStopDisabledBit;
   2053  }
   2054 }
   2055 
   2056 void Simulator::disableStop(uint32_t code) {
   2057  if (isEnabledStop(code)) {
   2058    watchedStops_[code].count_ |= kStopDisabledBit;
   2059  }
   2060 }
   2061 
   2062 void Simulator::increaseStopCounter(uint32_t code) {
   2063  MOZ_ASSERT(code <= kMaxStopCode);
   2064  if ((watchedStops_[code].count_ & ~(1 << 31)) == 0x7fffffff) {
   2065    printf(
   2066        "Stop counter for code %i has overflowed.\n"
   2067        "Enabling this code and reseting the counter to 0.\n",
   2068        code);
   2069    watchedStops_[code].count_ = 0;
   2070    enableStop(code);
   2071  } else {
   2072    watchedStops_[code].count_++;
   2073  }
   2074 }
   2075 
   2076 // Print a stop status.
   2077 void Simulator::printStopInfo(uint32_t code) {
   2078  if (code <= kMaxWatchpointCode) {
   2079    printf("That is a watchpoint, not a stop.\n");
   2080    return;
   2081  } else if (code > kMaxStopCode) {
   2082    printf("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
   2083    return;
   2084  }
   2085  const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
   2086  int32_t count = watchedStops_[code].count_ & ~kStopDisabledBit;
   2087  // Don't print the state of unused breakpoints.
   2088  if (count != 0) {
   2089    if (watchedStops_[code].desc_) {
   2090      printf("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", code, code, state,
   2091             count, watchedStops_[code].desc_);
   2092    } else {
   2093      printf("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state,
   2094             count);
   2095    }
   2096  }
   2097 }
   2098 
   2099 void Simulator::signalExceptions() {
   2100  for (int i = 1; i < kNumExceptions; i++) {
   2101    if (exceptions[i] != 0) {
   2102      MOZ_CRASH("Error: Exception raised.");
   2103    }
   2104  }
   2105 }
   2106 
   2107 // Helper function for decodeTypeRegister.
   2108 void Simulator::configureTypeRegister(SimInstruction* instr, int64_t& alu_out,
   2109                                      __int128& i128hilo,
   2110                                      unsigned __int128& u128hilo,
   2111                                      int64_t& next_pc,
   2112                                      int32_t& return_addr_reg,
   2113                                      bool& do_interrupt) {
   2114  // Every local variable declared here needs to be const.
   2115  // This is to make sure that changed values are sent back to
   2116  // decodeTypeRegister correctly.
   2117 
   2118  // Instruction fields.
   2119  const OpcodeField op = instr->opcodeFieldRaw();
   2120  const int32_t rs_reg = instr->rsValue();
   2121  const int64_t rs = getRegister(rs_reg);
   2122  const int32_t rt_reg = instr->rtValue();
   2123  const int64_t rt = getRegister(rt_reg);
   2124  const int32_t rd_reg = instr->rdValue();
   2125  const uint32_t sa = instr->saValue();
   2126 
   2127  const int32_t fs_reg = instr->fsValue();
   2128  __int128 temp;
   2129 
   2130  // ---------- Configuration.
   2131  switch (op) {
   2132    case op_cop1:  // Coprocessor instructions.
   2133      switch (instr->rsFieldRaw()) {
   2134        case rs_bc1:  // Handled in DecodeTypeImmed, should never come here.
   2135          MOZ_CRASH();
   2136          break;
   2137        case rs_cfc1:
   2138          // At the moment only FCSR is supported.
   2139          MOZ_ASSERT(fs_reg == kFCSRRegister);
   2140          alu_out = FCSR_;
   2141          break;
   2142        case rs_mfc1:
   2143          alu_out = getFpuRegisterLo(fs_reg);
   2144          break;
   2145        case rs_dmfc1:
   2146          alu_out = getFpuRegister(fs_reg);
   2147          break;
   2148        case rs_mfhc1:
   2149          alu_out = getFpuRegisterHi(fs_reg);
   2150          break;
   2151        case rs_ctc1:
   2152        case rs_mtc1:
   2153        case rs_dmtc1:
   2154        case rs_mthc1:
   2155          // Do the store in the execution step.
   2156          break;
   2157        case rs_s:
   2158        case rs_d:
   2159        case rs_w:
   2160        case rs_l:
   2161        case rs_ps:
   2162          // Do everything in the execution step.
   2163          break;
   2164        default:
   2165          MOZ_CRASH();
   2166      };
   2167      break;
   2168    case op_cop1x:
   2169      break;
   2170    case op_special:
   2171      switch (instr->functionFieldRaw()) {
   2172        case ff_jr:
   2173        case ff_jalr:
   2174          next_pc = getRegister(instr->rsValue());
   2175          return_addr_reg = instr->rdValue();
   2176          break;
   2177        case ff_sll:
   2178          alu_out = I64(I32(rt) << sa);
   2179          break;
   2180        case ff_dsll:
   2181          alu_out = rt << sa;
   2182          break;
   2183        case ff_dsll32:
   2184          alu_out = rt << (sa + 32);
   2185          break;
   2186        case ff_srl:
   2187          if (rs_reg == 0) {
   2188            // Regular logical right shift of a word by a fixed number of
   2189            // bits instruction. RS field is always equal to 0.
   2190            alu_out = I64(I32(U32(I32_CHECK(rt)) >> sa));
   2191          } else {
   2192            // Logical right-rotate of a word by a fixed number of bits. This
   2193            // is special case of SRL instruction, added in MIPS32 Release 2.
   2194            // RS field is equal to 00001.
   2195            alu_out = I64(I32((U32(I32_CHECK(rt)) >> sa) |
   2196                              (U32(I32_CHECK(rt)) << (32 - sa))));
   2197          }
   2198          break;
   2199        case ff_dsrl:
   2200          if (rs_reg == 0) {
   2201            // Regular logical right shift of a double word by a fixed number of
   2202            // bits instruction. RS field is always equal to 0.
   2203            alu_out = U64(rt) >> sa;
   2204          } else {
   2205            // Logical right-rotate of a word by a fixed number of bits. This
   2206            // is special case of DSRL instruction, added in MIPS64 Release 2.
   2207            // RS field is equal to 00001.
   2208            alu_out = (U64(rt) >> sa) | (U64(rt) << (64 - sa));
   2209          }
   2210          break;
   2211        case ff_dsrl32:
   2212          if (rs_reg == 0) {
   2213            // Regular logical right shift of a double word by a fixed number of
   2214            // bits instruction. RS field is always equal to 0.
   2215            alu_out = U64(rt) >> (sa + 32);
   2216          } else {
   2217            // Logical right-rotate of a double word by a fixed number of bits.
   2218            // This is special case of DSRL instruction, added in MIPS64
   2219            // Release 2. RS field is equal to 00001.
   2220            alu_out = (U64(rt) >> (sa + 32)) | (U64(rt) << (64 - (sa + 32)));
   2221          }
   2222          break;
   2223        case ff_sra:
   2224          alu_out = I64(I32_CHECK(rt)) >> sa;
   2225          break;
   2226        case ff_dsra:
   2227          alu_out = rt >> sa;
   2228          break;
   2229        case ff_dsra32:
   2230          alu_out = rt >> (sa + 32);
   2231          break;
   2232        case ff_sllv:
   2233          alu_out = I64(I32(rt) << rs);
   2234          break;
   2235        case ff_dsllv:
   2236          alu_out = rt << rs;
   2237          break;
   2238        case ff_srlv:
   2239          if (sa == 0) {
   2240            // Regular logical right-shift of a word by a variable number of
   2241            // bits instruction. SA field is always equal to 0.
   2242            alu_out = I64(I32(U32(I32_CHECK(rt)) >> rs));
   2243          } else {
   2244            // Logical right-rotate of a word by a variable number of bits.
   2245            // This is special case od SRLV instruction, added in MIPS32
   2246            // Release 2. SA field is equal to 00001.
   2247            alu_out = I64(I32((U32(I32_CHECK(rt)) >> rs) |
   2248                              (U32(I32_CHECK(rt)) << (32 - rs))));
   2249          }
   2250          break;
   2251        case ff_dsrlv:
   2252          if (sa == 0) {
   2253            // Regular logical right-shift of a double word by a variable number
   2254            // of bits instruction. SA field is always equal to 0.
   2255            alu_out = U64(rt) >> rs;
   2256          } else {
   2257            // Logical right-rotate of a double word by a variable number of
   2258            // bits. This is special case od DSRLV instruction, added in MIPS64
   2259            // Release 2. SA field is equal to 00001.
   2260            alu_out = (U64(rt) >> rs) | (U64(rt) << (64 - rs));
   2261          }
   2262          break;
   2263        case ff_srav:
   2264          alu_out = I64(I32_CHECK(rt) >> rs);
   2265          break;
   2266        case ff_dsrav:
   2267          alu_out = rt >> rs;
   2268          break;
   2269        case ff_mfhi:
   2270          alu_out = getRegister(HI);
   2271          break;
   2272        case ff_mflo:
   2273          alu_out = getRegister(LO);
   2274          break;
   2275        case ff_mult:
   2276          i128hilo = I64(U32(I32_CHECK(rs))) * I64(U32(I32_CHECK(rt)));
   2277          break;
   2278        case ff_dmult:
   2279          i128hilo = I128(rs) * I128(rt);
   2280          break;
   2281        case ff_multu:
   2282          u128hilo = U64(U32(I32_CHECK(rs))) * U64(U32(I32_CHECK(rt)));
   2283          break;
   2284        case ff_dmultu:
   2285          u128hilo = U128(rs) * U128(rt);
   2286          break;
   2287        case ff_add:
   2288          alu_out = I32_CHECK(rs) + I32_CHECK(rt);
   2289          if ((alu_out << 32) != (alu_out << 31)) {
   2290            exceptions[kIntegerOverflow] = 1;
   2291          }
   2292          alu_out = I32(alu_out);
   2293          break;
   2294        case ff_dadd:
   2295          temp = I128(rs) + I128(rt);
   2296          if ((temp << 64) != (temp << 63)) {
   2297            exceptions[kIntegerOverflow] = 1;
   2298          }
   2299          alu_out = I64(temp);
   2300          break;
   2301        case ff_addu:
   2302          alu_out = I32(I32_CHECK(rs) + I32_CHECK(rt));
   2303          break;
   2304        case ff_daddu:
   2305          alu_out = rs + rt;
   2306          break;
   2307        case ff_sub:
   2308          alu_out = I32_CHECK(rs) - I32_CHECK(rt);
   2309          if ((alu_out << 32) != (alu_out << 31)) {
   2310            exceptions[kIntegerUnderflow] = 1;
   2311          }
   2312          alu_out = I32(alu_out);
   2313          break;
   2314        case ff_dsub:
   2315          temp = I128(rs) - I128(rt);
   2316          if ((temp << 64) != (temp << 63)) {
   2317            exceptions[kIntegerUnderflow] = 1;
   2318          }
   2319          alu_out = I64(temp);
   2320          break;
   2321        case ff_subu:
   2322          alu_out = I32(I32_CHECK(rs) - I32_CHECK(rt));
   2323          break;
   2324        case ff_dsubu:
   2325          alu_out = rs - rt;
   2326          break;
   2327        case ff_and:
   2328          alu_out = rs & rt;
   2329          break;
   2330        case ff_or:
   2331          alu_out = rs | rt;
   2332          break;
   2333        case ff_xor:
   2334          alu_out = rs ^ rt;
   2335          break;
   2336        case ff_nor:
   2337          alu_out = ~(rs | rt);
   2338          break;
   2339        case ff_slt:
   2340          alu_out = I64(rs) < I64(rt) ? 1 : 0;
   2341          break;
   2342        case ff_sltu:
   2343          alu_out = U64(rs) < U64(rt) ? 1 : 0;
   2344          break;
   2345        case ff_sync:
   2346          break;
   2347          // Break and trap instructions.
   2348        case ff_break:
   2349          do_interrupt = true;
   2350          break;
   2351        case ff_tge:
   2352          do_interrupt = rs >= rt;
   2353          break;
   2354        case ff_tgeu:
   2355          do_interrupt = U64(rs) >= U64(rt);
   2356          break;
   2357        case ff_tlt:
   2358          do_interrupt = rs < rt;
   2359          break;
   2360        case ff_tltu:
   2361          do_interrupt = U64(rs) < U64(rt);
   2362          break;
   2363        case ff_teq:
   2364          do_interrupt = rs == rt;
   2365          break;
   2366        case ff_tne:
   2367          do_interrupt = rs != rt;
   2368          break;
   2369        case ff_movn:
   2370        case ff_movz:
   2371        case ff_movci:
   2372          // No action taken on decode.
   2373          break;
   2374        case ff_div:
   2375          if (I32_CHECK(rs) == INT_MIN && I32_CHECK(rt) == -1) {
   2376            i128hilo = U32(INT_MIN);
   2377          } else {
   2378            uint32_t div = I32_CHECK(rs) / I32_CHECK(rt);
   2379            uint32_t mod = I32_CHECK(rs) % I32_CHECK(rt);
   2380            i128hilo = (I64(mod) << 32) | div;
   2381          }
   2382          break;
   2383        case ff_ddiv:
   2384          if (I64(rs) == INT64_MIN && I64(rt) == -1) {
   2385            i128hilo = U64(INT64_MIN);
   2386          } else {
   2387            uint64_t div = rs / rt;
   2388            uint64_t mod = rs % rt;
   2389            i128hilo = (I128(mod) << 64) | div;
   2390          }
   2391          break;
   2392        case ff_divu: {
   2393          uint32_t div = U32(I32_CHECK(rs)) / U32(I32_CHECK(rt));
   2394          uint32_t mod = U32(I32_CHECK(rs)) % U32(I32_CHECK(rt));
   2395          i128hilo = (U64(mod) << 32) | div;
   2396        } break;
   2397        case ff_ddivu:
   2398          if (0 == rt) {
   2399            i128hilo = (I128(Unpredictable) << 64) | I64(Unpredictable);
   2400          } else {
   2401            uint64_t div = U64(rs) / U64(rt);
   2402            uint64_t mod = U64(rs) % U64(rt);
   2403            i128hilo = (I128(mod) << 64) | div;
   2404          }
   2405          break;
   2406        default:
   2407          MOZ_CRASH();
   2408      };
   2409      break;
   2410    case op_special2:
   2411      switch (instr->functionFieldRaw()) {
   2412        case ff_mul:
   2413          alu_out = I32(I32_CHECK(rs) *
   2414                        I32_CHECK(rt));  // Only the lower 32 bits are kept.
   2415          break;
   2416        case ff_clz:
   2417          alu_out = U32(I32_CHECK(rs)) ? __builtin_clz(U32(I32_CHECK(rs))) : 32;
   2418          break;
   2419        case ff_dclz:
   2420          alu_out = U64(rs) ? __builtin_clzl(U64(rs)) : 64;
   2421          break;
   2422        default:
   2423          MOZ_CRASH();
   2424      };
   2425      break;
   2426    case op_special3:
   2427      switch (instr->functionFieldRaw()) {
   2428        case ff_ins: {  // Mips64r2 instruction.
   2429          // Interpret rd field as 5-bit msb of insert.
   2430          uint16_t msb = rd_reg;
   2431          // Interpret sa field as 5-bit lsb of insert.
   2432          uint16_t lsb = sa;
   2433          uint16_t size = msb - lsb + 1;
   2434          uint32_t mask = (1 << size) - 1;
   2435          if (lsb > msb) {
   2436            alu_out = Unpredictable;
   2437          } else {
   2438            alu_out = I32((U32(I32_CHECK(rt)) & ~(mask << lsb)) |
   2439                          ((U32(I32_CHECK(rs)) & mask) << lsb));
   2440          }
   2441          break;
   2442        }
   2443        case ff_dins: {  // Mips64r2 instruction.
   2444          // Interpret rd field as 5-bit msb of insert.
   2445          uint16_t msb = rd_reg;
   2446          // Interpret sa field as 5-bit lsb of insert.
   2447          uint16_t lsb = sa;
   2448          uint16_t size = msb - lsb + 1;
   2449          uint64_t mask = (1ul << size) - 1;
   2450          if (lsb > msb) {
   2451            alu_out = Unpredictable;
   2452          } else {
   2453            alu_out = (U64(rt) & ~(mask << lsb)) | ((U64(rs) & mask) << lsb);
   2454          }
   2455          break;
   2456        }
   2457        case ff_dinsm: {  // Mips64r2 instruction.
   2458          // Interpret rd field as 5-bit msb of insert.
   2459          uint16_t msb = rd_reg;
   2460          // Interpret sa field as 5-bit lsb of insert.
   2461          uint16_t lsb = sa;
   2462          uint16_t size = msb - lsb + 33;
   2463          uint64_t mask = (1ul << size) - 1;
   2464          alu_out = (U64(rt) & ~(mask << lsb)) | ((U64(rs) & mask) << lsb);
   2465          break;
   2466        }
   2467        case ff_dinsu: {  // Mips64r2 instruction.
   2468          // Interpret rd field as 5-bit msb of insert.
   2469          uint16_t msb = rd_reg;
   2470          // Interpret sa field as 5-bit lsb of insert.
   2471          uint16_t lsb = sa + 32;
   2472          uint16_t size = msb - lsb + 33;
   2473          uint64_t mask = (1ul << size) - 1;
   2474          if (sa > msb) {
   2475            alu_out = Unpredictable;
   2476          } else {
   2477            alu_out = (U64(rt) & ~(mask << lsb)) | ((U64(rs) & mask) << lsb);
   2478          }
   2479          break;
   2480        }
   2481        case ff_ext: {  // Mips64r2 instruction.
   2482          // Interpret rd field as 5-bit msb of extract.
   2483          uint16_t msb = rd_reg;
   2484          // Interpret sa field as 5-bit lsb of extract.
   2485          uint16_t lsb = sa;
   2486          uint16_t size = msb + 1;
   2487          uint32_t mask = (1 << size) - 1;
   2488          if ((lsb + msb) > 31) {
   2489            alu_out = Unpredictable;
   2490          } else {
   2491            alu_out = (U32(I32_CHECK(rs)) & (mask << lsb)) >> lsb;
   2492          }
   2493          break;
   2494        }
   2495        case ff_dext: {  // Mips64r2 instruction.
   2496          // Interpret rd field as 5-bit msb of extract.
   2497          uint16_t msb = rd_reg;
   2498          // Interpret sa field as 5-bit lsb of extract.
   2499          uint16_t lsb = sa;
   2500          uint16_t size = msb + 1;
   2501          uint64_t mask = (1ul << size) - 1;
   2502          alu_out = (U64(rs) & (mask << lsb)) >> lsb;
   2503          break;
   2504        }
   2505        case ff_dextm: {  // Mips64r2 instruction.
   2506          // Interpret rd field as 5-bit msb of extract.
   2507          uint16_t msb = rd_reg;
   2508          // Interpret sa field as 5-bit lsb of extract.
   2509          uint16_t lsb = sa;
   2510          uint16_t size = msb + 33;
   2511          uint64_t mask = (1ul << size) - 1;
   2512          if ((lsb + msb + 32 + 1) > 64) {
   2513            alu_out = Unpredictable;
   2514          } else {
   2515            alu_out = (U64(rs) & (mask << lsb)) >> lsb;
   2516          }
   2517          break;
   2518        }
   2519        case ff_dextu: {  // Mips64r2 instruction.
   2520          // Interpret rd field as 5-bit msb of extract.
   2521          uint16_t msb = rd_reg;
   2522          // Interpret sa field as 5-bit lsb of extract.
   2523          uint16_t lsb = sa + 32;
   2524          uint16_t size = msb + 1;
   2525          uint64_t mask = (1ul << size) - 1;
   2526          if ((lsb + msb + 1) > 64) {
   2527            alu_out = Unpredictable;
   2528          } else {
   2529            alu_out = (U64(rs) & (mask << lsb)) >> lsb;
   2530          }
   2531          break;
   2532        }
   2533        case ff_bshfl: {   // Mips32r2 instruction.
   2534          if (16 == sa) {  // seb
   2535            alu_out = I64(I8(I32_CHECK(rt)));
   2536          } else if (24 == sa) {  // seh
   2537            alu_out = I64(I16(I32_CHECK(rt)));
   2538          } else if (2 == sa) {  // wsbh
   2539            uint32_t input = U32(I32_CHECK(rt));
   2540            uint64_t output = 0;
   2541 
   2542            uint32_t mask = 0xFF000000;
   2543            for (int i = 0; i < 4; i++) {
   2544              uint32_t tmp = mask & input;
   2545              if (i % 2 == 0) {
   2546                tmp = tmp >> 8;
   2547              } else {
   2548                tmp = tmp << 8;
   2549              }
   2550              output = output | tmp;
   2551              mask = mask >> 8;
   2552            }
   2553            alu_out = I64(I32(output));
   2554          } else {
   2555            MOZ_CRASH();
   2556          }
   2557          break;
   2558        }
   2559        case ff_dbshfl: {  // Mips64r2 instruction.
   2560          uint64_t input = U64(rt);
   2561          uint64_t output = 0;
   2562 
   2563          if (2 == sa) {  // dsbh
   2564            uint64_t mask = 0xFF00000000000000;
   2565            for (int i = 0; i < 8; i++) {
   2566              uint64_t tmp = mask & input;
   2567              if (i % 2 == 0)
   2568                tmp = tmp >> 8;
   2569              else
   2570                tmp = tmp << 8;
   2571 
   2572              output = output | tmp;
   2573              mask = mask >> 8;
   2574            }
   2575          } else if (5 == sa) {  // dshd
   2576            uint64_t mask = 0xFFFF000000000000;
   2577            for (int i = 0; i < 4; i++) {
   2578              uint64_t tmp = mask & input;
   2579              if (i == 0)
   2580                tmp = tmp >> 48;
   2581              else if (i == 1)
   2582                tmp = tmp >> 16;
   2583              else if (i == 2)
   2584                tmp = tmp << 16;
   2585              else
   2586                tmp = tmp << 48;
   2587              output = output | tmp;
   2588              mask = mask >> 16;
   2589            }
   2590          } else {
   2591            MOZ_CRASH();
   2592          }
   2593 
   2594          alu_out = I64(output);
   2595          break;
   2596        }
   2597        default:
   2598          MOZ_CRASH();
   2599      };
   2600      break;
   2601    default:
   2602      MOZ_CRASH();
   2603  };
   2604 }
   2605 
   2606 // Handle execution based on instruction types.
   2607 void Simulator::decodeTypeRegister(SimInstruction* instr) {
   2608  // Instruction fields.
   2609  const OpcodeField op = instr->opcodeFieldRaw();
   2610  const int32_t rs_reg = instr->rsValue();
   2611  const int64_t rs = getRegister(rs_reg);
   2612  const int32_t rt_reg = instr->rtValue();
   2613  const int64_t rt = getRegister(rt_reg);
   2614  const int32_t rd_reg = instr->rdValue();
   2615 
   2616  const int32_t fr_reg = instr->frValue();
   2617  const int32_t fs_reg = instr->fsValue();
   2618  const int32_t ft_reg = instr->ftValue();
   2619  const int32_t fd_reg = instr->fdValue();
   2620  __int128 i128hilo = 0;
   2621  unsigned __int128 u128hilo = 0;
   2622 
   2623  // ALU output.
   2624  // It should not be used as is. Instructions using it should always
   2625  // initialize it first.
   2626  int64_t alu_out = 0x12345678;
   2627 
   2628  // For break and trap instructions.
   2629  bool do_interrupt = false;
   2630 
   2631  // For jr and jalr.
   2632  // Get current pc.
   2633  int64_t current_pc = get_pc();
   2634  // Next pc
   2635  int64_t next_pc = 0;
   2636  int32_t return_addr_reg = 31;
   2637 
   2638  // Set up the variables if needed before executing the instruction.
   2639  configureTypeRegister(instr, alu_out, i128hilo, u128hilo, next_pc,
   2640                        return_addr_reg, do_interrupt);
   2641 
   2642  // ---------- Raise exceptions triggered.
   2643  signalExceptions();
   2644 
   2645  // ---------- Execution.
   2646  switch (op) {
   2647    case op_cop1:
   2648      switch (instr->rsFieldRaw()) {
   2649        case rs_bc1:  // Branch on coprocessor condition.
   2650          MOZ_CRASH();
   2651          break;
   2652        case rs_cfc1:
   2653          setRegister(rt_reg, alu_out);
   2654          [[fallthrough]];
   2655        case rs_mfc1:
   2656          setRegister(rt_reg, alu_out);
   2657          break;
   2658        case rs_dmfc1:
   2659          setRegister(rt_reg, alu_out);
   2660          break;
   2661        case rs_mfhc1:
   2662          setRegister(rt_reg, alu_out);
   2663          break;
   2664        case rs_ctc1:
   2665          // At the moment only FCSR is supported.
   2666          MOZ_ASSERT(fs_reg == kFCSRRegister);
   2667          FCSR_ = registers_[rt_reg];
   2668          break;
   2669        case rs_mtc1:
   2670          setFpuRegisterLo(fs_reg, registers_[rt_reg]);
   2671          break;
   2672        case rs_dmtc1:
   2673          setFpuRegister(fs_reg, registers_[rt_reg]);
   2674          break;
   2675        case rs_mthc1:
   2676          setFpuRegisterHi(fs_reg, registers_[rt_reg]);
   2677          break;
   2678        case rs_s:
   2679          float f, ft_value, fs_value;
   2680          uint32_t cc, fcsr_cc, cc_value;
   2681          bool do_movf;
   2682          int64_t i64;
   2683          fs_value = getFpuRegisterFloat(fs_reg);
   2684          ft_value = getFpuRegisterFloat(ft_reg);
   2685 
   2686          // fcc is bits[10:8] for c.cond.fmt
   2687          // but is bits[20:18] for movt.fmt and movf.fmt
   2688          switch (instr->functionFieldRaw()) {
   2689            case ff_movf_fmt:
   2690              cc = instr->fbccValue();
   2691              break;
   2692            default:
   2693              cc = instr->fcccValue();
   2694              break;
   2695          }
   2696          fcsr_cc = GetFCSRConditionBit(cc);
   2697          switch (instr->functionFieldRaw()) {
   2698            case ff_add_fmt:
   2699              setFpuRegisterFloat(fd_reg, fs_value + ft_value);
   2700              break;
   2701            case ff_sub_fmt:
   2702              setFpuRegisterFloat(fd_reg, fs_value - ft_value);
   2703              break;
   2704            case ff_mul_fmt:
   2705              setFpuRegisterFloat(fd_reg, fs_value * ft_value);
   2706              break;
   2707            case ff_div_fmt:
   2708              setFpuRegisterFloat(fd_reg, fs_value / ft_value);
   2709              break;
   2710            case ff_abs_fmt:
   2711              setFpuRegisterFloat(fd_reg, fabsf(fs_value));
   2712              break;
   2713            case ff_mov_fmt:
   2714              setFpuRegisterFloat(fd_reg, fs_value);
   2715              break;
   2716            case ff_neg_fmt:
   2717              setFpuRegisterFloat(fd_reg, -fs_value);
   2718              break;
   2719            case ff_sqrt_fmt:
   2720              setFpuRegisterFloat(fd_reg, sqrtf(fs_value));
   2721              break;
   2722            case ff_c_un_fmt:
   2723              setFCSRBit(fcsr_cc, std::isnan(fs_value) || std::isnan(ft_value));
   2724              break;
   2725            case ff_c_eq_fmt:
   2726              setFCSRBit(fcsr_cc, (fs_value == ft_value));
   2727              break;
   2728            case ff_c_ueq_fmt:
   2729              setFCSRBit(fcsr_cc,
   2730                         (fs_value == ft_value) ||
   2731                             (std::isnan(fs_value) || std::isnan(ft_value)));
   2732              break;
   2733            case ff_c_olt_fmt:
   2734              setFCSRBit(fcsr_cc, (fs_value < ft_value));
   2735              break;
   2736            case ff_c_ult_fmt:
   2737              setFCSRBit(fcsr_cc,
   2738                         (fs_value < ft_value) ||
   2739                             (std::isnan(fs_value) || std::isnan(ft_value)));
   2740              break;
   2741            case ff_c_ole_fmt:
   2742              setFCSRBit(fcsr_cc, (fs_value <= ft_value));
   2743              break;
   2744            case ff_c_ule_fmt:
   2745              setFCSRBit(fcsr_cc,
   2746                         (fs_value <= ft_value) ||
   2747                             (std::isnan(fs_value) || std::isnan(ft_value)));
   2748              break;
   2749            case ff_cvt_d_fmt:
   2750              f = getFpuRegisterFloat(fs_reg);
   2751              setFpuRegisterDouble(fd_reg, static_cast<double>(f));
   2752              break;
   2753            case ff_cvt_w_fmt:  // Convert float to word.
   2754              // Rounding modes are not yet supported.
   2755              MOZ_ASSERT((FCSR_ & 3) == 0);
   2756              // In rounding mode 0 it should behave like ROUND.
   2757              [[fallthrough]];
   2758            case ff_round_w_fmt: {  // Round double to word (round half to
   2759                                    // even).
   2760              float rounded = std::floor(fs_value + 0.5);
   2761              int32_t result = I32(rounded);
   2762              if ((result & 1) != 0 && result - fs_value == 0.5) {
   2763                // If the number is halfway between two integers,
   2764                // round to the even one.
   2765                result--;
   2766              }
   2767              setFpuRegisterLo(fd_reg, result);
   2768              if (setFCSRRoundError<int32_t>(fs_value, rounded)) {
   2769                setFpuRegisterLo(fd_reg, kFPUInvalidResult);
   2770              }
   2771              break;
   2772            }
   2773            case ff_trunc_w_fmt: {  // Truncate float to word (round towards 0).
   2774              float rounded = truncf(fs_value);
   2775              int32_t result = I32(rounded);
   2776              setFpuRegisterLo(fd_reg, result);
   2777              if (setFCSRRoundError<int32_t>(fs_value, rounded)) {
   2778                setFpuRegisterLo(fd_reg, kFPUInvalidResult);
   2779              }
   2780              break;
   2781            }
   2782            case ff_floor_w_fmt: {  // Round float to word towards negative
   2783                                    // infinity.
   2784              float rounded = std::floor(fs_value);
   2785              int32_t result = I32(rounded);
   2786              setFpuRegisterLo(fd_reg, result);
   2787              if (setFCSRRoundError<int32_t>(fs_value, rounded)) {
   2788                setFpuRegisterLo(fd_reg, kFPUInvalidResult);
   2789              }
   2790              break;
   2791            }
   2792            case ff_ceil_w_fmt: {  // Round double to word towards positive
   2793                                   // infinity.
   2794              float rounded = std::ceil(fs_value);
   2795              int32_t result = I32(rounded);
   2796              setFpuRegisterLo(fd_reg, result);
   2797              if (setFCSRRoundError<int32_t>(fs_value, rounded)) {
   2798                setFpuRegisterLo(fd_reg, kFPUInvalidResult);
   2799              }
   2800              break;
   2801            }
   2802            case ff_cvt_l_fmt:  // Mips64r2: Truncate float to 64-bit long-word.
   2803              // Rounding modes are not yet supported.
   2804              MOZ_ASSERT((FCSR_ & 3) == 0);
   2805              // In rounding mode 0 it should behave like ROUND.
   2806              [[fallthrough]];
   2807            case ff_round_l_fmt: {  // Mips64r2 instruction.
   2808              float rounded = fs_value > 0 ? std::floor(fs_value + 0.5)
   2809                                           : std::ceil(fs_value - 0.5);
   2810              i64 = I64(rounded);
   2811              setFpuRegister(fd_reg, i64);
   2812              if (setFCSRRoundError<int64_t>(fs_value, rounded)) {
   2813                setFpuRegister(fd_reg, kFPUInvalidResult64);
   2814              }
   2815              break;
   2816            }
   2817            case ff_trunc_l_fmt: {  // Mips64r2 instruction.
   2818              float rounded = truncf(fs_value);
   2819              i64 = I64(rounded);
   2820              setFpuRegister(fd_reg, i64);
   2821              if (setFCSRRoundError<int64_t>(fs_value, rounded)) {
   2822                setFpuRegister(fd_reg, kFPUInvalidResult64);
   2823              }
   2824              break;
   2825            }
   2826            case ff_floor_l_fmt: {  // Mips64r2 instruction.
   2827              float rounded = std::floor(fs_value);
   2828              i64 = I64(rounded);
   2829              setFpuRegister(fd_reg, i64);
   2830              if (setFCSRRoundError<int64_t>(fs_value, rounded)) {
   2831                setFpuRegister(fd_reg, kFPUInvalidResult64);
   2832              }
   2833              break;
   2834            }
   2835            case ff_ceil_l_fmt: {  // Mips64r2 instruction.
   2836              float rounded = std::ceil(fs_value);
   2837              i64 = I64(rounded);
   2838              setFpuRegister(fd_reg, i64);
   2839              if (setFCSRRoundError<int64_t>(fs_value, rounded)) {
   2840                setFpuRegister(fd_reg, kFPUInvalidResult64);
   2841              }
   2842              break;
   2843            }
   2844            case ff_cvt_ps_s:
   2845            case ff_c_f_fmt:
   2846              MOZ_CRASH();
   2847              break;
   2848            case ff_movf_fmt:
   2849              cc_value = testFCSRBit(fcsr_cc);
   2850              do_movf = (instr->fbtrueValue()) ? cc_value : !cc_value;
   2851              if (do_movf) {
   2852                setFpuRegisterFloat(fd_reg, getFpuRegisterFloat(fs_reg));
   2853              }
   2854              break;
   2855            case ff_movz_fmt:
   2856              if (rt == 0) {
   2857                setFpuRegisterFloat(fd_reg, getFpuRegisterFloat(fs_reg));
   2858              }
   2859              break;
   2860            case ff_movn_fmt:
   2861              if (rt != 0) {
   2862                setFpuRegisterFloat(fd_reg, getFpuRegisterFloat(fs_reg));
   2863              }
   2864              break;
   2865            default:
   2866              MOZ_CRASH();
   2867          }
   2868          break;
   2869        case rs_d:
   2870          double dt_value, ds_value;
   2871          ds_value = getFpuRegisterDouble(fs_reg);
   2872          dt_value = getFpuRegisterDouble(ft_reg);
   2873 
   2874          // fcc is bits[10:8] for c.cond.fmt
   2875          // but is bits[20:18] for movt.fmt and movf.fmt
   2876          switch (instr->functionFieldRaw()) {
   2877            case ff_movf_fmt:
   2878              cc = instr->fbccValue();
   2879              break;
   2880            default:
   2881              cc = instr->fcccValue();
   2882              break;
   2883          }
   2884          fcsr_cc = GetFCSRConditionBit(cc);
   2885          switch (instr->functionFieldRaw()) {
   2886            case ff_add_fmt:
   2887              setFpuRegisterDouble(fd_reg, ds_value + dt_value);
   2888              break;
   2889            case ff_sub_fmt:
   2890              setFpuRegisterDouble(fd_reg, ds_value - dt_value);
   2891              break;
   2892            case ff_mul_fmt:
   2893              setFpuRegisterDouble(fd_reg, ds_value * dt_value);
   2894              break;
   2895            case ff_div_fmt:
   2896              setFpuRegisterDouble(fd_reg, ds_value / dt_value);
   2897              break;
   2898            case ff_abs_fmt:
   2899              setFpuRegisterDouble(fd_reg, fabs(ds_value));
   2900              break;
   2901            case ff_mov_fmt:
   2902              setFpuRegisterDouble(fd_reg, ds_value);
   2903              break;
   2904            case ff_neg_fmt:
   2905              setFpuRegisterDouble(fd_reg, -ds_value);
   2906              break;
   2907            case ff_sqrt_fmt:
   2908              setFpuRegisterDouble(fd_reg, sqrt(ds_value));
   2909              break;
   2910            case ff_c_un_fmt:
   2911              setFCSRBit(fcsr_cc, std::isnan(ds_value) || std::isnan(dt_value));
   2912              break;
   2913            case ff_c_eq_fmt:
   2914              setFCSRBit(fcsr_cc, (ds_value == dt_value));
   2915              break;
   2916            case ff_c_ueq_fmt:
   2917              setFCSRBit(fcsr_cc,
   2918                         (ds_value == dt_value) ||
   2919                             (std::isnan(ds_value) || std::isnan(dt_value)));
   2920              break;
   2921            case ff_c_olt_fmt:
   2922              setFCSRBit(fcsr_cc, (ds_value < dt_value));
   2923              break;
   2924            case ff_c_ult_fmt:
   2925              setFCSRBit(fcsr_cc,
   2926                         (ds_value < dt_value) ||
   2927                             (std::isnan(ds_value) || std::isnan(dt_value)));
   2928              break;
   2929            case ff_c_ole_fmt:
   2930              setFCSRBit(fcsr_cc, (ds_value <= dt_value));
   2931              break;
   2932            case ff_c_ule_fmt:
   2933              setFCSRBit(fcsr_cc,
   2934                         (ds_value <= dt_value) ||
   2935                             (std::isnan(ds_value) || std::isnan(dt_value)));
   2936              break;
   2937            case ff_cvt_w_fmt:  // Convert double to word.
   2938              // Rounding modes are not yet supported.
   2939              MOZ_ASSERT((FCSR_ & 3) == 0);
   2940              // In rounding mode 0 it should behave like ROUND.
   2941              [[fallthrough]];
   2942            case ff_round_w_fmt: {  // Round double to word (round half to
   2943                                    // even).
   2944              double rounded = std::floor(ds_value + 0.5);
   2945              int32_t result = I32(rounded);
   2946              if ((result & 1) != 0 && result - ds_value == 0.5) {
   2947                // If the number is halfway between two integers,
   2948                // round to the even one.
   2949                result--;
   2950              }
   2951              setFpuRegisterLo(fd_reg, result);
   2952              if (setFCSRRoundError<int32_t>(ds_value, rounded)) {
   2953                setFpuRegisterLo(fd_reg, kFPUInvalidResult);
   2954              }
   2955              break;
   2956            }
   2957            case ff_trunc_w_fmt: {  // Truncate double to word (round towards
   2958                                    // 0).
   2959              double rounded = trunc(ds_value);
   2960              int32_t result = I32(rounded);
   2961              setFpuRegisterLo(fd_reg, result);
   2962              if (setFCSRRoundError<int32_t>(ds_value, rounded)) {
   2963                setFpuRegisterLo(fd_reg, kFPUInvalidResult);
   2964              }
   2965              break;
   2966            }
   2967            case ff_floor_w_fmt: {  // Round double to word towards negative
   2968                                    // infinity.
   2969              double rounded = std::floor(ds_value);
   2970              int32_t result = I32(rounded);
   2971              setFpuRegisterLo(fd_reg, result);
   2972              if (setFCSRRoundError<int32_t>(ds_value, rounded)) {
   2973                setFpuRegisterLo(fd_reg, kFPUInvalidResult);
   2974              }
   2975              break;
   2976            }
   2977            case ff_ceil_w_fmt: {  // Round double to word towards positive
   2978                                   // infinity.
   2979              double rounded = std::ceil(ds_value);
   2980              int32_t result = I32(rounded);
   2981              setFpuRegisterLo(fd_reg, result);
   2982              if (setFCSRRoundError<int32_t>(ds_value, rounded)) {
   2983                setFpuRegisterLo(fd_reg, kFPUInvalidResult);
   2984              }
   2985              break;
   2986            }
   2987            case ff_cvt_s_fmt:  // Convert double to float (single).
   2988              setFpuRegisterFloat(fd_reg, static_cast<float>(ds_value));
   2989              break;
   2990            case ff_cvt_l_fmt:  // Mips64r2: Truncate double to 64-bit
   2991                                // long-word.
   2992              // Rounding modes are not yet supported.
   2993              MOZ_ASSERT((FCSR_ & 3) == 0);
   2994              // In rounding mode 0 it should behave like ROUND.
   2995              [[fallthrough]];
   2996            case ff_round_l_fmt: {  // Mips64r2 instruction.
   2997              double rounded = ds_value > 0 ? std::floor(ds_value + 0.5)
   2998                                            : std::ceil(ds_value - 0.5);
   2999              i64 = I64(rounded);
   3000              setFpuRegister(fd_reg, i64);
   3001              if (setFCSRRoundError<int64_t>(ds_value, rounded)) {
   3002                setFpuRegister(fd_reg, kFPUInvalidResult64);
   3003              }
   3004              break;
   3005            }
   3006            case ff_trunc_l_fmt: {  // Mips64r2 instruction.
   3007              double rounded = trunc(ds_value);
   3008              i64 = I64(rounded);
   3009              setFpuRegister(fd_reg, i64);
   3010              if (setFCSRRoundError<int64_t>(ds_value, rounded)) {
   3011                setFpuRegister(fd_reg, kFPUInvalidResult64);
   3012              }
   3013              break;
   3014            }
   3015            case ff_floor_l_fmt: {  // Mips64r2 instruction.
   3016              double rounded = std::floor(ds_value);
   3017              i64 = I64(rounded);
   3018              setFpuRegister(fd_reg, i64);
   3019              if (setFCSRRoundError<int64_t>(ds_value, rounded)) {
   3020                setFpuRegister(fd_reg, kFPUInvalidResult64);
   3021              }
   3022              break;
   3023            }
   3024            case ff_ceil_l_fmt: {  // Mips64r2 instruction.
   3025              double rounded = std::ceil(ds_value);
   3026              i64 = I64(rounded);
   3027              setFpuRegister(fd_reg, i64);
   3028              if (setFCSRRoundError<int64_t>(ds_value, rounded)) {
   3029                setFpuRegister(fd_reg, kFPUInvalidResult64);
   3030              }
   3031              break;
   3032            }
   3033            case ff_c_f_fmt:
   3034              MOZ_CRASH();
   3035              break;
   3036            case ff_movz_fmt:
   3037              if (rt == 0) {
   3038                setFpuRegisterDouble(fd_reg, getFpuRegisterDouble(fs_reg));
   3039              }
   3040              break;
   3041            case ff_movn_fmt:
   3042              if (rt != 0) {
   3043                setFpuRegisterDouble(fd_reg, getFpuRegisterDouble(fs_reg));
   3044              }
   3045              break;
   3046            case ff_movf_fmt:
   3047              cc_value = testFCSRBit(fcsr_cc);
   3048              do_movf = (instr->fbtrueValue()) ? cc_value : !cc_value;
   3049              if (do_movf) {
   3050                setFpuRegisterDouble(fd_reg, getFpuRegisterDouble(fs_reg));
   3051              }
   3052              break;
   3053            default:
   3054              MOZ_CRASH();
   3055          }
   3056          break;
   3057        case rs_w:
   3058          switch (instr->functionFieldRaw()) {
   3059            case ff_cvt_s_fmt:  // Convert word to float (single).
   3060              i64 = getFpuRegisterLo(fs_reg);
   3061              setFpuRegisterFloat(fd_reg, static_cast<float>(i64));
   3062              break;
   3063            case ff_cvt_d_fmt:  // Convert word to double.
   3064              i64 = getFpuRegisterLo(fs_reg);
   3065              setFpuRegisterDouble(fd_reg, static_cast<double>(i64));
   3066              break;
   3067            default:
   3068              MOZ_CRASH();
   3069          };
   3070          break;
   3071        case rs_l:
   3072          switch (instr->functionFieldRaw()) {
   3073            case ff_cvt_d_fmt:  // Mips64r2 instruction.
   3074              i64 = getFpuRegister(fs_reg);
   3075              setFpuRegisterDouble(fd_reg, static_cast<double>(i64));
   3076              break;
   3077            case ff_cvt_s_fmt:
   3078              i64 = getFpuRegister(fs_reg);
   3079              setFpuRegisterFloat(fd_reg, static_cast<float>(i64));
   3080              break;
   3081            default:
   3082              MOZ_CRASH();
   3083          }
   3084          break;
   3085        case rs_ps:
   3086          break;
   3087        default:
   3088          MOZ_CRASH();
   3089      };
   3090      break;
   3091    case op_cop1x:
   3092      switch (instr->functionFieldRaw()) {
   3093        case ff_madd_s:
   3094          float fr, ft, fs;
   3095          fr = getFpuRegisterFloat(fr_reg);
   3096          fs = getFpuRegisterFloat(fs_reg);
   3097          ft = getFpuRegisterFloat(ft_reg);
   3098          setFpuRegisterFloat(fd_reg, fs * ft + fr);
   3099          break;
   3100        case ff_madd_d:
   3101          double dr, dt, ds;
   3102          dr = getFpuRegisterDouble(fr_reg);
   3103          ds = getFpuRegisterDouble(fs_reg);
   3104          dt = getFpuRegisterDouble(ft_reg);
   3105          setFpuRegisterDouble(fd_reg, ds * dt + dr);
   3106          break;
   3107        default:
   3108          MOZ_CRASH();
   3109      };
   3110      break;
   3111    case op_special:
   3112      switch (instr->functionFieldRaw()) {
   3113        case ff_jr: {
   3114          SimInstruction* branch_delay_instr =
   3115              reinterpret_cast<SimInstruction*>(current_pc +
   3116                                                SimInstruction::kInstrSize);
   3117          branchDelayInstructionDecode(branch_delay_instr);
   3118          set_pc(next_pc);
   3119          pc_modified_ = true;
   3120          break;
   3121        }
   3122        case ff_jalr: {
   3123          SimInstruction* branch_delay_instr =
   3124              reinterpret_cast<SimInstruction*>(current_pc +
   3125                                                SimInstruction::kInstrSize);
   3126          setRegister(return_addr_reg,
   3127                      current_pc + 2 * SimInstruction::kInstrSize);
   3128          branchDelayInstructionDecode(branch_delay_instr);
   3129          set_pc(next_pc);
   3130          pc_modified_ = true;
   3131          break;
   3132        }
   3133        // Instructions using HI and LO registers.
   3134        case ff_mult:
   3135          setRegister(LO, I32(i128hilo & 0xffffffff));
   3136          setRegister(HI, I32(i128hilo >> 32));
   3137          break;
   3138        case ff_dmult:
   3139          setRegister(LO, I64(i128hilo & 0xfffffffffffffffful));
   3140          setRegister(HI, I64(i128hilo >> 64));
   3141          break;
   3142        case ff_multu:
   3143          setRegister(LO, I32(u128hilo & 0xffffffff));
   3144          setRegister(HI, I32(u128hilo >> 32));
   3145          break;
   3146        case ff_dmultu:
   3147          setRegister(LO, I64(u128hilo & 0xfffffffffffffffful));
   3148          setRegister(HI, I64(u128hilo >> 64));
   3149          break;
   3150        case ff_div:
   3151        case ff_divu:
   3152          // Divide by zero and overflow was not checked in the configuration
   3153          // step - div and divu do not raise exceptions. On division by 0
   3154          // the result will be UNPREDICTABLE. On overflow (INT_MIN/-1),
   3155          // return INT_MIN which is what the hardware does.
   3156          setRegister(LO, I32(i128hilo & 0xffffffff));
   3157          setRegister(HI, I32(i128hilo >> 32));
   3158          break;
   3159        case ff_ddiv:
   3160        case ff_ddivu:
   3161          // Divide by zero and overflow was not checked in the configuration
   3162          // step - div and divu do not raise exceptions. On division by 0
   3163          // the result will be UNPREDICTABLE. On overflow (INT_MIN/-1),
   3164          // return INT_MIN which is what the hardware does.
   3165          setRegister(LO, I64(i128hilo & 0xfffffffffffffffful));
   3166          setRegister(HI, I64(i128hilo >> 64));
   3167          break;
   3168        case ff_sync:
   3169          break;
   3170          // Break and trap instructions.
   3171        case ff_break:
   3172        case ff_tge:
   3173        case ff_tgeu:
   3174        case ff_tlt:
   3175        case ff_tltu:
   3176        case ff_teq:
   3177        case ff_tne:
   3178          if (do_interrupt) {
   3179            softwareInterrupt(instr);
   3180          }
   3181          break;
   3182          // Conditional moves.
   3183        case ff_movn:
   3184          if (rt) {
   3185            setRegister(rd_reg, rs);
   3186          }
   3187          break;
   3188        case ff_movci: {
   3189          uint32_t cc = instr->fbccValue();
   3190          uint32_t fcsr_cc = GetFCSRConditionBit(cc);
   3191          if (instr->bit(16)) {  // Read Tf bit.
   3192            if (testFCSRBit(fcsr_cc)) {
   3193              setRegister(rd_reg, rs);
   3194            }
   3195          } else {
   3196            if (!testFCSRBit(fcsr_cc)) {
   3197              setRegister(rd_reg, rs);
   3198            }
   3199          }
   3200          break;
   3201        }
   3202        case ff_movz:
   3203          if (!rt) {
   3204            setRegister(rd_reg, rs);
   3205          }
   3206          break;
   3207        default:  // For other special opcodes we do the default operation.
   3208          setRegister(rd_reg, alu_out);
   3209      };
   3210      break;
   3211    case op_special2:
   3212      switch (instr->functionFieldRaw()) {
   3213        case ff_mul:
   3214          setRegister(rd_reg, alu_out);
   3215          // HI and LO are UNPREDICTABLE after the operation.
   3216          setRegister(LO, Unpredictable);
   3217          setRegister(HI, Unpredictable);
   3218          break;
   3219        default:  // For other special2 opcodes we do the default operation.
   3220          setRegister(rd_reg, alu_out);
   3221      }
   3222      break;
   3223    case op_special3:
   3224      switch (instr->functionFieldRaw()) {
   3225        case ff_ins:
   3226        case ff_dins:
   3227        case ff_dinsm:
   3228        case ff_dinsu:
   3229          // Ins instr leaves result in Rt, rather than Rd.
   3230          setRegister(rt_reg, alu_out);
   3231          break;
   3232        case ff_ext:
   3233        case ff_dext:
   3234        case ff_dextm:
   3235        case ff_dextu:
   3236          // Ext instr leaves result in Rt, rather than Rd.
   3237          setRegister(rt_reg, alu_out);
   3238          break;
   3239        case ff_bshfl:
   3240          setRegister(rd_reg, alu_out);
   3241          break;
   3242        case ff_dbshfl:
   3243          setRegister(rd_reg, alu_out);
   3244          break;
   3245        default:
   3246          MOZ_CRASH();
   3247      };
   3248      break;
   3249      // Unimplemented opcodes raised an error in the configuration step before,
   3250      // so we can use the default here to set the destination register in
   3251      // common cases.
   3252    default:
   3253      setRegister(rd_reg, alu_out);
   3254  };
   3255 }
   3256 
   3257 // Type 2: instructions using a 16 bits immediate. (e.g. addi, beq).
   3258 void Simulator::decodeTypeImmediate(SimInstruction* instr) {
   3259  // Instruction fields.
   3260  OpcodeField op = instr->opcodeFieldRaw();
   3261  int64_t rs = getRegister(instr->rsValue());
   3262  int32_t rt_reg = instr->rtValue();  // Destination register.
   3263  int64_t rt = getRegister(rt_reg);
   3264  int16_t imm16 = instr->imm16Value();
   3265 
   3266  int32_t ft_reg = instr->ftValue();  // Destination register.
   3267 
   3268  // Zero extended immediate.
   3269  uint32_t oe_imm16 = 0xffff & imm16;
   3270  // Sign extended immediate.
   3271  int32_t se_imm16 = imm16;
   3272 
   3273  // Get current pc.
   3274  int64_t current_pc = get_pc();
   3275  // Next pc.
   3276  int64_t next_pc = bad_ra;
   3277 
   3278  // Used for conditional branch instructions.
   3279  bool do_branch = false;
   3280  bool execute_branch_delay_instruction = false;
   3281 
   3282  // Used for arithmetic instructions.
   3283  int64_t alu_out = 0;
   3284  // Unaligned access
   3285  uint8_t al_offset = 0;
   3286  uint64_t al_addr = 0;
   3287  // Floating point.
   3288  double fp_out = 0.0;
   3289  uint32_t cc, cc_value, fcsr_cc;
   3290 
   3291  // Used for memory instructions.
   3292  uint64_t addr = 0x0;
   3293  // Value to be written in memory.
   3294  uint64_t mem_value = 0x0;
   3295  __int128 temp;
   3296 
   3297  // ---------- Configuration (and execution for op_regimm).
   3298  switch (op) {
   3299      // ------------- op_cop1. Coprocessor instructions.
   3300    case op_cop1:
   3301      switch (instr->rsFieldRaw()) {
   3302        case rs_bc1:  // Branch on coprocessor condition.
   3303          cc = instr->fbccValue();
   3304          fcsr_cc = GetFCSRConditionBit(cc);
   3305          cc_value = testFCSRBit(fcsr_cc);
   3306          do_branch = (instr->fbtrueValue()) ? cc_value : !cc_value;
   3307          execute_branch_delay_instruction = true;
   3308          // Set next_pc.
   3309          if (do_branch) {
   3310            next_pc = current_pc + (imm16 << 2) + SimInstruction::kInstrSize;
   3311          } else {
   3312            next_pc = current_pc + kBranchReturnOffset;
   3313          }
   3314          break;
   3315        default:
   3316          MOZ_CRASH();
   3317      };
   3318      break;
   3319      // ------------- op_regimm class.
   3320    case op_regimm:
   3321      switch (instr->rtFieldRaw()) {
   3322        case rt_bltz:
   3323          do_branch = (rs < 0);
   3324          break;
   3325        case rt_bltzal:
   3326          do_branch = rs < 0;
   3327          break;
   3328        case rt_bgez:
   3329          do_branch = rs >= 0;
   3330          break;
   3331        case rt_bgezal:
   3332          do_branch = rs >= 0;
   3333          break;
   3334        default:
   3335          MOZ_CRASH();
   3336      };
   3337      switch (instr->rtFieldRaw()) {
   3338        case rt_bltz:
   3339        case rt_bltzal:
   3340        case rt_bgez:
   3341        case rt_bgezal:
   3342          // Branch instructions common part.
   3343          execute_branch_delay_instruction = true;
   3344          // Set next_pc.
   3345          if (do_branch) {
   3346            next_pc = current_pc + (imm16 << 2) + SimInstruction::kInstrSize;
   3347            if (instr->isLinkingInstruction()) {
   3348              setRegister(31, current_pc + kBranchReturnOffset);
   3349            }
   3350          } else {
   3351            next_pc = current_pc + kBranchReturnOffset;
   3352          }
   3353          break;
   3354        default:
   3355          break;
   3356      };
   3357      break;  // case op_regimm.
   3358      // ------------- Branch instructions.
   3359      // When comparing to zero, the encoding of rt field is always 0, so we
   3360      // don't need to replace rt with zero.
   3361    case op_beq:
   3362      do_branch = (rs == rt);
   3363      break;
   3364    case op_bne:
   3365      do_branch = rs != rt;
   3366      break;
   3367    case op_blez:
   3368      do_branch = rs <= 0;
   3369      break;
   3370    case op_bgtz:
   3371      do_branch = rs > 0;
   3372      break;
   3373      // ------------- Arithmetic instructions.
   3374    case op_addi:
   3375      alu_out = I32_CHECK(rs) + se_imm16;
   3376      if ((alu_out << 32) != (alu_out << 31)) {
   3377        exceptions[kIntegerOverflow] = 1;
   3378      }
   3379      alu_out = I32_CHECK(alu_out);
   3380      break;
   3381    case op_daddi:
   3382      temp = alu_out = rs + se_imm16;
   3383      if ((temp << 64) != (temp << 63)) {
   3384        exceptions[kIntegerOverflow] = 1;
   3385      }
   3386      alu_out = I64(temp);
   3387      break;
   3388    case op_addiu:
   3389      alu_out = I32(I32_CHECK(rs) + se_imm16);
   3390      break;
   3391    case op_daddiu:
   3392      alu_out = rs + se_imm16;
   3393      break;
   3394    case op_slti:
   3395      alu_out = (rs < se_imm16) ? 1 : 0;
   3396      break;
   3397    case op_sltiu:
   3398      alu_out = (U64(rs) < U64(se_imm16)) ? 1 : 0;
   3399      break;
   3400    case op_andi:
   3401      alu_out = rs & oe_imm16;
   3402      break;
   3403    case op_ori:
   3404      alu_out = rs | oe_imm16;
   3405      break;
   3406    case op_xori:
   3407      alu_out = rs ^ oe_imm16;
   3408      break;
   3409    case op_lui:
   3410      alu_out = (se_imm16 << 16);
   3411      break;
   3412      // ------------- Memory instructions.
   3413    case op_lbu:
   3414      addr = rs + se_imm16;
   3415      alu_out = readBU(addr, instr);
   3416      break;
   3417    case op_lb:
   3418      addr = rs + se_imm16;
   3419      alu_out = readB(addr, instr);
   3420      break;
   3421    case op_lhu:
   3422      addr = rs + se_imm16;
   3423      alu_out = readHU(addr, instr);
   3424      break;
   3425    case op_lh:
   3426      addr = rs + se_imm16;
   3427      alu_out = readH(addr, instr);
   3428      break;
   3429    case op_lwu:
   3430      addr = rs + se_imm16;
   3431      alu_out = readWU(addr, instr);
   3432      break;
   3433    case op_lw:
   3434      addr = rs + se_imm16;
   3435      alu_out = readW(addr, instr);
   3436      break;
   3437    case op_lwl: {
   3438      // al_offset is offset of the effective address within an aligned word.
   3439      al_offset = (rs + se_imm16) & 3;
   3440      uint8_t byte_shift = 3 - al_offset;
   3441      uint32_t mask = (1 << byte_shift * 8) - 1;
   3442      addr = rs + se_imm16;
   3443      al_addr = addr - al_offset;
   3444      // handle segfault at the unaligned address first
   3445      if (handleWasmSegFault(addr - 3, 4)) {
   3446        alu_out = -1;
   3447      } else {
   3448        alu_out = readW(al_addr, instr);
   3449      }
   3450      alu_out <<= byte_shift * 8;
   3451      alu_out |= rt & mask;
   3452      break;
   3453    }
   3454    case op_lwr: {
   3455      // al_offset is offset of the effective address within an aligned word.
   3456      al_offset = (rs + se_imm16) & 3;
   3457      uint8_t byte_shift = 3 - al_offset;
   3458      uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
   3459      addr = rs + se_imm16;
   3460      al_addr = addr - al_offset;
   3461      // handle segfault at the unaligned address first
   3462      if (handleWasmSegFault(addr, 4)) {
   3463        alu_out = -1;
   3464      } else {
   3465        alu_out = readW(al_addr, instr);
   3466      }
   3467      alu_out = U32(alu_out) >> al_offset * 8;
   3468      alu_out |= rt & mask;
   3469      alu_out = I32(alu_out);
   3470      break;
   3471    }
   3472    case op_ll:
   3473      addr = rs + se_imm16;
   3474      alu_out = loadLinkedW(addr, instr);
   3475      break;
   3476    case op_lld:
   3477      addr = rs + se_imm16;
   3478      alu_out = loadLinkedD(addr, instr);
   3479      break;
   3480    case op_ld:
   3481      addr = rs + se_imm16;
   3482      alu_out = readDW(addr, instr);
   3483      break;
   3484    case op_ldl: {
   3485      // al_offset is offset of the effective address within an aligned word.
   3486      al_offset = (rs + se_imm16) & 7;
   3487      addr = rs + se_imm16;
   3488      al_addr = addr - al_offset;
   3489      uint8_t byte_shift = 7 - al_offset;
   3490      uint64_t mask = (1ul << byte_shift * 8) - 1;
   3491      // handle segfault at the unaligned address first
   3492      if (handleWasmSegFault(addr - 7, 8)) {
   3493        alu_out = -1;
   3494      } else {
   3495        alu_out = readDW(al_addr, instr);
   3496      }
   3497      alu_out <<= byte_shift * 8;
   3498      alu_out |= rt & mask;
   3499      break;
   3500    }
   3501    case op_ldr: {
   3502      // al_offset is offset of the effective address within an aligned word.
   3503      al_offset = (rs + se_imm16) & 7;
   3504      addr = rs + se_imm16;
   3505      al_addr = addr - al_offset;
   3506      uint8_t byte_shift = 7 - al_offset;
   3507      uint64_t mask = al_offset ? (~0ul << (byte_shift + 1) * 8) : 0;
   3508      // handle segfault at the unaligned address first
   3509      if (handleWasmSegFault(addr, 8)) {
   3510        alu_out = -1;
   3511      } else {
   3512        alu_out = readDW(al_addr, instr);
   3513      }
   3514      alu_out = U64(alu_out) >> al_offset * 8;
   3515      alu_out |= rt & mask;
   3516      break;
   3517    }
   3518    case op_sb:
   3519      addr = rs + se_imm16;
   3520      break;
   3521    case op_sh:
   3522      addr = rs + se_imm16;
   3523      break;
   3524    case op_sw:
   3525      addr = rs + se_imm16;
   3526      break;
   3527    case op_swl:
   3528    case op_swr:
   3529      al_offset = (rs + se_imm16) & 3;
   3530      addr = rs + se_imm16;
   3531      al_addr = addr - al_offset;
   3532      break;
   3533    case op_sc:
   3534      addr = rs + se_imm16;
   3535      break;
   3536    case op_scd:
   3537      addr = rs + se_imm16;
   3538      break;
   3539    case op_sd:
   3540      addr = rs + se_imm16;
   3541      break;
   3542    case op_sdl:
   3543    case op_sdr: {
   3544      al_offset = (rs + se_imm16) & 7;
   3545      addr = rs + se_imm16;
   3546      al_addr = addr - al_offset;
   3547      break;
   3548    }
   3549    case op_lwc1:
   3550      addr = rs + se_imm16;
   3551      alu_out = readW(addr, instr);
   3552      break;
   3553    case op_ldc1:
   3554      addr = rs + se_imm16;
   3555      fp_out = readD(addr, instr);
   3556      break;
   3557    case op_swc1:
   3558    case op_sdc1:
   3559      addr = rs + se_imm16;
   3560      break;
   3561    default:
   3562      MOZ_CRASH();
   3563  };
   3564 
   3565  // ---------- Raise exceptions triggered.
   3566  signalExceptions();
   3567 
   3568  // ---------- Execution.
   3569  switch (op) {
   3570      // ------------- Branch instructions.
   3571    case op_beq:
   3572    case op_bne:
   3573    case op_blez:
   3574    case op_bgtz:
   3575      // Branch instructions common part.
   3576      execute_branch_delay_instruction = true;
   3577      // Set next_pc.
   3578      if (do_branch) {
   3579        next_pc = current_pc + (imm16 << 2) + SimInstruction::kInstrSize;
   3580        if (instr->isLinkingInstruction()) {
   3581          setRegister(31, current_pc + 2 * SimInstruction::kInstrSize);
   3582        }
   3583      } else {
   3584        next_pc = current_pc + 2 * SimInstruction::kInstrSize;
   3585      }
   3586      break;
   3587      // ------------- Arithmetic instructions.
   3588    case op_addi:
   3589    case op_daddi:
   3590    case op_addiu:
   3591    case op_daddiu:
   3592    case op_slti:
   3593    case op_sltiu:
   3594    case op_andi:
   3595    case op_ori:
   3596    case op_xori:
   3597    case op_lui:
   3598      setRegister(rt_reg, alu_out);
   3599      break;
   3600      // ------------- Memory instructions.
   3601    case op_lbu:
   3602    case op_lb:
   3603    case op_lhu:
   3604    case op_lh:
   3605    case op_lwu:
   3606    case op_lw:
   3607    case op_lwl:
   3608    case op_lwr:
   3609    case op_ll:
   3610    case op_lld:
   3611    case op_ld:
   3612    case op_ldl:
   3613    case op_ldr:
   3614      setRegister(rt_reg, alu_out);
   3615      break;
   3616    case op_sb:
   3617      writeB(addr, I8(rt), instr);
   3618      break;
   3619    case op_sh:
   3620      writeH(addr, U16(rt), instr);
   3621      break;
   3622    case op_sw:
   3623      writeW(addr, I32(rt), instr);
   3624      break;
   3625    case op_swl: {
   3626      // handle segfault at the unaligned address first
   3627      if (handleWasmSegFault(addr - 3, 4)) {
   3628        break;
   3629      }
   3630      uint8_t byte_shift = 3 - al_offset;
   3631      uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
   3632      mem_value = readW(al_addr, instr) & mask;
   3633      mem_value |= U32(rt) >> byte_shift * 8;
   3634      writeW(al_addr, I32(mem_value), instr);
   3635      break;
   3636    }
   3637    case op_swr: {
   3638      // handle segfault at the unaligned address first
   3639      if (handleWasmSegFault(addr, 4)) {
   3640        break;
   3641      }
   3642      uint32_t mask = (1 << al_offset * 8) - 1;
   3643      mem_value = readW(al_addr, instr);
   3644      mem_value = (rt << al_offset * 8) | (mem_value & mask);
   3645      writeW(al_addr, I32(mem_value), instr);
   3646      break;
   3647    }
   3648    case op_sc:
   3649      setRegister(rt_reg, storeConditionalW(addr, I32(rt), instr));
   3650      break;
   3651    case op_scd:
   3652      setRegister(rt_reg, storeConditionalD(addr, rt, instr));
   3653      break;
   3654    case op_sd:
   3655      writeDW(addr, rt, instr);
   3656      break;
   3657    case op_sdl: {
   3658      // handle segfault at the unaligned address first
   3659      if (handleWasmSegFault(addr - 7, 8)) {
   3660        break;
   3661      }
   3662      uint8_t byte_shift = 7 - al_offset;
   3663      uint64_t mask = byte_shift ? (~0ul << (al_offset + 1) * 8) : 0;
   3664      mem_value = readW(al_addr, instr) & mask;
   3665      mem_value |= U64(rt) >> byte_shift * 8;
   3666      writeDW(al_addr, mem_value, instr);
   3667      break;
   3668    }
   3669    case op_sdr: {
   3670      // handle segfault at the unaligned address first
   3671      if (handleWasmSegFault(addr, 8)) {
   3672        break;
   3673      }
   3674      uint64_t mask = (1ul << al_offset * 8) - 1;
   3675      mem_value = readW(al_addr, instr);
   3676      mem_value = (rt << al_offset * 8) | (mem_value & mask);
   3677      writeDW(al_addr, mem_value, instr);
   3678      break;
   3679    }
   3680    case op_lwc1:
   3681      setFpuRegisterLo(ft_reg, alu_out);
   3682      break;
   3683    case op_ldc1:
   3684      setFpuRegisterDouble(ft_reg, fp_out);
   3685      break;
   3686    case op_swc1:
   3687      writeW(addr, getFpuRegisterLo(ft_reg), instr);
   3688      break;
   3689    case op_sdc1:
   3690      writeD(addr, getFpuRegisterDouble(ft_reg), instr);
   3691      break;
   3692    default:
   3693      break;
   3694  };
   3695 
   3696  if (execute_branch_delay_instruction) {
   3697    // Execute branch delay slot
   3698    // We don't check for end_sim_pc. First it should not be met as the current
   3699    // pc is valid. Secondly a jump should always execute its branch delay slot.
   3700    SimInstruction* branch_delay_instr = reinterpret_cast<SimInstruction*>(
   3701        current_pc + SimInstruction::kInstrSize);
   3702    branchDelayInstructionDecode(branch_delay_instr);
   3703  }
   3704 
   3705  // If needed update pc after the branch delay execution.
   3706  if (next_pc != bad_ra) {
   3707    set_pc(next_pc);
   3708  }
   3709 }
   3710 
   3711 // Type 3: instructions using a 26 bits immediate. (e.g. j, jal).
   3712 void Simulator::decodeTypeJump(SimInstruction* instr) {
   3713  // Get current pc.
   3714  int64_t current_pc = get_pc();
   3715  // Get unchanged bits of pc.
   3716  int64_t pc_high_bits = current_pc & 0xfffffffff0000000ul;
   3717  // Next pc.
   3718  int64_t next_pc = pc_high_bits | (instr->imm26Value() << 2);
   3719 
   3720  // Execute branch delay slot.
   3721  // We don't check for end_sim_pc. First it should not be met as the current pc
   3722  // is valid. Secondly a jump should always execute its branch delay slot.
   3723  SimInstruction* branch_delay_instr = reinterpret_cast<SimInstruction*>(
   3724      current_pc + SimInstruction::kInstrSize);
   3725  branchDelayInstructionDecode(branch_delay_instr);
   3726 
   3727  // Update pc and ra if necessary.
   3728  // Do this after the branch delay execution.
   3729  if (instr->isLinkingInstruction()) {
   3730    setRegister(31, current_pc + 2 * SimInstruction::kInstrSize);
   3731  }
   3732  set_pc(next_pc);
   3733  pc_modified_ = true;
   3734 }
   3735 
   3736 // Executes the current instruction.
   3737 void Simulator::instructionDecode(SimInstruction* instr) {
   3738  if (!SimulatorProcess::ICacheCheckingDisableCount) {
   3739    AutoLockSimulatorCache als;
   3740    SimulatorProcess::checkICacheLocked(instr);
   3741  }
   3742  pc_modified_ = false;
   3743 
   3744  switch (instr->instructionType()) {
   3745    case SimInstruction::kRegisterType:
   3746      decodeTypeRegister(instr);
   3747      break;
   3748    case SimInstruction::kImmediateType:
   3749      decodeTypeImmediate(instr);
   3750      break;
   3751    case SimInstruction::kJumpType:
   3752      decodeTypeJump(instr);
   3753      break;
   3754    default:
   3755      UNSUPPORTED();
   3756  }
   3757  if (!pc_modified_) {
   3758    setRegister(pc,
   3759                reinterpret_cast<int64_t>(instr) + SimInstruction::kInstrSize);
   3760  }
   3761 }
   3762 
   3763 void Simulator::branchDelayInstructionDecode(SimInstruction* instr) {
   3764  if (instr->instructionBits() == NopInst) {
   3765    // Short-cut generic nop instructions. They are always valid and they
   3766    // never change the simulator state.
   3767    return;
   3768  }
   3769 
   3770  if (instr->isForbiddenInBranchDelay()) {
   3771    MOZ_CRASH("Error: Unexpected opcode in a branch delay slot.");
   3772  }
   3773  instructionDecode(instr);
   3774 }
   3775 
   3776 void Simulator::enable_single_stepping(SingleStepCallback cb, void* arg) {
   3777  single_stepping_ = true;
   3778  single_step_callback_ = cb;
   3779  single_step_callback_arg_ = arg;
   3780  single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
   3781 }
   3782 
   3783 void Simulator::disable_single_stepping() {
   3784  if (!single_stepping_) {
   3785    return;
   3786  }
   3787  single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
   3788  single_stepping_ = false;
   3789  single_step_callback_ = nullptr;
   3790  single_step_callback_arg_ = nullptr;
   3791 }
   3792 
   3793 template <bool enableStopSimAt>
   3794 void Simulator::execute() {
   3795  if (single_stepping_) {
   3796    single_step_callback_(single_step_callback_arg_, this, nullptr);
   3797  }
   3798 
   3799  // Get the PC to simulate. Cannot use the accessor here as we need the
   3800  // raw PC value and not the one used as input to arithmetic instructions.
   3801  int64_t program_counter = get_pc();
   3802 
   3803  while (program_counter != end_sim_pc) {
   3804    if (enableStopSimAt && (icount_ == Simulator::StopSimAt)) {
   3805      MipsDebugger dbg(this);
   3806      dbg.debug();
   3807    } else {
   3808      if (single_stepping_) {
   3809        single_step_callback_(single_step_callback_arg_, this,
   3810                              (void*)program_counter);
   3811      }
   3812      SimInstruction* instr =
   3813          reinterpret_cast<SimInstruction*>(program_counter);
   3814      instructionDecode(instr);
   3815      icount_++;
   3816    }
   3817    program_counter = get_pc();
   3818  }
   3819 
   3820  if (single_stepping_) {
   3821    single_step_callback_(single_step_callback_arg_, this, nullptr);
   3822  }
   3823 }
   3824 
   3825 void Simulator::callInternal(uint8_t* entry) {
   3826  // Prepare to execute the code at entry.
   3827  setRegister(pc, reinterpret_cast<int64_t>(entry));
   3828  // Put down marker for end of simulation. The simulator will stop simulation
   3829  // when the PC reaches this value. By saving the "end simulation" value into
   3830  // the LR the simulation stops when returning to this call point.
   3831  setRegister(ra, end_sim_pc);
   3832 
   3833  // Remember the values of callee-saved registers.
   3834  // The code below assumes that r9 is not used as sb (static base) in
   3835  // simulator code and therefore is regarded as a callee-saved register.
   3836  int64_t s0_val = getRegister(s0);
   3837  int64_t s1_val = getRegister(s1);
   3838  int64_t s2_val = getRegister(s2);
   3839  int64_t s3_val = getRegister(s3);
   3840  int64_t s4_val = getRegister(s4);
   3841  int64_t s5_val = getRegister(s5);
   3842  int64_t s6_val = getRegister(s6);
   3843  int64_t s7_val = getRegister(s7);
   3844  int64_t gp_val = getRegister(gp);
   3845  int64_t sp_val = getRegister(sp);
   3846  int64_t fp_val = getRegister(fp);
   3847 
   3848  // Set up the callee-saved registers with a known value. To be able to check
   3849  // that they are preserved properly across JS execution.
   3850  int64_t callee_saved_value = icount_;
   3851  setRegister(s0, callee_saved_value);
   3852  setRegister(s1, callee_saved_value);
   3853  setRegister(s2, callee_saved_value);
   3854  setRegister(s3, callee_saved_value);
   3855  setRegister(s4, callee_saved_value);
   3856  setRegister(s5, callee_saved_value);
   3857  setRegister(s6, callee_saved_value);
   3858  setRegister(s7, callee_saved_value);
   3859  setRegister(gp, callee_saved_value);
   3860  setRegister(fp, callee_saved_value);
   3861 
   3862  // Start the simulation.
   3863  if (Simulator::StopSimAt != -1) {
   3864    execute<true>();
   3865  } else {
   3866    execute<false>();
   3867  }
   3868 
   3869  // Check that the callee-saved registers have been preserved.
   3870  MOZ_ASSERT(callee_saved_value == getRegister(s0));
   3871  MOZ_ASSERT(callee_saved_value == getRegister(s1));
   3872  MOZ_ASSERT(callee_saved_value == getRegister(s2));
   3873  MOZ_ASSERT(callee_saved_value == getRegister(s3));
   3874  MOZ_ASSERT(callee_saved_value == getRegister(s4));
   3875  MOZ_ASSERT(callee_saved_value == getRegister(s5));
   3876  MOZ_ASSERT(callee_saved_value == getRegister(s6));
   3877  MOZ_ASSERT(callee_saved_value == getRegister(s7));
   3878  MOZ_ASSERT(callee_saved_value == getRegister(gp));
   3879  MOZ_ASSERT(callee_saved_value == getRegister(fp));
   3880 
   3881  // Restore callee-saved registers with the original value.
   3882  setRegister(s0, s0_val);
   3883  setRegister(s1, s1_val);
   3884  setRegister(s2, s2_val);
   3885  setRegister(s3, s3_val);
   3886  setRegister(s4, s4_val);
   3887  setRegister(s5, s5_val);
   3888  setRegister(s6, s6_val);
   3889  setRegister(s7, s7_val);
   3890  setRegister(gp, gp_val);
   3891  setRegister(sp, sp_val);
   3892  setRegister(fp, fp_val);
   3893 }
   3894 
   3895 int64_t Simulator::call(uint8_t* entry, int argument_count, ...) {
   3896  va_list parameters;
   3897  va_start(parameters, argument_count);
   3898 
   3899  int64_t original_stack = getRegister(sp);
   3900  // Compute position of stack on entry to generated code.
   3901  int64_t entry_stack = original_stack;
   3902  if (argument_count > kCArgSlotCount) {
   3903    entry_stack = entry_stack - argument_count * sizeof(int64_t);
   3904  } else {
   3905    entry_stack = entry_stack - kCArgsSlotsSize;
   3906  }
   3907 
   3908  entry_stack &= ~U64(ABIStackAlignment - 1);
   3909 
   3910  intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
   3911 
   3912  // Setup the arguments.
   3913  for (int i = 0; i < argument_count; i++) {
   3914    js::jit::Register argReg;
   3915    if (GetIntArgReg(i, &argReg)) {
   3916      setRegister(argReg.code(), va_arg(parameters, int64_t));
   3917    } else {
   3918      stack_argument[i] = va_arg(parameters, int64_t);
   3919    }
   3920  }
   3921 
   3922  va_end(parameters);
   3923  setRegister(sp, entry_stack);
   3924 
   3925  callInternal(entry);
   3926 
   3927  // Pop stack passed arguments.
   3928  MOZ_ASSERT(entry_stack == getRegister(sp));
   3929  setRegister(sp, original_stack);
   3930 
   3931  int64_t result = getRegister(v0);
   3932  return result;
   3933 }
   3934 
   3935 uintptr_t Simulator::pushAddress(uintptr_t address) {
   3936  int new_sp = getRegister(sp) - sizeof(uintptr_t);
   3937  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
   3938  *stack_slot = address;
   3939  setRegister(sp, new_sp);
   3940  return new_sp;
   3941 }
   3942 
   3943 uintptr_t Simulator::popAddress() {
   3944  int current_sp = getRegister(sp);
   3945  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
   3946  uintptr_t address = *stack_slot;
   3947  setRegister(sp, current_sp + sizeof(uintptr_t));
   3948  return address;
   3949 }
   3950 
   3951 }  // namespace jit
   3952 }  // namespace js
   3953 
   3954 js::jit::Simulator* JSContext::simulator() const { return simulator_; }