Simulator-mips64.h (16551B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright 2011 the V8 project authors. All rights reserved. 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following 12 // disclaimer in the documentation and/or other materials provided 13 // with the distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived 16 // from this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 #ifndef jit_mips64_Simulator_mips64_h 31 #define jit_mips64_Simulator_mips64_h 32 33 #ifdef JS_SIMULATOR_MIPS64 34 35 # include "mozilla/Atomics.h" 36 37 # include "jit/IonTypes.h" 38 # include "js/ProfilingFrameIterator.h" 39 # include "threading/Thread.h" 40 # include "vm/MutexIDs.h" 41 # include "wasm/WasmSignalHandlers.h" 42 43 namespace js { 44 45 namespace jit { 46 47 class JitActivation; 48 49 class Simulator; 50 class Redirection; 51 class CachePage; 52 class AutoLockSimulator; 53 54 // When the SingleStepCallback is called, the simulator is about to execute 55 // sim->get_pc() and the current machine state represents the completed 56 // execution of the previous pc. 57 typedef void (*SingleStepCallback)(void* arg, Simulator* sim, void* pc); 58 59 const intptr_t kPointerAlignment = 8; 60 const intptr_t kPointerAlignmentMask = kPointerAlignment - 1; 61 62 const intptr_t kDoubleAlignment = 8; 63 const intptr_t kDoubleAlignmentMask = kDoubleAlignment - 1; 64 65 // Number of general purpose registers. 66 const int kNumRegisters = 32; 67 68 // In the simulator, the PC register is simulated as the 34th register. 69 const int kPCRegister = 34; 70 71 // Number coprocessor registers. 72 const int kNumFPURegisters = 32; 73 74 // FPU (coprocessor 1) control registers. Currently only FCSR is implemented. 75 const int kFCSRRegister = 31; 76 const int kInvalidFPUControlRegister = -1; 77 const uint32_t kFPUInvalidResult = static_cast<uint32_t>(1 << 31) - 1; 78 const uint64_t kFPUInvalidResult64 = static_cast<uint64_t>(1ULL << 63) - 1; 79 80 // FCSR constants. 81 const uint32_t kFCSRInexactFlagBit = 2; 82 const uint32_t kFCSRUnderflowFlagBit = 3; 83 const uint32_t kFCSROverflowFlagBit = 4; 84 const uint32_t kFCSRDivideByZeroFlagBit = 5; 85 const uint32_t kFCSRInvalidOpFlagBit = 6; 86 87 const uint32_t kFCSRInexactCauseBit = 12; 88 const uint32_t kFCSRUnderflowCauseBit = 13; 89 const uint32_t kFCSROverflowCauseBit = 14; 90 const uint32_t kFCSRDivideByZeroCauseBit = 15; 91 const uint32_t kFCSRInvalidOpCauseBit = 16; 92 93 const uint32_t kFCSRInexactFlagMask = 1 << kFCSRInexactFlagBit; 94 const uint32_t kFCSRUnderflowFlagMask = 1 << kFCSRUnderflowFlagBit; 95 const uint32_t kFCSROverflowFlagMask = 1 << kFCSROverflowFlagBit; 96 const uint32_t kFCSRDivideByZeroFlagMask = 1 << kFCSRDivideByZeroFlagBit; 97 const uint32_t kFCSRInvalidOpFlagMask = 1 << kFCSRInvalidOpFlagBit; 98 99 const uint32_t kFCSRFlagMask = 100 kFCSRInexactFlagMask | kFCSRUnderflowFlagMask | kFCSROverflowFlagMask | 101 kFCSRDivideByZeroFlagMask | kFCSRInvalidOpFlagMask; 102 103 const uint32_t kFCSRExceptionFlagMask = kFCSRFlagMask ^ kFCSRInexactFlagMask; 104 105 // On MIPS64 Simulator breakpoints can have different codes: 106 // - Breaks between 0 and kMaxWatchpointCode are treated as simple watchpoints, 107 // the simulator will run through them and print the registers. 108 // - Breaks between kMaxWatchpointCode and kMaxStopCode are treated as stop() 109 // instructions (see Assembler::stop()). 110 // - Breaks larger than kMaxStopCode are simple breaks, dropping you into the 111 // debugger. 112 const uint32_t kMaxWatchpointCode = 31; 113 const uint32_t kMaxStopCode = 127; 114 const uint32_t kWasmTrapCode = 6; 115 116 // ----------------------------------------------------------------------------- 117 // Utility functions 118 119 typedef uint32_t Instr; 120 class SimInstruction; 121 122 // Per thread simulator state. 123 class Simulator { 124 friend class MipsDebugger; 125 126 public: 127 // Registers are declared in order. See "See MIPS Run Linux" chapter 2. 128 enum Register { 129 no_reg = -1, 130 zero_reg = 0, 131 at, 132 v0, 133 v1, 134 a0, 135 a1, 136 a2, 137 a3, 138 a4, 139 a5, 140 a6, 141 a7, 142 t4, 143 t5, 144 t6, 145 t7, 146 s0, 147 s1, 148 s2, 149 s3, 150 s4, 151 s5, 152 s6, 153 s7, 154 t8, 155 t9, 156 k0, 157 k1, 158 gp, 159 sp, 160 s8, 161 ra, 162 // LO, HI, and pc. 163 LO, 164 HI, 165 pc, // pc must be the last register. 166 kNumSimuRegisters, 167 // aliases 168 fp = s8 169 }; 170 171 // Coprocessor registers. 172 enum FPURegister { 173 f0, 174 f1, 175 f2, 176 f3, 177 f4, 178 f5, 179 f6, 180 f7, 181 f8, 182 f9, 183 f10, 184 f11, 185 f12, 186 f13, 187 f14, 188 f15, 189 f16, 190 f17, 191 f18, 192 f19, 193 f20, 194 f21, 195 f22, 196 f23, 197 f24, 198 f25, 199 f26, 200 f27, 201 f28, 202 f29, 203 f30, 204 f31, 205 kNumFPURegisters 206 }; 207 208 // Returns nullptr on OOM. 209 static Simulator* Create(); 210 211 static void Destroy(Simulator* simulator); 212 213 // Constructor/destructor are for internal use only; use the static methods 214 // above. 215 Simulator(); 216 ~Simulator(); 217 218 // The currently executing Simulator instance. Potentially there can be one 219 // for each native thread. 220 static Simulator* Current(); 221 222 static inline uintptr_t StackLimit() { 223 return Simulator::Current()->stackLimit(); 224 } 225 226 uintptr_t* addressOfStackLimit(); 227 228 // Accessors for register state. Reading the pc value adheres to the MIPS 229 // architecture specification and is off by a 8 from the currently executing 230 // instruction. 231 void setRegister(int reg, int64_t value); 232 int64_t getRegister(int reg) const; 233 // Same for FPURegisters. 234 void setFpuRegister(int fpureg, int64_t value); 235 void setFpuRegisterLo(int fpureg, int32_t value); 236 void setFpuRegisterHi(int fpureg, int32_t value); 237 void setFpuRegisterFloat(int fpureg, float value); 238 void setFpuRegisterDouble(int fpureg, double value); 239 int64_t getFpuRegister(int fpureg) const; 240 int32_t getFpuRegisterLo(int fpureg) const; 241 int32_t getFpuRegisterHi(int fpureg) const; 242 float getFpuRegisterFloat(int fpureg) const; 243 double getFpuRegisterDouble(int fpureg) const; 244 void setFCSRBit(uint32_t cc, bool value); 245 bool testFCSRBit(uint32_t cc); 246 template <typename T> 247 bool setFCSRRoundError(double original, double rounded); 248 249 // Special case of set_register and get_register to access the raw PC value. 250 void set_pc(int64_t value); 251 int64_t get_pc() const; 252 253 template <typename T> 254 T get_pc_as() const { 255 return reinterpret_cast<T>(get_pc()); 256 } 257 258 void enable_single_stepping(SingleStepCallback cb, void* arg); 259 void disable_single_stepping(); 260 261 // Accessor to the internal simulator stack area. 262 uintptr_t stackLimit() const; 263 bool overRecursed(uintptr_t newsp = 0) const; 264 bool overRecursedWithExtra(uint32_t extra) const; 265 266 // Executes MIPS instructions until the PC reaches end_sim_pc. 267 template <bool enableStopSimAt> 268 void execute(); 269 270 // Sets up the simulator state and grabs the result on return. 271 int64_t call(uint8_t* entry, int argument_count, ...); 272 273 // Push an address onto the JS stack. 274 uintptr_t pushAddress(uintptr_t address); 275 276 // Pop an address from the JS stack. 277 uintptr_t popAddress(); 278 279 // Debugger input. 280 void setLastDebuggerInput(char* input); 281 char* lastDebuggerInput() { return lastDebuggerInput_; } 282 283 // Returns true if pc register contains one of the 'SpecialValues' defined 284 // below (bad_ra, end_sim_pc). 285 bool has_bad_pc() const; 286 287 private: 288 enum SpecialValues { 289 // Known bad pc value to ensure that the simulator does not execute 290 // without being properly setup. 291 bad_ra = -1, 292 // A pc value used to signal the simulator to stop execution. Generally 293 // the ra is set to this value on transition from native C code to 294 // simulated execution, so that the simulator can "return" to the native 295 // C code. 296 end_sim_pc = -2, 297 // Unpredictable value. 298 Unpredictable = 0xbadbeaf 299 }; 300 301 bool init(); 302 303 // Unsupported instructions use Format to print an error and stop execution. 304 void format(SimInstruction* instr, const char* format); 305 306 // Read and write memory. 307 inline uint8_t readBU(uint64_t addr, SimInstruction* instr); 308 inline int8_t readB(uint64_t addr, SimInstruction* instr); 309 inline void writeB(uint64_t addr, uint8_t value, SimInstruction* instr); 310 inline void writeB(uint64_t addr, int8_t value, SimInstruction* instr); 311 312 inline uint16_t readHU(uint64_t addr, SimInstruction* instr); 313 inline int16_t readH(uint64_t addr, SimInstruction* instr); 314 inline void writeH(uint64_t addr, uint16_t value, SimInstruction* instr); 315 inline void writeH(uint64_t addr, int16_t value, SimInstruction* instr); 316 317 inline uint32_t readWU(uint64_t addr, SimInstruction* instr); 318 inline int32_t readW(uint64_t addr, SimInstruction* instr); 319 inline void writeW(uint64_t addr, uint32_t value, SimInstruction* instr); 320 inline void writeW(uint64_t addr, int32_t value, SimInstruction* instr); 321 322 inline int64_t readDW(uint64_t addr, SimInstruction* instr); 323 inline int64_t readDWL(uint64_t addr, SimInstruction* instr); 324 inline int64_t readDWR(uint64_t addr, SimInstruction* instr); 325 inline void writeDW(uint64_t addr, int64_t value, SimInstruction* instr); 326 327 inline double readD(uint64_t addr, SimInstruction* instr); 328 inline void writeD(uint64_t addr, double value, SimInstruction* instr); 329 330 inline int32_t loadLinkedW(uint64_t addr, SimInstruction* instr); 331 inline int storeConditionalW(uint64_t addr, int32_t value, 332 SimInstruction* instr); 333 334 inline int64_t loadLinkedD(uint64_t addr, SimInstruction* instr); 335 inline int storeConditionalD(uint64_t addr, int64_t value, 336 SimInstruction* instr); 337 338 // Helper function for decodeTypeRegister. 339 void configureTypeRegister(SimInstruction* instr, int64_t& alu_out, 340 __int128& i128hilo, unsigned __int128& u128hilo, 341 int64_t& next_pc, int32_t& return_addr_reg, 342 bool& do_interrupt); 343 344 // Executing is handled based on the instruction type. 345 void decodeTypeRegister(SimInstruction* instr); 346 void decodeTypeImmediate(SimInstruction* instr); 347 void decodeTypeJump(SimInstruction* instr); 348 349 // Used for breakpoints and traps. 350 void softwareInterrupt(SimInstruction* instr); 351 352 // Stop helper functions. 353 bool isWatchpoint(uint32_t code); 354 void printWatchpoint(uint32_t code); 355 void handleStop(uint32_t code, SimInstruction* instr); 356 bool isStopInstruction(SimInstruction* instr); 357 bool isEnabledStop(uint32_t code); 358 void enableStop(uint32_t code); 359 void disableStop(uint32_t code); 360 void increaseStopCounter(uint32_t code); 361 void printStopInfo(uint32_t code); 362 363 JS::ProfilingFrameIterator::RegisterState registerState(); 364 365 // Handle any wasm faults, returning true if the fault was handled. 366 // This method is rather hot so inline the normal (no-wasm) case. 367 bool MOZ_ALWAYS_INLINE handleWasmSegFault(uint64_t addr, unsigned numBytes) { 368 if (MOZ_LIKELY(!js::wasm::CodeExists)) { 369 return false; 370 } 371 372 uint8_t* newPC; 373 if (!js::wasm::MemoryAccessTraps(registerState(), (uint8_t*)addr, numBytes, 374 &newPC)) { 375 return false; 376 } 377 378 LLBit_ = false; 379 set_pc(int64_t(newPC)); 380 return true; 381 } 382 383 // Executes one instruction. 384 void instructionDecode(SimInstruction* instr); 385 // Execute one instruction placed in a branch delay slot. 386 void branchDelayInstructionDecode(SimInstruction* instr); 387 388 public: 389 static int64_t StopSimAt; 390 391 // Runtime call support. 392 static void* RedirectNativeFunction(void* nativeFunction, 393 ABIFunctionType type); 394 395 private: 396 enum Exception { 397 kNone, 398 kIntegerOverflow, 399 kIntegerUnderflow, 400 kDivideByZero, 401 kNumExceptions 402 }; 403 int16_t exceptions[kNumExceptions]; 404 405 // Exceptions. 406 void signalExceptions(); 407 408 // Handle return value for runtime FP functions. 409 void setCallResultDouble(double result); 410 void setCallResultFloat(float result); 411 void setCallResult(int64_t res); 412 # ifdef XP_DARWIN 413 // add a dedicated setCallResult for intptr_t on Darwin 414 void setCallResult(intptr_t res); 415 # endif 416 void setCallResult(__int128 res); 417 418 void callInternal(uint8_t* entry); 419 420 // Architecture state. 421 // Registers. 422 int64_t registers_[kNumSimuRegisters]; 423 // Coprocessor Registers. 424 int64_t FPUregisters_[kNumFPURegisters]; 425 // FPU control register. 426 uint32_t FCSR_; 427 428 bool LLBit_; 429 uintptr_t LLAddr_; 430 int64_t lastLLValue_; 431 432 // Simulator support. 433 char* stack_; 434 uintptr_t stackLimit_; 435 bool pc_modified_; 436 int64_t icount_; 437 int64_t break_count_; 438 439 // Debugger input. 440 char* lastDebuggerInput_; 441 442 // Registered breakpoints. 443 SimInstruction* break_pc_; 444 Instr break_instr_; 445 446 // Single-stepping support 447 bool single_stepping_; 448 SingleStepCallback single_step_callback_; 449 void* single_step_callback_arg_; 450 451 // A stop is watched if its code is less than kNumOfWatchedStops. 452 // Only watched stops support enabling/disabling and the counter feature. 453 static const uint32_t kNumOfWatchedStops = 256; 454 455 // Stop is disabled if bit 31 is set. 456 static const uint32_t kStopDisabledBit = 1U << 31; 457 458 // A stop is enabled, meaning the simulator will stop when meeting the 459 // instruction, if bit 31 of watchedStops_[code].count is unset. 460 // The value watchedStops_[code].count & ~(1 << 31) indicates how many times 461 // the breakpoint was hit or gone through. 462 struct StopCountAndDesc { 463 uint32_t count_; 464 char* desc_; 465 }; 466 StopCountAndDesc watchedStops_[kNumOfWatchedStops]; 467 }; 468 469 // Process wide simulator state. 470 class SimulatorProcess { 471 friend class Redirection; 472 friend class AutoLockSimulatorCache; 473 474 private: 475 // ICache checking. 476 struct ICacheHasher { 477 typedef void* Key; 478 typedef void* Lookup; 479 static HashNumber hash(const Lookup& l); 480 static bool match(const Key& k, const Lookup& l); 481 }; 482 483 public: 484 typedef HashMap<void*, CachePage*, ICacheHasher, SystemAllocPolicy> ICacheMap; 485 486 static mozilla::Atomic<size_t, mozilla::ReleaseAcquire> 487 ICacheCheckingDisableCount; 488 static void FlushICache(void* start, size_t size); 489 490 static void checkICacheLocked(SimInstruction* instr); 491 492 static bool initialize() { 493 singleton_ = js_new<SimulatorProcess>(); 494 return singleton_; 495 } 496 static void destroy() { 497 js_delete(singleton_); 498 singleton_ = nullptr; 499 } 500 501 SimulatorProcess(); 502 ~SimulatorProcess(); 503 504 private: 505 static SimulatorProcess* singleton_; 506 507 // This lock creates a critical section around 'redirection_' and 508 // 'icache_', which are referenced both by the execution engine 509 // and by the off-thread compiler (see Redirection::Get in the cpp file). 510 Mutex cacheLock_ MOZ_UNANNOTATED; 511 512 Redirection* redirection_; 513 ICacheMap icache_; 514 515 public: 516 static ICacheMap& icache() { 517 // Technically we need the lock to access the innards of the 518 // icache, not to take its address, but the latter condition 519 // serves as a useful complement to the former. 520 singleton_->cacheLock_.assertOwnedByCurrentThread(); 521 return singleton_->icache_; 522 } 523 524 static Redirection* redirection() { 525 singleton_->cacheLock_.assertOwnedByCurrentThread(); 526 return singleton_->redirection_; 527 } 528 529 static void setRedirection(js::jit::Redirection* redirection) { 530 singleton_->cacheLock_.assertOwnedByCurrentThread(); 531 singleton_->redirection_ = redirection; 532 } 533 }; 534 535 } // namespace jit 536 } // namespace js 537 538 #endif /* JS_SIMULATOR_MIPS64 */ 539 540 #endif /* jit_mips64_Simulator_mips64_h */