1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 6 // Declares a Simulator for ARM instructions if we are not generating a native 7 // ARM binary. This Simulator allows us to run and debug ARM code generation on 8 // regular desktop machines. 9 // V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro, 10 // which will start execution in the Simulator or forwards to the real entry 11 // on a ARM HW platform. 12 13 #ifndef V8_ARM_SIMULATOR_ARM_H_ 14 #define V8_ARM_SIMULATOR_ARM_H_ 15 16 #include "src/allocation.h" 17 18 #if !defined(USE_SIMULATOR) 19 // Running without a simulator on a native arm platform. 20 21 namespace v8 { 22 namespace internal { 23 24 // When running without a simulator we call the entry directly. 25 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \ 26 (entry(p0, p1, p2, p3, p4)) 27 28 typedef int (*arm_regexp_matcher)(String*, int, const byte*, const byte*, 29 void*, int*, int, Address, int, Isolate*); 30 31 32 // Call the generated regexp code directly. The code at the entry address 33 // should act as a function matching the type arm_regexp_matcher. 34 // The fifth argument is a dummy that reserves the space used for 35 // the return address added by the ExitFrame in native calls. 36 #define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \ 37 p7, p8) \ 38 (FUNCTION_CAST<arm_regexp_matcher>(entry)(p0, p1, p2, p3, NULL, p4, p5, p6, \ 39 p7, p8)) 40 41 // The stack limit beyond which we will throw stack overflow errors in 42 // generated code. Because generated code on arm uses the C stack, we 43 // just use the C stack limit. 44 class SimulatorStack : public v8::internal::AllStatic { 45 public: JsLimitFromCLimit(v8::internal::Isolate * isolate,uintptr_t c_limit)46 static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate, 47 uintptr_t c_limit) { 48 USE(isolate); 49 return c_limit; 50 } 51 RegisterCTryCatch(v8::internal::Isolate * isolate,uintptr_t try_catch_address)52 static inline uintptr_t RegisterCTryCatch(v8::internal::Isolate* isolate, 53 uintptr_t try_catch_address) { 54 USE(isolate); 55 return try_catch_address; 56 } 57 UnregisterCTryCatch(v8::internal::Isolate * isolate)58 static inline void UnregisterCTryCatch(v8::internal::Isolate* isolate) { 59 USE(isolate); 60 } 61 }; 62 63 } // namespace internal 64 } // namespace v8 65 66 #else // !defined(USE_SIMULATOR) 67 // Running with a simulator. 68 69 #include "src/arm/constants-arm.h" 70 #include "src/assembler.h" 71 #include "src/hashmap.h" 72 73 namespace v8 { 74 namespace internal { 75 76 class CachePage { 77 public: 78 static const int LINE_VALID = 0; 79 static const int LINE_INVALID = 1; 80 81 static const int kPageShift = 12; 82 static const int kPageSize = 1 << kPageShift; 83 static const int kPageMask = kPageSize - 1; 84 static const int kLineShift = 2; // The cache line is only 4 bytes right now. 85 static const int kLineLength = 1 << kLineShift; 86 static const int kLineMask = kLineLength - 1; 87 CachePage()88 CachePage() { 89 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); 90 } 91 ValidityByte(int offset)92 char* ValidityByte(int offset) { 93 return &validity_map_[offset >> kLineShift]; 94 } 95 CachedData(int offset)96 char* CachedData(int offset) { 97 return &data_[offset]; 98 } 99 100 private: 101 char data_[kPageSize]; // The cached data. 102 static const int kValidityMapSize = kPageSize >> kLineShift; 103 char validity_map_[kValidityMapSize]; // One byte per line. 104 }; 105 106 107 class Simulator { 108 public: 109 friend class ArmDebugger; 110 enum Register { 111 no_reg = -1, 112 r0 = 0, r1, r2, r3, r4, r5, r6, r7, 113 r8, r9, r10, r11, r12, r13, r14, r15, 114 num_registers, 115 sp = 13, 116 lr = 14, 117 pc = 15, 118 s0 = 0, s1, s2, s3, s4, s5, s6, s7, 119 s8, s9, s10, s11, s12, s13, s14, s15, 120 s16, s17, s18, s19, s20, s21, s22, s23, 121 s24, s25, s26, s27, s28, s29, s30, s31, 122 num_s_registers = 32, 123 d0 = 0, d1, d2, d3, d4, d5, d6, d7, 124 d8, d9, d10, d11, d12, d13, d14, d15, 125 d16, d17, d18, d19, d20, d21, d22, d23, 126 d24, d25, d26, d27, d28, d29, d30, d31, 127 num_d_registers = 32, 128 q0 = 0, q1, q2, q3, q4, q5, q6, q7, 129 q8, q9, q10, q11, q12, q13, q14, q15, 130 num_q_registers = 16 131 }; 132 133 explicit Simulator(Isolate* isolate); 134 ~Simulator(); 135 136 // The currently executing Simulator instance. Potentially there can be one 137 // for each native thread. 138 static Simulator* current(v8::internal::Isolate* isolate); 139 140 // Accessors for register state. Reading the pc value adheres to the ARM 141 // architecture specification and is off by a 8 from the currently executing 142 // instruction. 143 void set_register(int reg, int32_t value); 144 int32_t get_register(int reg) const; 145 double get_double_from_register_pair(int reg); 146 void set_register_pair_from_double(int reg, double* value); 147 void set_dw_register(int dreg, const int* dbl); 148 149 // Support for VFP. 150 void get_d_register(int dreg, uint64_t* value); 151 void set_d_register(int dreg, const uint64_t* value); 152 void get_d_register(int dreg, uint32_t* value); 153 void set_d_register(int dreg, const uint32_t* value); 154 void get_q_register(int qreg, uint64_t* value); 155 void set_q_register(int qreg, const uint64_t* value); 156 void get_q_register(int qreg, uint32_t* value); 157 void set_q_register(int qreg, const uint32_t* value); 158 159 void set_s_register(int reg, unsigned int value); 160 unsigned int get_s_register(int reg) const; 161 set_d_register_from_double(int dreg,const double & dbl)162 void set_d_register_from_double(int dreg, const double& dbl) { 163 SetVFPRegister<double, 2>(dreg, dbl); 164 } 165 get_double_from_d_register(int dreg)166 double get_double_from_d_register(int dreg) { 167 return GetFromVFPRegister<double, 2>(dreg); 168 } 169 set_s_register_from_float(int sreg,const float flt)170 void set_s_register_from_float(int sreg, const float flt) { 171 SetVFPRegister<float, 1>(sreg, flt); 172 } 173 get_float_from_s_register(int sreg)174 float get_float_from_s_register(int sreg) { 175 return GetFromVFPRegister<float, 1>(sreg); 176 } 177 set_s_register_from_sinteger(int sreg,const int sint)178 void set_s_register_from_sinteger(int sreg, const int sint) { 179 SetVFPRegister<int, 1>(sreg, sint); 180 } 181 get_sinteger_from_s_register(int sreg)182 int get_sinteger_from_s_register(int sreg) { 183 return GetFromVFPRegister<int, 1>(sreg); 184 } 185 186 // Special case of set_register and get_register to access the raw PC value. 187 void set_pc(int32_t value); 188 int32_t get_pc() const; 189 get_sp()190 Address get_sp() const { 191 return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp))); 192 } 193 194 // Accessor to the internal simulator stack area. 195 uintptr_t StackLimit(uintptr_t c_limit) const; 196 197 // Executes ARM instructions until the PC reaches end_sim_pc. 198 void Execute(); 199 200 // Call on program start. 201 static void Initialize(Isolate* isolate); 202 203 static void TearDown(HashMap* i_cache, Redirection* first); 204 205 // V8 generally calls into generated JS code with 5 parameters and into 206 // generated RegExp code with 7 parameters. This is a convenience function, 207 // which sets up the simulator state and grabs the result on return. 208 int32_t Call(byte* entry, int argument_count, ...); 209 // Alternative: call a 2-argument double function. 210 void CallFP(byte* entry, double d0, double d1); 211 int32_t CallFPReturnsInt(byte* entry, double d0, double d1); 212 double CallFPReturnsDouble(byte* entry, double d0, double d1); 213 214 // Push an address onto the JS stack. 215 uintptr_t PushAddress(uintptr_t address); 216 217 // Pop an address from the JS stack. 218 uintptr_t PopAddress(); 219 220 // Debugger input. 221 void set_last_debugger_input(char* input); last_debugger_input()222 char* last_debugger_input() { return last_debugger_input_; } 223 224 // ICache checking. 225 static void FlushICache(v8::internal::HashMap* i_cache, void* start, 226 size_t size); 227 228 // Returns true if pc register contains one of the 'special_values' defined 229 // below (bad_lr, end_sim_pc). 230 bool has_bad_pc() const; 231 232 // EABI variant for double arguments in use. use_eabi_hardfloat()233 bool use_eabi_hardfloat() { 234 #if USE_EABI_HARDFLOAT 235 return true; 236 #else 237 return false; 238 #endif 239 } 240 241 private: 242 enum special_values { 243 // Known bad pc value to ensure that the simulator does not execute 244 // without being properly setup. 245 bad_lr = -1, 246 // A pc value used to signal the simulator to stop execution. Generally 247 // the lr is set to this value on transition from native C code to 248 // simulated execution, so that the simulator can "return" to the native 249 // C code. 250 end_sim_pc = -2 251 }; 252 253 // Unsupported instructions use Format to print an error and stop execution. 254 void Format(Instruction* instr, const char* format); 255 256 // Checks if the current instruction should be executed based on its 257 // condition bits. 258 inline bool ConditionallyExecute(Instruction* instr); 259 260 // Helper functions to set the conditional flags in the architecture state. 261 void SetNZFlags(int32_t val); 262 void SetCFlag(bool val); 263 void SetVFlag(bool val); 264 bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0); 265 bool BorrowFrom(int32_t left, int32_t right); 266 bool OverflowFrom(int32_t alu_out, 267 int32_t left, 268 int32_t right, 269 bool addition); 270 GetCarry()271 inline int GetCarry() { 272 return c_flag_ ? 1 : 0; 273 } 274 275 // Support for VFP. 276 void Compute_FPSCR_Flags(float val1, float val2); 277 void Compute_FPSCR_Flags(double val1, double val2); 278 void Copy_FPSCR_to_APSR(); 279 inline float canonicalizeNaN(float value); 280 inline double canonicalizeNaN(double value); 281 282 // Helper functions to decode common "addressing" modes 283 int32_t GetShiftRm(Instruction* instr, bool* carry_out); 284 int32_t GetImm(Instruction* instr, bool* carry_out); 285 int32_t ProcessPU(Instruction* instr, 286 int num_regs, 287 int operand_size, 288 intptr_t* start_address, 289 intptr_t* end_address); 290 void HandleRList(Instruction* instr, bool load); 291 void HandleVList(Instruction* inst); 292 void SoftwareInterrupt(Instruction* instr); 293 294 // Stop helper functions. 295 inline bool isStopInstruction(Instruction* instr); 296 inline bool isWatchedStop(uint32_t bkpt_code); 297 inline bool isEnabledStop(uint32_t bkpt_code); 298 inline void EnableStop(uint32_t bkpt_code); 299 inline void DisableStop(uint32_t bkpt_code); 300 inline void IncreaseStopCounter(uint32_t bkpt_code); 301 void PrintStopInfo(uint32_t code); 302 303 // Read and write memory. 304 inline uint8_t ReadBU(int32_t addr); 305 inline int8_t ReadB(int32_t addr); 306 inline void WriteB(int32_t addr, uint8_t value); 307 inline void WriteB(int32_t addr, int8_t value); 308 309 inline uint16_t ReadHU(int32_t addr, Instruction* instr); 310 inline int16_t ReadH(int32_t addr, Instruction* instr); 311 // Note: Overloaded on the sign of the value. 312 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr); 313 inline void WriteH(int32_t addr, int16_t value, Instruction* instr); 314 315 inline int ReadW(int32_t addr, Instruction* instr); 316 inline void WriteW(int32_t addr, int value, Instruction* instr); 317 318 int32_t* ReadDW(int32_t addr); 319 void WriteDW(int32_t addr, int32_t value1, int32_t value2); 320 321 // Executing is handled based on the instruction type. 322 // Both type 0 and type 1 rolled into one. 323 void DecodeType01(Instruction* instr); 324 void DecodeType2(Instruction* instr); 325 void DecodeType3(Instruction* instr); 326 void DecodeType4(Instruction* instr); 327 void DecodeType5(Instruction* instr); 328 void DecodeType6(Instruction* instr); 329 void DecodeType7(Instruction* instr); 330 331 // Support for VFP. 332 void DecodeTypeVFP(Instruction* instr); 333 void DecodeType6CoprocessorIns(Instruction* instr); 334 void DecodeSpecialCondition(Instruction* instr); 335 336 void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instruction* instr); 337 void DecodeVCMP(Instruction* instr); 338 void DecodeVCVTBetweenDoubleAndSingle(Instruction* instr); 339 void DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr); 340 341 // Executes one instruction. 342 void InstructionDecode(Instruction* instr); 343 344 // ICache. 345 static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr); 346 static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start, 347 int size); 348 static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page); 349 350 // Runtime call support. 351 static void* RedirectExternalReference( 352 Isolate* isolate, void* external_function, 353 v8::internal::ExternalReference::Type type); 354 355 // Handle arguments and return value for runtime FP functions. 356 void GetFpArgs(double* x, double* y, int32_t* z); 357 void SetFpResult(const double& result); 358 void TrashCallerSaveRegisters(); 359 360 template<class ReturnType, int register_size> 361 ReturnType GetFromVFPRegister(int reg_index); 362 363 template<class InputType, int register_size> 364 void SetVFPRegister(int reg_index, const InputType& value); 365 366 void CallInternal(byte* entry); 367 368 // Architecture state. 369 // Saturating instructions require a Q flag to indicate saturation. 370 // There is currently no way to read the CPSR directly, and thus read the Q 371 // flag, so this is left unimplemented. 372 int32_t registers_[16]; 373 bool n_flag_; 374 bool z_flag_; 375 bool c_flag_; 376 bool v_flag_; 377 378 // VFP architecture state. 379 unsigned int vfp_registers_[num_d_registers * 2]; 380 bool n_flag_FPSCR_; 381 bool z_flag_FPSCR_; 382 bool c_flag_FPSCR_; 383 bool v_flag_FPSCR_; 384 385 // VFP rounding mode. See ARM DDI 0406B Page A2-29. 386 VFPRoundingMode FPSCR_rounding_mode_; 387 bool FPSCR_default_NaN_mode_; 388 389 // VFP FP exception flags architecture state. 390 bool inv_op_vfp_flag_; 391 bool div_zero_vfp_flag_; 392 bool overflow_vfp_flag_; 393 bool underflow_vfp_flag_; 394 bool inexact_vfp_flag_; 395 396 // Simulator support. 397 char* stack_; 398 bool pc_modified_; 399 int icount_; 400 401 // Debugger input. 402 char* last_debugger_input_; 403 404 // Icache simulation 405 v8::internal::HashMap* i_cache_; 406 407 // Registered breakpoints. 408 Instruction* break_pc_; 409 Instr break_instr_; 410 411 v8::internal::Isolate* isolate_; 412 413 // A stop is watched if its code is less than kNumOfWatchedStops. 414 // Only watched stops support enabling/disabling and the counter feature. 415 static const uint32_t kNumOfWatchedStops = 256; 416 417 // Breakpoint is disabled if bit 31 is set. 418 static const uint32_t kStopDisabledBit = 1 << 31; 419 420 // A stop is enabled, meaning the simulator will stop when meeting the 421 // instruction, if bit 31 of watched_stops_[code].count is unset. 422 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times 423 // the breakpoint was hit or gone through. 424 struct StopCountAndDesc { 425 uint32_t count; 426 char* desc; 427 }; 428 StopCountAndDesc watched_stops_[kNumOfWatchedStops]; 429 }; 430 431 432 // When running with the simulator transition into simulated execution at this 433 // point. 434 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \ 435 reinterpret_cast<Object*>(Simulator::current(isolate)->Call( \ 436 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4)) 437 438 #define CALL_GENERATED_FP_INT(isolate, entry, p0, p1) \ 439 Simulator::current(isolate)->CallFPReturnsInt(FUNCTION_ADDR(entry), p0, p1) 440 441 #define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \ 442 p7, p8) \ 443 Simulator::current(isolate) \ 444 ->Call(entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8) 445 446 447 // The simulator has its own stack. Thus it has a different stack limit from 448 // the C-based native code. The JS-based limit normally points near the end of 449 // the simulator stack. When the C-based limit is exhausted we reflect that by 450 // lowering the JS-based limit as well, to make stack checks trigger. 451 class SimulatorStack : public v8::internal::AllStatic { 452 public: JsLimitFromCLimit(v8::internal::Isolate * isolate,uintptr_t c_limit)453 static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate, 454 uintptr_t c_limit) { 455 return Simulator::current(isolate)->StackLimit(c_limit); 456 } 457 RegisterCTryCatch(v8::internal::Isolate * isolate,uintptr_t try_catch_address)458 static inline uintptr_t RegisterCTryCatch(v8::internal::Isolate* isolate, 459 uintptr_t try_catch_address) { 460 Simulator* sim = Simulator::current(isolate); 461 return sim->PushAddress(try_catch_address); 462 } 463 UnregisterCTryCatch(v8::internal::Isolate * isolate)464 static inline void UnregisterCTryCatch(v8::internal::Isolate* isolate) { 465 Simulator::current(isolate)->PopAddress(); 466 } 467 }; 468 469 } // namespace internal 470 } // namespace v8 471 472 #endif // !defined(USE_SIMULATOR) 473 #endif // V8_ARM_SIMULATOR_ARM_H_ 474