tor-browser

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

Simulator-riscv64.h (42258B)


      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 
     30 #ifndef jit_riscv64_Simulator_riscv64_h
     31 #define jit_riscv64_Simulator_riscv64_h
     32 
     33 #ifdef JS_SIMULATOR_RISCV64
     34 #  include "mozilla/Atomics.h"
     35 
     36 #  include <vector>
     37 
     38 #  include "jit/IonTypes.h"
     39 #  include "jit/riscv64/constant/Constant-riscv64.h"
     40 #  include "jit/riscv64/constant/util-riscv64.h"
     41 #  include "jit/riscv64/disasm/Disasm-riscv64.h"
     42 #  include "js/ProfilingFrameIterator.h"
     43 #  include "js/Utility.h"
     44 #  include "js/Vector.h"
     45 #  include "threading/Thread.h"
     46 #  include "vm/MutexIDs.h"
     47 #  include "wasm/WasmSignalHandlers.h"
     48 
     49 namespace js {
     50 
     51 namespace jit {
     52 
     53 template <class Dest, class Source>
     54 inline Dest bit_cast(const Source& source) {
     55  static_assert(sizeof(Dest) == sizeof(Source),
     56                "bit_cast requires source and destination to be the same size");
     57  static_assert(std::is_trivially_copyable<Dest>::value,
     58                "bit_cast requires the destination type to be copyable");
     59  static_assert(std::is_trivially_copyable<Source>::value,
     60                "bit_cast requires the source type to be copyable");
     61 
     62  Dest dest;
     63  memcpy(&dest, &source, sizeof(dest));
     64  return dest;
     65 }
     66 
     67 #  define ASSERT_TRIVIALLY_COPYABLE(T)                  \
     68    static_assert(std::is_trivially_copyable<T>::value, \
     69                  #T " should be trivially copyable")
     70 #  define ASSERT_NOT_TRIVIALLY_COPYABLE(T)               \
     71    static_assert(!std::is_trivially_copyable<T>::value, \
     72                  #T " should not be trivially copyable")
     73 
     74 constexpr uint32_t kHoleNanUpper32 = 0xFFF7FFFF;
     75 constexpr uint32_t kHoleNanLower32 = 0xFFF7FFFF;
     76 
     77 constexpr uint64_t kHoleNanInt64 =
     78    (static_cast<uint64_t>(kHoleNanUpper32) << 32) | kHoleNanLower32;
     79 // Safety wrapper for a 32-bit floating-point value to make sure we don't lose
     80 // the exact bit pattern during deoptimization when passing this value.
     81 class Float32 {
     82 public:
     83  Float32() = default;
     84 
     85  // This constructor does not guarantee that bit pattern of the input value
     86  // is preserved if the input is a NaN.
     87  explicit Float32(float value) : bit_pattern_(bit_cast<uint32_t>(value)) {
     88    // Check that the provided value is not a NaN, because the bit pattern of a
     89    // NaN may be changed by a bit_cast, e.g. for signalling NaNs on
     90    // ia32.
     91    MOZ_ASSERT(!std::isnan(value));
     92  }
     93 
     94  uint32_t get_bits() const { return bit_pattern_; }
     95 
     96  float get_scalar() const { return bit_cast<float>(bit_pattern_); }
     97 
     98  bool is_nan() const {
     99    // Even though {get_scalar()} might flip the quiet NaN bit, it's ok here,
    100    // because this does not change the is_nan property.
    101    return std::isnan(get_scalar());
    102  }
    103 
    104  // Return a pointer to the field storing the bit pattern. Used in code
    105  // generation tests to store generated values there directly.
    106  uint32_t* get_bits_address() { return &bit_pattern_; }
    107 
    108  static constexpr Float32 FromBits(uint32_t bits) { return Float32(bits); }
    109 
    110 private:
    111  uint32_t bit_pattern_ = 0;
    112 
    113  explicit constexpr Float32(uint32_t bit_pattern)
    114      : bit_pattern_(bit_pattern) {}
    115 };
    116 
    117 ASSERT_TRIVIALLY_COPYABLE(Float32);
    118 
    119 // Safety wrapper for a 64-bit floating-point value to make sure we don't lose
    120 // the exact bit pattern during deoptimization when passing this value.
    121 // TODO(ahaas): Unify this class with Double in double.h
    122 class Float64 {
    123 public:
    124  Float64() = default;
    125 
    126  // This constructor does not guarantee that bit pattern of the input value
    127  // is preserved if the input is a NaN.
    128  explicit Float64(double value) : bit_pattern_(bit_cast<uint64_t>(value)) {
    129    // Check that the provided value is not a NaN, because the bit pattern of a
    130    // NaN may be changed by a bit_cast, e.g. for signalling NaNs on
    131    // ia32.
    132    MOZ_ASSERT(!std::isnan(value));
    133  }
    134 
    135  uint64_t get_bits() const { return bit_pattern_; }
    136  double get_scalar() const { return bit_cast<double>(bit_pattern_); }
    137  bool is_hole_nan() const { return bit_pattern_ == kHoleNanInt64; }
    138  bool is_nan() const {
    139    // Even though {get_scalar()} might flip the quiet NaN bit, it's ok here,
    140    // because this does not change the is_nan property.
    141    return std::isnan(get_scalar());
    142  }
    143 
    144  // Return a pointer to the field storing the bit pattern. Used in code
    145  // generation tests to store generated values there directly.
    146  uint64_t* get_bits_address() { return &bit_pattern_; }
    147 
    148  static constexpr Float64 FromBits(uint64_t bits) { return Float64(bits); }
    149 
    150 private:
    151  uint64_t bit_pattern_ = 0;
    152 
    153  explicit constexpr Float64(uint64_t bit_pattern)
    154      : bit_pattern_(bit_pattern) {}
    155 };
    156 
    157 ASSERT_TRIVIALLY_COPYABLE(Float64);
    158 
    159 class JitActivation;
    160 
    161 class Simulator;
    162 class Redirection;
    163 class CachePage;
    164 class AutoLockSimulator;
    165 
    166 // When the SingleStepCallback is called, the simulator is about to execute
    167 // sim->get_pc() and the current machine state represents the completed
    168 // execution of the previous pc.
    169 typedef void (*SingleStepCallback)(void* arg, Simulator* sim, void* pc);
    170 
    171 const intptr_t kPointerAlignment = 8;
    172 const intptr_t kPointerAlignmentMask = kPointerAlignment - 1;
    173 
    174 const intptr_t kDoubleAlignment = 8;
    175 const intptr_t kDoubleAlignmentMask = kDoubleAlignment - 1;
    176 
    177 // Number of general purpose registers.
    178 const int kNumRegisters = 32;
    179 
    180 // In the simulator, the PC register is simulated as the 34th register.
    181 const int kPCRegister = 32;
    182 
    183 // Number coprocessor registers.
    184 const int kNumFPURegisters = 32;
    185 
    186 // FPU (coprocessor 1) control registers. Currently only FCSR is implemented.
    187 const int kFCSRRegister = 31;
    188 const int kInvalidFPUControlRegister = -1;
    189 const uint32_t kFPUInvalidResult = static_cast<uint32_t>(1 << 31) - 1;
    190 const uint64_t kFPUInvalidResult64 = static_cast<uint64_t>(1ULL << 63) - 1;
    191 
    192 // FCSR constants.
    193 const uint32_t kFCSRInexactFlagBit = 2;
    194 const uint32_t kFCSRUnderflowFlagBit = 3;
    195 const uint32_t kFCSROverflowFlagBit = 4;
    196 const uint32_t kFCSRDivideByZeroFlagBit = 5;
    197 const uint32_t kFCSRInvalidOpFlagBit = 6;
    198 
    199 const uint32_t kFCSRInexactCauseBit = 12;
    200 const uint32_t kFCSRUnderflowCauseBit = 13;
    201 const uint32_t kFCSROverflowCauseBit = 14;
    202 const uint32_t kFCSRDivideByZeroCauseBit = 15;
    203 const uint32_t kFCSRInvalidOpCauseBit = 16;
    204 
    205 const uint32_t kFCSRInexactFlagMask = 1 << kFCSRInexactFlagBit;
    206 const uint32_t kFCSRUnderflowFlagMask = 1 << kFCSRUnderflowFlagBit;
    207 const uint32_t kFCSROverflowFlagMask = 1 << kFCSROverflowFlagBit;
    208 const uint32_t kFCSRDivideByZeroFlagMask = 1 << kFCSRDivideByZeroFlagBit;
    209 const uint32_t kFCSRInvalidOpFlagMask = 1 << kFCSRInvalidOpFlagBit;
    210 
    211 const uint32_t kFCSRFlagMask =
    212    kFCSRInexactFlagMask | kFCSRUnderflowFlagMask | kFCSROverflowFlagMask |
    213    kFCSRDivideByZeroFlagMask | kFCSRInvalidOpFlagMask;
    214 
    215 const uint32_t kFCSRExceptionFlagMask = kFCSRFlagMask ^ kFCSRInexactFlagMask;
    216 
    217 // -----------------------------------------------------------------------------
    218 // Utility types and functions for RISCV
    219 #  ifdef JS_CODEGEN_RISCV32
    220 using sreg_t = int32_t;
    221 using reg_t = uint32_t;
    222 using freg_t = uint64_t;
    223 using sfreg_t = int64_t;
    224 #  elif JS_CODEGEN_RISCV64
    225 using sreg_t = int64_t;
    226 using reg_t = uint64_t;
    227 using freg_t = uint64_t;
    228 using sfreg_t = int64_t;
    229 #  else
    230 #    error "Cannot detect Riscv's bitwidth"
    231 #  endif
    232 
    233 #  define sext32(x) ((sreg_t)(int32_t)(x))
    234 #  define zext32(x) ((reg_t)(uint32_t)(x))
    235 
    236 #  ifdef JS_CODEGEN_RISCV64
    237 #    define sext_xlen(x) (((sreg_t)(x) << (64 - xlen)) >> (64 - xlen))
    238 #    define zext_xlen(x) (((reg_t)(x) << (64 - xlen)) >> (64 - xlen))
    239 #  elif JS_CODEGEN_RISCV32
    240 #    define sext_xlen(x) (((sreg_t)(x) << (32 - xlen)) >> (32 - xlen))
    241 #    define zext_xlen(x) (((reg_t)(x) << (32 - xlen)) >> (32 - xlen))
    242 #  endif
    243 
    244 #  define BIT(n) (0x1LL << n)
    245 #  define QUIET_BIT_S(nan) (bit_cast<int32_t>(nan) & BIT(22))
    246 #  define QUIET_BIT_D(nan) (bit_cast<int64_t>(nan) & BIT(51))
    247 static inline bool isSnan(float fp) { return !QUIET_BIT_S(fp); }
    248 static inline bool isSnan(double fp) { return !QUIET_BIT_D(fp); }
    249 #  undef QUIET_BIT_S
    250 #  undef QUIET_BIT_D
    251 
    252 #  ifdef JS_CODEGEN_RISCV64
    253 inline uint64_t mulhu(uint64_t a, uint64_t b) {
    254  __uint128_t full_result = ((__uint128_t)a) * ((__uint128_t)b);
    255  return full_result >> 64;
    256 }
    257 
    258 inline int64_t mulh(int64_t a, int64_t b) {
    259  __int128_t full_result = ((__int128_t)a) * ((__int128_t)b);
    260  return full_result >> 64;
    261 }
    262 
    263 inline int64_t mulhsu(int64_t a, uint64_t b) {
    264  __int128_t full_result = ((__int128_t)a) * ((__uint128_t)b);
    265  return full_result >> 64;
    266 }
    267 #  elif JS_CODEGEN_RISCV32
    268 inline uint32_t mulhu(uint32_t a, uint32_t b) {
    269  uint64_t full_result = ((uint64_t)a) * ((uint64_t)b);
    270  uint64_t upper_part = full_result >> 32;
    271  return (uint32_t)upper_part;
    272 }
    273 
    274 inline int32_t mulh(int32_t a, int32_t b) {
    275  int64_t full_result = ((int64_t)a) * ((int64_t)b);
    276  int64_t upper_part = full_result >> 32;
    277  return (int32_t)upper_part;
    278 }
    279 
    280 inline int32_t mulhsu(int32_t a, uint32_t b) {
    281  int64_t full_result = ((int64_t)a) * ((uint64_t)b);
    282  int64_t upper_part = full_result >> 32;
    283  return (int32_t)upper_part;
    284 }
    285 #  endif
    286 
    287 // Floating point helpers
    288 #  define F32_SIGN ((uint32_t)1 << 31)
    289 union u32_f32 {
    290  uint32_t u;
    291  float f;
    292 };
    293 inline float fsgnj32(float rs1, float rs2, bool n, bool x) {
    294  u32_f32 a = {.f = rs1}, b = {.f = rs2};
    295  u32_f32 res;
    296  res.u = (a.u & ~F32_SIGN) | ((((x)   ? a.u
    297                                 : (n) ? F32_SIGN
    298                                       : 0) ^
    299                                b.u) &
    300                               F32_SIGN);
    301  return res.f;
    302 }
    303 
    304 inline Float32 fsgnj32(Float32 rs1, Float32 rs2, bool n, bool x) {
    305  u32_f32 a = {.u = rs1.get_bits()}, b = {.u = rs2.get_bits()};
    306  u32_f32 res;
    307  if (x) {  // RO_FSQNJX_S
    308    res.u = (a.u & ~F32_SIGN) | ((a.u ^ b.u) & F32_SIGN);
    309  } else {
    310    if (n) {  // RO_FSGNJN_S
    311      res.u = (a.u & ~F32_SIGN) | ((F32_SIGN ^ b.u) & F32_SIGN);
    312    } else {  // RO_FSGNJ_S
    313      res.u = (a.u & ~F32_SIGN) | ((0 ^ b.u) & F32_SIGN);
    314    }
    315  }
    316  return Float32::FromBits(res.u);
    317 }
    318 #  define F64_SIGN ((uint64_t)1 << 63)
    319 union u64_f64 {
    320  uint64_t u;
    321  double d;
    322 };
    323 inline double fsgnj64(double rs1, double rs2, bool n, bool x) {
    324  u64_f64 a = {.d = rs1}, b = {.d = rs2};
    325  u64_f64 res;
    326  res.u = (a.u & ~F64_SIGN) | ((((x)   ? a.u
    327                                 : (n) ? F64_SIGN
    328                                       : 0) ^
    329                                b.u) &
    330                               F64_SIGN);
    331  return res.d;
    332 }
    333 
    334 inline Float64 fsgnj64(Float64 rs1, Float64 rs2, bool n, bool x) {
    335  u64_f64 a = {.d = rs1.get_scalar()}, b = {.d = rs2.get_scalar()};
    336  u64_f64 res;
    337  if (x) {  // RO_FSQNJX_D
    338    res.u = (a.u & ~F64_SIGN) | ((a.u ^ b.u) & F64_SIGN);
    339  } else {
    340    if (n) {  // RO_FSGNJN_D
    341      res.u = (a.u & ~F64_SIGN) | ((F64_SIGN ^ b.u) & F64_SIGN);
    342    } else {  // RO_FSGNJ_D
    343      res.u = (a.u & ~F64_SIGN) | ((0 ^ b.u) & F64_SIGN);
    344    }
    345  }
    346  return Float64::FromBits(res.u);
    347 }
    348 inline bool is_boxed_float(int64_t v) { return (uint32_t)((v >> 32) + 1) == 0; }
    349 inline int64_t box_float(float v) {
    350  return (0xFFFFFFFF00000000 | bit_cast<int32_t>(v));
    351 }
    352 
    353 inline uint64_t box_float(uint32_t v) { return (0xFFFFFFFF00000000 | v); }
    354 
    355 // -----------------------------------------------------------------------------
    356 // Utility functions
    357 
    358 class SimInstructionBase : public InstructionBase {
    359 public:
    360  Type InstructionType() const { return type_; }
    361  inline Instruction* instr() const { return instr_; }
    362  inline int32_t operand() const { return operand_; }
    363 
    364 protected:
    365  SimInstructionBase() : operand_(-1), instr_(nullptr), type_(kUnsupported) {}
    366  explicit SimInstructionBase(Instruction* instr) {}
    367 
    368  int32_t operand_;
    369  Instruction* instr_;
    370  Type type_;
    371 
    372 private:
    373  SimInstructionBase& operator=(const SimInstructionBase&) = delete;
    374 };
    375 
    376 class SimInstruction : public InstructionGetters<SimInstructionBase> {
    377 public:
    378  SimInstruction() {}
    379 
    380  explicit SimInstruction(Instruction* instr) { *this = instr; }
    381 
    382  SimInstruction& operator=(Instruction* instr) {
    383    operand_ = *reinterpret_cast<const int32_t*>(instr);
    384    instr_ = instr;
    385    type_ = InstructionBase::InstructionType();
    386    MOZ_ASSERT(reinterpret_cast<void*>(&operand_) == this);
    387    return *this;
    388  }
    389 };
    390 
    391 // std::vector shim for breakpoints
    392 template <typename T>
    393 class BreakpointVector final {
    394  js::Vector<T, 0, js::SystemAllocPolicy> vector_;
    395 
    396 public:
    397  BreakpointVector() = default;
    398 
    399  size_t size() const { return vector_.length(); }
    400 
    401  T& at(size_t i) { return vector_[i]; }
    402  const T& at(size_t i) const { return vector_[i]; }
    403 
    404  template <typename U>
    405  void push_back(U&& u) {
    406    js::AutoEnterOOMUnsafeRegion oomUnsafe;
    407    if (!vector_.emplaceBack(std::move(u))) {
    408      oomUnsafe.crash("breakpoint vector push_back");
    409    }
    410  }
    411 };
    412 
    413 // Per thread simulator state.
    414 class Simulator {
    415  friend class RiscvDebugger;
    416 
    417 public:
    418  static bool FLAG_riscv_trap_to_simulator_debugger;
    419  static bool FLAG_trace_sim;
    420  static bool FLAG_debug_sim;
    421  static bool FLAG_riscv_print_watchpoint;
    422  // Registers are declared in order.
    423  enum Register {
    424    no_reg = -1,
    425    x0 = 0,
    426    x1,
    427    x2,
    428    x3,
    429    x4,
    430    x5,
    431    x6,
    432    x7,
    433    x8,
    434    x9,
    435    x10,
    436    x11,
    437    x12,
    438    x13,
    439    x14,
    440    x15,
    441    x16,
    442    x17,
    443    x18,
    444    x19,
    445    x20,
    446    x21,
    447    x22,
    448    x23,
    449    x24,
    450    x25,
    451    x26,
    452    x27,
    453    x28,
    454    x29,
    455    x30,
    456    x31,
    457    pc,
    458    kNumSimuRegisters,
    459    // alias
    460    zero = x0,
    461    ra = x1,
    462    sp = x2,
    463    gp = x3,
    464    tp = x4,
    465    t0 = x5,
    466    t1 = x6,
    467    t2 = x7,
    468    fp = x8,
    469    s1 = x9,
    470    a0 = x10,
    471    a1 = x11,
    472    a2 = x12,
    473    a3 = x13,
    474    a4 = x14,
    475    a5 = x15,
    476    a6 = x16,
    477    a7 = x17,
    478    s2 = x18,
    479    s3 = x19,
    480    s4 = x20,
    481    s5 = x21,
    482    s6 = x22,
    483    s7 = x23,
    484    s8 = x24,
    485    s9 = x25,
    486    s10 = x26,
    487    s11 = x27,
    488    t3 = x28,
    489    t4 = x29,
    490    t5 = x30,
    491    t6 = x31,
    492  };
    493 
    494  // Coprocessor registers.
    495  enum FPURegister {
    496    f0,
    497    f1,
    498    f2,
    499    f3,
    500    f4,
    501    f5,
    502    f6,
    503    f7,
    504    f8,
    505    f9,
    506    f10,
    507    f11,
    508    f12,
    509    f13,
    510    f14,
    511    f15,
    512    f16,
    513    f17,
    514    f18,
    515    f19,
    516    f20,
    517    f21,
    518    f22,
    519    f23,
    520    f24,
    521    f25,
    522    f26,
    523    f27,
    524    f28,
    525    f29,
    526    f30,
    527    f31,
    528    kNumFPURegisters,
    529    // alias
    530    ft0 = f0,
    531    ft1 = f1,
    532    ft2 = f2,
    533    ft3 = f3,
    534    ft4 = f4,
    535    ft5 = f5,
    536    ft6 = f6,
    537    ft7 = f7,
    538    fs0 = f8,
    539    fs1 = f9,
    540    fa0 = f10,
    541    fa1 = f11,
    542    fa2 = f12,
    543    fa3 = f13,
    544    fa4 = f14,
    545    fa5 = f15,
    546    fa6 = f16,
    547    fa7 = f17,
    548    fs2 = f18,
    549    fs3 = f19,
    550    fs4 = f20,
    551    fs5 = f21,
    552    fs6 = f22,
    553    fs7 = f23,
    554    fs8 = f24,
    555    fs9 = f25,
    556    fs10 = f26,
    557    fs11 = f27,
    558    ft8 = f28,
    559    ft9 = f29,
    560    ft10 = f30,
    561    ft11 = f31
    562  };
    563 
    564  // Returns nullptr on OOM.
    565  static Simulator* Create();
    566 
    567  static void Destroy(Simulator* simulator);
    568 
    569  // Constructor/destructor are for internal use only; use the static methods
    570  // above.
    571  Simulator();
    572  ~Simulator();
    573 
    574  // RISCV decoding routine
    575  void DecodeRVRType();
    576  void DecodeRVR4Type();
    577  void DecodeRVRFPType();  // Special routine for R/OP_FP type
    578  void DecodeRVRAType();   // Special routine for R/AMO type
    579  void DecodeRVIType();
    580  void DecodeRVSType();
    581  void DecodeRVBType();
    582  void DecodeRVUType();
    583  void DecodeRVJType();
    584  void DecodeCRType();
    585  void DecodeCAType();
    586  void DecodeCIType();
    587  void DecodeCIWType();
    588  void DecodeCSSType();
    589  void DecodeCLType();
    590  void DecodeCSType();
    591  void DecodeCJType();
    592  void DecodeCBType();
    593 #  ifdef CAN_USE_RVV_INSTRUCTIONS
    594  void DecodeVType();
    595  void DecodeRvvIVV();
    596  void DecodeRvvIVI();
    597  void DecodeRvvIVX();
    598  void DecodeRvvMVV();
    599  void DecodeRvvMVX();
    600  void DecodeRvvFVV();
    601  void DecodeRvvFVF();
    602  bool DecodeRvvVL();
    603  bool DecodeRvvVS();
    604 #  endif
    605  // The currently executing Simulator instance. Potentially there can be one
    606  // for each native thread.
    607  static Simulator* Current();
    608 
    609  static inline uintptr_t StackLimit() {
    610    return Simulator::Current()->stackLimit();
    611  }
    612 
    613  uintptr_t* addressOfStackLimit();
    614 
    615  // Accessors for register state. Reading the pc value adheres to the MIPS
    616  // architecture specification and is off by a 8 from the currently executing
    617  // instruction.
    618  void setRegister(int reg, int64_t value);
    619  int64_t getRegister(int reg) const;
    620  // Same for FPURegisters.
    621  void setFpuRegister(int fpureg, int64_t value);
    622  void setFpuRegisterLo(int fpureg, int32_t value);
    623  void setFpuRegisterHi(int fpureg, int32_t value);
    624  void setFpuRegisterFloat(int fpureg, float value);
    625  void setFpuRegisterDouble(int fpureg, double value);
    626  void setFpuRegisterFloat(int fpureg, Float32 value);
    627  void setFpuRegisterDouble(int fpureg, Float64 value);
    628 
    629  int64_t getFpuRegister(int fpureg) const;
    630  int32_t getFpuRegisterLo(int fpureg) const;
    631  int32_t getFpuRegisterHi(int fpureg) const;
    632  float getFpuRegisterFloat(int fpureg) const;
    633  double getFpuRegisterDouble(int fpureg) const;
    634  Float32 getFpuRegisterFloat32(int fpureg) const;
    635  Float64 getFpuRegisterFloat64(int fpureg) const;
    636 
    637  inline int16_t shamt6() const { return (imm12() & 0x3F); }
    638  inline int16_t shamt5() const { return (imm12() & 0x1F); }
    639  inline int16_t rvc_shamt6() const { return instr_.RvcShamt6(); }
    640  inline int32_t s_imm12() const { return instr_.StoreOffset(); }
    641  inline int32_t u_imm20() const { return instr_.Imm20UValue() << 12; }
    642  inline int32_t rvc_u_imm6() const { return instr_.RvcImm6Value() << 12; }
    643  inline void require(bool check) {
    644    if (!check) {
    645      SignalException(kIllegalInstruction);
    646    }
    647  }
    648 
    649  // Special case of setRegister and getRegister to access the raw PC value.
    650  void set_pc(int64_t value);
    651  int64_t get_pc() const;
    652 
    653  SimInstruction instr_;
    654  // RISCV utlity API to access register value
    655  // Helpers for data value tracing.
    656  enum TraceType {
    657    BYTE,
    658    HALF,
    659    WORD,
    660 #  if JS_CODEGEN_RISCV64
    661    DWORD,
    662 #  endif
    663    FLOAT,
    664    DOUBLE,
    665    // FLOAT_DOUBLE,
    666    // WORD_DWORD
    667  };
    668  inline int32_t rs1_reg() const { return instr_.Rs1Value(); }
    669  inline sreg_t rs1() const { return getRegister(rs1_reg()); }
    670  inline float frs1() const { return getFpuRegisterFloat(rs1_reg()); }
    671  inline double drs1() const { return getFpuRegisterDouble(rs1_reg()); }
    672  inline Float32 frs1_boxed() const { return getFpuRegisterFloat32(rs1_reg()); }
    673  inline Float64 drs1_boxed() const { return getFpuRegisterFloat64(rs1_reg()); }
    674  inline int32_t rs2_reg() const { return instr_.Rs2Value(); }
    675  inline sreg_t rs2() const { return getRegister(rs2_reg()); }
    676  inline float frs2() const { return getFpuRegisterFloat(rs2_reg()); }
    677  inline double drs2() const { return getFpuRegisterDouble(rs2_reg()); }
    678  inline Float32 frs2_boxed() const { return getFpuRegisterFloat32(rs2_reg()); }
    679  inline Float64 drs2_boxed() const { return getFpuRegisterFloat64(rs2_reg()); }
    680  inline int32_t rs3_reg() const { return instr_.Rs3Value(); }
    681  inline sreg_t rs3() const { return getRegister(rs3_reg()); }
    682  inline float frs3() const { return getFpuRegisterFloat(rs3_reg()); }
    683  inline double drs3() const { return getFpuRegisterDouble(rs3_reg()); }
    684  inline Float32 frs3_boxed() const { return getFpuRegisterFloat32(rs3_reg()); }
    685  inline Float64 drs3_boxed() const { return getFpuRegisterFloat64(rs3_reg()); }
    686  inline int32_t rd_reg() const { return instr_.RdValue(); }
    687  inline int32_t frd_reg() const { return instr_.RdValue(); }
    688  inline int32_t rvc_rs1_reg() const { return instr_.RvcRs1Value(); }
    689  inline sreg_t rvc_rs1() const { return getRegister(rvc_rs1_reg()); }
    690  inline int32_t rvc_rs2_reg() const { return instr_.RvcRs2Value(); }
    691  inline sreg_t rvc_rs2() const { return getRegister(rvc_rs2_reg()); }
    692  inline double rvc_drs2() const { return getFpuRegisterDouble(rvc_rs2_reg()); }
    693  inline int32_t rvc_rs1s_reg() const { return instr_.RvcRs1sValue(); }
    694  inline sreg_t rvc_rs1s() const { return getRegister(rvc_rs1s_reg()); }
    695  inline int32_t rvc_rs2s_reg() const { return instr_.RvcRs2sValue(); }
    696  inline sreg_t rvc_rs2s() const { return getRegister(rvc_rs2s_reg()); }
    697  inline double rvc_drs2s() const {
    698    return getFpuRegisterDouble(rvc_rs2s_reg());
    699  }
    700  inline int32_t rvc_rd_reg() const { return instr_.RvcRdValue(); }
    701  inline int32_t rvc_frd_reg() const { return instr_.RvcRdValue(); }
    702  inline int16_t boffset() const { return instr_.BranchOffset(); }
    703  inline int16_t imm12() const { return instr_.Imm12Value(); }
    704  inline int32_t imm20J() const { return instr_.Imm20JValue(); }
    705  inline int32_t imm5CSR() const { return instr_.Rs1Value(); }
    706  inline int16_t csr_reg() const { return instr_.CsrValue(); }
    707  inline int16_t rvc_imm6() const { return instr_.RvcImm6Value(); }
    708  inline int16_t rvc_imm6_addi16sp() const {
    709    return instr_.RvcImm6Addi16spValue();
    710  }
    711  inline int16_t rvc_imm8_addi4spn() const {
    712    return instr_.RvcImm8Addi4spnValue();
    713  }
    714  inline int16_t rvc_imm6_lwsp() const { return instr_.RvcImm6LwspValue(); }
    715  inline int16_t rvc_imm6_ldsp() const { return instr_.RvcImm6LdspValue(); }
    716  inline int16_t rvc_imm6_swsp() const { return instr_.RvcImm6SwspValue(); }
    717  inline int16_t rvc_imm6_sdsp() const { return instr_.RvcImm6SdspValue(); }
    718  inline int16_t rvc_imm5_w() const { return instr_.RvcImm5WValue(); }
    719  inline int16_t rvc_imm5_d() const { return instr_.RvcImm5DValue(); }
    720  inline int16_t rvc_imm8_b() const { return instr_.RvcImm8BValue(); }
    721 
    722  // Helper for debugging memory access.
    723  inline void DieOrDebug();
    724 
    725 #  if JS_CODEGEN_RISCV32
    726  template <typename T>
    727  void TraceRegWr(T value, TraceType t = WORD);
    728 #  elif JS_CODEGEN_RISCV64
    729  void TraceRegWr(sreg_t value, TraceType t = DWORD);
    730 #  endif
    731  void TraceMemWr(sreg_t addr, sreg_t value, TraceType t);
    732  template <typename T>
    733  void TraceMemRd(sreg_t addr, T value, sreg_t reg_value);
    734  void TraceMemRdDouble(sreg_t addr, double value, int64_t reg_value);
    735  void TraceMemRdDouble(sreg_t addr, Float64 value, int64_t reg_value);
    736  void TraceMemRdFloat(sreg_t addr, Float32 value, int64_t reg_value);
    737 
    738  template <typename T>
    739  void TraceLr(sreg_t addr, T value, sreg_t reg_value);
    740 
    741  template <typename T>
    742  void TraceSc(sreg_t addr, T value);
    743 
    744  template <typename T>
    745  void TraceMemWr(sreg_t addr, T value);
    746  void TraceMemWrDouble(sreg_t addr, double value);
    747 
    748  inline void set_rd(sreg_t value, bool trace = true) {
    749    setRegister(rd_reg(), value);
    750 #  if JS_CODEGEN_RISCV64
    751    if (trace) TraceRegWr(getRegister(rd_reg()), DWORD);
    752 #  elif JS_CODEGEN_RISCV32
    753    if (trace) TraceRegWr(getRegister(rd_reg()), WORD);
    754 #  endif
    755  }
    756  inline void set_frd(float value, bool trace = true) {
    757    setFpuRegisterFloat(rd_reg(), value);
    758    if (trace) TraceRegWr(getFpuRegister(rd_reg()), FLOAT);
    759  }
    760  inline void set_frd(Float32 value, bool trace = true) {
    761    setFpuRegisterFloat(rd_reg(), value);
    762    if (trace) TraceRegWr(getFpuRegister(rd_reg()), FLOAT);
    763  }
    764  inline void set_drd(double value, bool trace = true) {
    765    setFpuRegisterDouble(rd_reg(), value);
    766    if (trace) TraceRegWr(getFpuRegister(rd_reg()), DOUBLE);
    767  }
    768  inline void set_drd(Float64 value, bool trace = true) {
    769    setFpuRegisterDouble(rd_reg(), value);
    770    if (trace) TraceRegWr(getFpuRegister(rd_reg()), DOUBLE);
    771  }
    772  inline void set_rvc_rd(sreg_t value, bool trace = true) {
    773    setRegister(rvc_rd_reg(), value);
    774 #  if JS_CODEGEN_RISCV64
    775    if (trace) TraceRegWr(getRegister(rvc_rd_reg()), DWORD);
    776 #  elif JS_CODEGEN_RISCV32
    777    if (trace) TraceRegWr(getRegister(rvc_rd_reg()), WORD);
    778 #  endif
    779  }
    780  inline void set_rvc_rs1s(sreg_t value, bool trace = true) {
    781    setRegister(rvc_rs1s_reg(), value);
    782 #  if JS_CODEGEN_RISCV64
    783    if (trace) TraceRegWr(getRegister(rvc_rs1s_reg()), DWORD);
    784 #  elif JS_CODEGEN_RISCV32
    785    if (trace) TraceRegWr(getRegister(rvc_rs1s_reg()), WORD);
    786 #  endif
    787  }
    788  inline void set_rvc_rs2(sreg_t value, bool trace = true) {
    789    setRegister(rvc_rs2_reg(), value);
    790 #  if JS_CODEGEN_RISCV64
    791    if (trace) TraceRegWr(getRegister(rvc_rs2_reg()), DWORD);
    792 #  elif JS_CODEGEN_RISCV32
    793    if (trace) TraceRegWr(getRegister(rvc_rs2_reg()), WORD);
    794 #  endif
    795  }
    796  inline void set_rvc_drd(double value, bool trace = true) {
    797    setFpuRegisterDouble(rvc_rd_reg(), value);
    798    if (trace) TraceRegWr(getFpuRegister(rvc_rd_reg()), DOUBLE);
    799  }
    800  inline void set_rvc_drd(Float64 value, bool trace = true) {
    801    setFpuRegisterDouble(rvc_rd_reg(), value);
    802    if (trace) TraceRegWr(getFpuRegister(rvc_rd_reg()), DOUBLE);
    803  }
    804  inline void set_rvc_frd(Float32 value, bool trace = true) {
    805    setFpuRegisterFloat(rvc_rd_reg(), value);
    806    if (trace) TraceRegWr(getFpuRegister(rvc_rd_reg()), DOUBLE);
    807  }
    808  inline void set_rvc_rs2s(sreg_t value, bool trace = true) {
    809    setRegister(rvc_rs2s_reg(), value);
    810 #  if JS_CODEGEN_RISCV64
    811    if (trace) TraceRegWr(getRegister(rvc_rs2s_reg()), DWORD);
    812 #  elif JS_CODEGEN_RISCV32
    813    if (trace) TraceRegWr(getRegister(rvc_rs2s_reg()), WORD);
    814 #  endif
    815  }
    816  inline void set_rvc_drs2s(double value, bool trace = true) {
    817    setFpuRegisterDouble(rvc_rs2s_reg(), value);
    818    if (trace) TraceRegWr(getFpuRegister(rvc_rs2s_reg()), DOUBLE);
    819  }
    820  inline void set_rvc_drs2s(Float64 value, bool trace = true) {
    821    setFpuRegisterDouble(rvc_rs2s_reg(), value);
    822    if (trace) TraceRegWr(getFpuRegister(rvc_rs2s_reg()), DOUBLE);
    823  }
    824 
    825  inline void set_rvc_frs2s(Float32 value, bool trace = true) {
    826    setFpuRegisterFloat(rvc_rs2s_reg(), value);
    827    if (trace) TraceRegWr(getFpuRegister(rvc_rs2s_reg()), FLOAT);
    828  }
    829 
    830  uint32_t get_dynamic_rounding_mode() { return read_csr_value(csr_frm); }
    831 
    832  // helper functions to read/write/set/clear CRC values/bits
    833  uint32_t read_csr_value(uint32_t csr) {
    834    switch (csr) {
    835      case csr_fflags:  // Floating-Point Accrued Exceptions (RW)
    836        return (FCSR_ & kFcsrFlagsMask);
    837      case csr_frm:  // Floating-Point Dynamic Rounding Mode (RW)
    838        return (FCSR_ & kFcsrFrmMask) >> kFcsrFrmShift;
    839      case csr_fcsr:  // Floating-Point Control and Status Register (RW)
    840        return (FCSR_ & kFcsrMask);
    841      default:
    842        MOZ_CRASH("UNIMPLEMENTED");
    843    }
    844  }
    845 
    846  void write_csr_value(uint32_t csr, reg_t val) {
    847    uint32_t value = (uint32_t)val;
    848    switch (csr) {
    849      case csr_fflags:  // Floating-Point Accrued Exceptions (RW)
    850        MOZ_ASSERT(value <= ((1 << kFcsrFlagsBits) - 1));
    851        FCSR_ = (FCSR_ & (~kFcsrFlagsMask)) | value;
    852        break;
    853      case csr_frm:  // Floating-Point Dynamic Rounding Mode (RW)
    854        MOZ_ASSERT(value <= ((1 << kFcsrFrmBits) - 1));
    855        FCSR_ = (FCSR_ & (~kFcsrFrmMask)) | (value << kFcsrFrmShift);
    856        break;
    857      case csr_fcsr:  // Floating-Point Control and Status Register (RW)
    858        MOZ_ASSERT(value <= ((1 << kFcsrBits) - 1));
    859        FCSR_ = (FCSR_ & (~kFcsrMask)) | value;
    860        break;
    861      default:
    862        MOZ_CRASH("UNIMPLEMENTED");
    863    }
    864  }
    865 
    866  void set_csr_bits(uint32_t csr, reg_t val) {
    867    uint32_t value = (uint32_t)val;
    868    switch (csr) {
    869      case csr_fflags:  // Floating-Point Accrued Exceptions (RW)
    870        MOZ_ASSERT(value <= ((1 << kFcsrFlagsBits) - 1));
    871        FCSR_ = FCSR_ | value;
    872        break;
    873      case csr_frm:  // Floating-Point Dynamic Rounding Mode (RW)
    874        MOZ_ASSERT(value <= ((1 << kFcsrFrmBits) - 1));
    875        FCSR_ = FCSR_ | (value << kFcsrFrmShift);
    876        break;
    877      case csr_fcsr:  // Floating-Point Control and Status Register (RW)
    878        MOZ_ASSERT(value <= ((1 << kFcsrBits) - 1));
    879        FCSR_ = FCSR_ | value;
    880        break;
    881      default:
    882        MOZ_CRASH("UNIMPLEMENTED");
    883    }
    884  }
    885 
    886  void clear_csr_bits(uint32_t csr, reg_t val) {
    887    uint32_t value = (uint32_t)val;
    888    switch (csr) {
    889      case csr_fflags:  // Floating-Point Accrued Exceptions (RW)
    890        MOZ_ASSERT(value <= ((1 << kFcsrFlagsBits) - 1));
    891        FCSR_ = FCSR_ & (~value);
    892        break;
    893      case csr_frm:  // Floating-Point Dynamic Rounding Mode (RW)
    894        MOZ_ASSERT(value <= ((1 << kFcsrFrmBits) - 1));
    895        FCSR_ = FCSR_ & (~(value << kFcsrFrmShift));
    896        break;
    897      case csr_fcsr:  // Floating-Point Control and Status Register (RW)
    898        MOZ_ASSERT(value <= ((1 << kFcsrBits) - 1));
    899        FCSR_ = FCSR_ & (~value);
    900        break;
    901      default:
    902        MOZ_CRASH("UNIMPLEMENTED");
    903    }
    904  }
    905 
    906  bool test_fflags_bits(uint32_t mask) {
    907    return (FCSR_ & kFcsrFlagsMask & mask) != 0;
    908  }
    909 
    910  void set_fflags(uint32_t flags) { set_csr_bits(csr_fflags, flags); }
    911  void clear_fflags(int32_t flags) { clear_csr_bits(csr_fflags, flags); }
    912 
    913  float RoundF2FHelper(float input_val, int rmode);
    914  double RoundF2FHelper(double input_val, int rmode);
    915  template <typename I_TYPE, typename F_TYPE>
    916  I_TYPE RoundF2IHelper(F_TYPE original, int rmode);
    917 
    918  template <typename T>
    919  T FMaxMinHelper(T a, T b, MaxMinKind kind);
    920 
    921  template <typename T>
    922  bool CompareFHelper(T input1, T input2, FPUCondition cc);
    923 
    924  template <typename T>
    925  T get_pc_as() const {
    926    return reinterpret_cast<T>(get_pc());
    927  }
    928 
    929  void enable_single_stepping(SingleStepCallback cb, void* arg);
    930  void disable_single_stepping();
    931 
    932  // Accessor to the internal simulator stack area.
    933  uintptr_t stackLimit() const;
    934  bool overRecursed(uintptr_t newsp = 0) const;
    935  bool overRecursedWithExtra(uint32_t extra) const;
    936 
    937  // Executes MIPS instructions until the PC reaches end_sim_pc.
    938  template <bool enableStopSimAt>
    939  void execute();
    940 
    941  // Sets up the simulator state and grabs the result on return.
    942  int64_t call(uint8_t* entry, int argument_count, ...);
    943 
    944  // Push an address onto the JS stack.
    945  uintptr_t pushAddress(uintptr_t address);
    946 
    947  // Pop an address from the JS stack.
    948  uintptr_t popAddress();
    949 
    950  // Debugger input.
    951  void setLastDebuggerInput(char* input);
    952  char* lastDebuggerInput() { return lastDebuggerInput_; }
    953 
    954  // Returns true if pc register contains one of the 'SpecialValues' defined
    955  // below (bad_ra, end_sim_pc).
    956  bool has_bad_pc() const;
    957 
    958 private:
    959  enum SpecialValues {
    960    // Known bad pc value to ensure that the simulator does not execute
    961    // without being properly setup.
    962    bad_ra = -1,
    963    // A pc value used to signal the simulator to stop execution.  Generally
    964    // the ra is set to this value on transition from native C code to
    965    // simulated execution, so that the simulator can "return" to the native
    966    // C code.
    967    end_sim_pc = -2,
    968    // Unpredictable value.
    969    Unpredictable = 0xbadbeaf
    970  };
    971 
    972  bool init();
    973 
    974  // Unsupported instructions use Format to print an error and stop execution.
    975  void format(SimInstruction* instr, const char* format);
    976 
    977  // Read and write memory.
    978  // RISCV Memory read/write methods
    979  template <typename T>
    980  T ReadMem(sreg_t addr, Instruction* instr);
    981  template <typename T>
    982  void WriteMem(sreg_t addr, T value, Instruction* instr);
    983  template <typename T, typename OP>
    984  T amo(sreg_t addr, OP f, Instruction* instr, TraceType t) {
    985    auto lhs = ReadMem<T>(addr, instr);
    986    // TODO(RISCV): trace memory read for AMO
    987    WriteMem<T>(addr, (T)f(lhs), instr);
    988    return lhs;
    989  }
    990 
    991  inline int32_t loadLinkedW(uint64_t addr, SimInstruction* instr);
    992  inline int storeConditionalW(uint64_t addr, int32_t value,
    993                               SimInstruction* instr);
    994 
    995  inline int64_t loadLinkedD(uint64_t addr, SimInstruction* instr);
    996  inline int storeConditionalD(uint64_t addr, int64_t value,
    997                               SimInstruction* instr);
    998 
    999  // Used for breakpoints and traps.
   1000  void SoftwareInterrupt();
   1001 
   1002  // Stop helper functions.
   1003  bool isWatchpoint(uint32_t code);
   1004  bool IsTracepoint(uint32_t code);
   1005  void printWatchpoint(uint32_t code);
   1006  void handleStop(uint32_t code);
   1007  bool isStopInstruction(SimInstruction* instr);
   1008  bool isEnabledStop(uint32_t code);
   1009  void enableStop(uint32_t code);
   1010  void disableStop(uint32_t code);
   1011  void increaseStopCounter(uint32_t code);
   1012  void printStopInfo(uint32_t code);
   1013 
   1014  // Simulator breakpoints.
   1015  struct Breakpoint {
   1016    SimInstruction* location;
   1017    bool enabled;
   1018    bool is_tbreak;
   1019  };
   1020  BreakpointVector<Breakpoint> breakpoints_;
   1021  void SetBreakpoint(SimInstruction* breakpoint, bool is_tbreak);
   1022  void ListBreakpoints();
   1023  void CheckBreakpoints();
   1024 
   1025  JS::ProfilingFrameIterator::RegisterState registerState();
   1026  void HandleWasmTrap();
   1027 
   1028  // Handle any wasm faults, returning true if the fault was handled.
   1029  // This method is rather hot so inline the normal (no-wasm) case.
   1030  bool MOZ_ALWAYS_INLINE handleWasmSegFault(uint64_t addr, unsigned numBytes) {
   1031    if (MOZ_LIKELY(!js::wasm::CodeExists)) {
   1032      return false;
   1033    }
   1034 
   1035    uint8_t* newPC;
   1036    if (!js::wasm::MemoryAccessTraps(registerState(), (uint8_t*)addr, numBytes,
   1037                                     &newPC)) {
   1038      return false;
   1039    }
   1040 
   1041    LLBit_ = false;
   1042    set_pc(int64_t(newPC));
   1043    return true;
   1044  }
   1045 
   1046  // Executes one instruction.
   1047  void InstructionDecode(Instruction* instr);
   1048 
   1049  // ICache.
   1050  // static void CheckICache(base::CustomMatcherHashMap* i_cache,
   1051  //                         Instruction* instr);
   1052  // static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t
   1053  // start,
   1054  //                          size_t size);
   1055  // static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache,
   1056  //                                void* page);
   1057  template <typename T, typename Func>
   1058  inline T CanonicalizeFPUOpFMA(Func fn, T dst, T src1, T src2) {
   1059    static_assert(std::is_floating_point<T>::value);
   1060    auto alu_out = fn(dst, src1, src2);
   1061    // if any input or result is NaN, the result is quiet_NaN
   1062    if (std::isnan(alu_out) || std::isnan(src1) || std::isnan(src2) ||
   1063        std::isnan(dst)) {
   1064      // signaling_nan sets kInvalidOperation bit
   1065      if (isSnan(alu_out) || isSnan(src1) || isSnan(src2) || isSnan(dst))
   1066        set_fflags(kInvalidOperation);
   1067      alu_out = std::numeric_limits<T>::quiet_NaN();
   1068    }
   1069    return alu_out;
   1070  }
   1071 
   1072  template <typename T, typename Func>
   1073  inline T CanonicalizeFPUOp3(Func fn) {
   1074    static_assert(std::is_floating_point<T>::value);
   1075    T src1 = std::is_same<float, T>::value ? frs1() : drs1();
   1076    T src2 = std::is_same<float, T>::value ? frs2() : drs2();
   1077    T src3 = std::is_same<float, T>::value ? frs3() : drs3();
   1078    auto alu_out = fn(src1, src2, src3);
   1079    // if any input or result is NaN, the result is quiet_NaN
   1080    if (std::isnan(alu_out) || std::isnan(src1) || std::isnan(src2) ||
   1081        std::isnan(src3)) {
   1082      // signaling_nan sets kInvalidOperation bit
   1083      if (isSnan(alu_out) || isSnan(src1) || isSnan(src2) || isSnan(src3))
   1084        set_fflags(kInvalidOperation);
   1085      alu_out = std::numeric_limits<T>::quiet_NaN();
   1086    }
   1087    return alu_out;
   1088  }
   1089 
   1090  template <typename T, typename Func>
   1091  inline T CanonicalizeFPUOp2(Func fn) {
   1092    static_assert(std::is_floating_point<T>::value);
   1093    T src1 = std::is_same<float, T>::value ? frs1() : drs1();
   1094    T src2 = std::is_same<float, T>::value ? frs2() : drs2();
   1095    auto alu_out = fn(src1, src2);
   1096    // if any input or result is NaN, the result is quiet_NaN
   1097    if (std::isnan(alu_out) || std::isnan(src1) || std::isnan(src2)) {
   1098      // signaling_nan sets kInvalidOperation bit
   1099      if (isSnan(alu_out) || isSnan(src1) || isSnan(src2))
   1100        set_fflags(kInvalidOperation);
   1101      alu_out = std::numeric_limits<T>::quiet_NaN();
   1102    }
   1103    return alu_out;
   1104  }
   1105 
   1106  template <typename T, typename Func>
   1107  inline T CanonicalizeFPUOp1(Func fn) {
   1108    static_assert(std::is_floating_point<T>::value);
   1109    T src1 = std::is_same<float, T>::value ? frs1() : drs1();
   1110    auto alu_out = fn(src1);
   1111    // if any input or result is NaN, the result is quiet_NaN
   1112    if (std::isnan(alu_out) || std::isnan(src1)) {
   1113      // signaling_nan sets kInvalidOperation bit
   1114      if (isSnan(alu_out) || isSnan(src1)) set_fflags(kInvalidOperation);
   1115      alu_out = std::numeric_limits<T>::quiet_NaN();
   1116    }
   1117    return alu_out;
   1118  }
   1119 
   1120  template <typename Func>
   1121  inline float CanonicalizeDoubleToFloatOperation(Func fn) {
   1122    float alu_out = fn(drs1());
   1123    if (std::isnan(alu_out) || std::isnan(drs1()))
   1124      alu_out = std::numeric_limits<float>::quiet_NaN();
   1125    return alu_out;
   1126  }
   1127 
   1128  template <typename Func>
   1129  inline float CanonicalizeDoubleToFloatOperation(Func fn, double frs) {
   1130    float alu_out = fn(frs);
   1131    if (std::isnan(alu_out) || std::isnan(drs1()))
   1132      alu_out = std::numeric_limits<float>::quiet_NaN();
   1133    return alu_out;
   1134  }
   1135 
   1136  template <typename Func>
   1137  inline float CanonicalizeFloatToDoubleOperation(Func fn, float frs) {
   1138    double alu_out = fn(frs);
   1139    if (std::isnan(alu_out) || std::isnan(frs1()))
   1140      alu_out = std::numeric_limits<double>::quiet_NaN();
   1141    return alu_out;
   1142  }
   1143 
   1144  template <typename Func>
   1145  inline float CanonicalizeFloatToDoubleOperation(Func fn) {
   1146    double alu_out = fn(frs1());
   1147    if (std::isnan(alu_out) || std::isnan(frs1()))
   1148      alu_out = std::numeric_limits<double>::quiet_NaN();
   1149    return alu_out;
   1150  }
   1151 
   1152 public:
   1153  static int64_t StopSimAt;
   1154 
   1155  // Runtime call support.
   1156  static void* RedirectNativeFunction(void* nativeFunction,
   1157                                      ABIFunctionType type);
   1158 
   1159 private:
   1160  enum Exception {
   1161    none,
   1162    kIntegerOverflow,
   1163    kIntegerUnderflow,
   1164    kDivideByZero,
   1165    kNumExceptions,
   1166    // RISCV illegual instruction exception
   1167    kIllegalInstruction,
   1168  };
   1169  int16_t exceptions[kNumExceptions];
   1170 
   1171  // Exceptions.
   1172  void SignalException(Exception e);
   1173 
   1174  // Handle return value for runtime FP functions.
   1175  void setCallResultDouble(double result);
   1176  void setCallResultFloat(float result);
   1177  void setCallResult(int64_t res);
   1178  void setCallResult(__int128 res);
   1179 
   1180  void callInternal(uint8_t* entry);
   1181 
   1182  // Architecture state.
   1183  // Registers.
   1184  int64_t registers_[kNumSimuRegisters];
   1185  // Coprocessor Registers.
   1186  int64_t FPUregisters_[kNumFPURegisters];
   1187  // FPU control register.
   1188  uint32_t FCSR_;
   1189 
   1190  bool LLBit_;
   1191  uintptr_t LLAddr_;
   1192  int64_t lastLLValue_;
   1193 
   1194  // Simulator support.
   1195  char* stack_;
   1196  uintptr_t stackLimit_;
   1197  bool pc_modified_;
   1198  int64_t icount_;
   1199  int64_t break_count_;
   1200 
   1201  // Debugger input.
   1202  char* lastDebuggerInput_;
   1203 
   1204  intptr_t* watch_address_ = nullptr;
   1205  intptr_t watch_value_ = 0;
   1206 
   1207  // Registered breakpoints.
   1208  SimInstruction* break_pc_;
   1209  Instr break_instr_;
   1210  EmbeddedVector<char, 256> trace_buf_;
   1211 
   1212  // Single-stepping support
   1213  bool single_stepping_;
   1214  SingleStepCallback single_step_callback_;
   1215  void* single_step_callback_arg_;
   1216 
   1217  // A stop is watched if its code is less than kNumOfWatchedStops.
   1218  // Only watched stops support enabling/disabling and the counter feature.
   1219  static const uint32_t kNumOfWatchedStops = 256;
   1220 
   1221  // Stop is disabled if bit 31 is set.
   1222  static const uint32_t kStopDisabledBit = 1U << 31;
   1223 
   1224  // A stop is enabled, meaning the simulator will stop when meeting the
   1225  // instruction, if bit 31 of watchedStops_[code].count is unset.
   1226  // The value watchedStops_[code].count & ~(1 << 31) indicates how many times
   1227  // the breakpoint was hit or gone through.
   1228  struct StopCountAndDesc {
   1229    uint32_t count_;
   1230    char* desc_;
   1231  };
   1232  StopCountAndDesc watchedStops_[kNumOfWatchedStops];
   1233 };
   1234 
   1235 // Process wide simulator state.
   1236 class SimulatorProcess {
   1237  friend class Redirection;
   1238  friend class AutoLockSimulatorCache;
   1239 
   1240 private:
   1241  // ICache checking.
   1242  struct ICacheHasher {
   1243    typedef void* Key;
   1244    typedef void* Lookup;
   1245    static HashNumber hash(const Lookup& l);
   1246    static bool match(const Key& k, const Lookup& l);
   1247  };
   1248 
   1249 public:
   1250  typedef HashMap<void*, CachePage*, ICacheHasher, SystemAllocPolicy> ICacheMap;
   1251 
   1252  static mozilla::Atomic<size_t, mozilla::ReleaseAcquire>
   1253      ICacheCheckingDisableCount;
   1254  static void FlushICache(void* start, size_t size);
   1255 
   1256  static void checkICacheLocked(SimInstruction* instr);
   1257 
   1258  static bool initialize() {
   1259    singleton_ = js_new<SimulatorProcess>();
   1260    return singleton_;
   1261  }
   1262  static void destroy() {
   1263    js_delete(singleton_);
   1264    singleton_ = nullptr;
   1265  }
   1266 
   1267  SimulatorProcess();
   1268  ~SimulatorProcess();
   1269 
   1270 private:
   1271  static SimulatorProcess* singleton_;
   1272 
   1273  // This lock creates a critical section around 'redirection_' and
   1274  // 'icache_', which are referenced both by the execution engine
   1275  // and by the off-thread compiler (see Redirection::Get in the cpp file).
   1276  Mutex cacheLock_ MOZ_UNANNOTATED;
   1277 
   1278  Redirection* redirection_;
   1279  ICacheMap icache_;
   1280 
   1281 public:
   1282  static ICacheMap& icache() {
   1283    // Technically we need the lock to access the innards of the
   1284    // icache, not to take its address, but the latter condition
   1285    // serves as a useful complement to the former.
   1286    singleton_->cacheLock_.assertOwnedByCurrentThread();
   1287    return singleton_->icache_;
   1288  }
   1289 
   1290  static Redirection* redirection() {
   1291    singleton_->cacheLock_.assertOwnedByCurrentThread();
   1292    return singleton_->redirection_;
   1293  }
   1294 
   1295  static void setRedirection(js::jit::Redirection* redirection) {
   1296    singleton_->cacheLock_.assertOwnedByCurrentThread();
   1297    singleton_->redirection_ = redirection;
   1298  }
   1299 };
   1300 
   1301 }  // namespace jit
   1302 }  // namespace js
   1303 
   1304 #endif /* JS_SIMULATOR_MIPS64 */
   1305 
   1306 #endif /* jit_riscv64_Simulator_riscv64_h */