Simulator-arm.h (19231B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 // Copyright 2012 the V8 project authors. All rights reserved. 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following 11 // disclaimer in the documentation and/or other materials provided 12 // with the distribution. 13 // * Neither the name of Google Inc. nor the names of its 14 // contributors may be used to endorse or promote products derived 15 // from this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #ifndef jit_arm_Simulator_arm_h 30 #define jit_arm_Simulator_arm_h 31 32 #ifdef JS_SIMULATOR_ARM 33 34 # include "mozilla/Atomics.h" 35 36 # include "jit/arm/Architecture-arm.h" 37 # include "jit/arm/disasm/Disasm-arm.h" 38 # include "jit/IonTypes.h" 39 # include "js/AllocPolicy.h" 40 # include "js/ProfilingFrameIterator.h" 41 # include "threading/Thread.h" 42 # include "vm/MutexIDs.h" 43 # include "wasm/WasmSignalHandlers.h" 44 45 namespace js { 46 namespace jit { 47 48 class JitActivation; 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 using SingleStepCallback = void (*)(void* arg, Simulator* sim, void* pc); 58 59 // VFP rounding modes. See ARM DDI 0406B Page A2-29. 60 enum VFPRoundingMode { 61 SimRN = 0 << 22, // Round to Nearest. 62 SimRP = 1 << 22, // Round towards Plus Infinity. 63 SimRM = 2 << 22, // Round towards Minus Infinity. 64 SimRZ = 3 << 22, // Round towards zero. 65 66 // Aliases. 67 kRoundToNearest = SimRN, 68 kRoundToPlusInf = SimRP, 69 kRoundToMinusInf = SimRM, 70 kRoundToZero = SimRZ 71 }; 72 73 const uint32_t kVFPRoundingModeMask = 3 << 22; 74 75 using Instr = int32_t; 76 class SimInstruction; 77 78 // Per thread simulator state. 79 class Simulator { 80 public: 81 friend class ArmDebugger; 82 enum Register { 83 no_reg = -1, 84 r0 = 0, 85 r1, 86 r2, 87 r3, 88 r4, 89 r5, 90 r6, 91 r7, 92 r8, 93 r9, 94 r10, 95 r11, 96 r12, 97 r13, 98 r14, 99 r15, 100 num_registers, 101 fp = 11, 102 ip = 12, 103 sp = 13, 104 lr = 14, 105 pc = 15, 106 s0 = 0, 107 s1, 108 s2, 109 s3, 110 s4, 111 s5, 112 s6, 113 s7, 114 s8, 115 s9, 116 s10, 117 s11, 118 s12, 119 s13, 120 s14, 121 s15, 122 s16, 123 s17, 124 s18, 125 s19, 126 s20, 127 s21, 128 s22, 129 s23, 130 s24, 131 s25, 132 s26, 133 s27, 134 s28, 135 s29, 136 s30, 137 s31, 138 num_s_registers = 32, 139 d0 = 0, 140 d1, 141 d2, 142 d3, 143 d4, 144 d5, 145 d6, 146 d7, 147 d8, 148 d9, 149 d10, 150 d11, 151 d12, 152 d13, 153 d14, 154 d15, 155 d16, 156 d17, 157 d18, 158 d19, 159 d20, 160 d21, 161 d22, 162 d23, 163 d24, 164 d25, 165 d26, 166 d27, 167 d28, 168 d29, 169 d30, 170 d31, 171 num_d_registers = 32, 172 q0 = 0, 173 q1, 174 q2, 175 q3, 176 q4, 177 q5, 178 q6, 179 q7, 180 q8, 181 q9, 182 q10, 183 q11, 184 q12, 185 q13, 186 q14, 187 q15, 188 num_q_registers = 16 189 }; 190 191 // Returns nullptr on OOM. 192 static Simulator* Create(); 193 194 static void Destroy(Simulator* simulator); 195 196 // Constructor/destructor are for internal use only; use the static methods 197 // above. 198 Simulator(); 199 ~Simulator(); 200 201 // The currently executing Simulator instance. Potentially there can be one 202 // for each native thread. 203 static Simulator* Current(); 204 205 static uintptr_t StackLimit() { return Simulator::Current()->stackLimit(); } 206 207 // Disassemble some instructions starting at instr and print them 208 // on stdout. Useful for working within GDB after a MOZ_CRASH(), 209 // among other things. 210 // 211 // Typical use within a crashed instruction decoding method is simply: 212 // 213 // call Simulator::disassemble(instr, 1) 214 // 215 // or use one of the more convenient inline methods below. 216 static void disassemble(SimInstruction* instr, size_t n); 217 218 // Disassemble one instruction. 219 // "call disasm(instr)" 220 void disasm(SimInstruction* instr); 221 222 // Disassemble n instructions starting at instr. 223 // "call disasm(instr, 3)" 224 void disasm(SimInstruction* instr, size_t n); 225 226 // Skip backwards m instructions before starting, then disassemble n 227 // instructions. 228 // "call disasm(instr, 3, 7)" 229 void disasm(SimInstruction* instr, size_t m, size_t n); 230 231 uintptr_t* addressOfStackLimit(); 232 233 // Accessors for register state. Reading the pc value adheres to the ARM 234 // architecture specification and is off by a 8 from the currently executing 235 // instruction. 236 void set_register(int reg, int32_t value); 237 int32_t get_register(int reg) const; 238 double get_double_from_register_pair(int reg); 239 void set_register_pair_from_double(int reg, double* value); 240 void set_dw_register(int dreg, const int* dbl); 241 242 // Support for VFP. 243 void get_d_register(int dreg, uint64_t* value); 244 void set_d_register(int dreg, const uint64_t* value); 245 void get_d_register(int dreg, uint32_t* value); 246 void set_d_register(int dreg, const uint32_t* value); 247 void get_q_register(int qreg, uint64_t* value); 248 void set_q_register(int qreg, const uint64_t* value); 249 void get_q_register(int qreg, uint32_t* value); 250 void set_q_register(int qreg, const uint32_t* value); 251 void set_s_register(int reg, unsigned int value); 252 unsigned int get_s_register(int reg) const; 253 254 void set_d_register_from_double(int dreg, const double& dbl) { 255 setVFPRegister<double, 2>(dreg, dbl); 256 } 257 void get_double_from_d_register(int dreg, double* out) { 258 getFromVFPRegister<double, 2>(dreg, out); 259 } 260 void set_s_register_from_float(int sreg, const float flt) { 261 setVFPRegister<float, 1>(sreg, flt); 262 } 263 void get_float_from_s_register(int sreg, float* out) { 264 getFromVFPRegister<float, 1>(sreg, out); 265 } 266 void set_s_register_from_sinteger(int sreg, const int sint) { 267 setVFPRegister<int, 1>(sreg, sint); 268 } 269 int get_sinteger_from_s_register(int sreg) { 270 int ret; 271 getFromVFPRegister<int, 1>(sreg, &ret); 272 return ret; 273 } 274 275 // Special case of set_register and get_register to access the raw PC value. 276 void set_pc(int32_t value); 277 int32_t get_pc() const; 278 279 template <typename T> 280 T get_pc_as() const { 281 return reinterpret_cast<T>(get_pc()); 282 } 283 284 void enable_single_stepping(SingleStepCallback cb, void* arg); 285 void disable_single_stepping(); 286 287 uintptr_t stackLimit() const; 288 bool overRecursed(uintptr_t newsp = 0) const; 289 bool overRecursedWithExtra(uint32_t extra) const; 290 291 // Executes ARM instructions until the PC reaches end_sim_pc. 292 template <bool EnableStopSimAt> 293 void execute(); 294 295 // Sets up the simulator state and grabs the result on return. 296 int32_t call(uint8_t* entry, int argument_count, ...); 297 298 // Debugger input. 299 void setLastDebuggerInput(char* input); 300 char* lastDebuggerInput() { return lastDebuggerInput_; } 301 302 // Returns true if pc register contains one of the 'special_values' defined 303 // below (bad_lr, end_sim_pc). 304 bool has_bad_pc() const; 305 306 private: 307 enum special_values { 308 // Known bad pc value to ensure that the simulator does not execute 309 // without being properly setup. 310 bad_lr = -1, 311 // A pc value used to signal the simulator to stop execution. Generally 312 // the lr is set to this value on transition from native C code to 313 // simulated execution, so that the simulator can "return" to the native 314 // C code. 315 end_sim_pc = -2 316 }; 317 318 // ForbidUnaligned means "always fault on unaligned access". 319 // 320 // AllowUnaligned means "allow the unaligned access if other conditions are 321 // met". The "other conditions" vary with the instruction: For all 322 // instructions the base condition is !ARMFlags::HasAlignmentFault(), ie, the 323 // chip is configured to allow unaligned accesses. For instructions like VLD1 324 // there is an additional constraint that the alignment attribute in the 325 // instruction must be set to "default alignment". 326 327 enum UnalignedPolicy { ForbidUnaligned, AllowUnaligned }; 328 329 bool init(); 330 331 // Checks if the current instruction should be executed based on its 332 // condition bits. 333 inline bool conditionallyExecute(SimInstruction* instr); 334 335 // Helper functions to set the conditional flags in the architecture state. 336 void setNZFlags(int32_t val); 337 void setCFlag(bool val); 338 void setVFlag(bool val); 339 bool carryFrom(int32_t left, int32_t right, int32_t carry = 0); 340 bool borrowFrom(int32_t left, int32_t right); 341 bool overflowFrom(int32_t alu_out, int32_t left, int32_t right, 342 bool addition); 343 344 inline int getCarry() { return c_flag_ ? 1 : 0; }; 345 346 // Support for VFP. 347 void compute_FPSCR_Flags(double val1, double val2); 348 void copy_FPSCR_to_APSR(); 349 inline void canonicalizeNaN(double* value); 350 inline void canonicalizeNaN(float* value); 351 352 // Helper functions to decode common "addressing" modes 353 int32_t getShiftRm(SimInstruction* instr, bool* carry_out); 354 int32_t getImm(SimInstruction* instr, bool* carry_out); 355 int32_t processPU(SimInstruction* instr, int num_regs, int operand_size, 356 intptr_t* start_address, intptr_t* end_address); 357 void handleRList(SimInstruction* instr, bool load); 358 void handleVList(SimInstruction* inst); 359 void softwareInterrupt(SimInstruction* instr); 360 361 // Stop helper functions. 362 inline bool isStopInstruction(SimInstruction* instr); 363 inline bool isWatchedStop(uint32_t bkpt_code); 364 inline bool isEnabledStop(uint32_t bkpt_code); 365 inline void enableStop(uint32_t bkpt_code); 366 inline void disableStop(uint32_t bkpt_code); 367 inline void increaseStopCounter(uint32_t bkpt_code); 368 void printStopInfo(uint32_t code); 369 370 // Handle a wasm interrupt triggered by an async signal handler. 371 JS::ProfilingFrameIterator::RegisterState registerState(); 372 373 // Handle any wasm faults, returning true if the fault was handled. 374 // This method is rather hot so inline the normal (no-wasm) case. 375 bool MOZ_ALWAYS_INLINE handleWasmSegFault(int32_t addr, unsigned numBytes) { 376 if (MOZ_LIKELY(!wasm::CodeExists)) { 377 return false; 378 } 379 380 uint8_t* newPC; 381 if (!wasm::MemoryAccessTraps(registerState(), (uint8_t*)addr, numBytes, 382 &newPC)) { 383 return false; 384 } 385 386 set_pc(int32_t(newPC)); 387 return true; 388 } 389 390 // Read and write memory. 391 inline uint8_t readBU(int32_t addr); 392 inline int8_t readB(int32_t addr); 393 inline void writeB(int32_t addr, uint8_t value); 394 inline void writeB(int32_t addr, int8_t value); 395 396 inline uint8_t readExBU(int32_t addr); 397 inline int32_t writeExB(int32_t addr, uint8_t value); 398 399 inline uint16_t readHU(int32_t addr, SimInstruction* instr); 400 inline int16_t readH(int32_t addr, SimInstruction* instr); 401 // Note: Overloaded on the sign of the value. 402 inline void writeH(int32_t addr, uint16_t value, SimInstruction* instr); 403 inline void writeH(int32_t addr, int16_t value, SimInstruction* instr); 404 405 inline uint16_t readExHU(int32_t addr, SimInstruction* instr); 406 inline int32_t writeExH(int32_t addr, uint16_t value, SimInstruction* instr); 407 408 inline int readW(int32_t addr, SimInstruction* instr, 409 UnalignedPolicy f = ForbidUnaligned); 410 inline void writeW(int32_t addr, int value, SimInstruction* instr, 411 UnalignedPolicy f = ForbidUnaligned); 412 413 inline uint64_t readQ(int32_t addr, SimInstruction* instr, 414 UnalignedPolicy f = ForbidUnaligned); 415 inline void writeQ(int32_t addr, uint64_t value, SimInstruction* instr, 416 UnalignedPolicy f = ForbidUnaligned); 417 418 inline int readExW(int32_t addr, SimInstruction* instr); 419 inline int writeExW(int32_t addr, int value, SimInstruction* instr); 420 421 int32_t* readDW(int32_t addr); 422 void writeDW(int32_t addr, int32_t value1, int32_t value2); 423 424 int32_t readExDW(int32_t addr, int32_t* hibits); 425 int32_t writeExDW(int32_t addr, int32_t value1, int32_t value2); 426 427 // Executing is handled based on the instruction type. 428 // Both type 0 and type 1 rolled into one. 429 void decodeType01(SimInstruction* instr); 430 void decodeType2(SimInstruction* instr); 431 void decodeType3(SimInstruction* instr); 432 void decodeType4(SimInstruction* instr); 433 void decodeType5(SimInstruction* instr); 434 void decodeType6(SimInstruction* instr); 435 void decodeType7(SimInstruction* instr); 436 437 // Support for VFP. 438 void decodeTypeVFP(SimInstruction* instr); 439 void decodeType6CoprocessorIns(SimInstruction* instr); 440 void decodeSpecialCondition(SimInstruction* instr); 441 442 void decodeVMOVBetweenCoreAndSinglePrecisionRegisters(SimInstruction* instr); 443 void decodeVCMP(SimInstruction* instr); 444 void decodeVCVTBetweenDoubleAndSingle(SimInstruction* instr); 445 void decodeVCVTBetweenFloatingPointAndInteger(SimInstruction* instr); 446 void decodeVCVTBetweenFloatingPointAndIntegerFrac(SimInstruction* instr); 447 void decodeVCVTBetweenFloatingPointAndHalf(SimInstruction* instr); 448 449 // Support for some system functions. 450 void decodeType7CoprocessorIns(SimInstruction* instr); 451 452 // Executes one instruction. 453 void instructionDecode(SimInstruction* instr); 454 455 public: 456 static int64_t StopSimAt; 457 458 // For testing the MoveResolver code, a MoveResolver is set up, and 459 // the VFP registers are loaded with pre-determined values, 460 // then the sequence of code is simulated. In order to test this with the 461 // simulator, the callee-saved registers can't be trashed. This flag 462 // disables that feature. 463 bool skipCalleeSavedRegsCheck; 464 465 // Runtime call support. 466 static void* RedirectNativeFunction(void* nativeFunction, 467 ABIFunctionType type); 468 469 private: 470 // Handle arguments and return value for runtime FP functions. 471 void getFpArgs(double* x, double* y, int32_t* z); 472 void getFpFromStack(int32_t* stack, double* x1); 473 void setCallResultDouble(double result); 474 void setCallResultFloat(float result); 475 void setCallResult(int64_t res); 476 void scratchVolatileRegisters(void* target = nullptr); 477 478 template <class ReturnType, int register_size> 479 void getFromVFPRegister(int reg_index, ReturnType* out); 480 481 template <class InputType, int register_size> 482 void setVFPRegister(int reg_index, const InputType& value); 483 484 void callInternal(uint8_t* entry); 485 486 // Architecture state. 487 // Saturating instructions require a Q flag to indicate saturation. 488 // There is currently no way to read the CPSR directly, and thus read the Q 489 // flag, so this is left unimplemented. 490 int32_t registers_[16]; 491 bool n_flag_; 492 bool z_flag_; 493 bool c_flag_; 494 bool v_flag_; 495 496 // VFP architecture state. 497 uint32_t vfp_registers_[num_d_registers * 2]; 498 bool n_flag_FPSCR_; 499 bool z_flag_FPSCR_; 500 bool c_flag_FPSCR_; 501 bool v_flag_FPSCR_; 502 503 // VFP rounding mode. See ARM DDI 0406B Page A2-29. 504 VFPRoundingMode FPSCR_rounding_mode_; 505 bool FPSCR_default_NaN_mode_; 506 507 // VFP FP exception flags architecture state. 508 bool inv_op_vfp_flag_; 509 bool div_zero_vfp_flag_; 510 bool overflow_vfp_flag_; 511 bool underflow_vfp_flag_; 512 bool inexact_vfp_flag_; 513 514 // Simulator support. 515 char* stack_; 516 uintptr_t stackLimit_; 517 bool pc_modified_; 518 int64_t icount_; 519 520 // Debugger input. 521 char* lastDebuggerInput_; 522 523 // Registered breakpoints. 524 SimInstruction* break_pc_; 525 Instr break_instr_; 526 527 // Single-stepping support 528 bool single_stepping_; 529 SingleStepCallback single_step_callback_; 530 void* single_step_callback_arg_; 531 532 // A stop is watched if its code is less than kNumOfWatchedStops. 533 // Only watched stops support enabling/disabling and the counter feature. 534 static const uint32_t kNumOfWatchedStops = 256; 535 536 // Breakpoint is disabled if bit 31 is set. 537 static const uint32_t kStopDisabledBit = 1 << 31; 538 539 // A stop is enabled, meaning the simulator will stop when meeting the 540 // instruction, if bit 31 of watched_stops_[code].count is unset. 541 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times 542 // the breakpoint was hit or gone through. 543 struct StopCountAndDesc { 544 uint32_t count; 545 char* desc; 546 }; 547 StopCountAndDesc watched_stops_[kNumOfWatchedStops]; 548 549 public: 550 int64_t icount() { return icount_; } 551 552 private: 553 // Exclusive access monitor 554 void exclusiveMonitorSet(uint64_t value); 555 uint64_t exclusiveMonitorGetAndClear(bool* held); 556 void exclusiveMonitorClear(); 557 558 bool exclusiveMonitorHeld_; 559 uint64_t exclusiveMonitor_; 560 }; 561 562 // Process wide simulator state. 563 class SimulatorProcess { 564 friend class Redirection; 565 friend class AutoLockSimulatorCache; 566 567 private: 568 // ICache checking. 569 struct ICacheHasher { 570 using Key = void*; 571 using Lookup = void*; 572 static HashNumber hash(const Lookup& l); 573 static bool match(const Key& k, const Lookup& l); 574 }; 575 576 public: 577 using ICacheMap = HashMap<void*, CachePage*, ICacheHasher, SystemAllocPolicy>; 578 579 static mozilla::Atomic<size_t, mozilla::ReleaseAcquire> 580 ICacheCheckingDisableCount; 581 static void FlushICache(void* start, size_t size); 582 583 static void checkICacheLocked(SimInstruction* instr); 584 585 static bool initialize() { 586 singleton_ = js_new<SimulatorProcess>(); 587 return singleton_; 588 } 589 static void destroy() { 590 js_delete(singleton_); 591 singleton_ = nullptr; 592 } 593 594 SimulatorProcess(); 595 ~SimulatorProcess(); 596 597 private: 598 static SimulatorProcess* singleton_; 599 600 // This lock creates a critical section around 'redirection_' and 601 // 'icache_', which are referenced both by the execution engine 602 // and by the off-thread compiler (see Redirection::Get in the cpp file). 603 Mutex cacheLock_ MOZ_UNANNOTATED; 604 605 Redirection* redirection_; 606 ICacheMap icache_; 607 608 public: 609 static ICacheMap& icache() { 610 // Technically we need the lock to access the innards of the 611 // icache, not to take its address, but the latter condition 612 // serves as a useful complement to the former. 613 singleton_->cacheLock_.assertOwnedByCurrentThread(); 614 return singleton_->icache_; 615 } 616 617 static Redirection* redirection() { 618 singleton_->cacheLock_.assertOwnedByCurrentThread(); 619 return singleton_->redirection_; 620 } 621 622 static void setRedirection(js::jit::Redirection* redirection) { 623 singleton_->cacheLock_.assertOwnedByCurrentThread(); 624 singleton_->redirection_ = redirection; 625 } 626 }; 627 628 } // namespace jit 629 } // namespace js 630 631 #endif /* JS_SIMULATOR_ARM */ 632 633 #endif /* jit_arm_Simulator_arm_h */