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 */