tor-browser

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

Simulator-riscv64.cpp (138695B)


      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 2021 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 #ifdef JS_SIMULATOR_RISCV64
     30 #  include "jit/riscv64/Simulator-riscv64.h"
     31 
     32 #  include "mozilla/Casting.h"
     33 #  include "mozilla/IntegerPrintfMacros.h"
     34 
     35 #  include <cinttypes>
     36 #  include <float.h>
     37 #  include <iostream>
     38 #  include <limits>
     39 
     40 #  include "jit/AtomicOperations.h"
     41 #  include "jit/riscv64/Assembler-riscv64.h"
     42 #  include "js/Conversions.h"
     43 #  include "js/UniquePtr.h"
     44 #  include "js/Utility.h"
     45 #  include "threading/LockGuard.h"
     46 #  include "vm/JSContext.h"
     47 #  include "vm/Runtime.h"
     48 #  include "wasm/WasmInstance.h"
     49 #  include "wasm/WasmSignalHandlers.h"
     50 
     51 #  define I8(v) static_cast<int8_t>(v)
     52 #  define I16(v) static_cast<int16_t>(v)
     53 #  define U16(v) static_cast<uint16_t>(v)
     54 #  define I32(v) static_cast<int32_t>(v)
     55 #  define U32(v) static_cast<uint32_t>(v)
     56 #  define I64(v) static_cast<int64_t>(v)
     57 #  define U64(v) static_cast<uint64_t>(v)
     58 #  define I128(v) static_cast<__int128_t>(v)
     59 #  define U128(v) static_cast<__uint128_t>(v)
     60 
     61 #  define REGIx_FORMAT PRIx64
     62 #  define REGId_FORMAT PRId64
     63 
     64 #  define I32_CHECK(v)                   \
     65    ({                                   \
     66      MOZ_ASSERT(I64(I32(v)) == I64(v)); \
     67      I32((v));                          \
     68    })
     69 
     70 namespace js {
     71 namespace jit {
     72 
     73 bool Simulator::FLAG_trace_sim = false;
     74 bool Simulator::FLAG_debug_sim = false;
     75 bool Simulator::FLAG_riscv_trap_to_simulator_debugger = false;
     76 bool Simulator::FLAG_riscv_print_watchpoint = false;
     77 
     78 static void UNIMPLEMENTED() {
     79  printf("UNIMPLEMENTED instruction.\n");
     80  MOZ_CRASH();
     81 }
     82 static void UNREACHABLE() {
     83  printf("UNREACHABLE instruction.\n");
     84  MOZ_CRASH();
     85 }
     86 #  define UNSUPPORTED()                                                \
     87    std::cout << "Unrecognized instruction [@pc=0x" << std::hex        \
     88              << registers_[pc] << "]: 0x" << instr_.InstructionBits() \
     89              << std::endl;                                            \
     90    printf("Unsupported instruction.\n");                              \
     91    MOZ_CRASH();
     92 
     93 static char* ReadLine(const char* prompt) {
     94  UniqueChars result;
     95  char lineBuf[256];
     96  int offset = 0;
     97  bool keepGoing = true;
     98  fprintf(stdout, "%s", prompt);
     99  fflush(stdout);
    100  while (keepGoing) {
    101    if (fgets(lineBuf, sizeof(lineBuf), stdin) == nullptr) {
    102      // fgets got an error. Just give up.
    103      return nullptr;
    104    }
    105    int len = strlen(lineBuf);
    106    if (len > 0 && lineBuf[len - 1] == '\n') {
    107      // Since we read a new line we are done reading the line. This
    108      // will exit the loop after copying this buffer into the result.
    109      keepGoing = false;
    110    }
    111    if (!result) {
    112      // Allocate the initial result and make room for the terminating '\0'
    113      result.reset(js_pod_malloc<char>(len + 1));
    114      if (!result) {
    115        return nullptr;
    116      }
    117    } else {
    118      // Allocate a new result with enough room for the new addition.
    119      int new_len = offset + len + 1;
    120      char* new_result = js_pod_malloc<char>(new_len);
    121      if (!new_result) {
    122        return nullptr;
    123      }
    124      // Copy the existing input into the new array and set the new
    125      // array as the result.
    126      memcpy(new_result, result.get(), offset * sizeof(char));
    127      result.reset(new_result);
    128    }
    129    // Copy the newly read line into the result.
    130    memcpy(result.get() + offset, lineBuf, len * sizeof(char));
    131    offset += len;
    132  }
    133 
    134  MOZ_ASSERT(result);
    135  result[offset] = '\0';
    136  return result.release();
    137 }
    138 
    139 // -----------------------------------------------------------------------------
    140 // Riscv assembly various constants.
    141 
    142 // C/C++ argument slots size.
    143 const int kCArgSlotCount = 0;
    144 const int kCArgsSlotsSize = kCArgSlotCount * sizeof(uintptr_t);
    145 const int kBranchReturnOffset = 2 * kInstrSize;
    146 
    147 class CachePage {
    148 public:
    149  static const int LINE_VALID = 0;
    150  static const int LINE_INVALID = 1;
    151 
    152  static const int kPageShift = 12;
    153  static const int kPageSize = 1 << kPageShift;
    154  static const int kPageMask = kPageSize - 1;
    155  static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
    156  static const int kLineLength = 1 << kLineShift;
    157  static const int kLineMask = kLineLength - 1;
    158 
    159  CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
    160 
    161  char* validityByte(int offset) {
    162    return &validity_map_[offset >> kLineShift];
    163  }
    164 
    165  char* cachedData(int offset) { return &data_[offset]; }
    166 
    167 private:
    168  char data_[kPageSize];  // The cached data.
    169  static const int kValidityMapSize = kPageSize >> kLineShift;
    170  char validity_map_[kValidityMapSize];  // One byte per line.
    171 };
    172 
    173 // Protects the icache() and redirection() properties of the
    174 // Simulator.
    175 class AutoLockSimulatorCache : public LockGuard<Mutex> {
    176  using Base = LockGuard<Mutex>;
    177 
    178 public:
    179  explicit AutoLockSimulatorCache()
    180      : Base(SimulatorProcess::singleton_->cacheLock_) {}
    181 };
    182 
    183 mozilla::Atomic<size_t, mozilla::ReleaseAcquire>
    184    SimulatorProcess::ICacheCheckingDisableCount(
    185        1);  // Checking is disabled by default.
    186 SimulatorProcess* SimulatorProcess::singleton_ = nullptr;
    187 
    188 int64_t Simulator::StopSimAt = -1;
    189 
    190 static bool IsFlag(const char* found, const char* flag) {
    191  return strlen(found) == strlen(flag) && strcmp(found, flag) == 0;
    192 }
    193 
    194 Simulator* Simulator::Create() {
    195  auto sim = MakeUnique<Simulator>();
    196  if (!sim) {
    197    return nullptr;
    198  }
    199 
    200  if (!sim->init()) {
    201    return nullptr;
    202  }
    203 
    204  int64_t stopAt;
    205  char* stopAtStr = getenv("RISCV_SIM_STOP_AT");
    206  if (stopAtStr && sscanf(stopAtStr, "%" PRIi64, &stopAt) == 1) {
    207    fprintf(stderr, "\nStopping simulation at icount %" PRIi64 "\n", stopAt);
    208    Simulator::StopSimAt = stopAt;
    209  }
    210  char* str = getenv("RISCV_TRACE_SIM");
    211  if (str != nullptr && IsFlag(str, "true")) {
    212    FLAG_trace_sim = true;
    213  }
    214 
    215  return sim.release();
    216 }
    217 
    218 void Simulator::Destroy(Simulator* sim) { js_delete(sim); }
    219 
    220 #  if JS_CODEGEN_RISCV64
    221 void Simulator::TraceRegWr(int64_t value, TraceType t) {
    222  if (FLAG_trace_sim) {
    223    union {
    224      int64_t fmt_int64;
    225      int32_t fmt_int32[2];
    226      float fmt_float[2];
    227      double fmt_double;
    228    } v;
    229    v.fmt_int64 = value;
    230 
    231    switch (t) {
    232      case WORD:
    233        SNPrintF(trace_buf_,
    234                 "%016" REGIx_FORMAT "    (%" PRId64 ")    int32:%" PRId32
    235                 " uint32:%" PRIu32,
    236                 v.fmt_int64, icount_, v.fmt_int32[0], v.fmt_int32[0]);
    237        break;
    238      case DWORD:
    239        SNPrintF(trace_buf_,
    240                 "%016" REGIx_FORMAT "    (%" PRId64 ")    int64:%" REGId_FORMAT
    241                 " uint64:%" PRIu64,
    242                 value, icount_, value, value);
    243        break;
    244      case FLOAT:
    245        SNPrintF(trace_buf_, "%016" REGIx_FORMAT "    (%" PRId64 ")    flt:%e",
    246                 v.fmt_int64, icount_, v.fmt_float[0]);
    247        break;
    248      case DOUBLE:
    249        SNPrintF(trace_buf_, "%016" REGIx_FORMAT "    (%" PRId64 ")    dbl:%e",
    250                 v.fmt_int64, icount_, v.fmt_double);
    251        break;
    252      default:
    253        UNREACHABLE();
    254    }
    255  }
    256 }
    257 
    258 #  elif JS_CODEGEN_RISCV32
    259 template <typename T>
    260 void Simulator::TraceRegWr(T value, TraceType t) {
    261  if (::v8::internal::FLAG_trace_sim) {
    262    union {
    263      int32_t fmt_int32;
    264      float fmt_float;
    265      double fmt_double;
    266    } v;
    267    if (t != DOUBLE) {
    268      v.fmt_int32 = value;
    269    } else {
    270      DCHECK_EQ(sizeof(T), 8);
    271      v.fmt_double = value;
    272    }
    273    switch (t) {
    274      case WORD:
    275        SNPrintF(trace_buf_,
    276                 "%016" REGIx_FORMAT "    (%" PRId64 ")    int32:%" REGId_FORMAT
    277                 " uint32:%" PRIu32,
    278                 v.fmt_int32, icount_, v.fmt_int32, v.fmt_int32);
    279        break;
    280      case FLOAT:
    281        SNPrintF(trace_buf_, "%016" REGIx_FORMAT "    (%" PRId64 ")    flt:%e",
    282                 v.fmt_int32, icount_, v.fmt_float);
    283        break;
    284      case DOUBLE:
    285        SNPrintF(trace_buf_, "%016" PRIx64 "    (%" PRId64 ")    dbl:%e",
    286                 static_cast<int64_t>(v.fmt_double), icount_, v.fmt_double);
    287        break;
    288      default:
    289        UNREACHABLE();
    290    }
    291  }
    292 }
    293 #  endif
    294 // The RiscvDebugger class is used by the simulator while debugging simulated
    295 // code.
    296 class RiscvDebugger {
    297 public:
    298  explicit RiscvDebugger(Simulator* sim) : sim_(sim) {}
    299 
    300  void Debug();
    301  // Print all registers with a nice formatting.
    302  void PrintRegs(char name_prefix, int start_index, int end_index);
    303  void printAllRegs();
    304  void printAllRegsIncludingFPU();
    305 
    306  static const Instr kNopInstr = 0x0;
    307 
    308 private:
    309  Simulator* sim_;
    310 
    311  int64_t GetRegisterValue(int regnum);
    312  int64_t GetFPURegisterValue(int regnum);
    313  float GetFPURegisterValueFloat(int regnum);
    314  double GetFPURegisterValueDouble(int regnum);
    315 #  ifdef CAN_USE_RVV_INSTRUCTIONS
    316  __int128_t GetVRegisterValue(int regnum);
    317 #  endif
    318  bool GetValue(const char* desc, int64_t* value);
    319 };
    320 
    321 int64_t RiscvDebugger::GetRegisterValue(int regnum) {
    322  if (regnum == Simulator::Register::kNumSimuRegisters) {
    323    return sim_->get_pc();
    324  } else {
    325    return sim_->getRegister(regnum);
    326  }
    327 }
    328 
    329 int64_t RiscvDebugger::GetFPURegisterValue(int regnum) {
    330  if (regnum == Simulator::FPURegister::kNumFPURegisters) {
    331    return sim_->get_pc();
    332  } else {
    333    return sim_->getFpuRegister(regnum);
    334  }
    335 }
    336 
    337 float RiscvDebugger::GetFPURegisterValueFloat(int regnum) {
    338  if (regnum == Simulator::FPURegister::kNumFPURegisters) {
    339    return sim_->get_pc();
    340  } else {
    341    return sim_->getFpuRegisterFloat(regnum);
    342  }
    343 }
    344 
    345 double RiscvDebugger::GetFPURegisterValueDouble(int regnum) {
    346  if (regnum == Simulator::FPURegister::kNumFPURegisters) {
    347    return sim_->get_pc();
    348  } else {
    349    return sim_->getFpuRegisterDouble(regnum);
    350  }
    351 }
    352 
    353 #  ifdef CAN_USE_RVV_INSTRUCTIONS
    354 __int128_t RiscvDebugger::GetVRegisterValue(int regnum) {
    355  if (regnum == kNumVRegisters) {
    356    return sim_->get_pc();
    357  } else {
    358    return sim_->get_vregister(regnum);
    359  }
    360 }
    361 #  endif
    362 
    363 bool RiscvDebugger::GetValue(const char* desc, int64_t* value) {
    364  int regnum = Registers::FromName(desc);
    365  int fpuregnum = FloatRegisters::FromName(desc);
    366 
    367  if (regnum != Registers::invalid_reg) {
    368    *value = GetRegisterValue(regnum);
    369    return true;
    370  } else if (fpuregnum != FloatRegisters::invalid_reg) {
    371    *value = GetFPURegisterValue(fpuregnum);
    372    return true;
    373  } else if (strncmp(desc, "0x", 2) == 0) {
    374    return sscanf(desc + 2, "%" SCNx64, reinterpret_cast<int64_t*>(value)) == 1;
    375  } else {
    376    return sscanf(desc, "%" SCNu64, reinterpret_cast<int64_t*>(value)) == 1;
    377  }
    378 }
    379 
    380 #  define REG_INFO(name)                               \
    381    name, GetRegisterValue(Registers::FromName(name)), \
    382        GetRegisterValue(Registers::FromName(name))
    383 
    384 void RiscvDebugger::PrintRegs(char name_prefix, int start_index,
    385                              int end_index) {
    386  EmbeddedVector<char, 10> name1, name2;
    387  MOZ_ASSERT(name_prefix == 'a' || name_prefix == 't' || name_prefix == 's');
    388  MOZ_ASSERT(start_index >= 0 && end_index <= 99);
    389  int num_registers = (end_index - start_index) + 1;
    390  for (int i = 0; i < num_registers / 2; i++) {
    391    SNPrintF(name1, "%c%d", name_prefix, start_index + 2 * i);
    392    SNPrintF(name2, "%c%d", name_prefix, start_index + 2 * i + 1);
    393    printf("%3s: 0x%016" REGIx_FORMAT "  %14" REGId_FORMAT
    394           " \t%3s: 0x%016" REGIx_FORMAT "  %14" REGId_FORMAT " \n",
    395           REG_INFO(name1.start()), REG_INFO(name2.start()));
    396  }
    397  if (num_registers % 2 == 1) {
    398    SNPrintF(name1, "%c%d", name_prefix, end_index);
    399    printf("%3s: 0x%016" REGIx_FORMAT "  %14" REGId_FORMAT " \n",
    400           REG_INFO(name1.start()));
    401  }
    402 }
    403 
    404 void RiscvDebugger::printAllRegs() {
    405  printf("\n");
    406  // ra, sp, gp
    407  printf("%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT
    408         "\t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT
    409         "\t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT "\n",
    410         REG_INFO("ra"), REG_INFO("sp"), REG_INFO("gp"));
    411 
    412  // tp, fp, pc
    413  printf("%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT
    414         "\t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT
    415         "\t%3s: 0x%016" REGIx_FORMAT " %14" REGId_FORMAT "\n",
    416         REG_INFO("tp"), REG_INFO("fp"), REG_INFO("pc"));
    417 
    418  // print register a0, .., a7
    419  PrintRegs('a', 0, 7);
    420  // print registers s1, ..., s11
    421  PrintRegs('s', 1, 11);
    422  // print registers t0, ..., t6
    423  PrintRegs('t', 0, 6);
    424 }
    425 
    426 #  undef REG_INFO
    427 
    428 void RiscvDebugger::printAllRegsIncludingFPU() {
    429 #  define FPU_REG_INFO(n)                               \
    430    FloatRegisters::GetName(n), GetFPURegisterValue(n), \
    431        GetFPURegisterValueDouble(n)
    432 
    433  printAllRegs();
    434 
    435  printf("\n\n");
    436  // f0, f1, f2, ... f31.
    437  MOZ_ASSERT(kNumFPURegisters % 2 == 0);
    438  for (int i = 0; i < kNumFPURegisters; i += 2)
    439    printf("%3s: 0x%016" PRIx64 "  %16.4e \t%3s: 0x%016" PRIx64 "  %16.4e\n",
    440           FPU_REG_INFO(i), FPU_REG_INFO(i + 1));
    441 #  undef FPU_REG_INFO
    442 }
    443 
    444 void RiscvDebugger::Debug() {
    445  intptr_t last_pc = -1;
    446  bool done = false;
    447 
    448 #  define COMMAND_SIZE 63
    449 #  define ARG_SIZE 255
    450 
    451 #  define STR(a) #a
    452 #  define XSTR(a) STR(a)
    453 
    454  char cmd[COMMAND_SIZE + 1];
    455  char arg1[ARG_SIZE + 1];
    456  char arg2[ARG_SIZE + 1];
    457  char* argv[3] = {cmd, arg1, arg2};
    458 
    459  // Make sure to have a proper terminating character if reaching the limit.
    460  cmd[COMMAND_SIZE] = 0;
    461  arg1[ARG_SIZE] = 0;
    462  arg2[ARG_SIZE] = 0;
    463 
    464  while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
    465    if (last_pc != sim_->get_pc()) {
    466      disasm::NameConverter converter;
    467      disasm::Disassembler dasm(converter);
    468      // Use a reasonably large buffer.
    469      EmbeddedVector<char, 256> buffer;
    470      dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(sim_->get_pc()));
    471      printf("  0x%016" REGIx_FORMAT "   %s\n", sim_->get_pc(), buffer.start());
    472      last_pc = sim_->get_pc();
    473    }
    474    char* line = ReadLine("sim> ");
    475    if (line == nullptr) {
    476      break;
    477    } else {
    478      char* last_input = sim_->lastDebuggerInput();
    479      if (strcmp(line, "\n") == 0 && last_input != nullptr) {
    480        line = last_input;
    481      } else {
    482        // Ownership is transferred to sim_;
    483        sim_->setLastDebuggerInput(line);
    484      }
    485      // Use sscanf to parse the individual parts of the command line. At the
    486      // moment no command expects more than two parameters.
    487      int argc = sscanf(
    488            line,
    489            "%" XSTR(COMMAND_SIZE) "s "
    490            "%" XSTR(ARG_SIZE) "s "
    491            "%" XSTR(ARG_SIZE) "s",
    492            cmd, arg1, arg2);
    493      if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
    494        SimInstruction* instr =
    495            reinterpret_cast<SimInstruction*>(sim_->get_pc());
    496        if (!(instr->IsTrap()) ||
    497            instr->InstructionBits() == rtCallRedirInstr) {
    498          sim_->icount_++;
    499          sim_->InstructionDecode(
    500              reinterpret_cast<Instruction*>(sim_->get_pc()));
    501        } else {
    502          // Allow si to jump over generated breakpoints.
    503          printf("/!\\ Jumping over generated breakpoint.\n");
    504          sim_->set_pc(sim_->get_pc() + kInstrSize);
    505        }
    506      } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
    507        // Leave the debugger shell.
    508        done = true;
    509      } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
    510        if (argc == 2) {
    511          int64_t value;
    512          int64_t fvalue;
    513          double dvalue;
    514          if (strcmp(arg1, "all") == 0) {
    515            printAllRegs();
    516          } else if (strcmp(arg1, "allf") == 0) {
    517            printAllRegsIncludingFPU();
    518          } else {
    519            int regnum = Registers::FromName(arg1);
    520            int fpuregnum = FloatRegisters::FromName(arg1);
    521 #  ifdef CAN_USE_RVV_INSTRUCTIONS
    522            int vregnum = VRegisters::FromName(arg1);
    523 #  endif
    524            if (regnum != Registers::invalid_reg) {
    525              value = GetRegisterValue(regnum);
    526              printf("%s: 0x%08" REGIx_FORMAT "  %" REGId_FORMAT "  \n", arg1,
    527                     value, value);
    528            } else if (fpuregnum != FloatRegisters::invalid_reg) {
    529              fvalue = GetFPURegisterValue(fpuregnum);
    530              dvalue = GetFPURegisterValueDouble(fpuregnum);
    531              printf("%3s: 0x%016" PRIx64 "  %16.4e\n",
    532                     FloatRegisters::GetName(fpuregnum), fvalue, dvalue);
    533 #  ifdef CAN_USE_RVV_INSTRUCTIONS
    534            } else if (vregnum != kInvalidVRegister) {
    535              __int128_t v = GetVRegisterValue(vregnum);
    536              printf("\t%s:0x%016" REGIx_FORMAT "%016" REGIx_FORMAT "\n",
    537                     VRegisters::GetName(vregnum), (uint64_t)(v >> 64),
    538                     (uint64_t)v);
    539 #  endif
    540            } else {
    541              printf("%s unrecognized\n", arg1);
    542            }
    543          }
    544        } else {
    545          if (argc == 3) {
    546            if (strcmp(arg2, "single") == 0) {
    547              int64_t value;
    548              float fvalue;
    549              int fpuregnum = FloatRegisters::FromName(arg1);
    550 
    551              if (fpuregnum != FloatRegisters::invalid_reg) {
    552                value = GetFPURegisterValue(fpuregnum);
    553                value &= 0xFFFFFFFFUL;
    554                fvalue = GetFPURegisterValueFloat(fpuregnum);
    555                printf("%s: 0x%08" PRIx64 "  %11.4e\n", arg1, value, fvalue);
    556              } else {
    557                printf("%s unrecognized\n", arg1);
    558              }
    559            } else {
    560              printf("print <fpu register> single\n");
    561            }
    562          } else {
    563            printf("print <register> or print <fpu register> single\n");
    564          }
    565        }
    566      } else if ((strcmp(cmd, "po") == 0) ||
    567                 (strcmp(cmd, "printobject") == 0)) {
    568        UNIMPLEMENTED();
    569      } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
    570        int64_t* cur = nullptr;
    571        int64_t* end = nullptr;
    572        int next_arg = 1;
    573        if (argc < 2) {
    574          printf("Need to specify <address> to memhex command\n");
    575          continue;
    576        }
    577        int64_t value;
    578        if (!GetValue(arg1, &value)) {
    579          printf("%s unrecognized\n", arg1);
    580          continue;
    581        }
    582        cur = reinterpret_cast<int64_t*>(value);
    583        next_arg++;
    584 
    585        int64_t words;
    586        if (argc == next_arg) {
    587          words = 10;
    588        } else {
    589          if (!GetValue(argv[next_arg], &words)) {
    590            words = 10;
    591          }
    592        }
    593        end = cur + words;
    594 
    595        while (cur < end) {
    596          printf("  0x%012" PRIxPTR " :  0x%016" REGIx_FORMAT
    597                 "  %14" REGId_FORMAT " ",
    598                 reinterpret_cast<intptr_t>(cur), *cur, *cur);
    599          printf("\n");
    600          cur++;
    601        }
    602      } else if ((strcmp(cmd, "watch") == 0)) {
    603        if (argc < 2) {
    604          printf("Need to specify <address> to mem command\n");
    605          continue;
    606        }
    607        int64_t value;
    608        if (!GetValue(arg1, &value)) {
    609          printf("%s unrecognized\n", arg1);
    610          continue;
    611        }
    612        sim_->watch_address_ = reinterpret_cast<intptr_t*>(value);
    613        sim_->watch_value_ = *(sim_->watch_address_);
    614      } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0) ||
    615                 (strcmp(cmd, "di") == 0)) {
    616        disasm::NameConverter converter;
    617        disasm::Disassembler dasm(converter);
    618        // Use a reasonably large buffer.
    619        EmbeddedVector<char, 256> buffer;
    620 
    621        byte* cur = nullptr;
    622        byte* end = nullptr;
    623 
    624        if (argc == 1) {
    625          cur = reinterpret_cast<byte*>(sim_->get_pc());
    626          end = cur + (10 * kInstrSize);
    627        } else if (argc == 2) {
    628          auto regnum = Registers::FromName(arg1);
    629          if (regnum != Registers::invalid_reg || strncmp(arg1, "0x", 2) == 0) {
    630            // The argument is an address or a register name.
    631            sreg_t value;
    632            if (GetValue(arg1, &value)) {
    633              cur = reinterpret_cast<byte*>(value);
    634              // Disassemble 10 instructions at <arg1>.
    635              end = cur + (10 * kInstrSize);
    636            }
    637          } else {
    638            // The argument is the number of instructions.
    639            sreg_t value;
    640            if (GetValue(arg1, &value)) {
    641              cur = reinterpret_cast<byte*>(sim_->get_pc());
    642              // Disassemble <arg1> instructions.
    643              end = cur + (value * kInstrSize);
    644            }
    645          }
    646        } else {
    647          sreg_t value1;
    648          sreg_t value2;
    649          if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
    650            cur = reinterpret_cast<byte*>(value1);
    651            end = cur + (value2 * kInstrSize);
    652          }
    653        }
    654        while (cur < end) {
    655          dasm.InstructionDecode(buffer, cur);
    656          printf("  0x%08" PRIxPTR "   %s\n", reinterpret_cast<intptr_t>(cur),
    657                 buffer.start());
    658          cur += kInstrSize;
    659        }
    660      } else if (strcmp(cmd, "trace") == 0) {
    661        Simulator::FLAG_trace_sim = true;
    662        Simulator::FLAG_riscv_print_watchpoint = true;
    663      } else if (strcmp(cmd, "break") == 0 || strcmp(cmd, "b") == 0 ||
    664                 strcmp(cmd, "tbreak") == 0) {
    665        bool is_tbreak = strcmp(cmd, "tbreak") == 0;
    666        if (argc == 2) {
    667          int64_t value;
    668          if (GetValue(arg1, &value)) {
    669            sim_->SetBreakpoint(reinterpret_cast<SimInstruction*>(value),
    670                                is_tbreak);
    671          } else {
    672            printf("%s unrecognized\n", arg1);
    673          }
    674        } else {
    675          sim_->ListBreakpoints();
    676          printf("Use `break <address>` to set or disable a breakpoint\n");
    677          printf(
    678              "Use `tbreak <address>` to set or disable a temporary "
    679              "breakpoint\n");
    680        }
    681      } else if (strcmp(cmd, "flags") == 0) {
    682        printf("No flags on RISC-V !\n");
    683      } else if (strcmp(cmd, "stop") == 0) {
    684        int64_t value;
    685        if (argc == 3) {
    686          // Print information about all/the specified breakpoint(s).
    687          if (strcmp(arg1, "info") == 0) {
    688            if (strcmp(arg2, "all") == 0) {
    689              printf("Stop information:\n");
    690              for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
    691                   i++) {
    692                sim_->printStopInfo(i);
    693              }
    694            } else if (GetValue(arg2, &value)) {
    695              sim_->printStopInfo(value);
    696            } else {
    697              printf("Unrecognized argument.\n");
    698            }
    699          } else if (strcmp(arg1, "enable") == 0) {
    700            // Enable all/the specified breakpoint(s).
    701            if (strcmp(arg2, "all") == 0) {
    702              for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
    703                   i++) {
    704                sim_->enableStop(i);
    705              }
    706            } else if (GetValue(arg2, &value)) {
    707              sim_->enableStop(value);
    708            } else {
    709              printf("Unrecognized argument.\n");
    710            }
    711          } else if (strcmp(arg1, "disable") == 0) {
    712            // Disable all/the specified breakpoint(s).
    713            if (strcmp(arg2, "all") == 0) {
    714              for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
    715                   i++) {
    716                sim_->disableStop(i);
    717              }
    718            } else if (GetValue(arg2, &value)) {
    719              sim_->disableStop(value);
    720            } else {
    721              printf("Unrecognized argument.\n");
    722            }
    723          }
    724        } else {
    725          printf("Wrong usage. Use help command for more information.\n");
    726        }
    727      } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
    728        UNIMPLEMENTED();
    729      } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
    730        printf("cont (alias 'c')\n");
    731        printf("  Continue execution\n");
    732        printf("stepi (alias 'si')\n");
    733        printf("  Step one instruction\n");
    734        printf("print (alias 'p')\n");
    735        printf("  print <register>\n");
    736        printf("  Print register content\n");
    737        printf("  Use register name 'all' to print all GPRs\n");
    738        printf("  Use register name 'allf' to print all GPRs and FPRs\n");
    739        printf("printobject (alias 'po')\n");
    740        printf("  printobject <register>\n");
    741        printf("  Print an object from a register\n");
    742        printf("stack\n");
    743        printf("  stack [<words>]\n");
    744        printf("  Dump stack content, default dump 10 words)\n");
    745        printf("mem\n");
    746        printf("  mem <address> [<words>]\n");
    747        printf("  Dump memory content, default dump 10 words)\n");
    748        printf("watch\n");
    749        printf("  watch <address> \n");
    750        printf("  watch memory content.)\n");
    751        printf("flags\n");
    752        printf("  print flags\n");
    753        printf("disasm (alias 'di')\n");
    754        printf("  disasm [<instructions>]\n");
    755        printf("  disasm [<address/register>] (e.g., disasm pc) \n");
    756        printf("  disasm [[<address/register>] <instructions>]\n");
    757        printf("  Disassemble code, default is 10 instructions\n");
    758        printf("  from pc\n");
    759        printf("gdb \n");
    760        printf("  Return to gdb if the simulator was started with gdb\n");
    761        printf("break (alias 'b')\n");
    762        printf("  break : list all breakpoints\n");
    763        printf("  break <address> : set / enable / disable a breakpoint.\n");
    764        printf("tbreak\n");
    765        printf("  tbreak : list all breakpoints\n");
    766        printf(
    767            "  tbreak <address> : set / enable / disable a temporary "
    768            "breakpoint.\n");
    769        printf("  Set a breakpoint enabled only for one stop. \n");
    770        printf("stop feature:\n");
    771        printf("  Description:\n");
    772        printf("    Stops are debug instructions inserted by\n");
    773        printf("    the Assembler::stop() function.\n");
    774        printf("    When hitting a stop, the Simulator will\n");
    775        printf("    stop and give control to the Debugger.\n");
    776        printf("    All stop codes are watched:\n");
    777        printf("    - They can be enabled / disabled: the Simulator\n");
    778        printf("       will / won't stop when hitting them.\n");
    779        printf("    - The Simulator keeps track of how many times they \n");
    780        printf("      are met. (See the info command.) Going over a\n");
    781        printf("      disabled stop still increases its counter. \n");
    782        printf("  Commands:\n");
    783        printf("    stop info all/<code> : print infos about number <code>\n");
    784        printf("      or all stop(s).\n");
    785        printf("    stop enable/disable all/<code> : enables / disables\n");
    786        printf("      all or number <code> stop(s)\n");
    787      } else {
    788        printf("Unknown command: %s\n", cmd);
    789      }
    790    }
    791  }
    792 
    793 #  undef COMMAND_SIZE
    794 #  undef ARG_SIZE
    795 
    796 #  undef STR
    797 #  undef XSTR
    798 }
    799 
    800 void Simulator::SetBreakpoint(SimInstruction* location, bool is_tbreak) {
    801  for (unsigned i = 0; i < breakpoints_.size(); i++) {
    802    if (breakpoints_.at(i).location == location) {
    803      if (breakpoints_.at(i).is_tbreak != is_tbreak) {
    804        printf("Change breakpoint at %p to %s breakpoint\n",
    805               reinterpret_cast<void*>(location),
    806               is_tbreak ? "temporary" : "regular");
    807        breakpoints_.at(i).is_tbreak = is_tbreak;
    808        return;
    809      }
    810      printf("Existing breakpoint at %p was %s\n",
    811             reinterpret_cast<void*>(location),
    812             breakpoints_.at(i).enabled ? "disabled" : "enabled");
    813      breakpoints_.at(i).enabled = !breakpoints_.at(i).enabled;
    814      return;
    815    }
    816  }
    817  Breakpoint new_breakpoint = {location, true, is_tbreak};
    818  breakpoints_.push_back(new_breakpoint);
    819  printf("Set a %sbreakpoint at %p\n", is_tbreak ? "temporary " : "",
    820         reinterpret_cast<void*>(location));
    821 }
    822 
    823 void Simulator::ListBreakpoints() {
    824  printf("Breakpoints:\n");
    825  for (unsigned i = 0; i < breakpoints_.size(); i++) {
    826    printf("%p  : %s %s\n",
    827           reinterpret_cast<void*>(breakpoints_.at(i).location),
    828           breakpoints_.at(i).enabled ? "enabled" : "disabled",
    829           breakpoints_.at(i).is_tbreak ? ": temporary" : "");
    830  }
    831 }
    832 
    833 void Simulator::CheckBreakpoints() {
    834  bool hit_a_breakpoint = false;
    835  bool is_tbreak = false;
    836  SimInstruction* pc_ = reinterpret_cast<SimInstruction*>(get_pc());
    837  for (unsigned i = 0; i < breakpoints_.size(); i++) {
    838    if ((breakpoints_.at(i).location == pc_) && breakpoints_.at(i).enabled) {
    839      hit_a_breakpoint = true;
    840      if (breakpoints_.at(i).is_tbreak) {
    841        // Disable a temporary breakpoint.
    842        is_tbreak = true;
    843        breakpoints_.at(i).enabled = false;
    844      }
    845      break;
    846    }
    847  }
    848  if (hit_a_breakpoint) {
    849    printf("Hit %sa breakpoint at %p.\n", is_tbreak ? "and disabled " : "",
    850           reinterpret_cast<void*>(pc_));
    851    RiscvDebugger dbg(this);
    852    dbg.Debug();
    853  }
    854 }
    855 
    856 static bool AllOnOnePage(uintptr_t start, int size) {
    857  intptr_t start_page = (start & ~CachePage::kPageMask);
    858  intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
    859  return start_page == end_page;
    860 }
    861 
    862 void Simulator::setLastDebuggerInput(char* input) {
    863  js_free(lastDebuggerInput_);
    864  lastDebuggerInput_ = input;
    865 }
    866 
    867 static CachePage* GetCachePageLocked(SimulatorProcess::ICacheMap& i_cache,
    868                                     void* page) {
    869  SimulatorProcess::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
    870  if (p) {
    871    return p->value();
    872  }
    873  AutoEnterOOMUnsafeRegion oomUnsafe;
    874  CachePage* new_page = js_new<CachePage>();
    875  if (!new_page || !i_cache.add(p, page, new_page)) {
    876    oomUnsafe.crash("Simulator CachePage");
    877  }
    878  return new_page;
    879 }
    880 
    881 // Flush from start up to and not including start + size.
    882 static void FlushOnePageLocked(SimulatorProcess::ICacheMap& i_cache,
    883                               intptr_t start, int size) {
    884  MOZ_ASSERT(size <= CachePage::kPageSize);
    885  MOZ_ASSERT(AllOnOnePage(start, size - 1));
    886  MOZ_ASSERT((start & CachePage::kLineMask) == 0);
    887  MOZ_ASSERT((size & CachePage::kLineMask) == 0);
    888  void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
    889  int offset = (start & CachePage::kPageMask);
    890  CachePage* cache_page = GetCachePageLocked(i_cache, page);
    891  char* valid_bytemap = cache_page->validityByte(offset);
    892  memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
    893 }
    894 
    895 static void FlushICacheLocked(SimulatorProcess::ICacheMap& i_cache,
    896                              void* start_addr, size_t size) {
    897  intptr_t start = reinterpret_cast<intptr_t>(start_addr);
    898  int intra_line = (start & CachePage::kLineMask);
    899  start -= intra_line;
    900  size += intra_line;
    901  size = ((size - 1) | CachePage::kLineMask) + 1;
    902  int offset = (start & CachePage::kPageMask);
    903  while (!AllOnOnePage(start, size - 1)) {
    904    int bytes_to_flush = CachePage::kPageSize - offset;
    905    FlushOnePageLocked(i_cache, start, bytes_to_flush);
    906    start += bytes_to_flush;
    907    size -= bytes_to_flush;
    908    MOZ_ASSERT((start & CachePage::kPageMask) == 0);
    909    offset = 0;
    910  }
    911  if (size != 0) {
    912    FlushOnePageLocked(i_cache, start, size);
    913  }
    914 }
    915 
    916 /* static */
    917 void SimulatorProcess::checkICacheLocked(SimInstruction* instr) {
    918  intptr_t address = reinterpret_cast<intptr_t>(instr);
    919  void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
    920  void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
    921  int offset = (address & CachePage::kPageMask);
    922  CachePage* cache_page = GetCachePageLocked(icache(), page);
    923  char* cache_valid_byte = cache_page->validityByte(offset);
    924  bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
    925  char* cached_line = cache_page->cachedData(offset & ~CachePage::kLineMask);
    926 
    927  if (cache_hit) {
    928 #  ifdef DEBUG
    929    // Check that the data in memory matches the contents of the I-cache.
    930    int cmpret = memcmp(reinterpret_cast<void*>(instr),
    931                        cache_page->cachedData(offset), kInstrSize);
    932    MOZ_ASSERT(cmpret == 0);
    933 #  endif
    934  } else {
    935    // Cache miss.  Load memory into the cache.
    936    memcpy(cached_line, line, CachePage::kLineLength);
    937    *cache_valid_byte = CachePage::LINE_VALID;
    938  }
    939 }
    940 
    941 HashNumber SimulatorProcess::ICacheHasher::hash(const Lookup& l) {
    942  return U32(reinterpret_cast<uintptr_t>(l)) >> 2;
    943 }
    944 
    945 bool SimulatorProcess::ICacheHasher::match(const Key& k, const Lookup& l) {
    946  MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0);
    947  MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0);
    948  return k == l;
    949 }
    950 
    951 /* static */
    952 void SimulatorProcess::FlushICache(void* start_addr, size_t size) {
    953  if (!ICacheCheckingDisableCount) {
    954    AutoLockSimulatorCache als;
    955    js::jit::FlushICacheLocked(icache(), start_addr, size);
    956  }
    957 }
    958 
    959 Simulator::Simulator() {
    960  // Set up simulator support first. Some of this information is needed to
    961  // setup the architecture state.
    962 
    963  // Note, allocation and anything that depends on allocated memory is
    964  // deferred until init(), in order to handle OOM properly.
    965 
    966  stack_ = nullptr;
    967  stackLimit_ = 0;
    968  pc_modified_ = false;
    969  icount_ = 0;
    970  break_count_ = 0;
    971  break_pc_ = nullptr;
    972  break_instr_ = 0;
    973  single_stepping_ = false;
    974  single_step_callback_ = nullptr;
    975  single_step_callback_arg_ = nullptr;
    976 
    977  // Set up architecture state.
    978  // All registers are initialized to zero to start with.
    979  for (int i = 0; i < Simulator::Register::kNumSimuRegisters; i++) {
    980    registers_[i] = 0;
    981  }
    982  for (int i = 0; i < Simulator::FPURegister::kNumFPURegisters; i++) {
    983    FPUregisters_[i] = 0;
    984  }
    985  FCSR_ = 0;
    986  LLBit_ = false;
    987  LLAddr_ = 0;
    988  lastLLValue_ = 0;
    989 
    990  // The ra and pc are initialized to a known bad value that will cause an
    991  // access violation if the simulator ever tries to execute it.
    992  registers_[pc] = bad_ra;
    993  registers_[ra] = bad_ra;
    994 
    995  for (int i = 0; i < kNumExceptions; i++) {
    996    exceptions[i] = 0;
    997  }
    998 
    999  lastDebuggerInput_ = nullptr;
   1000 }
   1001 
   1002 bool Simulator::init() {
   1003  // Allocate 2MB for the stack. Note that we will only use 1MB, see below.
   1004  static const size_t stackSize = 2 * 1024 * 1024;
   1005  stack_ = js_pod_malloc<char>(stackSize);
   1006  if (!stack_) {
   1007    return false;
   1008  }
   1009 
   1010  // Leave a safety margin of 1MB to prevent overrunning the stack when
   1011  // pushing values (total stack size is 2MB).
   1012  stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
   1013 
   1014  // The sp is initialized to point to the bottom (high address) of the
   1015  // allocated stack area. To be safe in potential stack underflows we leave
   1016  // some buffer below.
   1017  registers_[sp] = reinterpret_cast<int64_t>(stack_) + stackSize - 64;
   1018 
   1019  return true;
   1020 }
   1021 
   1022 // When the generated code calls an external reference we need to catch that in
   1023 // the simulator.  The external reference will be a function compiled for the
   1024 // host architecture.  We need to call that function instead of trying to
   1025 // execute it with the simulator.  We do that by redirecting the external
   1026 // reference to a swi (software-interrupt) instruction that is handled by
   1027 // the simulator.  We write the original destination of the jump just at a known
   1028 // offset from the swi instruction so the simulator knows what to call.
   1029 class Redirection {
   1030  friend class SimulatorProcess;
   1031 
   1032  // sim's lock must already be held.
   1033  Redirection(void* nativeFunction, ABIFunctionType type)
   1034      : nativeFunction_(nativeFunction),
   1035        swiInstruction_(rtCallRedirInstr),
   1036        type_(type),
   1037        next_(nullptr) {
   1038    next_ = SimulatorProcess::redirection();
   1039    if (!SimulatorProcess::ICacheCheckingDisableCount) {
   1040      FlushICacheLocked(SimulatorProcess::icache(), addressOfSwiInstruction(),
   1041                        kInstrSize);
   1042    }
   1043    SimulatorProcess::setRedirection(this);
   1044  }
   1045 
   1046 public:
   1047  void* addressOfSwiInstruction() { return &swiInstruction_; }
   1048  void* nativeFunction() const { return nativeFunction_; }
   1049  ABIFunctionType type() const { return type_; }
   1050 
   1051  static Redirection* Get(void* nativeFunction, ABIFunctionType type) {
   1052    AutoLockSimulatorCache als;
   1053 
   1054    Redirection* current = SimulatorProcess::redirection();
   1055    for (; current != nullptr; current = current->next_) {
   1056      if (current->nativeFunction_ == nativeFunction) {
   1057        MOZ_ASSERT(current->type() == type);
   1058        return current;
   1059      }
   1060    }
   1061 
   1062    // Note: we can't use js_new here because the constructor is private.
   1063    AutoEnterOOMUnsafeRegion oomUnsafe;
   1064    Redirection* redir = js_pod_malloc<Redirection>(1);
   1065    if (!redir) {
   1066      oomUnsafe.crash("Simulator redirection");
   1067    }
   1068    new (redir) Redirection(nativeFunction, type);
   1069    return redir;
   1070  }
   1071 
   1072  static Redirection* FromSwiInstruction(Instruction* swiInstruction) {
   1073    uint8_t* addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction);
   1074    uint8_t* addrOfRedirection =
   1075        addrOfSwi - offsetof(Redirection, swiInstruction_);
   1076    return reinterpret_cast<Redirection*>(addrOfRedirection);
   1077  }
   1078 
   1079 private:
   1080  void* nativeFunction_;
   1081  uint32_t swiInstruction_;
   1082  ABIFunctionType type_;
   1083  Redirection* next_;
   1084 };
   1085 
   1086 Simulator::~Simulator() { js_free(stack_); }
   1087 
   1088 SimulatorProcess::SimulatorProcess()
   1089    : cacheLock_(mutexid::SimulatorCacheLock), redirection_(nullptr) {
   1090  if (getenv("MIPS_SIM_ICACHE_CHECKS")) {
   1091    ICacheCheckingDisableCount = 0;
   1092  }
   1093 }
   1094 
   1095 SimulatorProcess::~SimulatorProcess() {
   1096  Redirection* r = redirection_;
   1097  while (r) {
   1098    Redirection* next = r->next_;
   1099    js_delete(r);
   1100    r = next;
   1101  }
   1102 }
   1103 
   1104 /* static */
   1105 void* Simulator::RedirectNativeFunction(void* nativeFunction,
   1106                                        ABIFunctionType type) {
   1107  Redirection* redirection = Redirection::Get(nativeFunction, type);
   1108  return redirection->addressOfSwiInstruction();
   1109 }
   1110 
   1111 // Get the active Simulator for the current thread.
   1112 Simulator* Simulator::Current() {
   1113  JSContext* cx = TlsContext.get();
   1114  MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
   1115  return cx->simulator();
   1116 }
   1117 
   1118 // Sets the register in the architecture state. It will also deal with updating
   1119 // Simulator internal state for special registers such as PC.
   1120 void Simulator::setRegister(int reg, int64_t value) {
   1121  MOZ_ASSERT((reg >= 0) && (reg < Simulator::Register::kNumSimuRegisters));
   1122  if (reg == pc) {
   1123    pc_modified_ = true;
   1124  }
   1125 
   1126  // Zero register always holds 0.
   1127  registers_[reg] = (reg == 0) ? 0 : value;
   1128 }
   1129 
   1130 void Simulator::setFpuRegister(int fpureg, int64_t value) {
   1131  MOZ_ASSERT((fpureg >= 0) &&
   1132             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1133  FPUregisters_[fpureg] = value;
   1134 }
   1135 
   1136 void Simulator::setFpuRegisterLo(int fpureg, int32_t value) {
   1137  MOZ_ASSERT((fpureg >= 0) &&
   1138             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1139  *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]) = value;
   1140 }
   1141 
   1142 void Simulator::setFpuRegisterHi(int fpureg, int32_t value) {
   1143  MOZ_ASSERT((fpureg >= 0) &&
   1144             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1145  *((mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg])) + 1) = value;
   1146 }
   1147 
   1148 void Simulator::setFpuRegisterFloat(int fpureg, float value) {
   1149  MOZ_ASSERT((fpureg >= 0) &&
   1150             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1151  *mozilla::BitwiseCast<int64_t*>(&FPUregisters_[fpureg]) = box_float(value);
   1152 }
   1153 
   1154 void Simulator::setFpuRegisterFloat(int fpureg, Float32 value) {
   1155  MOZ_ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
   1156  Float64 t = Float64::FromBits(box_float(value.get_bits()));
   1157  memcpy(&FPUregisters_[fpureg], &t, 8);
   1158 }
   1159 
   1160 void Simulator::setFpuRegisterDouble(int fpureg, double value) {
   1161  MOZ_ASSERT((fpureg >= 0) &&
   1162             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1163  *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]) = value;
   1164 }
   1165 
   1166 void Simulator::setFpuRegisterDouble(int fpureg, Float64 value) {
   1167  MOZ_ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
   1168  memcpy(&FPUregisters_[fpureg], &value, 8);
   1169 }
   1170 
   1171 // Get the register from the architecture state. This function does handle
   1172 // the special case of accessing the PC register.
   1173 int64_t Simulator::getRegister(int reg) const {
   1174  MOZ_ASSERT((reg >= 0) && (reg < Simulator::Register::kNumSimuRegisters));
   1175  if (reg == 0) {
   1176    return 0;
   1177  }
   1178  return registers_[reg] + ((reg == pc) ? SimInstruction::kPCReadOffset : 0);
   1179 }
   1180 
   1181 int64_t Simulator::getFpuRegister(int fpureg) const {
   1182  MOZ_ASSERT((fpureg >= 0) &&
   1183             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1184  return FPUregisters_[fpureg];
   1185 }
   1186 
   1187 int32_t Simulator::getFpuRegisterLo(int fpureg) const {
   1188  MOZ_ASSERT((fpureg >= 0) &&
   1189             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1190  return *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]);
   1191 }
   1192 
   1193 int32_t Simulator::getFpuRegisterHi(int fpureg) const {
   1194  MOZ_ASSERT((fpureg >= 0) &&
   1195             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1196  return *((mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg])) + 1);
   1197 }
   1198 
   1199 float Simulator::getFpuRegisterFloat(int fpureg) const {
   1200  MOZ_ASSERT((fpureg >= 0) &&
   1201             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1202  return *mozilla::BitwiseCast<float*>(&FPUregisters_[fpureg]);
   1203 }
   1204 
   1205 Float32 Simulator::getFpuRegisterFloat32(int fpureg) const {
   1206  MOZ_ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
   1207  if (!is_boxed_float(FPUregisters_[fpureg])) {
   1208    return Float32::FromBits(0x7ffc0000);
   1209  }
   1210  return Float32::FromBits(
   1211      *bit_cast<uint32_t*>(const_cast<int64_t*>(&FPUregisters_[fpureg])));
   1212 }
   1213 
   1214 double Simulator::getFpuRegisterDouble(int fpureg) const {
   1215  MOZ_ASSERT((fpureg >= 0) &&
   1216             (fpureg < Simulator::FPURegister::kNumFPURegisters));
   1217  return *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]);
   1218 }
   1219 
   1220 Float64 Simulator::getFpuRegisterFloat64(int fpureg) const {
   1221  MOZ_ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
   1222  return Float64::FromBits(FPUregisters_[fpureg]);
   1223 }
   1224 
   1225 void Simulator::setCallResultDouble(double result) {
   1226  setFpuRegisterDouble(fa0, result);
   1227 }
   1228 
   1229 void Simulator::setCallResultFloat(float result) {
   1230  setFpuRegisterFloat(fa0, result);
   1231 }
   1232 
   1233 void Simulator::setCallResult(int64_t res) { setRegister(a0, res); }
   1234 
   1235 void Simulator::setCallResult(__int128_t res) {
   1236  setRegister(a0, I64(res));
   1237  setRegister(a1, I64(res >> 64));
   1238 }
   1239 
   1240 // Raw access to the PC register.
   1241 void Simulator::set_pc(int64_t value) {
   1242  pc_modified_ = true;
   1243  registers_[pc] = value;
   1244 }
   1245 
   1246 bool Simulator::has_bad_pc() const {
   1247  return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
   1248 }
   1249 
   1250 // Raw access to the PC register without the special adjustment when reading.
   1251 int64_t Simulator::get_pc() const { return registers_[pc]; }
   1252 
   1253 JS::ProfilingFrameIterator::RegisterState Simulator::registerState() {
   1254  wasm::RegisterState state;
   1255  state.pc = (void*)get_pc();
   1256  state.fp = (void*)getRegister(fp);
   1257  state.sp = (void*)getRegister(sp);
   1258  state.lr = (void*)getRegister(ra);
   1259  return state;
   1260 }
   1261 
   1262 void Simulator::HandleWasmTrap() {
   1263  uint8_t* newPC;
   1264  if (wasm::HandleIllegalInstruction(registerState(), &newPC)) {
   1265    set_pc(int64_t(newPC));
   1266    return;
   1267  }
   1268 }
   1269 
   1270 // TODO(plind): consider making icount_ printing a flag option.
   1271 template <typename T>
   1272 void Simulator::TraceMemRd(sreg_t addr, T value, sreg_t reg_value) {
   1273  if (FLAG_trace_sim) {
   1274    if (std::is_integral<T>::value) {
   1275      switch (sizeof(T)) {
   1276        case 1:
   1277          SNPrintF(trace_buf_,
   1278                   "%016" REGIx_FORMAT "    (%" PRId64 ")    int8:%" PRId8
   1279                   " uint8:%" PRIu8 " <-- [addr: %" REGIx_FORMAT "]",
   1280                   reg_value, icount_, static_cast<int8_t>(value),
   1281                   static_cast<uint8_t>(value), addr);
   1282          break;
   1283        case 2:
   1284          SNPrintF(trace_buf_,
   1285                   "%016" REGIx_FORMAT "    (%" PRId64 ")    int16:%" PRId16
   1286                   " uint16:%" PRIu16 " <-- [addr: %" REGIx_FORMAT "]",
   1287                   reg_value, icount_, static_cast<int16_t>(value),
   1288                   static_cast<uint16_t>(value), addr);
   1289          break;
   1290        case 4:
   1291          SNPrintF(trace_buf_,
   1292                   "%016" REGIx_FORMAT "    (%" PRId64 ")    int32:%" PRId32
   1293                   " uint32:%" PRIu32 " <-- [addr: %" REGIx_FORMAT "]",
   1294                   reg_value, icount_, static_cast<int32_t>(value),
   1295                   static_cast<uint32_t>(value), addr);
   1296          break;
   1297        case 8:
   1298          SNPrintF(trace_buf_,
   1299                   "%016" REGIx_FORMAT "    (%" PRId64 ")    int64:%" PRId64
   1300                   " uint64:%" PRIu64 " <-- [addr: %" REGIx_FORMAT "]",
   1301                   reg_value, icount_, static_cast<int64_t>(value),
   1302                   static_cast<uint64_t>(value), addr);
   1303          break;
   1304        default:
   1305          UNREACHABLE();
   1306      }
   1307    } else if (std::is_same<float, T>::value) {
   1308      SNPrintF(trace_buf_,
   1309               "%016" REGIx_FORMAT "    (%" PRId64
   1310               ")    flt:%e <-- [addr: %" REGIx_FORMAT "]",
   1311               reg_value, icount_, static_cast<float>(value), addr);
   1312    } else if (std::is_same<double, T>::value) {
   1313      SNPrintF(trace_buf_,
   1314               "%016" REGIx_FORMAT "    (%" PRId64
   1315               ")    dbl:%e <-- [addr: %" REGIx_FORMAT "]",
   1316               reg_value, icount_, static_cast<double>(value), addr);
   1317    } else {
   1318      UNREACHABLE();
   1319    }
   1320  }
   1321 }
   1322 
   1323 void Simulator::TraceMemRdFloat(sreg_t addr, Float32 value, int64_t reg_value) {
   1324  if (FLAG_trace_sim) {
   1325    SNPrintF(trace_buf_,
   1326             "%016" PRIx64 "    (%" PRId64
   1327             ")    flt:%e <-- [addr: %" REGIx_FORMAT "]",
   1328             reg_value, icount_, static_cast<float>(value.get_scalar()), addr);
   1329  }
   1330 }
   1331 
   1332 void Simulator::TraceMemRdDouble(sreg_t addr, double value, int64_t reg_value) {
   1333  if (FLAG_trace_sim) {
   1334    SNPrintF(trace_buf_,
   1335             "%016" PRIx64 "    (%" PRId64
   1336             ")    dbl:%e <-- [addr: %" REGIx_FORMAT "]",
   1337             reg_value, icount_, static_cast<double>(value), addr);
   1338  }
   1339 }
   1340 
   1341 void Simulator::TraceMemRdDouble(sreg_t addr, Float64 value,
   1342                                 int64_t reg_value) {
   1343  if (FLAG_trace_sim) {
   1344    SNPrintF(trace_buf_,
   1345             "%016" PRIx64 "    (%" PRId64
   1346             ")    dbl:%e <-- [addr: %" REGIx_FORMAT "]",
   1347             reg_value, icount_, static_cast<double>(value.get_scalar()), addr);
   1348  }
   1349 }
   1350 
   1351 template <typename T>
   1352 void Simulator::TraceMemWr(sreg_t addr, T value) {
   1353  if (FLAG_trace_sim) {
   1354    switch (sizeof(T)) {
   1355      case 1:
   1356        SNPrintF(trace_buf_,
   1357                 "                    (%" PRIu64 ")    int8:%" PRId8
   1358                 " uint8:%" PRIu8 " --> [addr: %" REGIx_FORMAT "]",
   1359                 icount_, static_cast<int8_t>(value),
   1360                 static_cast<uint8_t>(value), addr);
   1361        break;
   1362      case 2:
   1363        SNPrintF(trace_buf_,
   1364                 "                    (%" PRIu64 ")    int16:%" PRId16
   1365                 " uint16:%" PRIu16 " --> [addr: %" REGIx_FORMAT "]",
   1366                 icount_, static_cast<int16_t>(value),
   1367                 static_cast<uint16_t>(value), addr);
   1368        break;
   1369      case 4:
   1370        if (std::is_integral<T>::value) {
   1371          SNPrintF(trace_buf_,
   1372                   "                    (%" PRIu64 ")    int32:%" PRId32
   1373                   " uint32:%" PRIu32 " --> [addr: %" REGIx_FORMAT "]",
   1374                   icount_, static_cast<int32_t>(value),
   1375                   static_cast<uint32_t>(value), addr);
   1376        } else {
   1377          SNPrintF(trace_buf_,
   1378                   "                    (%" PRIu64
   1379                   ")    flt:%e --> [addr: %" REGIx_FORMAT "]",
   1380                   icount_, static_cast<float>(value), addr);
   1381        }
   1382        break;
   1383      case 8:
   1384        if (std::is_integral<T>::value) {
   1385          SNPrintF(trace_buf_,
   1386                   "                    (%" PRIu64 ")    int64:%" PRId64
   1387                   " uint64:%" PRIu64 " --> [addr: %" REGIx_FORMAT "]",
   1388                   icount_, static_cast<int64_t>(value),
   1389                   static_cast<uint64_t>(value), addr);
   1390        } else {
   1391          SNPrintF(trace_buf_,
   1392                   "                    (%" PRIu64
   1393                   ")    dbl:%e --> [addr: %" REGIx_FORMAT "]",
   1394                   icount_, static_cast<double>(value), addr);
   1395        }
   1396        break;
   1397      default:
   1398        UNREACHABLE();
   1399    }
   1400  }
   1401 }
   1402 
   1403 void Simulator::TraceMemWrDouble(sreg_t addr, double value) {
   1404  if (FLAG_trace_sim) {
   1405    SNPrintF(trace_buf_,
   1406             "                    (%" PRIu64
   1407             ")    dbl:%e --> [addr: %" REGIx_FORMAT "]",
   1408             icount_, value, addr);
   1409  }
   1410 }
   1411 
   1412 template <typename T>
   1413 void Simulator::TraceLr(sreg_t addr, T value, sreg_t reg_value) {
   1414  if (FLAG_trace_sim) {
   1415    if (std::is_integral<T>::value) {
   1416      switch (sizeof(T)) {
   1417        case 4:
   1418          SNPrintF(trace_buf_,
   1419                   "%016" REGIx_FORMAT "    (%" PRId64 ")    int32:%" PRId32
   1420                   " uint32:%" PRIu32 " <-- [addr: %" REGIx_FORMAT "]",
   1421                   reg_value, icount_, static_cast<int32_t>(value),
   1422                   static_cast<uint32_t>(value), addr);
   1423          break;
   1424        case 8:
   1425          SNPrintF(trace_buf_,
   1426                   "%016" REGIx_FORMAT "    (%" PRId64 ")    int64:%" PRId64
   1427                   " uint64:%" PRIu64 " <-- [addr: %" REGIx_FORMAT "]",
   1428                   reg_value, icount_, static_cast<int64_t>(value),
   1429                   static_cast<uint64_t>(value), addr);
   1430          break;
   1431        default:
   1432          UNREACHABLE();
   1433      }
   1434    } else {
   1435      UNREACHABLE();
   1436    }
   1437  }
   1438 }
   1439 
   1440 template <typename T>
   1441 void Simulator::TraceSc(sreg_t addr, T value) {
   1442  if (FLAG_trace_sim) {
   1443    switch (sizeof(T)) {
   1444      case 4:
   1445        SNPrintF(trace_buf_,
   1446                 "%016" REGIx_FORMAT "    (%" PRIu64 ")    int32:%" PRId32
   1447                 " uint32:%" PRIu32 " --> [addr: %" REGIx_FORMAT "]",
   1448                 getRegister(rd_reg()), icount_, static_cast<int32_t>(value),
   1449                 static_cast<uint32_t>(value), addr);
   1450        break;
   1451      case 8:
   1452        SNPrintF(trace_buf_,
   1453                 "%016" REGIx_FORMAT "    (%" PRIu64 ")    int64:%" PRId64
   1454                 " uint64:%" PRIu64 " --> [addr: %" REGIx_FORMAT "]",
   1455                 getRegister(rd_reg()), icount_, static_cast<int64_t>(value),
   1456                 static_cast<uint64_t>(value), addr);
   1457        break;
   1458      default:
   1459        UNREACHABLE();
   1460    }
   1461  }
   1462 }
   1463 
   1464 // TODO(RISCV): check whether the specific board supports unaligned load/store
   1465 // (determined by EEI). For now, we assume the board does not support unaligned
   1466 // load/store (e.g., trapping)
   1467 template <typename T>
   1468 T Simulator::ReadMem(sreg_t addr, Instruction* instr) {
   1469  if (handleWasmSegFault(addr, sizeof(T))) {
   1470    return -1;
   1471  }
   1472  if (addr >= 0 && addr < 0x400) {
   1473    // This has to be a nullptr-dereference, drop into debugger.
   1474    printf("Memory read from bad address: 0x%08" REGIx_FORMAT
   1475           " , pc=0x%08" PRIxPTR " \n",
   1476           addr, reinterpret_cast<intptr_t>(instr));
   1477    DieOrDebug();
   1478  }
   1479  T* ptr = reinterpret_cast<T*>(addr);
   1480  T value = *ptr;
   1481  return value;
   1482 }
   1483 
   1484 template <typename T>
   1485 void Simulator::WriteMem(sreg_t addr, T value, Instruction* instr) {
   1486  if (handleWasmSegFault(addr, sizeof(T))) {
   1487    value = -1;
   1488    return;
   1489  }
   1490  if (addr >= 0 && addr < 0x400) {
   1491    // This has to be a nullptr-dereference, drop into debugger.
   1492    printf("Memory write to bad address: 0x%08" REGIx_FORMAT
   1493           " , pc=0x%08" PRIxPTR " \n",
   1494           addr, reinterpret_cast<intptr_t>(instr));
   1495    DieOrDebug();
   1496  }
   1497  T* ptr = reinterpret_cast<T*>(addr);
   1498  if (!std::is_same<double, T>::value) {
   1499    TraceMemWr(addr, value);
   1500  } else {
   1501    TraceMemWrDouble(addr, value);
   1502  }
   1503  *ptr = value;
   1504 }
   1505 
   1506 template <>
   1507 void Simulator::WriteMem(sreg_t addr, Float32 value, Instruction* instr) {
   1508  if (handleWasmSegFault(addr, 4)) {
   1509    value = Float32(-1.0f);
   1510    return;
   1511  }
   1512  if (addr >= 0 && addr < 0x400) {
   1513    // This has to be a nullptr-dereference, drop into debugger.
   1514    printf("Memory write to bad address: 0x%08" REGIx_FORMAT
   1515           " , pc=0x%08" PRIxPTR " \n",
   1516           addr, reinterpret_cast<intptr_t>(instr));
   1517    DieOrDebug();
   1518  }
   1519  float* ptr = reinterpret_cast<float*>(addr);
   1520  TraceMemWr(addr, value.get_scalar());
   1521  memcpy(ptr, &value, 4);
   1522 }
   1523 
   1524 template <>
   1525 void Simulator::WriteMem(sreg_t addr, Float64 value, Instruction* instr) {
   1526  if (handleWasmSegFault(addr, 8)) {
   1527    value = Float64(-1.0);
   1528    return;
   1529  }
   1530  if (addr >= 0 && addr < 0x400) {
   1531    // This has to be a nullptr-dereference, drop into debugger.
   1532    printf("Memory write to bad address: 0x%08" REGIx_FORMAT
   1533           " , pc=0x%08" PRIxPTR " \n",
   1534           addr, reinterpret_cast<intptr_t>(instr));
   1535    DieOrDebug();
   1536  }
   1537  double* ptr = reinterpret_cast<double*>(addr);
   1538  TraceMemWrDouble(addr, value.get_scalar());
   1539  memcpy(ptr, &value, 8);
   1540 }
   1541 
   1542 uintptr_t Simulator::stackLimit() const { return stackLimit_; }
   1543 
   1544 uintptr_t* Simulator::addressOfStackLimit() { return &stackLimit_; }
   1545 
   1546 bool Simulator::overRecursed(uintptr_t newsp) const {
   1547  if (newsp == 0) {
   1548    newsp = getRegister(sp);
   1549  }
   1550  return newsp <= stackLimit();
   1551 }
   1552 
   1553 bool Simulator::overRecursedWithExtra(uint32_t extra) const {
   1554  uintptr_t newsp = getRegister(sp) - extra;
   1555  return newsp <= stackLimit();
   1556 }
   1557 
   1558 // Unsupported instructions use format to print an error and stop execution.
   1559 void Simulator::format(SimInstruction* instr, const char* format) {
   1560  printf("Simulator found unsupported instruction:\n 0x%016" PRIxPTR ": %s\n",
   1561         reinterpret_cast<intptr_t>(instr), format);
   1562  MOZ_CRASH();
   1563 }
   1564 
   1565 // Note: With the code below we assume that all runtime calls return a 64 bits
   1566 // result. If they don't, the v1 result register contains a bogus value, which
   1567 // is fine because it is caller-saved.
   1568 ABI_FUNCTION_TYPE_SIM_PROTOTYPES
   1569 
   1570 // Generated by Assembler::break_()/stop(), ebreak code is passed as immediate
   1571 // field of a subsequent LUI instruction; otherwise returns -1
   1572 static inline uint32_t get_ebreak_code(Instruction* instr) {
   1573  MOZ_ASSERT(instr->InstructionBits() == kBreakInstr);
   1574  uint8_t* cur = reinterpret_cast<uint8_t*>(instr);
   1575  Instruction* next_instr = reinterpret_cast<Instruction*>(cur + kInstrSize);
   1576  if (next_instr->BaseOpcodeFieldRaw() == LUI)
   1577    return (next_instr->Imm20UValue());
   1578  else
   1579    return -1;
   1580 }
   1581 
   1582 // Software interrupt instructions are used by the simulator to call into C++.
   1583 void Simulator::SoftwareInterrupt() {
   1584  // There are two instructions that could get us here, the ebreak or ecall
   1585  // instructions are "SYSTEM" class opcode distinuished by Imm12Value field w/
   1586  // the rest of instruction fields being zero
   1587  // We first check if we met a call_rt_redirected.
   1588  if (instr_.InstructionBits() == rtCallRedirInstr) {
   1589    Redirection* redirection = Redirection::FromSwiInstruction(instr_.instr());
   1590    uintptr_t nativeFn =
   1591        reinterpret_cast<uintptr_t>(redirection->nativeFunction());
   1592 
   1593    intptr_t arg0 = getRegister(a0);
   1594    intptr_t arg1 = getRegister(a1);
   1595    intptr_t arg2 = getRegister(a2);
   1596    intptr_t arg3 = getRegister(a3);
   1597    intptr_t arg4 = getRegister(a4);
   1598    intptr_t arg5 = getRegister(a5);
   1599    intptr_t arg6 = getRegister(a6);
   1600    intptr_t arg7 = getRegister(a7);
   1601 
   1602    // This is dodgy but it works because the C entry stubs are never moved.
   1603    // See comment in codegen-arm.cc and bug 1242173.
   1604    intptr_t saved_ra = getRegister(ra);
   1605 
   1606    intptr_t external =
   1607        reinterpret_cast<intptr_t>(redirection->nativeFunction());
   1608 
   1609    bool stack_aligned = (getRegister(sp) & (ABIStackAlignment - 1)) == 0;
   1610    if (!stack_aligned) {
   1611      fprintf(stderr, "Runtime call with unaligned stack!\n");
   1612      MOZ_CRASH();
   1613    }
   1614    int64_t* sp_ = reinterpret_cast<int64_t*>(getRegister(sp));
   1615 
   1616    if (single_stepping_) {
   1617      single_step_callback_(single_step_callback_arg_, this, nullptr);
   1618    }
   1619    if (FLAG_trace_sim) {
   1620      printf("Call to host function at %p with args %" PRIdPTR ", %" PRIdPTR
   1621             ", %" PRIdPTR ", %" PRIdPTR ", %" PRIdPTR ", %" PRIdPTR
   1622             ", %" PRIdPTR ", %" PRIdPTR "\n",
   1623             reinterpret_cast<void*>(external), arg0, arg1, arg2, arg3, arg4,
   1624             arg5, arg6, arg7);
   1625    }
   1626    switch (redirection->type()) {
   1627      ABI_FUNCTION_TYPE_RISCV64_SIM_DISPATCH
   1628      default:
   1629        MOZ_CRASH("Unknown function type.");
   1630    }
   1631 
   1632    if (single_stepping_) {
   1633      single_step_callback_(single_step_callback_arg_, this, nullptr);
   1634    }
   1635 
   1636    setRegister(ra, saved_ra);
   1637    set_pc(getRegister(ra));
   1638 
   1639  } else if (instr_.InstructionBits() == kBreakInstr &&
   1640             (get_ebreak_code(instr_.instr()) <= kMaxStopCode)) {
   1641    uint32_t code = get_ebreak_code(instr_.instr());
   1642    if (code == 0) {
   1643      // Default `ebreak`s generated by
   1644      // MacroAssemblerRiscv64Compat::breakpoint().
   1645      DieOrDebug();
   1646    } else if (isWatchpoint(code)) {
   1647      printWatchpoint(code);
   1648    } else if (IsTracepoint(code)) {
   1649      if (!FLAG_debug_sim) {
   1650        MOZ_CRASH("Add --debug-sim when tracepoint instruction is used.\n");
   1651      }
   1652      // printf("%d %d %d %d %d %d %d\n", code, code & LOG_TRACE, code &
   1653      // LOG_REGS,
   1654      //        code & kDebuggerTracingDirectivesMask, TRACE_ENABLE,
   1655      //        TRACE_DISABLE, kDebuggerTracingDirectivesMask);
   1656      switch (code & kDebuggerTracingDirectivesMask) {
   1657        case TRACE_ENABLE:
   1658          if (code & LOG_TRACE) {
   1659            FLAG_trace_sim = true;
   1660          }
   1661          if (code & LOG_REGS) {
   1662            RiscvDebugger dbg(this);
   1663            dbg.printAllRegs();
   1664          }
   1665          break;
   1666        case TRACE_DISABLE:
   1667          if (code & LOG_TRACE) {
   1668            FLAG_trace_sim = false;
   1669          }
   1670          break;
   1671        default:
   1672          UNREACHABLE();
   1673      }
   1674    } else {
   1675      increaseStopCounter(code);
   1676      handleStop(code);
   1677    }
   1678  } else {
   1679    //     uint8_t code = get_ebreak_code(instr_.instr()) - kMaxStopCode - 1;
   1680    //     switch (LNode::Opcode(code)) {
   1681    // #define EMIT_OP(OP, ...)  \
   1682 //       case LNode::Opcode::OP:\
   1683 //            std::cout << #OP << std::endl; \
   1684 //            break;
   1685    //     LIR_OPCODE_LIST(EMIT_OP);
   1686    // #undef EMIT_OP
   1687    //     }
   1688    DieOrDebug();
   1689  }
   1690 }
   1691 
   1692 // Stop helper functions.
   1693 bool Simulator::isWatchpoint(uint32_t code) {
   1694  return (code <= kMaxWatchpointCode);
   1695 }
   1696 
   1697 bool Simulator::IsTracepoint(uint32_t code) {
   1698  return (code <= kMaxTracepointCode && code > kMaxWatchpointCode);
   1699 }
   1700 
   1701 void Simulator::printWatchpoint(uint32_t code) {
   1702  RiscvDebugger dbg(this);
   1703  ++break_count_;
   1704  if (FLAG_riscv_print_watchpoint) {
   1705    printf("\n---- break %d marker: %20" PRIi64 "  (instr count: %20" PRIi64
   1706           ") ----\n",
   1707           code, break_count_, icount_);
   1708    dbg.printAllRegs();  // Print registers and continue running.
   1709  }
   1710 }
   1711 
   1712 void Simulator::handleStop(uint32_t code) {
   1713  // Stop if it is enabled, otherwise go on jumping over the stop
   1714  // and the message address.
   1715  if (isEnabledStop(code)) {
   1716    RiscvDebugger dbg(this);
   1717    dbg.Debug();
   1718  } else {
   1719    set_pc(get_pc() + 2 * kInstrSize);
   1720  }
   1721 }
   1722 
   1723 bool Simulator::isStopInstruction(SimInstruction* instr) {
   1724  if (instr->InstructionBits() != kBreakInstr) return false;
   1725  int32_t code = get_ebreak_code(instr->instr());
   1726  return code != -1 && static_cast<uint32_t>(code) > kMaxWatchpointCode &&
   1727         static_cast<uint32_t>(code) <= kMaxStopCode;
   1728 }
   1729 
   1730 bool Simulator::isEnabledStop(uint32_t code) {
   1731  MOZ_ASSERT(code <= kMaxStopCode);
   1732  MOZ_ASSERT(code > kMaxWatchpointCode);
   1733  return !(watchedStops_[code].count_ & kStopDisabledBit);
   1734 }
   1735 
   1736 void Simulator::enableStop(uint32_t code) {
   1737  if (!isEnabledStop(code)) {
   1738    watchedStops_[code].count_ &= ~kStopDisabledBit;
   1739  }
   1740 }
   1741 
   1742 void Simulator::disableStop(uint32_t code) {
   1743  if (isEnabledStop(code)) {
   1744    watchedStops_[code].count_ |= kStopDisabledBit;
   1745  }
   1746 }
   1747 
   1748 void Simulator::increaseStopCounter(uint32_t code) {
   1749  MOZ_ASSERT(code <= kMaxStopCode);
   1750  if ((watchedStops_[code].count_ & ~(1 << 31)) == 0x7fffffff) {
   1751    printf(
   1752        "Stop counter for code %i has overflowed.\n"
   1753        "Enabling this code and reseting the counter to 0.\n",
   1754        code);
   1755    watchedStops_[code].count_ = 0;
   1756    enableStop(code);
   1757  } else {
   1758    watchedStops_[code].count_++;
   1759  }
   1760 }
   1761 
   1762 // Print a stop status.
   1763 void Simulator::printStopInfo(uint32_t code) {
   1764  if (code <= kMaxWatchpointCode) {
   1765    printf("That is a watchpoint, not a stop.\n");
   1766    return;
   1767  } else if (code > kMaxStopCode) {
   1768    printf("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
   1769    return;
   1770  }
   1771  const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
   1772  int32_t count = watchedStops_[code].count_ & ~kStopDisabledBit;
   1773  // Don't print the state of unused breakpoints.
   1774  if (count != 0) {
   1775    if (watchedStops_[code].desc_) {
   1776      printf("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", code, code, state,
   1777             count, watchedStops_[code].desc_);
   1778    } else {
   1779      printf("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state,
   1780             count);
   1781    }
   1782  }
   1783 }
   1784 
   1785 void Simulator::SignalException(Exception e) {
   1786  printf("Error: Exception %i raised.", static_cast<int>(e));
   1787  MOZ_CRASH();
   1788 }
   1789 
   1790 // TODO(plind): refactor this messy debug code when we do unaligned access.
   1791 void Simulator::DieOrDebug() {
   1792  if (FLAG_riscv_trap_to_simulator_debugger) {
   1793    RiscvDebugger dbg(this);
   1794    dbg.Debug();
   1795  } else {
   1796    MOZ_CRASH("Die");
   1797  }
   1798 }
   1799 
   1800 // Executes the current instruction.
   1801 void Simulator::InstructionDecode(Instruction* instr) {
   1802  // if (FLAG_check_icache) {
   1803  //   CheckICache(SimulatorProcess::icache(), instr);
   1804  // }
   1805  pc_modified_ = false;
   1806 
   1807  EmbeddedVector<char, 256> buffer;
   1808 
   1809  if (FLAG_trace_sim || FLAG_debug_sim) {
   1810    SNPrintF(trace_buf_, " ");
   1811    disasm::NameConverter converter;
   1812    disasm::Disassembler dasm(converter);
   1813    // Use a reasonably large buffer.
   1814    dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
   1815 
   1816    // printf("EXECUTING  0x%08" PRIxPTR "   %-44s\n",
   1817    //        reinterpret_cast<intptr_t>(instr), buffer.begin());
   1818  }
   1819 
   1820  instr_ = instr;
   1821  switch (instr_.InstructionType()) {
   1822    case Instruction::kRType:
   1823      DecodeRVRType();
   1824      break;
   1825    case Instruction::kR4Type:
   1826      DecodeRVR4Type();
   1827      break;
   1828    case Instruction::kIType:
   1829      DecodeRVIType();
   1830      break;
   1831    case Instruction::kSType:
   1832      DecodeRVSType();
   1833      break;
   1834    case Instruction::kBType:
   1835      DecodeRVBType();
   1836      break;
   1837    case Instruction::kUType:
   1838      DecodeRVUType();
   1839      break;
   1840    case Instruction::kJType:
   1841      DecodeRVJType();
   1842      break;
   1843    case Instruction::kCRType:
   1844      DecodeCRType();
   1845      break;
   1846    case Instruction::kCAType:
   1847      DecodeCAType();
   1848      break;
   1849    case Instruction::kCJType:
   1850      DecodeCJType();
   1851      break;
   1852    case Instruction::kCBType:
   1853      DecodeCBType();
   1854      break;
   1855    case Instruction::kCIType:
   1856      DecodeCIType();
   1857      break;
   1858    case Instruction::kCIWType:
   1859      DecodeCIWType();
   1860      break;
   1861    case Instruction::kCSSType:
   1862      DecodeCSSType();
   1863      break;
   1864    case Instruction::kCLType:
   1865      DecodeCLType();
   1866      break;
   1867    case Instruction::kCSType:
   1868      DecodeCSType();
   1869      break;
   1870 #  ifdef CAN_USE_RVV_INSTRUCTIONS
   1871    case Instruction::kVType:
   1872      DecodeVType();
   1873      break;
   1874 #  endif
   1875    default:
   1876      UNSUPPORTED();
   1877  }
   1878 
   1879  if (FLAG_trace_sim) {
   1880    printf("  0x%012" PRIxPTR "      %-44s\t%s\n",
   1881           reinterpret_cast<intptr_t>(instr), buffer.start(),
   1882           trace_buf_.start());
   1883  }
   1884 
   1885  if (!pc_modified_) {
   1886    setRegister(pc, reinterpret_cast<sreg_t>(instr) + instr->InstructionSize());
   1887  }
   1888 
   1889  if (watch_address_ != nullptr) {
   1890    printf("  0x%012" PRIxPTR " :  0x%016" REGIx_FORMAT "  %14" REGId_FORMAT
   1891           " \n",
   1892           reinterpret_cast<intptr_t>(watch_address_), I64(*watch_address_),
   1893           I64(*watch_address_));
   1894    if (watch_value_ != *watch_address_) {
   1895      RiscvDebugger dbg(this);
   1896      dbg.Debug();
   1897      watch_value_ = *watch_address_;
   1898    }
   1899  }
   1900 }
   1901 
   1902 void Simulator::enable_single_stepping(SingleStepCallback cb, void* arg) {
   1903  single_stepping_ = true;
   1904  single_step_callback_ = cb;
   1905  single_step_callback_arg_ = arg;
   1906  single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
   1907 }
   1908 
   1909 void Simulator::disable_single_stepping() {
   1910  if (!single_stepping_) {
   1911    return;
   1912  }
   1913  single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
   1914  single_stepping_ = false;
   1915  single_step_callback_ = nullptr;
   1916  single_step_callback_arg_ = nullptr;
   1917 }
   1918 
   1919 template <bool enableStopSimAt>
   1920 void Simulator::execute() {
   1921  if (single_stepping_) {
   1922    single_step_callback_(single_step_callback_arg_, this, nullptr);
   1923  }
   1924 
   1925  // Get the PC to simulate. Cannot use the accessor here as we need the
   1926  // raw PC value and not the one used as input to arithmetic instructions.
   1927  int64_t program_counter = get_pc();
   1928 
   1929  while (program_counter != end_sim_pc) {
   1930    if (enableStopSimAt && (icount_ == Simulator::StopSimAt)) {
   1931      RiscvDebugger dbg(this);
   1932      dbg.Debug();
   1933    }
   1934    if (single_stepping_) {
   1935      single_step_callback_(single_step_callback_arg_, this,
   1936                            (void*)program_counter);
   1937    }
   1938    Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
   1939    InstructionDecode(instr);
   1940    icount_++;
   1941    program_counter = get_pc();
   1942  }
   1943 
   1944  if (single_stepping_) {
   1945    single_step_callback_(single_step_callback_arg_, this, nullptr);
   1946  }
   1947 }
   1948 
   1949 // RISCV Instruction Decode Routine
   1950 void Simulator::DecodeRVRType() {
   1951  switch (instr_.InstructionBits() & kRTypeMask) {
   1952    case RO_ADD: {
   1953      set_rd(sext_xlen(rs1() + rs2()));
   1954      break;
   1955    }
   1956    case RO_SUB: {
   1957      set_rd(sext_xlen(rs1() - rs2()));
   1958      break;
   1959    }
   1960    case RO_SLL: {
   1961      set_rd(sext_xlen(rs1() << (rs2() & (xlen - 1))));
   1962      break;
   1963    }
   1964    case RO_SLT: {
   1965      set_rd(sreg_t(rs1()) < sreg_t(rs2()));
   1966      break;
   1967    }
   1968    case RO_SLTU: {
   1969      set_rd(reg_t(rs1()) < reg_t(rs2()));
   1970      break;
   1971    }
   1972    case RO_XOR: {
   1973      set_rd(rs1() ^ rs2());
   1974      break;
   1975    }
   1976    case RO_SRL: {
   1977      set_rd(sext_xlen(zext_xlen(rs1()) >> (rs2() & (xlen - 1))));
   1978      break;
   1979    }
   1980    case RO_SRA: {
   1981      set_rd(sext_xlen(sext_xlen(rs1()) >> (rs2() & (xlen - 1))));
   1982      break;
   1983    }
   1984    case RO_OR: {
   1985      set_rd(rs1() | rs2());
   1986      break;
   1987    }
   1988    case RO_AND: {
   1989      set_rd(rs1() & rs2());
   1990      break;
   1991    }
   1992    case RO_ANDN:
   1993      set_rd(rs1() & ~rs2());
   1994      break;
   1995    case RO_ORN:
   1996      set_rd(rs1() | (~rs2()));
   1997      break;
   1998    case RO_XNOR:
   1999      set_rd((~rs1()) ^ (~rs2()));
   2000      break;
   2001 #  ifdef JS_CODEGEN_RISCV64
   2002    case RO_ADDW: {
   2003      set_rd(sext32(rs1() + rs2()));
   2004      break;
   2005    }
   2006    case RO_ADDUW:
   2007      set_rd(zext32(rs1()) + rs2());
   2008      break;
   2009    case RO_SUBW: {
   2010      set_rd(sext32(rs1() - rs2()));
   2011      break;
   2012    }
   2013    case RO_SLLW: {
   2014      set_rd(sext32(rs1() << (rs2() & 0x1F)));
   2015      break;
   2016    }
   2017    case RO_SRLW: {
   2018      set_rd(sext32(uint32_t(rs1()) >> (rs2() & 0x1F)));
   2019      break;
   2020    }
   2021    case RO_SRAW: {
   2022      set_rd(sext32(int32_t(rs1()) >> (rs2() & 0x1F)));
   2023      break;
   2024    }
   2025    case RO_SH1ADDUW: {
   2026      set_rd(rs2() + (zext32(rs1()) << 1));
   2027      break;
   2028    }
   2029    case RO_SH2ADDUW: {
   2030      set_rd(rs2() + (zext32(rs1()) << 2));
   2031      break;
   2032    }
   2033    case RO_SH3ADDUW: {
   2034      set_rd(rs2() + (zext32(rs1()) << 3));
   2035      break;
   2036    }
   2037    case RO_ROLW: {
   2038      reg_t extz_rs1 = zext32(rs1());
   2039      sreg_t shamt = rs2() & 31;
   2040      set_rd(sext32((extz_rs1 << shamt) | (extz_rs1 >> (32 - shamt))));
   2041      break;
   2042    }
   2043    case RO_RORW: {
   2044      reg_t extz_rs1 = zext32(rs1());
   2045      sreg_t shamt = rs2() & 31;
   2046      set_rd(sext32((extz_rs1 >> shamt) | (extz_rs1 << (32 - shamt))));
   2047      break;
   2048    }
   2049 #  endif /* JS_CODEGEN_RISCV64 */
   2050      // TODO(riscv): Add RISCV M extension macro
   2051    case RO_MUL: {
   2052      set_rd(rs1() * rs2());
   2053      break;
   2054    }
   2055    case RO_MULH: {
   2056      set_rd(mulh(rs1(), rs2()));
   2057      break;
   2058    }
   2059    case RO_MULHSU: {
   2060      set_rd(mulhsu(rs1(), rs2()));
   2061      break;
   2062    }
   2063    case RO_MULHU: {
   2064      set_rd(mulhu(rs1(), rs2()));
   2065      break;
   2066    }
   2067    case RO_DIV: {
   2068      sreg_t lhs = sext_xlen(rs1());
   2069      sreg_t rhs = sext_xlen(rs2());
   2070      if (rhs == 0) {
   2071        set_rd(-1);
   2072      } else if (lhs == INTPTR_MIN && rhs == -1) {
   2073        set_rd(lhs);
   2074      } else {
   2075        set_rd(sext_xlen(lhs / rhs));
   2076      }
   2077      break;
   2078    }
   2079    case RO_DIVU: {
   2080      reg_t lhs = zext_xlen(rs1());
   2081      reg_t rhs = zext_xlen(rs2());
   2082      if (rhs == 0) {
   2083        set_rd(UINTPTR_MAX);
   2084      } else {
   2085        set_rd(zext_xlen(lhs / rhs));
   2086      }
   2087      break;
   2088    }
   2089    case RO_REM: {
   2090      sreg_t lhs = sext_xlen(rs1());
   2091      sreg_t rhs = sext_xlen(rs2());
   2092      if (rhs == 0) {
   2093        set_rd(lhs);
   2094      } else if (lhs == INTPTR_MIN && rhs == -1) {
   2095        set_rd(0);
   2096      } else {
   2097        set_rd(sext_xlen(lhs % rhs));
   2098      }
   2099      break;
   2100    }
   2101    case RO_REMU: {
   2102      reg_t lhs = zext_xlen(rs1());
   2103      reg_t rhs = zext_xlen(rs2());
   2104      if (rhs == 0) {
   2105        set_rd(lhs);
   2106      } else {
   2107        set_rd(zext_xlen(lhs % rhs));
   2108      }
   2109      break;
   2110    }
   2111 #  ifdef JS_CODEGEN_RISCV64
   2112    case RO_MULW: {
   2113      set_rd(sext32(sext32(rs1()) * sext32(rs2())));
   2114      break;
   2115    }
   2116    case RO_DIVW: {
   2117      sreg_t lhs = sext32(rs1());
   2118      sreg_t rhs = sext32(rs2());
   2119      if (rhs == 0) {
   2120        set_rd(-1);
   2121      } else if (lhs == INT32_MIN && rhs == -1) {
   2122        set_rd(lhs);
   2123      } else {
   2124        set_rd(sext32(lhs / rhs));
   2125      }
   2126      break;
   2127    }
   2128    case RO_DIVUW: {
   2129      reg_t lhs = zext32(rs1());
   2130      reg_t rhs = zext32(rs2());
   2131      if (rhs == 0) {
   2132        set_rd(UINT32_MAX);
   2133      } else {
   2134        set_rd(zext32(lhs / rhs));
   2135      }
   2136      break;
   2137    }
   2138    case RO_REMW: {
   2139      sreg_t lhs = sext32(rs1());
   2140      sreg_t rhs = sext32(rs2());
   2141      if (rhs == 0) {
   2142        set_rd(lhs);
   2143      } else if (lhs == INT32_MIN && rhs == -1) {
   2144        set_rd(0);
   2145      } else {
   2146        set_rd(sext32(lhs % rhs));
   2147      }
   2148      break;
   2149    }
   2150    case RO_REMUW: {
   2151      reg_t lhs = zext32(rs1());
   2152      reg_t rhs = zext32(rs2());
   2153      if (rhs == 0) {
   2154        set_rd(zext32(lhs));
   2155      } else {
   2156        set_rd(zext32(lhs % rhs));
   2157      }
   2158      break;
   2159    }
   2160 #  endif /*JS_CODEGEN_RISCV64*/
   2161    case RO_SH1ADD:
   2162      set_rd(rs2() + (rs1() << 1));
   2163      break;
   2164    case RO_SH2ADD:
   2165      set_rd(rs2() + (rs1() << 2));
   2166      break;
   2167    case RO_SH3ADD:
   2168      set_rd(rs2() + (rs1() << 3));
   2169      break;
   2170    case RO_MAX:
   2171      set_rd(rs1() < rs2() ? rs2() : rs1());
   2172      break;
   2173    case RO_MAXU:
   2174      set_rd(static_cast<reg_t>(rs1()) < static_cast<reg_t>(rs2()) ? rs2()
   2175                                                                   : rs1());
   2176      break;
   2177    case RO_MIN:
   2178      set_rd(rs1() < rs2() ? rs1() : rs2());
   2179      break;
   2180    case RO_MINU:
   2181      set_rd(static_cast<reg_t>(rs1()) < static_cast<reg_t>(rs2()) ? rs1()
   2182                                                                   : rs2());
   2183      break;
   2184    case RO_ZEXTH:
   2185      set_rd(zext_xlen(uint16_t(rs1())));
   2186      break;
   2187    case RO_ROL: {
   2188      sreg_t shamt = rs2() & (xlen - 1);
   2189      set_rd((static_cast<reg_t>(rs1()) << shamt) |
   2190             (static_cast<reg_t>(rs1()) >> (xlen - shamt)));
   2191      break;
   2192    }
   2193    case RO_ROR: {
   2194      sreg_t shamt = rs2() & (xlen - 1);
   2195      set_rd((static_cast<reg_t>(rs1()) >> shamt) |
   2196             (static_cast<reg_t>(rs1()) << (xlen - shamt)));
   2197      break;
   2198    }
   2199    case RO_BCLR: {
   2200      sreg_t index = rs2() & (xlen - 1);
   2201      set_rd(rs1() & ~(1l << index));
   2202      break;
   2203    }
   2204    case RO_BEXT: {
   2205      sreg_t index = rs2() & (xlen - 1);
   2206      set_rd((rs1() >> index) & 1);
   2207      break;
   2208    }
   2209    case RO_BINV: {
   2210      sreg_t index = rs2() & (xlen - 1);
   2211      set_rd(rs1() ^ (1 << index));
   2212      break;
   2213    }
   2214    case RO_BSET: {
   2215      sreg_t index = rs2() & (xlen - 1);
   2216      set_rd(rs1() | (1 << index));
   2217      break;
   2218    }
   2219      // TODO(riscv): End Add RISCV M extension macro
   2220    default: {
   2221      switch (instr_.BaseOpcode()) {
   2222        case AMO:
   2223          DecodeRVRAType();
   2224          break;
   2225        case OP_FP:
   2226          DecodeRVRFPType();
   2227          break;
   2228        default:
   2229          UNSUPPORTED();
   2230      }
   2231    }
   2232  }
   2233 }
   2234 
   2235 template <typename T>
   2236 T Simulator::FMaxMinHelper(T a, T b, MaxMinKind kind) {
   2237  // set invalid bit for signaling nan
   2238  if ((a == std::numeric_limits<T>::signaling_NaN()) ||
   2239      (b == std::numeric_limits<T>::signaling_NaN())) {
   2240    set_csr_bits(csr_fflags, kInvalidOperation);
   2241  }
   2242 
   2243  T result = 0;
   2244  if (std::isnan(a) && std::isnan(b)) {
   2245    result = std::numeric_limits<float>::quiet_NaN();
   2246  } else if (std::isnan(a)) {
   2247    result = b;
   2248  } else if (std::isnan(b)) {
   2249    result = a;
   2250  } else if (b == a) {  // Handle -0.0 == 0.0 case.
   2251    if (kind == MaxMinKind::kMax) {
   2252      result = std::signbit(b) ? a : b;
   2253    } else {
   2254      result = std::signbit(b) ? b : a;
   2255    }
   2256  } else {
   2257    result = (kind == MaxMinKind::kMax) ? fmax(a, b) : fmin(a, b);
   2258  }
   2259 
   2260  return result;
   2261 }
   2262 
   2263 float Simulator::RoundF2FHelper(float input_val, int rmode) {
   2264  if (rmode == DYN) rmode = get_dynamic_rounding_mode();
   2265 
   2266  float rounded = 0;
   2267  switch (rmode) {
   2268    case RNE: {  // Round to Nearest, tiest to Even
   2269      rounded = floorf(input_val);
   2270      float error = input_val - rounded;
   2271 
   2272      // Take care of correctly handling the range [-0.5, -0.0], which must
   2273      // yield -0.0.
   2274      if ((-0.5 <= input_val) && (input_val < 0.0)) {
   2275        rounded = -0.0;
   2276 
   2277        // If the error is greater than 0.5, or is equal to 0.5 and the integer
   2278        // result is odd, round up.
   2279      } else if ((error > 0.5) ||
   2280                 ((error == 0.5) && (std::fmod(rounded, 2) != 0))) {
   2281        rounded++;
   2282      }
   2283      break;
   2284    }
   2285    case RTZ:  // Round towards Zero
   2286      rounded = std::truncf(input_val);
   2287      break;
   2288    case RDN:  // Round Down (towards -infinity)
   2289      rounded = floorf(input_val);
   2290      break;
   2291    case RUP:  // Round Up (towards +infinity)
   2292      rounded = ceilf(input_val);
   2293      break;
   2294    case RMM:  // Round to Nearest, tiest to Max Magnitude
   2295      rounded = std::roundf(input_val);
   2296      break;
   2297    default:
   2298      UNREACHABLE();
   2299  }
   2300 
   2301  return rounded;
   2302 }
   2303 
   2304 double Simulator::RoundF2FHelper(double input_val, int rmode) {
   2305  if (rmode == DYN) rmode = get_dynamic_rounding_mode();
   2306 
   2307  double rounded = 0;
   2308  switch (rmode) {
   2309    case RNE: {  // Round to Nearest, tiest to Even
   2310      rounded = std::floor(input_val);
   2311      double error = input_val - rounded;
   2312 
   2313      // Take care of correctly handling the range [-0.5, -0.0], which must
   2314      // yield -0.0.
   2315      if ((-0.5 <= input_val) && (input_val < 0.0)) {
   2316        rounded = -0.0;
   2317 
   2318        // If the error is greater than 0.5, or is equal to 0.5 and the integer
   2319        // result is odd, round up.
   2320      } else if ((error > 0.5) ||
   2321                 ((error == 0.5) && (std::fmod(rounded, 2) != 0))) {
   2322        rounded++;
   2323      }
   2324      break;
   2325    }
   2326    case RTZ:  // Round towards Zero
   2327      rounded = std::trunc(input_val);
   2328      break;
   2329    case RDN:  // Round Down (towards -infinity)
   2330      rounded = std::floor(input_val);
   2331      break;
   2332    case RUP:  // Round Up (towards +infinity)
   2333      rounded = std::ceil(input_val);
   2334      break;
   2335    case RMM:  // Round to Nearest, tiest to Max Magnitude
   2336      rounded = std::round(input_val);
   2337      break;
   2338    default:
   2339      UNREACHABLE();
   2340  }
   2341  return rounded;
   2342 }
   2343 
   2344 // convert rounded floating-point to integer types, handle input values that
   2345 // are out-of-range, underflow, or NaN, and set appropriate fflags
   2346 template <typename I_TYPE, typename F_TYPE>
   2347 I_TYPE Simulator::RoundF2IHelper(F_TYPE original, int rmode) {
   2348  MOZ_ASSERT(std::is_integral<I_TYPE>::value);
   2349 
   2350  MOZ_ASSERT((std::is_same<F_TYPE, float>::value ||
   2351              std::is_same<F_TYPE, double>::value));
   2352 
   2353  I_TYPE max_i = std::numeric_limits<I_TYPE>::max();
   2354  I_TYPE min_i = std::numeric_limits<I_TYPE>::min();
   2355 
   2356  if (!std::isfinite(original)) {
   2357    set_fflags(kInvalidOperation);
   2358    if (std::isnan(original) ||
   2359        original == std::numeric_limits<F_TYPE>::infinity()) {
   2360      return max_i;
   2361    } else {
   2362      MOZ_ASSERT(original == -std::numeric_limits<F_TYPE>::infinity());
   2363      return min_i;
   2364    }
   2365  }
   2366 
   2367  F_TYPE rounded = RoundF2FHelper(original, rmode);
   2368  if (original != rounded) set_fflags(kInexact);
   2369 
   2370  if (!std::isfinite(rounded)) {
   2371    set_fflags(kInvalidOperation);
   2372    if (std::isnan(rounded) ||
   2373        rounded == std::numeric_limits<F_TYPE>::infinity()) {
   2374      return max_i;
   2375    } else {
   2376      MOZ_ASSERT(rounded == -std::numeric_limits<F_TYPE>::infinity());
   2377      return min_i;
   2378    }
   2379  }
   2380 
   2381  // Since integer max values are either all 1s (for unsigned) or all 1s
   2382  // except for sign-bit (for signed), they cannot be represented precisely in
   2383  // floating point, in order to precisely tell whether the rounded floating
   2384  // point is within the max range, we compare against (max_i+1) which would
   2385  // have a single 1 w/ many trailing zeros
   2386  float max_i_plus_1 =
   2387      std::is_same<uint64_t, I_TYPE>::value
   2388          ? 0x1p64f  // uint64_t::max + 1 cannot be represented in integers,
   2389                     // so use its float representation directly
   2390          : static_cast<float>(static_cast<uint64_t>(max_i) + 1);
   2391  if (rounded >= max_i_plus_1) {
   2392    set_fflags(kOverflow | kInvalidOperation);
   2393    return max_i;
   2394  }
   2395 
   2396  // Since min_i (either 0 for unsigned, or for signed) is represented
   2397  // precisely in floating-point,  comparing rounded directly against min_i
   2398  if (rounded <= min_i) {
   2399    if (rounded < min_i) set_fflags(kOverflow | kInvalidOperation);
   2400    return min_i;
   2401  }
   2402 
   2403  F_TYPE underflow_fval =
   2404      std::is_same<F_TYPE, float>::value ? FLT_MIN : DBL_MIN;
   2405  if (rounded < underflow_fval && rounded > -underflow_fval && rounded != 0) {
   2406    set_fflags(kUnderflow);
   2407  }
   2408 
   2409  return static_cast<I_TYPE>(rounded);
   2410 }
   2411 
   2412 template <typename T>
   2413 static int64_t FclassHelper(T value) {
   2414  switch (std::fpclassify(value)) {
   2415    case FP_INFINITE:
   2416      return (std::signbit(value) ? kNegativeInfinity : kPositiveInfinity);
   2417    case FP_NAN:
   2418      return (isSnan(value) ? kSignalingNaN : kQuietNaN);
   2419    case FP_NORMAL:
   2420      return (std::signbit(value) ? kNegativeNormalNumber
   2421                                  : kPositiveNormalNumber);
   2422    case FP_SUBNORMAL:
   2423      return (std::signbit(value) ? kNegativeSubnormalNumber
   2424                                  : kPositiveSubnormalNumber);
   2425    case FP_ZERO:
   2426      return (std::signbit(value) ? kNegativeZero : kPositiveZero);
   2427    default:
   2428      UNREACHABLE();
   2429  }
   2430  UNREACHABLE();
   2431  return FP_ZERO;
   2432 }
   2433 
   2434 template <typename T>
   2435 bool Simulator::CompareFHelper(T input1, T input2, FPUCondition cc) {
   2436  MOZ_ASSERT(std::is_floating_point<T>::value);
   2437  bool result = false;
   2438  switch (cc) {
   2439    case LT:
   2440    case LE:
   2441      // FLT, FLE are signaling compares
   2442      if (std::isnan(input1) || std::isnan(input2)) {
   2443        set_fflags(kInvalidOperation);
   2444        result = false;
   2445      } else {
   2446        result = (cc == LT) ? (input1 < input2) : (input1 <= input2);
   2447      }
   2448      break;
   2449    case EQ:
   2450      if (std::numeric_limits<T>::signaling_NaN() == input1 ||
   2451          std::numeric_limits<T>::signaling_NaN() == input2) {
   2452        set_fflags(kInvalidOperation);
   2453      }
   2454      if (std::isnan(input1) || std::isnan(input2)) {
   2455        result = false;
   2456      } else {
   2457        result = (input1 == input2);
   2458      }
   2459      break;
   2460    case NE:
   2461      if (std::numeric_limits<T>::signaling_NaN() == input1 ||
   2462          std::numeric_limits<T>::signaling_NaN() == input2) {
   2463        set_fflags(kInvalidOperation);
   2464      }
   2465      if (std::isnan(input1) || std::isnan(input2)) {
   2466        result = true;
   2467      } else {
   2468        result = (input1 != input2);
   2469      }
   2470      break;
   2471    default:
   2472      UNREACHABLE();
   2473  }
   2474  return result;
   2475 }
   2476 
   2477 template <typename T>
   2478 static inline bool is_invalid_fmul(T src1, T src2) {
   2479  return (isinf(src1) && src2 == static_cast<T>(0.0)) ||
   2480         (src1 == static_cast<T>(0.0) && isinf(src2));
   2481 }
   2482 
   2483 template <typename T>
   2484 static inline bool is_invalid_fadd(T src1, T src2) {
   2485  return (isinf(src1) && isinf(src2) &&
   2486          std::signbit(src1) != std::signbit(src2));
   2487 }
   2488 
   2489 template <typename T>
   2490 static inline bool is_invalid_fsub(T src1, T src2) {
   2491  return (isinf(src1) && isinf(src2) &&
   2492          std::signbit(src1) == std::signbit(src2));
   2493 }
   2494 
   2495 template <typename T>
   2496 static inline bool is_invalid_fdiv(T src1, T src2) {
   2497  return ((src1 == 0 && src2 == 0) || (isinf(src1) && isinf(src2)));
   2498 }
   2499 
   2500 template <typename T>
   2501 static inline bool is_invalid_fsqrt(T src1) {
   2502  return (src1 < 0);
   2503 }
   2504 
   2505 int Simulator::loadLinkedW(uint64_t addr, SimInstruction* instr) {
   2506  if ((addr & 3) == 0) {
   2507    if (handleWasmSegFault(addr, 4)) {
   2508      return -1;
   2509    }
   2510 
   2511    volatile int32_t* ptr = reinterpret_cast<volatile int32_t*>(addr);
   2512    int32_t value = *ptr;
   2513    lastLLValue_ = value;
   2514    LLAddr_ = addr;
   2515    // Note that any memory write or "external" interrupt should reset this
   2516    // value to false.
   2517    LLBit_ = true;
   2518    return value;
   2519  }
   2520  printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   2521         reinterpret_cast<intptr_t>(instr));
   2522  MOZ_CRASH();
   2523  return 0;
   2524 }
   2525 
   2526 int Simulator::storeConditionalW(uint64_t addr, int value,
   2527                                 SimInstruction* instr) {
   2528  // Correct behavior in this case, as defined by architecture, is to just
   2529  // return 0, but there is no point at allowing that. It is certainly an
   2530  // indicator of a bug.
   2531  if (addr != LLAddr_) {
   2532    printf("SC to bad address: 0x%016" PRIx64 ", pc=0x%016" PRIxPTR
   2533           ", expected: 0x%016" PRIxPTR "\n",
   2534           addr, reinterpret_cast<intptr_t>(instr), LLAddr_);
   2535    MOZ_CRASH();
   2536  }
   2537 
   2538  if ((addr & 3) == 0) {
   2539    SharedMem<int32_t*> ptr =
   2540        SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr));
   2541 
   2542    if (!LLBit_) {
   2543      return 1;
   2544    }
   2545 
   2546    LLBit_ = false;
   2547    LLAddr_ = 0;
   2548    int32_t expected = int32_t(lastLLValue_);
   2549    int32_t old =
   2550        AtomicOperations::compareExchangeSeqCst(ptr, expected, int32_t(value));
   2551    return (old == expected) ? 0 : 1;
   2552  }
   2553  printf("Unaligned SC at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   2554         reinterpret_cast<intptr_t>(instr));
   2555  MOZ_CRASH();
   2556  return 0;
   2557 }
   2558 
   2559 int64_t Simulator::loadLinkedD(uint64_t addr, SimInstruction* instr) {
   2560  if ((addr & kPointerAlignmentMask) == 0) {
   2561    if (handleWasmSegFault(addr, 8)) {
   2562      return -1;
   2563    }
   2564 
   2565    volatile int64_t* ptr = reinterpret_cast<volatile int64_t*>(addr);
   2566    int64_t value = *ptr;
   2567    lastLLValue_ = value;
   2568    LLAddr_ = addr;
   2569    // Note that any memory write or "external" interrupt should reset this
   2570    // value to false.
   2571    LLBit_ = true;
   2572    return value;
   2573  }
   2574  printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   2575         reinterpret_cast<intptr_t>(instr));
   2576  MOZ_CRASH();
   2577  return 0;
   2578 }
   2579 
   2580 int Simulator::storeConditionalD(uint64_t addr, int64_t value,
   2581                                 SimInstruction* instr) {
   2582  // Correct behavior in this case, as defined by architecture, is to just
   2583  // return 0, but there is no point at allowing that. It is certainly an
   2584  // indicator of a bug.
   2585  if (addr != LLAddr_) {
   2586    printf("SC to bad address: 0x%016" PRIx64 ", pc=0x%016" PRIxPTR
   2587           ", expected: 0x%016" PRIxPTR "\n",
   2588           addr, reinterpret_cast<intptr_t>(instr), LLAddr_);
   2589    MOZ_CRASH();
   2590  }
   2591 
   2592  if ((addr & kPointerAlignmentMask) == 0) {
   2593    SharedMem<int64_t*> ptr =
   2594        SharedMem<int64_t*>::shared(reinterpret_cast<int64_t*>(addr));
   2595 
   2596    if (!LLBit_) {
   2597      return 1;
   2598    }
   2599 
   2600    LLBit_ = false;
   2601    LLAddr_ = 0;
   2602    int64_t expected = lastLLValue_;
   2603    int64_t old =
   2604        AtomicOperations::compareExchangeSeqCst(ptr, expected, int64_t(value));
   2605    return (old == expected) ? 0 : 1;
   2606  }
   2607  printf("Unaligned SC at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
   2608         reinterpret_cast<intptr_t>(instr));
   2609  MOZ_CRASH();
   2610  return 0;
   2611 }
   2612 
   2613 void Simulator::DecodeRVRAType() {
   2614  // TODO(riscv): Add macro for RISCV A extension
   2615  // Special handling for A extension instructions because it uses func5
   2616  // For all A extension instruction, V8 simulator is pure sequential. No
   2617  // Memory address lock or other synchronizaiton behaviors.
   2618  switch (instr_.InstructionBits() & kRATypeMask) {
   2619    case RO_LR_W: {
   2620      sreg_t addr = rs1();
   2621      set_rd(loadLinkedW(addr, &instr_));
   2622      TraceLr(addr, getRegister(rd_reg()), getRegister(rd_reg()));
   2623      break;
   2624    }
   2625    case RO_SC_W: {
   2626      sreg_t addr = rs1();
   2627      auto value = static_cast<int32_t>(rs2());
   2628      auto result =
   2629          storeConditionalW(addr, static_cast<int32_t>(rs2()), &instr_);
   2630      set_rd(result);
   2631      if (!result) {
   2632        TraceSc(addr, value);
   2633      }
   2634      break;
   2635    }
   2636    case RO_AMOSWAP_W: {
   2637      if ((rs1() & 0x3) != 0) {
   2638        DieOrDebug();
   2639      }
   2640      set_rd(sext32(amo<uint32_t>(
   2641          rs1(), [&](uint32_t lhs) { return (uint32_t)rs2(); }, instr_.instr(),
   2642          WORD)));
   2643      break;
   2644    }
   2645    case RO_AMOADD_W: {
   2646      if ((rs1() & 0x3) != 0) {
   2647        DieOrDebug();
   2648      }
   2649      set_rd(sext32(amo<uint32_t>(
   2650          rs1(), [&](uint32_t lhs) { return lhs + (uint32_t)rs2(); },
   2651          instr_.instr(), WORD)));
   2652      break;
   2653    }
   2654    case RO_AMOXOR_W: {
   2655      if ((rs1() & 0x3) != 0) {
   2656        DieOrDebug();
   2657      }
   2658      set_rd(sext32(amo<uint32_t>(
   2659          rs1(), [&](uint32_t lhs) { return lhs ^ (uint32_t)rs2(); },
   2660          instr_.instr(), WORD)));
   2661      break;
   2662    }
   2663    case RO_AMOAND_W: {
   2664      if ((rs1() & 0x3) != 0) {
   2665        DieOrDebug();
   2666      }
   2667      set_rd(sext32(amo<uint32_t>(
   2668          rs1(), [&](uint32_t lhs) { return lhs & (uint32_t)rs2(); },
   2669          instr_.instr(), WORD)));
   2670      break;
   2671    }
   2672    case RO_AMOOR_W: {
   2673      if ((rs1() & 0x3) != 0) {
   2674        DieOrDebug();
   2675      }
   2676      set_rd(sext32(amo<uint32_t>(
   2677          rs1(), [&](uint32_t lhs) { return lhs | (uint32_t)rs2(); },
   2678          instr_.instr(), WORD)));
   2679      break;
   2680    }
   2681    case RO_AMOMIN_W: {
   2682      if ((rs1() & 0x3) != 0) {
   2683        DieOrDebug();
   2684      }
   2685      set_rd(sext32(amo<int32_t>(
   2686          rs1(), [&](int32_t lhs) { return std::min(lhs, (int32_t)rs2()); },
   2687          instr_.instr(), WORD)));
   2688      break;
   2689    }
   2690    case RO_AMOMAX_W: {
   2691      if ((rs1() & 0x3) != 0) {
   2692        DieOrDebug();
   2693      }
   2694      set_rd(sext32(amo<int32_t>(
   2695          rs1(), [&](int32_t lhs) { return std::max(lhs, (int32_t)rs2()); },
   2696          instr_.instr(), WORD)));
   2697      break;
   2698    }
   2699    case RO_AMOMINU_W: {
   2700      if ((rs1() & 0x3) != 0) {
   2701        DieOrDebug();
   2702      }
   2703      set_rd(sext32(amo<uint32_t>(
   2704          rs1(), [&](uint32_t lhs) { return std::min(lhs, (uint32_t)rs2()); },
   2705          instr_.instr(), WORD)));
   2706      break;
   2707    }
   2708    case RO_AMOMAXU_W: {
   2709      if ((rs1() & 0x3) != 0) {
   2710        DieOrDebug();
   2711      }
   2712      set_rd(sext32(amo<uint32_t>(
   2713          rs1(), [&](uint32_t lhs) { return std::max(lhs, (uint32_t)rs2()); },
   2714          instr_.instr(), WORD)));
   2715      break;
   2716    }
   2717 #  ifdef JS_CODEGEN_RISCV64
   2718    case RO_LR_D: {
   2719      sreg_t addr = rs1();
   2720      set_rd(loadLinkedD(addr, &instr_));
   2721      TraceLr(addr, getRegister(rd_reg()), getRegister(rd_reg()));
   2722      break;
   2723    }
   2724    case RO_SC_D: {
   2725      sreg_t addr = rs1();
   2726      auto value = static_cast<int64_t>(rs2());
   2727      auto result =
   2728          storeConditionalD(addr, static_cast<int64_t>(rs2()), &instr_);
   2729      set_rd(result);
   2730      if (!result) {
   2731        TraceSc(addr, value);
   2732      }
   2733      break;
   2734    }
   2735    case RO_AMOSWAP_D: {
   2736      set_rd(amo<int64_t>(
   2737          rs1(), [&](int64_t lhs) { return rs2(); }, instr_.instr(), DWORD));
   2738      break;
   2739    }
   2740    case RO_AMOADD_D: {
   2741      set_rd(amo<int64_t>(
   2742          rs1(), [&](int64_t lhs) { return lhs + rs2(); }, instr_.instr(),
   2743          DWORD));
   2744      break;
   2745    }
   2746    case RO_AMOXOR_D: {
   2747      set_rd(amo<int64_t>(
   2748          rs1(), [&](int64_t lhs) { return lhs ^ rs2(); }, instr_.instr(),
   2749          DWORD));
   2750      break;
   2751    }
   2752    case RO_AMOAND_D: {
   2753      set_rd(amo<int64_t>(
   2754          rs1(), [&](int64_t lhs) { return lhs & rs2(); }, instr_.instr(),
   2755          DWORD));
   2756      break;
   2757    }
   2758    case RO_AMOOR_D: {
   2759      set_rd(amo<int64_t>(
   2760          rs1(), [&](int64_t lhs) { return lhs | rs2(); }, instr_.instr(),
   2761          DWORD));
   2762      break;
   2763    }
   2764    case RO_AMOMIN_D: {
   2765      set_rd(amo<int64_t>(
   2766          rs1(), [&](int64_t lhs) { return std::min(lhs, rs2()); },
   2767          instr_.instr(), DWORD));
   2768      break;
   2769    }
   2770    case RO_AMOMAX_D: {
   2771      set_rd(amo<int64_t>(
   2772          rs1(), [&](int64_t lhs) { return std::max(lhs, rs2()); },
   2773          instr_.instr(), DWORD));
   2774      break;
   2775    }
   2776    case RO_AMOMINU_D: {
   2777      set_rd(amo<uint64_t>(
   2778          rs1(), [&](uint64_t lhs) { return std::min(lhs, (uint64_t)rs2()); },
   2779          instr_.instr(), DWORD));
   2780      break;
   2781    }
   2782    case RO_AMOMAXU_D: {
   2783      set_rd(amo<uint64_t>(
   2784          rs1(), [&](uint64_t lhs) { return std::max(lhs, (uint64_t)rs2()); },
   2785          instr_.instr(), DWORD));
   2786      break;
   2787    }
   2788 #  endif /*JS_CODEGEN_RISCV64*/
   2789    // TODO(riscv): End Add macro for RISCV A extension
   2790    default: {
   2791      UNSUPPORTED();
   2792    }
   2793  }
   2794 }
   2795 
   2796 void Simulator::DecodeRVRFPType() {
   2797  // OP_FP instructions (F/D) uses func7 first. Some further uses func3 and
   2798  // rs2()
   2799 
   2800  // kRATypeMask is only for func7
   2801  switch (instr_.InstructionBits() & kRFPTypeMask) {
   2802    // TODO(riscv): Add macro for RISCV F extension
   2803    case RO_FADD_S: {
   2804      // TODO(riscv): use rm value (round mode)
   2805      auto fn = [this](float frs1, float frs2) {
   2806        if (is_invalid_fadd(frs1, frs2)) {
   2807          this->set_fflags(kInvalidOperation);
   2808          return std::numeric_limits<float>::quiet_NaN();
   2809        } else {
   2810          return frs1 + frs2;
   2811        }
   2812      };
   2813      set_frd(CanonicalizeFPUOp2<float>(fn));
   2814      break;
   2815    }
   2816    case RO_FSUB_S: {
   2817      // TODO(riscv): use rm value (round mode)
   2818      auto fn = [this](float frs1, float frs2) {
   2819        if (is_invalid_fsub(frs1, frs2)) {
   2820          this->set_fflags(kInvalidOperation);
   2821          return std::numeric_limits<float>::quiet_NaN();
   2822        } else {
   2823          return frs1 - frs2;
   2824        }
   2825      };
   2826      set_frd(CanonicalizeFPUOp2<float>(fn));
   2827      break;
   2828    }
   2829    case RO_FMUL_S: {
   2830      // TODO(riscv): use rm value (round mode)
   2831      auto fn = [this](float frs1, float frs2) {
   2832        if (is_invalid_fmul(frs1, frs2)) {
   2833          this->set_fflags(kInvalidOperation);
   2834          return std::numeric_limits<float>::quiet_NaN();
   2835        } else {
   2836          return frs1 * frs2;
   2837        }
   2838      };
   2839      set_frd(CanonicalizeFPUOp2<float>(fn));
   2840      break;
   2841    }
   2842    case RO_FDIV_S: {
   2843      // TODO(riscv): use rm value (round mode)
   2844      auto fn = [this](float frs1, float frs2) {
   2845        if (is_invalid_fdiv(frs1, frs2)) {
   2846          this->set_fflags(kInvalidOperation);
   2847          return std::numeric_limits<float>::quiet_NaN();
   2848        } else if (frs2 == 0.0f) {
   2849          this->set_fflags(kDivideByZero);
   2850          return (std::signbit(frs1) == std::signbit(frs2)
   2851                      ? std::numeric_limits<float>::infinity()
   2852                      : -std::numeric_limits<float>::infinity());
   2853        } else {
   2854          return frs1 / frs2;
   2855        }
   2856      };
   2857      set_frd(CanonicalizeFPUOp2<float>(fn));
   2858      break;
   2859    }
   2860    case RO_FSQRT_S: {
   2861      if (instr_.Rs2Value() == 0b00000) {
   2862        // TODO(riscv): use rm value (round mode)
   2863        auto fn = [this](float frs) {
   2864          if (is_invalid_fsqrt(frs)) {
   2865            this->set_fflags(kInvalidOperation);
   2866            return std::numeric_limits<float>::quiet_NaN();
   2867          } else {
   2868            return std::sqrt(frs);
   2869          }
   2870        };
   2871        set_frd(CanonicalizeFPUOp1<float>(fn));
   2872      } else {
   2873        UNSUPPORTED();
   2874      }
   2875      break;
   2876    }
   2877    case RO_FSGNJ_S: {  // RO_FSGNJN_S  RO_FSQNJX_S
   2878      switch (instr_.Funct3Value()) {
   2879        case 0b000: {  // RO_FSGNJ_S
   2880          set_frd(fsgnj32(frs1_boxed(), frs2_boxed(), false, false));
   2881          break;
   2882        }
   2883        case 0b001: {  // RO_FSGNJN_S
   2884          set_frd(fsgnj32(frs1_boxed(), frs2_boxed(), true, false));
   2885          break;
   2886        }
   2887        case 0b010: {  // RO_FSQNJX_S
   2888          set_frd(fsgnj32(frs1_boxed(), frs2_boxed(), false, true));
   2889          break;
   2890        }
   2891        default: {
   2892          UNSUPPORTED();
   2893        }
   2894      }
   2895      break;
   2896    }
   2897    case RO_FMIN_S: {  // RO_FMAX_S
   2898      switch (instr_.Funct3Value()) {
   2899        case 0b000: {  // RO_FMIN_S
   2900          set_frd(FMaxMinHelper(frs1(), frs2(), MaxMinKind::kMin));
   2901          break;
   2902        }
   2903        case 0b001: {  // RO_FMAX_S
   2904          set_frd(FMaxMinHelper(frs1(), frs2(), MaxMinKind::kMax));
   2905          break;
   2906        }
   2907        default: {
   2908          UNSUPPORTED();
   2909        }
   2910      }
   2911      break;
   2912    }
   2913    case RO_FCVT_W_S: {  // RO_FCVT_WU_S , 64F RO_FCVT_L_S RO_FCVT_LU_S
   2914      float original_val = frs1();
   2915      switch (instr_.Rs2Value()) {
   2916        case 0b00000: {  // RO_FCVT_W_S
   2917          set_rd(RoundF2IHelper<int32_t>(original_val, instr_.RoundMode()));
   2918          break;
   2919        }
   2920        case 0b00001: {  // RO_FCVT_WU_S
   2921          set_rd(sext32(
   2922              RoundF2IHelper<uint32_t>(original_val, instr_.RoundMode())));
   2923          break;
   2924        }
   2925 #  ifdef JS_CODEGEN_RISCV64
   2926        case 0b00010: {  // RO_FCVT_L_S
   2927          set_rd(RoundF2IHelper<int64_t>(original_val, instr_.RoundMode()));
   2928          break;
   2929        }
   2930        case 0b00011: {  // RO_FCVT_LU_S
   2931          set_rd(RoundF2IHelper<uint64_t>(original_val, instr_.RoundMode()));
   2932          break;
   2933        }
   2934 #  endif /* JS_CODEGEN_RISCV64 */
   2935        default: {
   2936          UNSUPPORTED();
   2937        }
   2938      }
   2939      break;
   2940    }
   2941    case RO_FMV: {  // RO_FCLASS_S
   2942      switch (instr_.Funct3Value()) {
   2943        case 0b000: {
   2944          if (instr_.Rs2Value() == 0b00000) {
   2945            // RO_FMV_X_W
   2946            set_rd(sext32(getFpuRegister(rs1_reg())));
   2947          } else {
   2948            UNSUPPORTED();
   2949          }
   2950          break;
   2951        }
   2952        case 0b001: {  // RO_FCLASS_S
   2953          set_rd(FclassHelper(frs1()));
   2954          break;
   2955        }
   2956        default: {
   2957          UNSUPPORTED();
   2958        }
   2959      }
   2960      break;
   2961    }
   2962    case RO_FLE_S: {  // RO_FEQ_S RO_FLT_S RO_FLE_S
   2963      switch (instr_.Funct3Value()) {
   2964        case 0b010: {  // RO_FEQ_S
   2965          set_rd(CompareFHelper(frs1(), frs2(), EQ));
   2966          break;
   2967        }
   2968        case 0b001: {  // RO_FLT_S
   2969          set_rd(CompareFHelper(frs1(), frs2(), LT));
   2970          break;
   2971        }
   2972        case 0b000: {  // RO_FLE_S
   2973          set_rd(CompareFHelper(frs1(), frs2(), LE));
   2974          break;
   2975        }
   2976        default: {
   2977          UNSUPPORTED();
   2978        }
   2979      }
   2980      break;
   2981    }
   2982    case RO_FCVT_S_W: {  // RO_FCVT_S_WU , 64F RO_FCVT_S_L RO_FCVT_S_LU
   2983      switch (instr_.Rs2Value()) {
   2984        case 0b00000: {  // RO_FCVT_S_W
   2985          set_frd(static_cast<float>((int32_t)rs1()));
   2986          break;
   2987        }
   2988        case 0b00001: {  // RO_FCVT_S_WU
   2989          set_frd(static_cast<float>((uint32_t)rs1()));
   2990          break;
   2991        }
   2992 #  ifdef JS_CODEGEN_RISCV64
   2993        case 0b00010: {  // RO_FCVT_S_L
   2994          set_frd(static_cast<float>((int64_t)rs1()));
   2995          break;
   2996        }
   2997        case 0b00011: {  // RO_FCVT_S_LU
   2998          set_frd(static_cast<float>((uint64_t)rs1()));
   2999          break;
   3000        }
   3001 #  endif /* JS_CODEGEN_RISCV64 */
   3002        default: {
   3003          UNSUPPORTED();
   3004        }
   3005      }
   3006      break;
   3007    }
   3008    case RO_FMV_W_X: {
   3009      if (instr_.Funct3Value() == 0b000) {
   3010        // since FMV preserves source bit-pattern, no need to canonize
   3011        Float32 result = Float32::FromBits((uint32_t)rs1());
   3012        set_frd(result);
   3013      } else {
   3014        UNSUPPORTED();
   3015      }
   3016      break;
   3017    }
   3018      // TODO(riscv): Add macro for RISCV D extension
   3019    case RO_FADD_D: {
   3020      // TODO(riscv): use rm value (round mode)
   3021      auto fn = [this](double drs1, double drs2) {
   3022        if (is_invalid_fadd(drs1, drs2)) {
   3023          this->set_fflags(kInvalidOperation);
   3024          return std::numeric_limits<double>::quiet_NaN();
   3025        } else {
   3026          return drs1 + drs2;
   3027        }
   3028      };
   3029      set_drd(CanonicalizeFPUOp2<double>(fn));
   3030      break;
   3031    }
   3032    case RO_FSUB_D: {
   3033      // TODO(riscv): use rm value (round mode)
   3034      auto fn = [this](double drs1, double drs2) {
   3035        if (is_invalid_fsub(drs1, drs2)) {
   3036          this->set_fflags(kInvalidOperation);
   3037          return std::numeric_limits<double>::quiet_NaN();
   3038        } else {
   3039          return drs1 - drs2;
   3040        }
   3041      };
   3042      set_drd(CanonicalizeFPUOp2<double>(fn));
   3043      break;
   3044    }
   3045    case RO_FMUL_D: {
   3046      // TODO(riscv): use rm value (round mode)
   3047      auto fn = [this](double drs1, double drs2) {
   3048        if (is_invalid_fmul(drs1, drs2)) {
   3049          this->set_fflags(kInvalidOperation);
   3050          return std::numeric_limits<double>::quiet_NaN();
   3051        } else {
   3052          return drs1 * drs2;
   3053        }
   3054      };
   3055      set_drd(CanonicalizeFPUOp2<double>(fn));
   3056      break;
   3057    }
   3058    case RO_FDIV_D: {
   3059      // TODO(riscv): use rm value (round mode)
   3060      auto fn = [this](double drs1, double drs2) {
   3061        if (is_invalid_fdiv(drs1, drs2)) {
   3062          this->set_fflags(kInvalidOperation);
   3063          return std::numeric_limits<double>::quiet_NaN();
   3064        } else if (drs2 == 0.0) {
   3065          this->set_fflags(kDivideByZero);
   3066          return (std::signbit(drs1) == std::signbit(drs2)
   3067                      ? std::numeric_limits<double>::infinity()
   3068                      : -std::numeric_limits<double>::infinity());
   3069        } else {
   3070          return drs1 / drs2;
   3071        }
   3072      };
   3073      set_drd(CanonicalizeFPUOp2<double>(fn));
   3074      break;
   3075    }
   3076    case RO_FSQRT_D: {
   3077      if (instr_.Rs2Value() == 0b00000) {
   3078        // TODO(riscv): use rm value (round mode)
   3079        auto fn = [this](double drs) {
   3080          if (is_invalid_fsqrt(drs)) {
   3081            this->set_fflags(kInvalidOperation);
   3082            return std::numeric_limits<double>::quiet_NaN();
   3083          } else {
   3084            return std::sqrt(drs);
   3085          }
   3086        };
   3087        set_drd(CanonicalizeFPUOp1<double>(fn));
   3088      } else {
   3089        UNSUPPORTED();
   3090      }
   3091      break;
   3092    }
   3093    case RO_FSGNJ_D: {  // RO_FSGNJN_D RO_FSQNJX_D
   3094      switch (instr_.Funct3Value()) {
   3095        case 0b000: {  // RO_FSGNJ_D
   3096          set_drd(fsgnj64(drs1_boxed(), drs2_boxed(), false, false));
   3097          break;
   3098        }
   3099        case 0b001: {  // RO_FSGNJN_D
   3100          set_drd(fsgnj64(drs1_boxed(), drs2_boxed(), true, false));
   3101          break;
   3102        }
   3103        case 0b010: {  // RO_FSQNJX_D
   3104          set_drd(fsgnj64(drs1_boxed(), drs2_boxed(), false, true));
   3105          break;
   3106        }
   3107        default: {
   3108          UNSUPPORTED();
   3109        }
   3110      }
   3111      break;
   3112    }
   3113    case RO_FMIN_D: {  // RO_FMAX_D
   3114      switch (instr_.Funct3Value()) {
   3115        case 0b000: {  // RO_FMIN_D
   3116          set_drd(FMaxMinHelper(drs1(), drs2(), MaxMinKind::kMin));
   3117          break;
   3118        }
   3119        case 0b001: {  // RO_FMAX_D
   3120          set_drd(FMaxMinHelper(drs1(), drs2(), MaxMinKind::kMax));
   3121          break;
   3122        }
   3123        default: {
   3124          UNSUPPORTED();
   3125        }
   3126      }
   3127      break;
   3128    }
   3129    case (RO_FCVT_S_D & kRFPTypeMask): {
   3130      if (instr_.Rs2Value() == 0b00001) {
   3131        auto fn = [](double drs) { return static_cast<float>(drs); };
   3132        set_frd(CanonicalizeDoubleToFloatOperation(fn));
   3133      } else {
   3134        UNSUPPORTED();
   3135      }
   3136      break;
   3137    }
   3138    case RO_FCVT_D_S: {
   3139      if (instr_.Rs2Value() == 0b00000) {
   3140        auto fn = [](float frs) { return static_cast<double>(frs); };
   3141        set_drd(CanonicalizeFloatToDoubleOperation(fn));
   3142      } else {
   3143        UNSUPPORTED();
   3144      }
   3145      break;
   3146    }
   3147    case RO_FLE_D: {  // RO_FEQ_D RO_FLT_D RO_FLE_D
   3148      switch (instr_.Funct3Value()) {
   3149        case 0b010: {  // RO_FEQ_S
   3150          set_rd(CompareFHelper(drs1(), drs2(), EQ));
   3151          break;
   3152        }
   3153        case 0b001: {  // RO_FLT_D
   3154          set_rd(CompareFHelper(drs1(), drs2(), LT));
   3155          break;
   3156        }
   3157        case 0b000: {  // RO_FLE_D
   3158          set_rd(CompareFHelper(drs1(), drs2(), LE));
   3159          break;
   3160        }
   3161        default: {
   3162          UNSUPPORTED();
   3163        }
   3164      }
   3165      break;
   3166    }
   3167    case (RO_FCLASS_D & kRFPTypeMask): {  // RO_FCLASS_D , 64D RO_FMV_X_D
   3168      if (instr_.Rs2Value() != 0b00000) {
   3169        UNSUPPORTED();
   3170      }
   3171      switch (instr_.Funct3Value()) {
   3172        case 0b001: {  // RO_FCLASS_D
   3173          set_rd(FclassHelper(drs1()));
   3174          break;
   3175        }
   3176 #  ifdef JS_CODEGEN_RISCV64
   3177        case 0b000: {  // RO_FMV_X_D
   3178          set_rd(bit_cast<int64_t>(drs1()));
   3179          break;
   3180        }
   3181 #  endif /* JS_CODEGEN_RISCV64 */
   3182        default: {
   3183          UNSUPPORTED();
   3184        }
   3185      }
   3186      break;
   3187    }
   3188    case RO_FCVT_W_D: {  // RO_FCVT_WU_D , 64F RO_FCVT_L_D RO_FCVT_LU_D
   3189      double original_val = drs1();
   3190      switch (instr_.Rs2Value()) {
   3191        case 0b00000: {  // RO_FCVT_W_D
   3192          set_rd(RoundF2IHelper<int32_t>(original_val, instr_.RoundMode()));
   3193          break;
   3194        }
   3195        case 0b00001: {  // RO_FCVT_WU_D
   3196          set_rd(sext32(
   3197              RoundF2IHelper<uint32_t>(original_val, instr_.RoundMode())));
   3198          break;
   3199        }
   3200 #  ifdef JS_CODEGEN_RISCV64
   3201        case 0b00010: {  // RO_FCVT_L_D
   3202          set_rd(RoundF2IHelper<int64_t>(original_val, instr_.RoundMode()));
   3203          break;
   3204        }
   3205        case 0b00011: {  // RO_FCVT_LU_D
   3206          set_rd(RoundF2IHelper<uint64_t>(original_val, instr_.RoundMode()));
   3207          break;
   3208        }
   3209 #  endif /* JS_CODEGEN_RISCV64 */
   3210        default: {
   3211          UNSUPPORTED();
   3212        }
   3213      }
   3214      break;
   3215    }
   3216    case RO_FCVT_D_W: {  // RO_FCVT_D_WU , 64F RO_FCVT_D_L RO_FCVT_D_LU
   3217      switch (instr_.Rs2Value()) {
   3218        case 0b00000: {  // RO_FCVT_D_W
   3219          set_drd((int32_t)rs1());
   3220          break;
   3221        }
   3222        case 0b00001: {  // RO_FCVT_D_WU
   3223          set_drd((uint32_t)rs1());
   3224          break;
   3225        }
   3226 #  ifdef JS_CODEGEN_RISCV64
   3227        case 0b00010: {  // RO_FCVT_D_L
   3228          set_drd((int64_t)rs1());
   3229          break;
   3230        }
   3231        case 0b00011: {  // RO_FCVT_D_LU
   3232          set_drd((uint64_t)rs1());
   3233          break;
   3234        }
   3235 #  endif /* JS_CODEGEN_RISCV64 */
   3236        default: {
   3237          UNSUPPORTED();
   3238        }
   3239      }
   3240      break;
   3241    }
   3242 #  ifdef JS_CODEGEN_RISCV64
   3243    case RO_FMV_D_X: {
   3244      if (instr_.Funct3Value() == 0b000 && instr_.Rs2Value() == 0b00000) {
   3245        // Since FMV preserves source bit-pattern, no need to canonize
   3246        set_drd(bit_cast<double>(rs1()));
   3247      } else {
   3248        UNSUPPORTED();
   3249      }
   3250      break;
   3251    }
   3252 #  endif /* JS_CODEGEN_RISCV64 */
   3253    default: {
   3254      UNSUPPORTED();
   3255    }
   3256  }
   3257 }
   3258 
   3259 void Simulator::DecodeRVR4Type() {
   3260  switch (instr_.InstructionBits() & kR4TypeMask) {
   3261    // TODO(riscv): use F Extension macro block
   3262    case RO_FMADD_S: {
   3263      // TODO(riscv): use rm value (round mode)
   3264      auto fn = [this](float frs1, float frs2, float frs3) {
   3265        if (is_invalid_fmul(frs1, frs2) || is_invalid_fadd(frs1 * frs2, frs3)) {
   3266          this->set_fflags(kInvalidOperation);
   3267          return std::numeric_limits<float>::quiet_NaN();
   3268        } else {
   3269          return std::fma(frs1, frs2, frs3);
   3270        }
   3271      };
   3272      set_frd(CanonicalizeFPUOp3<float>(fn));
   3273      break;
   3274    }
   3275    case RO_FMSUB_S: {
   3276      // TODO(riscv): use rm value (round mode)
   3277      auto fn = [this](float frs1, float frs2, float frs3) {
   3278        if (is_invalid_fmul(frs1, frs2) || is_invalid_fsub(frs1 * frs2, frs3)) {
   3279          this->set_fflags(kInvalidOperation);
   3280          return std::numeric_limits<float>::quiet_NaN();
   3281        } else {
   3282          return std::fma(frs1, frs2, -frs3);
   3283        }
   3284      };
   3285      set_frd(CanonicalizeFPUOp3<float>(fn));
   3286      break;
   3287    }
   3288    case RO_FNMSUB_S: {
   3289      // TODO(riscv): use rm value (round mode)
   3290      auto fn = [this](float frs1, float frs2, float frs3) {
   3291        if (is_invalid_fmul(frs1, frs2) || is_invalid_fsub(frs3, frs1 * frs2)) {
   3292          this->set_fflags(kInvalidOperation);
   3293          return std::numeric_limits<float>::quiet_NaN();
   3294        } else {
   3295          return -std::fma(frs1, frs2, -frs3);
   3296        }
   3297      };
   3298      set_frd(CanonicalizeFPUOp3<float>(fn));
   3299      break;
   3300    }
   3301    case RO_FNMADD_S: {
   3302      // TODO(riscv): use rm value (round mode)
   3303      auto fn = [this](float frs1, float frs2, float frs3) {
   3304        if (is_invalid_fmul(frs1, frs2) || is_invalid_fadd(frs1 * frs2, frs3)) {
   3305          this->set_fflags(kInvalidOperation);
   3306          return std::numeric_limits<float>::quiet_NaN();
   3307        } else {
   3308          return -std::fma(frs1, frs2, frs3);
   3309        }
   3310      };
   3311      set_frd(CanonicalizeFPUOp3<float>(fn));
   3312      break;
   3313    }
   3314    // TODO(riscv): use F Extension macro block
   3315    case RO_FMADD_D: {
   3316      // TODO(riscv): use rm value (round mode)
   3317      auto fn = [this](double drs1, double drs2, double drs3) {
   3318        if (is_invalid_fmul(drs1, drs2) || is_invalid_fadd(drs1 * drs2, drs3)) {
   3319          this->set_fflags(kInvalidOperation);
   3320          return std::numeric_limits<double>::quiet_NaN();
   3321        } else {
   3322          return std::fma(drs1, drs2, drs3);
   3323        }
   3324      };
   3325      set_drd(CanonicalizeFPUOp3<double>(fn));
   3326      break;
   3327    }
   3328    case RO_FMSUB_D: {
   3329      // TODO(riscv): use rm value (round mode)
   3330      auto fn = [this](double drs1, double drs2, double drs3) {
   3331        if (is_invalid_fmul(drs1, drs2) || is_invalid_fsub(drs1 * drs2, drs3)) {
   3332          this->set_fflags(kInvalidOperation);
   3333          return std::numeric_limits<double>::quiet_NaN();
   3334        } else {
   3335          return std::fma(drs1, drs2, -drs3);
   3336        }
   3337      };
   3338      set_drd(CanonicalizeFPUOp3<double>(fn));
   3339      break;
   3340    }
   3341    case RO_FNMSUB_D: {
   3342      // TODO(riscv): use rm value (round mode)
   3343      auto fn = [this](double drs1, double drs2, double drs3) {
   3344        if (is_invalid_fmul(drs1, drs2) || is_invalid_fsub(drs3, drs1 * drs2)) {
   3345          this->set_fflags(kInvalidOperation);
   3346          return std::numeric_limits<double>::quiet_NaN();
   3347        } else {
   3348          return -std::fma(drs1, drs2, -drs3);
   3349        }
   3350      };
   3351      set_drd(CanonicalizeFPUOp3<double>(fn));
   3352      break;
   3353    }
   3354    case RO_FNMADD_D: {
   3355      // TODO(riscv): use rm value (round mode)
   3356      auto fn = [this](double drs1, double drs2, double drs3) {
   3357        if (is_invalid_fmul(drs1, drs2) || is_invalid_fadd(drs1 * drs2, drs3)) {
   3358          this->set_fflags(kInvalidOperation);
   3359          return std::numeric_limits<double>::quiet_NaN();
   3360        } else {
   3361          return -std::fma(drs1, drs2, drs3);
   3362        }
   3363      };
   3364      set_drd(CanonicalizeFPUOp3<double>(fn));
   3365      break;
   3366    }
   3367    default:
   3368      UNSUPPORTED();
   3369  }
   3370 }
   3371 
   3372 #  ifdef CAN_USE_RVV_INSTRUCTIONS
   3373 bool Simulator::DecodeRvvVL() {
   3374  uint32_t instr_temp =
   3375      instr_.InstructionBits() & (kRvvMopMask | kRvvNfMask | kBaseOpcodeMask);
   3376  if (RO_V_VL == instr_temp) {
   3377    if (!(instr_.InstructionBits() & (kRvvRs2Mask))) {
   3378      switch (instr_.vl_vs_width()) {
   3379        case 8: {
   3380          RVV_VI_LD(0, (i * nf + fn), int8, false);
   3381          break;
   3382        }
   3383        case 16: {
   3384          RVV_VI_LD(0, (i * nf + fn), int16, false);
   3385          break;
   3386        }
   3387        case 32: {
   3388          RVV_VI_LD(0, (i * nf + fn), int32, false);
   3389          break;
   3390        }
   3391        case 64: {
   3392          RVV_VI_LD(0, (i * nf + fn), int64, false);
   3393          break;
   3394        }
   3395        default:
   3396          UNIMPLEMENTED_RISCV();
   3397          break;
   3398      }
   3399      return true;
   3400    } else {
   3401      UNIMPLEMENTED_RISCV();
   3402      return true;
   3403    }
   3404  } else if (RO_V_VLS == instr_temp) {
   3405    UNIMPLEMENTED_RISCV();
   3406    return true;
   3407  } else if (RO_V_VLX == instr_temp) {
   3408    UNIMPLEMENTED_RISCV();
   3409    return true;
   3410  } else if (RO_V_VLSEG2 == instr_temp || RO_V_VLSEG3 == instr_temp ||
   3411             RO_V_VLSEG4 == instr_temp || RO_V_VLSEG5 == instr_temp ||
   3412             RO_V_VLSEG6 == instr_temp || RO_V_VLSEG7 == instr_temp ||
   3413             RO_V_VLSEG8 == instr_temp) {
   3414    if (!(instr_.InstructionBits() & (kRvvRs2Mask))) {
   3415      UNIMPLEMENTED_RISCV();
   3416      return true;
   3417    } else {
   3418      UNIMPLEMENTED_RISCV();
   3419      return true;
   3420    }
   3421  } else if (RO_V_VLSSEG2 == instr_temp || RO_V_VLSSEG3 == instr_temp ||
   3422             RO_V_VLSSEG4 == instr_temp || RO_V_VLSSEG5 == instr_temp ||
   3423             RO_V_VLSSEG6 == instr_temp || RO_V_VLSSEG7 == instr_temp ||
   3424             RO_V_VLSSEG8 == instr_temp) {
   3425    UNIMPLEMENTED_RISCV();
   3426    return true;
   3427  } else if (RO_V_VLXSEG2 == instr_temp || RO_V_VLXSEG3 == instr_temp ||
   3428             RO_V_VLXSEG4 == instr_temp || RO_V_VLXSEG5 == instr_temp ||
   3429             RO_V_VLXSEG6 == instr_temp || RO_V_VLXSEG7 == instr_temp ||
   3430             RO_V_VLXSEG8 == instr_temp) {
   3431    UNIMPLEMENTED_RISCV();
   3432    return true;
   3433  } else {
   3434    return false;
   3435  }
   3436 }
   3437 
   3438 bool Simulator::DecodeRvvVS() {
   3439  uint32_t instr_temp =
   3440      instr_.InstructionBits() & (kRvvMopMask | kRvvNfMask | kBaseOpcodeMask);
   3441  if (RO_V_VS == instr_temp) {
   3442    if (!(instr_.InstructionBits() & (kRvvRs2Mask))) {
   3443      switch (instr_.vl_vs_width()) {
   3444        case 8: {
   3445          RVV_VI_ST(0, (i * nf + fn), uint8, false);
   3446          break;
   3447        }
   3448        case 16: {
   3449          RVV_VI_ST(0, (i * nf + fn), uint16, false);
   3450          break;
   3451        }
   3452        case 32: {
   3453          RVV_VI_ST(0, (i * nf + fn), uint32, false);
   3454          break;
   3455        }
   3456        case 64: {
   3457          RVV_VI_ST(0, (i * nf + fn), uint64, false);
   3458          break;
   3459        }
   3460        default:
   3461          UNIMPLEMENTED_RISCV();
   3462          break;
   3463      }
   3464    } else {
   3465      UNIMPLEMENTED_RISCV();
   3466    }
   3467    return true;
   3468  } else if (RO_V_VSS == instr_temp) {
   3469    UNIMPLEMENTED_RISCV();
   3470    return true;
   3471  } else if (RO_V_VSX == instr_temp) {
   3472    UNIMPLEMENTED_RISCV();
   3473    return true;
   3474  } else if (RO_V_VSU == instr_temp) {
   3475    UNIMPLEMENTED_RISCV();
   3476    return true;
   3477  } else if (RO_V_VSSEG2 == instr_temp || RO_V_VSSEG3 == instr_temp ||
   3478             RO_V_VSSEG4 == instr_temp || RO_V_VSSEG5 == instr_temp ||
   3479             RO_V_VSSEG6 == instr_temp || RO_V_VSSEG7 == instr_temp ||
   3480             RO_V_VSSEG8 == instr_temp) {
   3481    UNIMPLEMENTED_RISCV();
   3482    return true;
   3483  } else if (RO_V_VSSSEG2 == instr_temp || RO_V_VSSSEG3 == instr_temp ||
   3484             RO_V_VSSSEG4 == instr_temp || RO_V_VSSSEG5 == instr_temp ||
   3485             RO_V_VSSSEG6 == instr_temp || RO_V_VSSSEG7 == instr_temp ||
   3486             RO_V_VSSSEG8 == instr_temp) {
   3487    UNIMPLEMENTED_RISCV();
   3488    return true;
   3489  } else if (RO_V_VSXSEG2 == instr_temp || RO_V_VSXSEG3 == instr_temp ||
   3490             RO_V_VSXSEG4 == instr_temp || RO_V_VSXSEG5 == instr_temp ||
   3491             RO_V_VSXSEG6 == instr_temp || RO_V_VSXSEG7 == instr_temp ||
   3492             RO_V_VSXSEG8 == instr_temp) {
   3493    UNIMPLEMENTED_RISCV();
   3494    return true;
   3495  } else {
   3496    return false;
   3497  }
   3498 }
   3499 #  endif
   3500 
   3501 void Simulator::DecodeRVIType() {
   3502  switch (instr_.InstructionBits() & kITypeMask) {
   3503    case RO_JALR: {
   3504      set_rd(get_pc() + kInstrSize);
   3505      // Note: No need to shift 2 for JALR's imm12, but set lowest bit to 0.
   3506      sreg_t next_pc = (rs1() + imm12()) & ~sreg_t(1);
   3507      set_pc(next_pc);
   3508      break;
   3509    }
   3510    case RO_LB: {
   3511      sreg_t addr = rs1() + imm12();
   3512      int8_t val = ReadMem<int8_t>(addr, instr_.instr());
   3513      set_rd(sext_xlen(val), false);
   3514      TraceMemRd(addr, val, getRegister(rd_reg()));
   3515      break;
   3516    }
   3517    case RO_LH: {
   3518      sreg_t addr = rs1() + imm12();
   3519      int16_t val = ReadMem<int16_t>(addr, instr_.instr());
   3520      set_rd(sext_xlen(val), false);
   3521      TraceMemRd(addr, val, getRegister(rd_reg()));
   3522      break;
   3523    }
   3524    case RO_LW: {
   3525      sreg_t addr = rs1() + imm12();
   3526      int32_t val = ReadMem<int32_t>(addr, instr_.instr());
   3527      set_rd(sext_xlen(val), false);
   3528      TraceMemRd(addr, val, getRegister(rd_reg()));
   3529      break;
   3530    }
   3531    case RO_LBU: {
   3532      sreg_t addr = rs1() + imm12();
   3533      uint8_t val = ReadMem<uint8_t>(addr, instr_.instr());
   3534      set_rd(zext_xlen(val), false);
   3535      TraceMemRd(addr, val, getRegister(rd_reg()));
   3536      break;
   3537    }
   3538    case RO_LHU: {
   3539      sreg_t addr = rs1() + imm12();
   3540      uint16_t val = ReadMem<uint16_t>(addr, instr_.instr());
   3541      set_rd(zext_xlen(val), false);
   3542      TraceMemRd(addr, val, getRegister(rd_reg()));
   3543      break;
   3544    }
   3545 #  ifdef JS_CODEGEN_RISCV64
   3546    case RO_LWU: {
   3547      int64_t addr = rs1() + imm12();
   3548      uint32_t val = ReadMem<uint32_t>(addr, instr_.instr());
   3549      set_rd(zext_xlen(val), false);
   3550      TraceMemRd(addr, val, getRegister(rd_reg()));
   3551      break;
   3552    }
   3553    case RO_LD: {
   3554      int64_t addr = rs1() + imm12();
   3555      int64_t val = ReadMem<int64_t>(addr, instr_.instr());
   3556      set_rd(sext_xlen(val), false);
   3557      TraceMemRd(addr, val, getRegister(rd_reg()));
   3558      break;
   3559    }
   3560 #  endif /*JS_CODEGEN_RISCV64*/
   3561    case RO_ADDI: {
   3562      set_rd(sext_xlen(rs1() + imm12()));
   3563      break;
   3564    }
   3565    case RO_SLTI: {
   3566      set_rd(sreg_t(rs1()) < sreg_t(imm12()));
   3567      break;
   3568    }
   3569    case RO_SLTIU: {
   3570      set_rd(reg_t(rs1()) < reg_t(imm12()));
   3571      break;
   3572    }
   3573    case RO_XORI: {
   3574      set_rd(imm12() ^ rs1());
   3575      break;
   3576    }
   3577    case RO_ORI: {
   3578      set_rd(imm12() | rs1());
   3579      break;
   3580    }
   3581    case RO_ANDI: {
   3582      set_rd(imm12() & rs1());
   3583      break;
   3584    }
   3585    case OP_SHL: {
   3586      switch (instr_.Funct6FieldRaw() | OP_SHL) {
   3587        case RO_SLLI:
   3588          require(shamt6() < xlen);
   3589          set_rd(sext_xlen(rs1() << shamt6()));
   3590          break;
   3591        case RO_BCLRI: {
   3592          require(shamt6() < xlen);
   3593          sreg_t index = shamt6() & (xlen - 1);
   3594          set_rd(rs1() & ~(1l << index));
   3595          break;
   3596        }
   3597        case RO_BINVI: {
   3598          require(shamt6() < xlen);
   3599          sreg_t index = shamt6() & (xlen - 1);
   3600          set_rd(rs1() ^ (1l << index));
   3601          break;
   3602        }
   3603        case RO_BSETI: {
   3604          require(shamt6() < xlen);
   3605          sreg_t index = shamt6() & (xlen - 1);
   3606          set_rd(rs1() | (1l << index));
   3607          break;
   3608        }
   3609        case OP_COUNT:
   3610          switch (instr_.Shamt()) {
   3611            case 0: {  // clz
   3612              sreg_t x = rs1();
   3613              int highest_setbit = -1;
   3614              for (auto i = xlen - 1; i >= 0; i--) {
   3615                if ((x & (1l << i))) {
   3616                  highest_setbit = i;
   3617                  break;
   3618                }
   3619              }
   3620              set_rd(xlen - 1 - highest_setbit);
   3621              break;
   3622            }
   3623            case 1: {  // ctz
   3624              sreg_t x = rs1();
   3625              int lowest_setbit = xlen;
   3626              for (auto i = 0; i < xlen; i++) {
   3627                if ((x & (1l << i))) {
   3628                  lowest_setbit = i;
   3629                  break;
   3630                }
   3631              }
   3632              set_rd(lowest_setbit);
   3633              break;
   3634            }
   3635            case 2: {  // cpop
   3636              int i = 0;
   3637              sreg_t n = rs1();
   3638              while (n) {
   3639                n &= (n - 1);
   3640                i++;
   3641              }
   3642              set_rd(i);
   3643              break;
   3644            }
   3645            case 4:
   3646              set_rd(static_cast<int8_t>(rs1()));
   3647              break;
   3648            case 5:
   3649              set_rd(static_cast<int16_t>(rs1()));
   3650              break;
   3651            default:
   3652              UNSUPPORTED();
   3653          }
   3654          break;
   3655        default:
   3656          UNSUPPORTED();
   3657      }
   3658      break;
   3659    }
   3660    case OP_SHR: {  //  RO_SRAI
   3661      switch (instr_.Funct6FieldRaw() | OP_SHR) {
   3662        case RO_SRLI:
   3663          require(shamt6() < xlen);
   3664          set_rd(sext_xlen(zext_xlen(rs1()) >> shamt6()));
   3665          break;
   3666        case RO_SRAI:
   3667          require(shamt6() < xlen);
   3668          set_rd(sext_xlen(sext_xlen(rs1()) >> shamt6()));
   3669          break;
   3670        case RO_BEXTI: {
   3671          require(shamt6() < xlen);
   3672          sreg_t index = shamt6() & (xlen - 1);
   3673          set_rd((rs1() >> index) & 1);
   3674          break;
   3675        }
   3676        case RO_ORCB&(kFunct6Mask | OP_SHR): {
   3677          reg_t rs1_val = rs1();
   3678          reg_t result = 0;
   3679          reg_t mask = 0xFF;
   3680          reg_t step = 8;
   3681          for (reg_t i = 0; i < xlen; i += step) {
   3682            if ((rs1_val & mask) != 0) {
   3683              result |= mask;
   3684            }
   3685            mask <<= step;
   3686          }
   3687          set_rd(result);
   3688          break;
   3689        }
   3690        case RO_RORI: {
   3691 #  ifdef JS_CODEGEN_RISCV64
   3692          int16_t shamt = shamt6();
   3693 #  else
   3694          int16_t shamt = shamt5();
   3695 #  endif
   3696          set_rd((static_cast<reg_t>(rs1()) >> shamt) |
   3697                 (static_cast<reg_t>(rs1()) << (xlen - shamt)));
   3698          break;
   3699        }
   3700        case RO_REV8: {
   3701          if (imm12() == RO_REV8_IMM12) {
   3702            reg_t input = rs1();
   3703            reg_t output = 0;
   3704            reg_t j = xlen - 1;
   3705            for (int i = 0; i < xlen; i += 8) {
   3706              output |= ((input >> (j - 7)) & 0xff) << i;
   3707              j -= 8;
   3708            }
   3709            set_rd(output);
   3710            break;
   3711          }
   3712          UNSUPPORTED();
   3713        }
   3714        default:
   3715          UNSUPPORTED();
   3716      }
   3717      break;
   3718    }
   3719 #  ifdef JS_CODEGEN_RISCV64
   3720    case RO_ADDIW: {
   3721      set_rd(sext32(rs1() + imm12()));
   3722      break;
   3723    }
   3724    case OP_SHLW:
   3725      switch (instr_.Funct7FieldRaw() | OP_SHLW) {
   3726        case RO_SLLIW:
   3727          set_rd(sext32(rs1() << shamt5()));
   3728          break;
   3729        case RO_SLLIUW:
   3730          set_rd(zext32(rs1()) << shamt6());
   3731          break;
   3732        case OP_COUNTW: {
   3733          switch (instr_.Shamt()) {
   3734            case 0: {  // clzw
   3735              sreg_t x = rs1();
   3736              int highest_setbit = -1;
   3737              for (auto i = 31; i >= 0; i--) {
   3738                if ((x & (1l << i))) {
   3739                  highest_setbit = i;
   3740                  break;
   3741                }
   3742              }
   3743              set_rd(31 - highest_setbit);
   3744              break;
   3745            }
   3746            case 1: {  // ctzw
   3747              sreg_t x = rs1();
   3748              int lowest_setbit = 32;
   3749              for (auto i = 0; i < 32; i++) {
   3750                if ((x & (1l << i))) {
   3751                  lowest_setbit = i;
   3752                  break;
   3753                }
   3754              }
   3755              set_rd(lowest_setbit);
   3756              break;
   3757            }
   3758            case 2: {  // cpopw
   3759              int i = 0;
   3760              int32_t n = static_cast<int32_t>(rs1());
   3761              while (n) {
   3762                n &= (n - 1);
   3763                i++;
   3764              }
   3765              set_rd(i);
   3766              break;
   3767            }
   3768            default:
   3769              UNSUPPORTED();
   3770          }
   3771          break;
   3772        }
   3773        default:
   3774          UNSUPPORTED();
   3775      }
   3776      break;
   3777    case OP_SHRW: {  //  RO_SRAI
   3778      switch (instr_.Funct7FieldRaw() | OP_SHRW) {
   3779        case RO_SRLIW:
   3780          set_rd(sext32(uint32_t(rs1()) >> shamt5()));
   3781          break;
   3782        case RO_SRAIW:
   3783          set_rd(sext32(int32_t(rs1()) >> shamt5()));
   3784          break;
   3785        case RO_RORIW: {
   3786          reg_t extz_rs1 = zext32(rs1());
   3787          int16_t shamt = shamt5();
   3788          set_rd(sext32((extz_rs1 >> shamt) | (extz_rs1 << (32 - shamt))));
   3789          break;
   3790        }
   3791        default:
   3792          UNSUPPORTED();
   3793      }
   3794      break;
   3795    }
   3796 #  endif /*JS_CODEGEN_RISCV64*/
   3797    case RO_FENCE: {
   3798      // DO nothing in sumulator
   3799      break;
   3800    }
   3801    case RO_ECALL: {                   // RO_EBREAK
   3802      if (instr_.Imm12Value() == 0) {  // ECALL
   3803        SoftwareInterrupt();
   3804      } else if (instr_.Imm12Value() == 1) {  // EBREAK
   3805        uint8_t code = get_ebreak_code(instr_.instr());
   3806        if (code == kWasmTrapCode) {
   3807          HandleWasmTrap();
   3808        }
   3809        SoftwareInterrupt();
   3810      } else {
   3811        UNSUPPORTED();
   3812      }
   3813      break;
   3814    }
   3815      // TODO(riscv): use Zifencei Standard Extension macro block
   3816    case RO_FENCE_I: {
   3817      // spike: flush icache.
   3818      break;
   3819    }
   3820      // TODO(riscv): use Zicsr Standard Extension macro block
   3821    case RO_CSRRW: {
   3822      if (rd_reg() != zero_reg) {
   3823        set_rd(zext_xlen(read_csr_value(csr_reg())));
   3824      }
   3825      write_csr_value(csr_reg(), rs1());
   3826      break;
   3827    }
   3828    case RO_CSRRS: {
   3829      set_rd(zext_xlen(read_csr_value(csr_reg())));
   3830      if (rs1_reg() != zero_reg) {
   3831        set_csr_bits(csr_reg(), rs1());
   3832      }
   3833      break;
   3834    }
   3835    case RO_CSRRC: {
   3836      set_rd(zext_xlen(read_csr_value(csr_reg())));
   3837      if (rs1_reg() != zero_reg) {
   3838        clear_csr_bits(csr_reg(), rs1());
   3839      }
   3840      break;
   3841    }
   3842    case RO_CSRRWI: {
   3843      if (rd_reg() != zero_reg) {
   3844        set_rd(zext_xlen(read_csr_value(csr_reg())));
   3845      }
   3846      if (csr_reg() == csr_cycle) {
   3847        if (imm5CSR() == kWasmTrapCode) {
   3848          HandleWasmTrap();
   3849          return;
   3850        }
   3851      }
   3852      write_csr_value(csr_reg(), imm5CSR());
   3853      break;
   3854    }
   3855    case RO_CSRRSI: {
   3856      set_rd(zext_xlen(read_csr_value(csr_reg())));
   3857      if (imm5CSR() != 0) {
   3858        set_csr_bits(csr_reg(), imm5CSR());
   3859      }
   3860      break;
   3861    }
   3862    case RO_CSRRCI: {
   3863      set_rd(zext_xlen(read_csr_value(csr_reg())));
   3864      if (imm5CSR() != 0) {
   3865        clear_csr_bits(csr_reg(), imm5CSR());
   3866      }
   3867      break;
   3868    }
   3869    // TODO(riscv): use F Extension macro block
   3870    case RO_FLW: {
   3871      sreg_t addr = rs1() + imm12();
   3872      uint32_t val = ReadMem<uint32_t>(addr, instr_.instr());
   3873      set_frd(Float32::FromBits(val), false);
   3874      TraceMemRdFloat(addr, Float32::FromBits(val), getFpuRegister(frd_reg()));
   3875      break;
   3876    }
   3877    // TODO(riscv): use D Extension macro block
   3878    case RO_FLD: {
   3879      sreg_t addr = rs1() + imm12();
   3880      uint64_t val = ReadMem<uint64_t>(addr, instr_.instr());
   3881      set_drd(Float64::FromBits(val), false);
   3882      TraceMemRdDouble(addr, Float64::FromBits(val), getFpuRegister(frd_reg()));
   3883      break;
   3884    }
   3885    default: {
   3886 #  ifdef CAN_USE_RVV_INSTRUCTIONS
   3887      if (!DecodeRvvVL()) {
   3888        UNSUPPORTED();
   3889      }
   3890      break;
   3891 #  else
   3892      UNSUPPORTED();
   3893 #  endif
   3894    }
   3895  }
   3896 }
   3897 
   3898 void Simulator::DecodeRVSType() {
   3899  switch (instr_.InstructionBits() & kSTypeMask) {
   3900    case RO_SB:
   3901      WriteMem<uint8_t>(rs1() + s_imm12(), (uint8_t)rs2(), instr_.instr());
   3902      break;
   3903    case RO_SH:
   3904      WriteMem<uint16_t>(rs1() + s_imm12(), (uint16_t)rs2(), instr_.instr());
   3905      break;
   3906    case RO_SW:
   3907      WriteMem<uint32_t>(rs1() + s_imm12(), (uint32_t)rs2(), instr_.instr());
   3908      break;
   3909 #  ifdef JS_CODEGEN_RISCV64
   3910    case RO_SD:
   3911      WriteMem<uint64_t>(rs1() + s_imm12(), (uint64_t)rs2(), instr_.instr());
   3912      break;
   3913 #  endif /*JS_CODEGEN_RISCV64*/
   3914    // TODO(riscv): use F Extension macro block
   3915    case RO_FSW: {
   3916      WriteMem<Float32>(rs1() + s_imm12(), getFpuRegisterFloat32(rs2_reg()),
   3917                        instr_.instr());
   3918      break;
   3919    }
   3920    // TODO(riscv): use D Extension macro block
   3921    case RO_FSD: {
   3922      WriteMem<Float64>(rs1() + s_imm12(), getFpuRegisterFloat64(rs2_reg()),
   3923                        instr_.instr());
   3924      break;
   3925    }
   3926    default:
   3927 #  ifdef CAN_USE_RVV_INSTRUCTIONS
   3928      if (!DecodeRvvVS()) {
   3929        UNSUPPORTED();
   3930      }
   3931      break;
   3932 #  else
   3933      UNSUPPORTED();
   3934 #  endif
   3935  }
   3936 }
   3937 
   3938 void Simulator::DecodeRVBType() {
   3939  switch (instr_.InstructionBits() & kBTypeMask) {
   3940    case RO_BEQ:
   3941      if (rs1() == rs2()) {
   3942        int64_t next_pc = get_pc() + boffset();
   3943        set_pc(next_pc);
   3944      }
   3945      break;
   3946    case RO_BNE:
   3947      if (rs1() != rs2()) {
   3948        int64_t next_pc = get_pc() + boffset();
   3949        set_pc(next_pc);
   3950      }
   3951      break;
   3952    case RO_BLT:
   3953      if (rs1() < rs2()) {
   3954        int64_t next_pc = get_pc() + boffset();
   3955        set_pc(next_pc);
   3956      }
   3957      break;
   3958    case RO_BGE:
   3959      if (rs1() >= rs2()) {
   3960        int64_t next_pc = get_pc() + boffset();
   3961        set_pc(next_pc);
   3962      }
   3963      break;
   3964    case RO_BLTU:
   3965      if ((reg_t)rs1() < (reg_t)rs2()) {
   3966        int64_t next_pc = get_pc() + boffset();
   3967        set_pc(next_pc);
   3968      }
   3969      break;
   3970    case RO_BGEU:
   3971      if ((reg_t)rs1() >= (reg_t)rs2()) {
   3972        int64_t next_pc = get_pc() + boffset();
   3973        set_pc(next_pc);
   3974      }
   3975      break;
   3976    default:
   3977      UNSUPPORTED();
   3978  }
   3979 }
   3980 void Simulator::DecodeRVUType() {
   3981  // U Type doesn't have additoinal mask
   3982  switch (instr_.BaseOpcodeFieldRaw()) {
   3983    case LUI:
   3984      set_rd(u_imm20());
   3985      break;
   3986    case AUIPC:
   3987      set_rd(sext_xlen(u_imm20() + get_pc()));
   3988      break;
   3989    default:
   3990      UNSUPPORTED();
   3991  }
   3992 }
   3993 void Simulator::DecodeRVJType() {
   3994  // J Type doesn't have additional mask
   3995  switch (instr_.BaseOpcodeValue()) {
   3996    case JAL: {
   3997      set_rd(get_pc() + kInstrSize);
   3998      int64_t next_pc = get_pc() + imm20J();
   3999      set_pc(next_pc);
   4000      break;
   4001    }
   4002    default:
   4003      UNSUPPORTED();
   4004  }
   4005 }
   4006 void Simulator::DecodeCRType() {
   4007  switch (instr_.RvcFunct4Value()) {
   4008    case 0b1000:
   4009      if (instr_.RvcRs1Value() != 0 && instr_.RvcRs2Value() == 0) {  // c.jr
   4010        set_pc(rvc_rs1());
   4011      } else if (instr_.RvcRdValue() != 0 &&
   4012                 instr_.RvcRs2Value() != 0) {  // c.mv
   4013        set_rvc_rd(sext_xlen(rvc_rs2()));
   4014      } else {
   4015        UNSUPPORTED();
   4016      }
   4017      break;
   4018    case 0b1001:
   4019      if (instr_.RvcRs1Value() == 0 && instr_.RvcRs2Value() == 0) {  // c.ebreak
   4020        DieOrDebug();
   4021      } else if (instr_.RvcRdValue() != 0 &&
   4022                 instr_.RvcRs2Value() == 0) {  // c.jalr
   4023        setRegister(ra, get_pc() + kShortInstrSize);
   4024        set_pc(rvc_rs1());
   4025      } else if (instr_.RvcRdValue() != 0 &&
   4026                 instr_.RvcRs2Value() != 0) {  // c.add
   4027        set_rvc_rd(sext_xlen(rvc_rs1() + rvc_rs2()));
   4028      } else {
   4029        UNSUPPORTED();
   4030      }
   4031      break;
   4032    default:
   4033      UNSUPPORTED();
   4034  }
   4035 }
   4036 
   4037 void Simulator::DecodeCAType() {
   4038  switch (instr_.InstructionBits() & kCATypeMask) {
   4039    case RO_C_SUB:
   4040      set_rvc_rs1s(sext_xlen(rvc_rs1s() - rvc_rs2s()));
   4041      break;
   4042    case RO_C_XOR:
   4043      set_rvc_rs1s(rvc_rs1s() ^ rvc_rs2s());
   4044      break;
   4045    case RO_C_OR:
   4046      set_rvc_rs1s(rvc_rs1s() | rvc_rs2s());
   4047      break;
   4048    case RO_C_AND:
   4049      set_rvc_rs1s(rvc_rs1s() & rvc_rs2s());
   4050      break;
   4051 #  if JS_CODEGEN_RISCV64
   4052    case RO_C_SUBW:
   4053      set_rvc_rs1s(sext32(rvc_rs1s() - rvc_rs2s()));
   4054      break;
   4055    case RO_C_ADDW:
   4056      set_rvc_rs1s(sext32(rvc_rs1s() + rvc_rs2s()));
   4057      break;
   4058 #  endif
   4059    default:
   4060      UNSUPPORTED();
   4061  }
   4062 }
   4063 
   4064 void Simulator::DecodeCIType() {
   4065  switch (instr_.RvcOpcode()) {
   4066    case RO_C_NOP_ADDI:
   4067      if (instr_.RvcRdValue() == 0)  // c.nop
   4068        break;
   4069      else  // c.addi
   4070        set_rvc_rd(sext_xlen(rvc_rs1() + rvc_imm6()));
   4071      break;
   4072 #  if JS_CODEGEN_RISCV64
   4073    case RO_C_ADDIW:
   4074      set_rvc_rd(sext32(rvc_rs1() + rvc_imm6()));
   4075      break;
   4076 #  endif
   4077    case RO_C_LI:
   4078      set_rvc_rd(sext_xlen(rvc_imm6()));
   4079      break;
   4080    case RO_C_LUI_ADD:
   4081      if (instr_.RvcRdValue() == 2) {
   4082        // c.addi16sp
   4083        int64_t value = getRegister(sp) + rvc_imm6_addi16sp();
   4084        setRegister(sp, value);
   4085      } else if (instr_.RvcRdValue() != 0 && instr_.RvcRdValue() != 2) {
   4086        // c.lui
   4087        set_rvc_rd(rvc_u_imm6());
   4088      } else {
   4089        UNSUPPORTED();
   4090      }
   4091      break;
   4092    case RO_C_SLLI:
   4093      set_rvc_rd(sext_xlen(rvc_rs1() << rvc_shamt6()));
   4094      break;
   4095    case RO_C_FLDSP: {
   4096      sreg_t addr = getRegister(sp) + rvc_imm6_ldsp();
   4097      uint64_t val = ReadMem<uint64_t>(addr, instr_.instr());
   4098      set_rvc_drd(Float64::FromBits(val), false);
   4099      TraceMemRdDouble(addr, Float64::FromBits(val),
   4100                       getFpuRegister(rvc_frd_reg()));
   4101      break;
   4102    }
   4103 #  if JS_CODEGEN_RISCV64
   4104    case RO_C_LWSP: {
   4105      sreg_t addr = getRegister(sp) + rvc_imm6_lwsp();
   4106      int64_t val = ReadMem<int32_t>(addr, instr_.instr());
   4107      set_rvc_rd(sext_xlen(val), false);
   4108      TraceMemRd(addr, val, getRegister(rvc_rd_reg()));
   4109      break;
   4110    }
   4111    case RO_C_LDSP: {
   4112      sreg_t addr = getRegister(sp) + rvc_imm6_ldsp();
   4113      int64_t val = ReadMem<int64_t>(addr, instr_.instr());
   4114      set_rvc_rd(sext_xlen(val), false);
   4115      TraceMemRd(addr, val, getRegister(rvc_rd_reg()));
   4116      break;
   4117    }
   4118 #  elif JS_CODEGEN_RISCV32
   4119    case RO_C_FLWSP: {
   4120      sreg_t addr = getRegister(sp) + rvc_imm6_ldsp();
   4121      uint32_t val = ReadMem<uint32_t>(addr, instr_.instr());
   4122      set_rvc_frd(Float32::FromBits(val), false);
   4123      TraceMemRdFloat(addr, Float32::FromBits(val),
   4124                      getFpuRegister(rvc_frd_reg()));
   4125      break;
   4126    }
   4127    case RO_C_LWSP: {
   4128      sreg_t addr = getRegister(sp) + rvc_imm6_lwsp();
   4129      int32_t val = ReadMem<int32_t>(addr, instr_.instr());
   4130      set_rvc_rd(sext_xlen(val), false);
   4131      TraceMemRd(addr, val, getRegister(rvc_rd_reg()));
   4132      break;
   4133    }
   4134 #  endif
   4135    default:
   4136      UNSUPPORTED();
   4137  }
   4138 }
   4139 
   4140 void Simulator::DecodeCIWType() {
   4141  switch (instr_.RvcOpcode()) {
   4142    case RO_C_ADDI4SPN: {
   4143      set_rvc_rs2s(getRegister(sp) + rvc_imm8_addi4spn());
   4144      break;
   4145      default:
   4146        UNSUPPORTED();
   4147    }
   4148  }
   4149 }
   4150 
   4151 void Simulator::DecodeCSSType() {
   4152  switch (instr_.RvcOpcode()) {
   4153    case RO_C_FSDSP: {
   4154      sreg_t addr = getRegister(sp) + rvc_imm6_sdsp();
   4155      WriteMem<Float64>(addr, getFpuRegisterFloat64(rvc_rs2_reg()),
   4156                        instr_.instr());
   4157      break;
   4158    }
   4159 #  if JS_CODEGEN_RISCV32
   4160    case RO_C_FSWSP: {
   4161      sreg_t addr = getRegister(sp) + rvc_imm6_sdsp();
   4162      WriteMem<Float32>(addr, getFpuRegisterFloat32(rvc_rs2_reg()),
   4163                        instr_.instr());
   4164      break;
   4165    }
   4166 #  endif
   4167    case RO_C_SWSP: {
   4168      sreg_t addr = getRegister(sp) + rvc_imm6_swsp();
   4169      WriteMem<int32_t>(addr, (int32_t)rvc_rs2(), instr_.instr());
   4170      break;
   4171    }
   4172 #  if JS_CODEGEN_RISCV64
   4173    case RO_C_SDSP: {
   4174      sreg_t addr = getRegister(sp) + rvc_imm6_sdsp();
   4175      WriteMem<int64_t>(addr, (int64_t)rvc_rs2(), instr_.instr());
   4176      break;
   4177    }
   4178 #  endif
   4179    default:
   4180      UNSUPPORTED();
   4181  }
   4182 }
   4183 
   4184 void Simulator::DecodeCLType() {
   4185  switch (instr_.RvcOpcode()) {
   4186    case RO_C_LW: {
   4187      sreg_t addr = rvc_rs1s() + rvc_imm5_w();
   4188      int64_t val = ReadMem<int32_t>(addr, instr_.instr());
   4189      set_rvc_rs2s(sext_xlen(val), false);
   4190      TraceMemRd(addr, val, getRegister(rvc_rs2s_reg()));
   4191      break;
   4192    }
   4193    case RO_C_FLD: {
   4194      sreg_t addr = rvc_rs1s() + rvc_imm5_d();
   4195      uint64_t val = ReadMem<uint64_t>(addr, instr_.instr());
   4196      set_rvc_drs2s(Float64::FromBits(val), false);
   4197      break;
   4198    }
   4199 #  if JS_CODEGEN_RISCV64
   4200    case RO_C_LD: {
   4201      sreg_t addr = rvc_rs1s() + rvc_imm5_d();
   4202      int64_t val = ReadMem<int64_t>(addr, instr_.instr());
   4203      set_rvc_rs2s(sext_xlen(val), false);
   4204      TraceMemRd(addr, val, getRegister(rvc_rs2s_reg()));
   4205      break;
   4206    }
   4207 #  elif JS_CODEGEN_RISCV32
   4208    case RO_C_FLW: {
   4209      sreg_t addr = rvc_rs1s() + rvc_imm5_d();
   4210      uint32_t val = ReadMem<uint32_t>(addr, instr_.instr());
   4211      set_rvc_frs2s(Float32::FromBits(val), false);
   4212      break;
   4213    }
   4214 #  endif
   4215    default:
   4216      UNSUPPORTED();
   4217  }
   4218 }
   4219 
   4220 void Simulator::DecodeCSType() {
   4221  switch (instr_.RvcOpcode()) {
   4222    case RO_C_SW: {
   4223      sreg_t addr = rvc_rs1s() + rvc_imm5_w();
   4224      WriteMem<int32_t>(addr, (int32_t)rvc_rs2s(), instr_.instr());
   4225      break;
   4226    }
   4227 #  if JS_CODEGEN_RISCV64
   4228    case RO_C_SD: {
   4229      sreg_t addr = rvc_rs1s() + rvc_imm5_d();
   4230      WriteMem<int64_t>(addr, (int64_t)rvc_rs2s(), instr_.instr());
   4231      break;
   4232    }
   4233 #  endif
   4234    case RO_C_FSD: {
   4235      sreg_t addr = rvc_rs1s() + rvc_imm5_d();
   4236      WriteMem<double>(addr, static_cast<double>(rvc_drs2s()), instr_.instr());
   4237      break;
   4238    }
   4239    default:
   4240      UNSUPPORTED();
   4241  }
   4242 }
   4243 
   4244 void Simulator::DecodeCJType() {
   4245  switch (instr_.RvcOpcode()) {
   4246    case RO_C_J: {
   4247      set_pc(get_pc() + instr_.RvcImm11CJValue());
   4248      break;
   4249    }
   4250    default:
   4251      UNSUPPORTED();
   4252  }
   4253 }
   4254 
   4255 void Simulator::DecodeCBType() {
   4256  switch (instr_.RvcOpcode()) {
   4257    case RO_C_BNEZ:
   4258      if (rvc_rs1() != 0) {
   4259        sreg_t next_pc = get_pc() + rvc_imm8_b();
   4260        set_pc(next_pc);
   4261      }
   4262      break;
   4263    case RO_C_BEQZ:
   4264      if (rvc_rs1() == 0) {
   4265        sreg_t next_pc = get_pc() + rvc_imm8_b();
   4266        set_pc(next_pc);
   4267      }
   4268      break;
   4269    case RO_C_MISC_ALU:
   4270      if (instr_.RvcFunct2BValue() == 0b00) {  // c.srli
   4271        set_rvc_rs1s(sext_xlen(sext_xlen(rvc_rs1s()) >> rvc_shamt6()));
   4272      } else if (instr_.RvcFunct2BValue() == 0b01) {  // c.srai
   4273        require(rvc_shamt6() < xlen);
   4274        set_rvc_rs1s(sext_xlen(sext_xlen(rvc_rs1s()) >> rvc_shamt6()));
   4275      } else if (instr_.RvcFunct2BValue() == 0b10) {  // c.andi
   4276        set_rvc_rs1s(rvc_imm6() & rvc_rs1s());
   4277      } else {
   4278        UNSUPPORTED();
   4279      }
   4280      break;
   4281    default:
   4282      UNSUPPORTED();
   4283  }
   4284 }
   4285 
   4286 void Simulator::callInternal(uint8_t* entry) {
   4287  // Prepare to execute the code at entry.
   4288  setRegister(pc, reinterpret_cast<int64_t>(entry));
   4289  // Put down marker for end of simulation. The simulator will stop simulation
   4290  // when the PC reaches this value. By saving the "end simulation" value into
   4291  // the LR the simulation stops when returning to this call point.
   4292  setRegister(ra, end_sim_pc);
   4293  // Remember the values of callee-saved registers.
   4294  intptr_t s0_val = getRegister(Simulator::Register::fp);
   4295  intptr_t s1_val = getRegister(Simulator::Register::s1);
   4296  intptr_t s2_val = getRegister(Simulator::Register::s2);
   4297  intptr_t s3_val = getRegister(Simulator::Register::s3);
   4298  intptr_t s4_val = getRegister(Simulator::Register::s4);
   4299  intptr_t s5_val = getRegister(Simulator::Register::s5);
   4300  intptr_t s6_val = getRegister(Simulator::Register::s6);
   4301  intptr_t s7_val = getRegister(Simulator::Register::s7);
   4302  intptr_t s8_val = getRegister(Simulator::Register::s8);
   4303  intptr_t s9_val = getRegister(Simulator::Register::s9);
   4304  intptr_t s10_val = getRegister(Simulator::Register::s10);
   4305  intptr_t s11_val = getRegister(Simulator::Register::s11);
   4306  intptr_t gp_val = getRegister(Simulator::Register::gp);
   4307  intptr_t sp_val = getRegister(Simulator::Register::sp);
   4308 
   4309  // Set up the callee-saved registers with a known value. To be able to check
   4310  // that they are preserved properly across JS execution. If this value is
   4311  // small int, it should be SMI.
   4312  intptr_t callee_saved_value = icount_;
   4313  setRegister(Simulator::Register::fp, callee_saved_value);
   4314  setRegister(Simulator::Register::s1, callee_saved_value);
   4315  setRegister(Simulator::Register::s2, callee_saved_value);
   4316  setRegister(Simulator::Register::s3, callee_saved_value);
   4317  setRegister(Simulator::Register::s4, callee_saved_value);
   4318  setRegister(Simulator::Register::s5, callee_saved_value);
   4319  setRegister(Simulator::Register::s6, callee_saved_value);
   4320  setRegister(Simulator::Register::s7, callee_saved_value);
   4321  setRegister(Simulator::Register::s8, callee_saved_value);
   4322  setRegister(Simulator::Register::s9, callee_saved_value);
   4323  setRegister(Simulator::Register::s10, callee_saved_value);
   4324  setRegister(Simulator::Register::s11, callee_saved_value);
   4325  setRegister(Simulator::Register::gp, callee_saved_value);
   4326 
   4327  // Start the simulation.
   4328  if (Simulator::StopSimAt != -1) {
   4329    execute<true>();
   4330  } else {
   4331    execute<false>();
   4332  }
   4333 
   4334  // Check that the callee-saved registers have been preserved.
   4335  MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::fp));
   4336  MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s1));
   4337  MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s2));
   4338  MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s3));
   4339  MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s4));
   4340  MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s5));
   4341  MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s6));
   4342  MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s7));
   4343  MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s8));
   4344  MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s9));
   4345  MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s10));
   4346  MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::s11));
   4347  MOZ_ASSERT(callee_saved_value == getRegister(Simulator::Register::gp));
   4348 
   4349  // Restore callee-saved registers with the original value.
   4350  setRegister(Simulator::Register::fp, s0_val);
   4351  setRegister(Simulator::Register::s1, s1_val);
   4352  setRegister(Simulator::Register::s2, s2_val);
   4353  setRegister(Simulator::Register::s3, s3_val);
   4354  setRegister(Simulator::Register::s4, s4_val);
   4355  setRegister(Simulator::Register::s5, s5_val);
   4356  setRegister(Simulator::Register::s6, s6_val);
   4357  setRegister(Simulator::Register::s7, s7_val);
   4358  setRegister(Simulator::Register::s8, s8_val);
   4359  setRegister(Simulator::Register::s9, s9_val);
   4360  setRegister(Simulator::Register::s10, s10_val);
   4361  setRegister(Simulator::Register::s11, s11_val);
   4362  setRegister(Simulator::Register::gp, gp_val);
   4363  setRegister(Simulator::Register::sp, sp_val);
   4364 }
   4365 
   4366 int64_t Simulator::call(uint8_t* entry, int argument_count, ...) {
   4367  va_list parameters;
   4368  va_start(parameters, argument_count);
   4369 
   4370  int64_t original_stack = getRegister(sp);
   4371  // Compute position of stack on entry to generated code.
   4372  int64_t entry_stack = original_stack;
   4373  if (argument_count > kCArgSlotCount) {
   4374    entry_stack = entry_stack - argument_count * sizeof(int64_t);
   4375  } else {
   4376    entry_stack = entry_stack - kCArgsSlotsSize;
   4377  }
   4378 
   4379  entry_stack &= ~U64(ABIStackAlignment - 1);
   4380 
   4381  intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
   4382 
   4383  // Setup the arguments.
   4384  for (int i = 0; i < argument_count; i++) {
   4385    js::jit::Register argReg;
   4386    if (GetIntArgReg(i, &argReg)) {
   4387      setRegister(argReg.code(), va_arg(parameters, int64_t));
   4388    } else {
   4389      stack_argument[i] = va_arg(parameters, int64_t);
   4390    }
   4391  }
   4392 
   4393  va_end(parameters);
   4394  setRegister(sp, entry_stack);
   4395 
   4396  callInternal(entry);
   4397 
   4398  // Pop stack passed arguments.
   4399  MOZ_ASSERT(entry_stack == getRegister(sp));
   4400  setRegister(sp, original_stack);
   4401 
   4402  int64_t result = getRegister(a0);
   4403  return result;
   4404 }
   4405 
   4406 uintptr_t Simulator::pushAddress(uintptr_t address) {
   4407  int new_sp = getRegister(sp) - sizeof(uintptr_t);
   4408  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
   4409  *stack_slot = address;
   4410  setRegister(sp, new_sp);
   4411  return new_sp;
   4412 }
   4413 
   4414 uintptr_t Simulator::popAddress() {
   4415  int current_sp = getRegister(sp);
   4416  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
   4417  uintptr_t address = *stack_slot;
   4418  setRegister(sp, current_sp + sizeof(uintptr_t));
   4419  return address;
   4420 }
   4421 
   4422 }  // namespace jit
   4423 }  // namespace js
   4424 
   4425 js::jit::Simulator* JSContext::simulator() const { return simulator_; }
   4426 
   4427 #endif  // JS_SIMULATOR_RISCV64