1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 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 "jslock.h" 35 36 #include "jit/arm/Architecture-arm.h" 37 #include "jit/arm/disasm/Disasm-arm.h" 38 #include "jit/IonTypes.h" 39 40 namespace js { 41 namespace jit { 42 43 class Simulator; 44 class Redirection; 45 class CachePage; 46 class AutoLockSimulator; 47 48 // When the SingleStepCallback is called, the simulator is about to execute 49 // sim->get_pc() and the current machine state represents the completed 50 // execution of the previous pc. 51 typedef void (*SingleStepCallback)(void* arg, Simulator* sim, void* pc); 52 53 // VFP rounding modes. See ARM DDI 0406B Page A2-29. 54 enum VFPRoundingMode { 55 SimRN = 0 << 22, // Round to Nearest. 56 SimRP = 1 << 22, // Round towards Plus Infinity. 57 SimRM = 2 << 22, // Round towards Minus Infinity. 58 SimRZ = 3 << 22, // Round towards zero. 59 60 // Aliases. 61 kRoundToNearest = SimRN, 62 kRoundToPlusInf = SimRP, 63 kRoundToMinusInf = SimRM, 64 kRoundToZero = SimRZ 65 }; 66 67 const uint32_t kVFPRoundingModeMask = 3 << 22; 68 69 typedef int32_t Instr; 70 class SimInstruction; 71 72 class Simulator 73 { 74 friend class Redirection; 75 friend class AutoLockSimulatorCache; 76 77 public: 78 friend class ArmDebugger; 79 enum Register { 80 no_reg = -1, 81 r0 = 0, r1, r2, r3, r4, r5, r6, r7, 82 r8, r9, r10, r11, r12, r13, r14, r15, 83 num_registers, 84 sp = 13, 85 lr = 14, 86 pc = 15, 87 s0 = 0, s1, s2, s3, s4, s5, s6, s7, 88 s8, s9, s10, s11, s12, s13, s14, s15, 89 s16, s17, s18, s19, s20, s21, s22, s23, 90 s24, s25, s26, s27, s28, s29, s30, s31, 91 num_s_registers = 32, 92 d0 = 0, d1, d2, d3, d4, d5, d6, d7, 93 d8, d9, d10, d11, d12, d13, d14, d15, 94 d16, d17, d18, d19, d20, d21, d22, d23, 95 d24, d25, d26, d27, d28, d29, d30, d31, 96 num_d_registers = 32, 97 q0 = 0, q1, q2, q3, q4, q5, q6, q7, 98 q8, q9, q10, q11, q12, q13, q14, q15, 99 num_q_registers = 16 100 }; 101 102 // Returns nullptr on OOM. 103 static Simulator* Create(); 104 105 static void Destroy(Simulator* simulator); 106 107 // Constructor/destructor are for internal use only; use the static methods above. 108 Simulator(); 109 ~Simulator(); 110 111 // The currently executing Simulator instance. Potentially there can be one 112 // for each native thread. 113 static Simulator* Current(); 114 StackLimit()115 static inline uintptr_t StackLimit() { 116 return Simulator::Current()->stackLimit(); 117 } 118 119 uintptr_t* addressOfStackLimit(); 120 121 // Accessors for register state. Reading the pc value adheres to the ARM 122 // architecture specification and is off by a 8 from the currently executing 123 // instruction. 124 void set_register(int reg, int32_t value); 125 int32_t get_register(int reg) const; 126 double get_double_from_register_pair(int reg); 127 void set_register_pair_from_double(int reg, double* value); 128 void set_dw_register(int dreg, const int* dbl); 129 130 // Support for VFP. 131 void get_d_register(int dreg, uint64_t* value); 132 void set_d_register(int dreg, const uint64_t* value); 133 void get_d_register(int dreg, uint32_t* value); 134 void set_d_register(int dreg, const uint32_t* value); 135 void get_q_register(int qreg, uint64_t* value); 136 void set_q_register(int qreg, const uint64_t* value); 137 void get_q_register(int qreg, uint32_t* value); 138 void set_q_register(int qreg, const uint32_t* value); 139 void set_s_register(int reg, unsigned int value); 140 unsigned int get_s_register(int reg) const; 141 set_d_register_from_double(int dreg,const double & dbl)142 void set_d_register_from_double(int dreg, const double& dbl) { 143 setVFPRegister<double, 2>(dreg, dbl); 144 } get_double_from_d_register(int dreg)145 double get_double_from_d_register(int dreg) { 146 return getFromVFPRegister<double, 2>(dreg); 147 } set_s_register_from_float(int sreg,const float flt)148 void set_s_register_from_float(int sreg, const float flt) { 149 setVFPRegister<float, 1>(sreg, flt); 150 } get_float_from_s_register(int sreg)151 float get_float_from_s_register(int sreg) { 152 return getFromVFPRegister<float, 1>(sreg); 153 } set_s_register_from_sinteger(int sreg,const int sint)154 void set_s_register_from_sinteger(int sreg, const int sint) { 155 setVFPRegister<int, 1>(sreg, sint); 156 } get_sinteger_from_s_register(int sreg)157 int get_sinteger_from_s_register(int sreg) { 158 return getFromVFPRegister<int, 1>(sreg); 159 } 160 161 // Special case of set_register and get_register to access the raw PC value. 162 void set_pc(int32_t value); 163 int32_t get_pc() const; 164 165 template <typename T> get_pc_as()166 T get_pc_as() const { return reinterpret_cast<T>(get_pc()); } 167 set_resume_pc(void * value)168 void set_resume_pc(void* value) { 169 resume_pc_ = int32_t(value); 170 } 171 172 void enable_single_stepping(SingleStepCallback cb, void* arg); 173 void disable_single_stepping(); 174 175 uintptr_t stackLimit() const; 176 bool overRecursed(uintptr_t newsp = 0) const; 177 bool overRecursedWithExtra(uint32_t extra) const; 178 179 // Executes ARM instructions until the PC reaches end_sim_pc. 180 template<bool EnableStopSimAt> 181 void execute(); 182 183 // Sets up the simulator state and grabs the result on return. 184 int32_t call(uint8_t* entry, int argument_count, ...); 185 186 // Debugger input. 187 void setLastDebuggerInput(char* input); lastDebuggerInput()188 char* lastDebuggerInput() { return lastDebuggerInput_; } 189 190 // Returns true if pc register contains one of the 'special_values' defined 191 // below (bad_lr, end_sim_pc). 192 bool has_bad_pc() const; 193 194 private: 195 enum special_values { 196 // Known bad pc value to ensure that the simulator does not execute 197 // without being properly setup. 198 bad_lr = -1, 199 // A pc value used to signal the simulator to stop execution. Generally 200 // the lr is set to this value on transition from native C code to 201 // simulated execution, so that the simulator can "return" to the native 202 // C code. 203 end_sim_pc = -2 204 }; 205 206 bool init(); 207 208 // Checks if the current instruction should be executed based on its 209 // condition bits. 210 inline bool conditionallyExecute(SimInstruction* instr); 211 212 // Helper functions to set the conditional flags in the architecture state. 213 void setNZFlags(int32_t val); 214 void setCFlag(bool val); 215 void setVFlag(bool val); 216 bool carryFrom(int32_t left, int32_t right, int32_t carry = 0); 217 bool borrowFrom(int32_t left, int32_t right); 218 bool overflowFrom(int32_t alu_out, int32_t left, int32_t right, bool addition); 219 getCarry()220 inline int getCarry() { return c_flag_ ? 1 : 0; }; 221 222 // Support for VFP. 223 void compute_FPSCR_Flags(double val1, double val2); 224 void copy_FPSCR_to_APSR(); 225 inline double canonicalizeNaN(double value); 226 227 // Helper functions to decode common "addressing" modes 228 int32_t getShiftRm(SimInstruction* instr, bool* carry_out); 229 int32_t getImm(SimInstruction* instr, bool* carry_out); 230 int32_t processPU(SimInstruction* instr, int num_regs, int operand_size, 231 intptr_t* start_address, intptr_t* end_address); 232 void handleRList(SimInstruction* instr, bool load); 233 void handleVList(SimInstruction* inst); 234 void softwareInterrupt(SimInstruction* instr); 235 236 // Stop helper functions. 237 inline bool isStopInstruction(SimInstruction* instr); 238 inline bool isWatchedStop(uint32_t bkpt_code); 239 inline bool isEnabledStop(uint32_t bkpt_code); 240 inline void enableStop(uint32_t bkpt_code); 241 inline void disableStop(uint32_t bkpt_code); 242 inline void increaseStopCounter(uint32_t bkpt_code); 243 void printStopInfo(uint32_t code); 244 245 // Read and write memory. 246 inline uint8_t readBU(int32_t addr); 247 inline int8_t readB(int32_t addr); 248 inline void writeB(int32_t addr, uint8_t value); 249 inline void writeB(int32_t addr, int8_t value); 250 251 inline uint8_t readExBU(int32_t addr); 252 inline int32_t writeExB(int32_t addr, uint8_t value); 253 254 inline uint16_t readHU(int32_t addr, SimInstruction* instr); 255 inline int16_t readH(int32_t addr, SimInstruction* instr); 256 // Note: Overloaded on the sign of the value. 257 inline void writeH(int32_t addr, uint16_t value, SimInstruction* instr); 258 inline void writeH(int32_t addr, int16_t value, SimInstruction* instr); 259 260 inline uint16_t readExHU(int32_t addr, SimInstruction* instr); 261 inline int32_t writeExH(int32_t addr, uint16_t value, SimInstruction* instr); 262 263 inline int readW(int32_t addr, SimInstruction* instr); 264 inline void writeW(int32_t addr, int value, SimInstruction* instr); 265 266 inline int readExW(int32_t addr, SimInstruction* instr); 267 inline int writeExW(int32_t addr, int value, SimInstruction* instr); 268 269 int32_t* readDW(int32_t addr); 270 void writeDW(int32_t addr, int32_t value1, int32_t value2); 271 272 int32_t readExDW(int32_t addr, int32_t* hibits); 273 int32_t writeExDW(int32_t addr, int32_t value1, int32_t value2); 274 275 // Executing is handled based on the instruction type. 276 // Both type 0 and type 1 rolled into one. 277 void decodeType01(SimInstruction* instr); 278 void decodeType2(SimInstruction* instr); 279 void decodeType3(SimInstruction* instr); 280 void decodeType4(SimInstruction* instr); 281 void decodeType5(SimInstruction* instr); 282 void decodeType6(SimInstruction* instr); 283 void decodeType7(SimInstruction* instr); 284 285 // Support for VFP. 286 void decodeTypeVFP(SimInstruction* instr); 287 void decodeType6CoprocessorIns(SimInstruction* instr); 288 void decodeSpecialCondition(SimInstruction* instr); 289 290 void decodeVMOVBetweenCoreAndSinglePrecisionRegisters(SimInstruction* instr); 291 void decodeVCMP(SimInstruction* instr); 292 void decodeVCVTBetweenDoubleAndSingle(SimInstruction* instr); 293 void decodeVCVTBetweenFloatingPointAndInteger(SimInstruction* instr); 294 void decodeVCVTBetweenFloatingPointAndIntegerFrac(SimInstruction* instr); 295 296 // Support for some system functions. 297 void decodeType7CoprocessorIns(SimInstruction* instr); 298 299 // Executes one instruction. 300 void instructionDecode(SimInstruction* instr); 301 302 public: 303 static bool ICacheCheckingEnabled; 304 static void FlushICache(void* start, size_t size); 305 306 static int64_t StopSimAt; 307 308 // For testing the MoveResolver code, a MoveResolver is set up, and 309 // the VFP registers are loaded with pre-determined values, 310 // then the sequence of code is simulated. In order to test this with the 311 // simulator, the callee-saved registers can't be trashed. This flag 312 // disables that feature. 313 bool skipCalleeSavedRegsCheck; 314 315 // Runtime call support. 316 static void* RedirectNativeFunction(void* nativeFunction, ABIFunctionType type); 317 318 private: 319 // Handle arguments and return value for runtime FP functions. 320 void getFpArgs(double* x, double* y, int32_t* z); 321 void getFpFromStack(int32_t* stack, double* x1); 322 void setCallResultDouble(double result); 323 void setCallResultFloat(float result); 324 void setCallResult(int64_t res); 325 void scratchVolatileRegisters(bool scratchFloat = true); 326 327 template<class ReturnType, int register_size> 328 ReturnType getFromVFPRegister(int reg_index); 329 330 template<class InputType, int register_size> 331 void setVFPRegister(int reg_index, const InputType& value); 332 333 void callInternal(uint8_t* entry); 334 335 // Architecture state. 336 // Saturating instructions require a Q flag to indicate saturation. 337 // There is currently no way to read the CPSR directly, and thus read the Q 338 // flag, so this is left unimplemented. 339 int32_t registers_[16]; 340 bool n_flag_; 341 bool z_flag_; 342 bool c_flag_; 343 bool v_flag_; 344 345 // VFP architecture state. 346 uint32_t vfp_registers_[num_d_registers * 2]; 347 bool n_flag_FPSCR_; 348 bool z_flag_FPSCR_; 349 bool c_flag_FPSCR_; 350 bool v_flag_FPSCR_; 351 352 // VFP rounding mode. See ARM DDI 0406B Page A2-29. 353 VFPRoundingMode FPSCR_rounding_mode_; 354 bool FPSCR_default_NaN_mode_; 355 356 // VFP FP exception flags architecture state. 357 bool inv_op_vfp_flag_; 358 bool div_zero_vfp_flag_; 359 bool overflow_vfp_flag_; 360 bool underflow_vfp_flag_; 361 bool inexact_vfp_flag_; 362 363 // Simulator support. 364 char* stack_; 365 uintptr_t stackLimit_; 366 bool pc_modified_; 367 int64_t icount_; 368 369 int32_t resume_pc_; 370 371 // Debugger input. 372 char* lastDebuggerInput_; 373 374 // Registered breakpoints. 375 SimInstruction* break_pc_; 376 Instr break_instr_; 377 378 // Single-stepping support 379 bool single_stepping_; 380 SingleStepCallback single_step_callback_; 381 void* single_step_callback_arg_; 382 383 // A stop is watched if its code is less than kNumOfWatchedStops. 384 // Only watched stops support enabling/disabling and the counter feature. 385 static const uint32_t kNumOfWatchedStops = 256; 386 387 // Breakpoint is disabled if bit 31 is set. 388 static const uint32_t kStopDisabledBit = 1 << 31; 389 390 // A stop is enabled, meaning the simulator will stop when meeting the 391 // instruction, if bit 31 of watched_stops_[code].count is unset. 392 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times 393 // the breakpoint was hit or gone through. 394 struct StopCountAndDesc { 395 uint32_t count; 396 char* desc; 397 }; 398 StopCountAndDesc watched_stops_[kNumOfWatchedStops]; 399 400 public: icount()401 int64_t icount() { 402 return icount_; 403 } 404 405 private: 406 // ICache checking. 407 struct ICacheHasher { 408 typedef void* Key; 409 typedef void* Lookup; 410 static HashNumber hash(const Lookup& l); 411 static bool match(const Key& k, const Lookup& l); 412 }; 413 414 public: 415 typedef HashMap<void*, CachePage*, ICacheHasher, SystemAllocPolicy> ICacheMap; 416 417 private: 418 // This lock creates a critical section around 'redirection_' and 419 // 'icache_', which are referenced both by the execution engine 420 // and by the off-thread compiler (see Redirection::Get in the cpp file). 421 PRLock* cacheLock_; 422 #ifdef DEBUG 423 PRThread* cacheLockHolder_; 424 #endif 425 426 Redirection* redirection_; 427 ICacheMap icache_; 428 429 public: icache()430 ICacheMap& icache() { 431 // Technically we need the lock to access the innards of the 432 // icache, not to take its address, but the latter condition 433 // serves as a useful complement to the former. 434 MOZ_ASSERT(cacheLockHolder_); 435 return icache_; 436 } 437 redirection()438 Redirection* redirection() const { 439 MOZ_ASSERT(cacheLockHolder_); 440 return redirection_; 441 } 442 setRedirection(js::jit::Redirection * redirection)443 void setRedirection(js::jit::Redirection* redirection) { 444 MOZ_ASSERT(cacheLockHolder_); 445 redirection_ = redirection; 446 } 447 448 private: 449 // Exclusive access monitor 450 void exclusiveMonitorSet(uint64_t value); 451 uint64_t exclusiveMonitorGetAndClear(bool* held); 452 void exclusiveMonitorClear(); 453 454 bool exclusiveMonitorHeld_; 455 uint64_t exclusiveMonitor_; 456 }; 457 458 #define JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, onerror) \ 459 JS_BEGIN_MACRO \ 460 if (cx->runtime()->simulator()->overRecursedWithExtra(extra)) { \ 461 js::ReportOverRecursed(cx); \ 462 onerror; \ 463 } \ 464 JS_END_MACRO 465 466 } // namespace jit 467 } // namespace js 468 469 #endif /* JS_SIMULATOR_ARM */ 470 471 #endif /* jit_arm_Simulator_arm_h */ 472