1 // Copyright 2011 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 MIPS instructions if we are not generating a native 7 // MIPS binary. This Simulator allows us to run and debug MIPS code generation 8 // on 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 MIPS HW platform. 12 13 #ifndef V8_MIPS_SIMULATOR_MIPS_H_ 14 #define V8_MIPS_SIMULATOR_MIPS_H_ 15 16 #include "src/allocation.h" 17 #include "src/mips64/constants-mips64.h" 18 19 #if !defined(USE_SIMULATOR) 20 // Running without a simulator on a native mips platform. 21 22 namespace v8 { 23 namespace internal { 24 25 // When running without a simulator we call the entry directly. 26 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \ 27 entry(p0, p1, p2, p3, p4) 28 29 30 // Call the generated regexp code directly. The code at the entry address 31 // should act as a function matching the type arm_regexp_matcher. 32 // The fifth (or ninth) argument is a dummy that reserves the space used for 33 // the return address added by the ExitFrame in native calls. 34 typedef int (*mips_regexp_matcher)(String* input, 35 int64_t start_offset, 36 const byte* input_start, 37 const byte* input_end, 38 int* output, 39 int64_t output_size, 40 Address stack_base, 41 int64_t direct_call, 42 void* return_address, 43 Isolate* isolate); 44 45 #define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \ 46 p7, p8) \ 47 (FUNCTION_CAST<mips_regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6, p7, \ 48 NULL, p8)) 49 50 51 // The stack limit beyond which we will throw stack overflow errors in 52 // generated code. Because generated code on mips uses the C stack, we 53 // just use the C stack limit. 54 class SimulatorStack : public v8::internal::AllStatic { 55 public: JsLimitFromCLimit(Isolate * isolate,uintptr_t c_limit)56 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate, 57 uintptr_t c_limit) { 58 return c_limit; 59 } 60 RegisterCTryCatch(Isolate * isolate,uintptr_t try_catch_address)61 static inline uintptr_t RegisterCTryCatch(Isolate* isolate, 62 uintptr_t try_catch_address) { 63 USE(isolate); 64 return try_catch_address; 65 } 66 UnregisterCTryCatch(Isolate * isolate)67 static inline void UnregisterCTryCatch(Isolate* isolate) { USE(isolate); } 68 }; 69 70 } // namespace internal 71 } // namespace v8 72 73 // Calculated the stack limit beyond which we will throw stack overflow errors. 74 // This macro must be called from a C++ method. It relies on being able to take 75 // the address of "this" to get a value on the current execution stack and then 76 // calculates the stack limit based on that value. 77 // NOTE: The check for overflow is not safe as there is no guarantee that the 78 // running thread has its stack in all memory up to address 0x00000000. 79 #define GENERATED_CODE_STACK_LIMIT(limit) \ 80 (reinterpret_cast<uintptr_t>(this) >= limit ? \ 81 reinterpret_cast<uintptr_t>(this) - limit : 0) 82 83 #else // !defined(USE_SIMULATOR) 84 // Running with a simulator. 85 86 #include "src/assembler.h" 87 #include "src/base/hashmap.h" 88 89 namespace v8 { 90 namespace internal { 91 92 // ----------------------------------------------------------------------------- 93 // Utility functions 94 95 class CachePage { 96 public: 97 static const int LINE_VALID = 0; 98 static const int LINE_INVALID = 1; 99 100 static const int kPageShift = 12; 101 static const int kPageSize = 1 << kPageShift; 102 static const int kPageMask = kPageSize - 1; 103 static const int kLineShift = 2; // The cache line is only 4 bytes right now. 104 static const int kLineLength = 1 << kLineShift; 105 static const int kLineMask = kLineLength - 1; 106 CachePage()107 CachePage() { 108 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); 109 } 110 ValidityByte(int offset)111 char* ValidityByte(int offset) { 112 return &validity_map_[offset >> kLineShift]; 113 } 114 CachedData(int offset)115 char* CachedData(int offset) { 116 return &data_[offset]; 117 } 118 119 private: 120 char data_[kPageSize]; // The cached data. 121 static const int kValidityMapSize = kPageSize >> kLineShift; 122 char validity_map_[kValidityMapSize]; // One byte per line. 123 }; 124 125 class Simulator { 126 public: 127 friend class MipsDebugger; 128 129 // Registers are declared in order. See SMRL chapter 2. 130 enum Register { 131 no_reg = -1, 132 zero_reg = 0, 133 at, 134 v0, v1, 135 a0, a1, a2, a3, a4, a5, a6, a7, 136 t0, t1, t2, t3, 137 s0, s1, s2, s3, s4, s5, s6, s7, 138 t8, t9, 139 k0, k1, 140 gp, 141 sp, 142 s8, 143 ra, 144 // LO, HI, and pc. 145 LO, 146 HI, 147 pc, // pc must be the last register. 148 kNumSimuRegisters, 149 // aliases 150 fp = s8 151 }; 152 153 // Coprocessor registers. 154 // Generated code will always use doubles. So we will only use even registers. 155 enum FPURegister { 156 f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, 157 f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters. 158 f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, 159 f26, f27, f28, f29, f30, f31, 160 kNumFPURegisters 161 }; 162 163 explicit Simulator(Isolate* isolate); 164 ~Simulator(); 165 166 // The currently executing Simulator instance. Potentially there can be one 167 // for each native thread. 168 static Simulator* current(v8::internal::Isolate* isolate); 169 170 // Accessors for register state. Reading the pc value adheres to the MIPS 171 // architecture specification and is off by a 8 from the currently executing 172 // instruction. 173 void set_register(int reg, int64_t value); 174 void set_register_word(int reg, int32_t value); 175 void set_dw_register(int dreg, const int* dbl); 176 int64_t get_register(int reg) const; 177 double get_double_from_register_pair(int reg); 178 // Same for FPURegisters. 179 void set_fpu_register(int fpureg, int64_t value); 180 void set_fpu_register_word(int fpureg, int32_t value); 181 void set_fpu_register_hi_word(int fpureg, int32_t value); 182 void set_fpu_register_float(int fpureg, float value); 183 void set_fpu_register_double(int fpureg, double value); 184 void set_fpu_register_invalid_result64(float original, float rounded); 185 void set_fpu_register_invalid_result(float original, float rounded); 186 void set_fpu_register_word_invalid_result(float original, float rounded); 187 void set_fpu_register_invalid_result64(double original, double rounded); 188 void set_fpu_register_invalid_result(double original, double rounded); 189 void set_fpu_register_word_invalid_result(double original, double rounded); 190 int64_t get_fpu_register(int fpureg) const; 191 int32_t get_fpu_register_word(int fpureg) const; 192 int32_t get_fpu_register_signed_word(int fpureg) const; 193 int32_t get_fpu_register_hi_word(int fpureg) const; 194 float get_fpu_register_float(int fpureg) const; 195 double get_fpu_register_double(int fpureg) const; 196 void set_fcsr_bit(uint32_t cc, bool value); 197 bool test_fcsr_bit(uint32_t cc); 198 bool set_fcsr_round_error(double original, double rounded); 199 bool set_fcsr_round64_error(double original, double rounded); 200 bool set_fcsr_round_error(float original, float rounded); 201 bool set_fcsr_round64_error(float original, float rounded); 202 void round_according_to_fcsr(double toRound, double& rounded, 203 int32_t& rounded_int, double fs); 204 void round64_according_to_fcsr(double toRound, double& rounded, 205 int64_t& rounded_int, double fs); 206 void round_according_to_fcsr(float toRound, float& rounded, 207 int32_t& rounded_int, float fs); 208 void round64_according_to_fcsr(float toRound, float& rounded, 209 int64_t& rounded_int, float fs); 210 void set_fcsr_rounding_mode(FPURoundingMode mode); 211 unsigned int get_fcsr_rounding_mode(); 212 // Special case of set_register and get_register to access the raw PC value. 213 void set_pc(int64_t value); 214 int64_t get_pc() const; 215 get_sp()216 Address get_sp() const { 217 return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp))); 218 } 219 220 // Accessor to the internal simulator stack area. 221 uintptr_t StackLimit(uintptr_t c_limit) const; 222 223 // Executes MIPS instructions until the PC reaches end_sim_pc. 224 void Execute(); 225 226 // Call on program start. 227 static void Initialize(Isolate* isolate); 228 229 static void TearDown(base::HashMap* i_cache, Redirection* first); 230 231 // V8 generally calls into generated JS code with 5 parameters and into 232 // generated RegExp code with 7 parameters. This is a convenience function, 233 // which sets up the simulator state and grabs the result on return. 234 int64_t Call(byte* entry, int argument_count, ...); 235 // Alternative: call a 2-argument double function. 236 double CallFP(byte* entry, double d0, double d1); 237 238 // Push an address onto the JS stack. 239 uintptr_t PushAddress(uintptr_t address); 240 241 // Pop an address from the JS stack. 242 uintptr_t PopAddress(); 243 244 // Debugger input. 245 void set_last_debugger_input(char* input); last_debugger_input()246 char* last_debugger_input() { return last_debugger_input_; } 247 248 // ICache checking. 249 static void FlushICache(base::HashMap* i_cache, void* start, size_t size); 250 251 // Returns true if pc register contains one of the 'special_values' defined 252 // below (bad_ra, end_sim_pc). 253 bool has_bad_pc() const; 254 255 private: 256 enum special_values { 257 // Known bad pc value to ensure that the simulator does not execute 258 // without being properly setup. 259 bad_ra = -1, 260 // A pc value used to signal the simulator to stop execution. Generally 261 // the ra is set to this value on transition from native C code to 262 // simulated execution, so that the simulator can "return" to the native 263 // C code. 264 end_sim_pc = -2, 265 // Unpredictable value. 266 Unpredictable = 0xbadbeaf 267 }; 268 269 // Unsupported instructions use Format to print an error and stop execution. 270 void Format(Instruction* instr, const char* format); 271 272 // Read and write memory. 273 inline uint32_t ReadBU(int64_t addr); 274 inline int32_t ReadB(int64_t addr); 275 inline void WriteB(int64_t addr, uint8_t value); 276 inline void WriteB(int64_t addr, int8_t value); 277 278 inline uint16_t ReadHU(int64_t addr, Instruction* instr); 279 inline int16_t ReadH(int64_t addr, Instruction* instr); 280 // Note: Overloaded on the sign of the value. 281 inline void WriteH(int64_t addr, uint16_t value, Instruction* instr); 282 inline void WriteH(int64_t addr, int16_t value, Instruction* instr); 283 284 inline uint32_t ReadWU(int64_t addr, Instruction* instr); 285 inline int32_t ReadW(int64_t addr, Instruction* instr); 286 inline void WriteW(int64_t addr, int32_t value, Instruction* instr); 287 inline int64_t Read2W(int64_t addr, Instruction* instr); 288 inline void Write2W(int64_t addr, int64_t value, Instruction* instr); 289 290 inline double ReadD(int64_t addr, Instruction* instr); 291 inline void WriteD(int64_t addr, double value, Instruction* instr); 292 293 // Helper for debugging memory access. 294 inline void DieOrDebug(); 295 296 // Helpers for data value tracing. 297 enum TraceType { 298 BYTE, 299 HALF, 300 WORD, 301 DWORD 302 // DFLOAT - Floats may have printing issues due to paired lwc1's 303 }; 304 305 void TraceRegWr(int64_t value); 306 void TraceMemWr(int64_t addr, int64_t value, TraceType t); 307 void TraceMemRd(int64_t addr, int64_t value); 308 309 // Operations depending on endianness. 310 // Get Double Higher / Lower word. 311 inline int32_t GetDoubleHIW(double* addr); 312 inline int32_t GetDoubleLOW(double* addr); 313 // Set Double Higher / Lower word. 314 inline int32_t SetDoubleHIW(double* addr); 315 inline int32_t SetDoubleLOW(double* addr); 316 317 // functions called from DecodeTypeRegister. 318 void DecodeTypeRegisterCOP1(); 319 320 void DecodeTypeRegisterCOP1X(); 321 322 void DecodeTypeRegisterSPECIAL(); 323 324 325 void DecodeTypeRegisterSPECIAL2(); 326 327 void DecodeTypeRegisterSPECIAL3(); 328 329 void DecodeTypeRegisterSRsType(); 330 331 void DecodeTypeRegisterDRsType(); 332 333 void DecodeTypeRegisterWRsType(); 334 335 void DecodeTypeRegisterLRsType(); 336 337 // Executing is handled based on the instruction type. 338 void DecodeTypeRegister(Instruction* instr); 339 340 Instruction* currentInstr_; get_instr()341 inline Instruction* get_instr() const { return currentInstr_; } set_instr(Instruction * instr)342 inline void set_instr(Instruction* instr) { currentInstr_ = instr; } 343 rs_reg()344 inline int32_t rs_reg() const { return currentInstr_->RsValue(); } rs()345 inline int64_t rs() const { return get_register(rs_reg()); } rs_u()346 inline uint64_t rs_u() const { 347 return static_cast<uint64_t>(get_register(rs_reg())); 348 } rt_reg()349 inline int32_t rt_reg() const { return currentInstr_->RtValue(); } rt()350 inline int64_t rt() const { return get_register(rt_reg()); } rt_u()351 inline uint64_t rt_u() const { 352 return static_cast<uint64_t>(get_register(rt_reg())); 353 } rd_reg()354 inline int32_t rd_reg() const { return currentInstr_->RdValue(); } fr_reg()355 inline int32_t fr_reg() const { return currentInstr_->FrValue(); } fs_reg()356 inline int32_t fs_reg() const { return currentInstr_->FsValue(); } ft_reg()357 inline int32_t ft_reg() const { return currentInstr_->FtValue(); } fd_reg()358 inline int32_t fd_reg() const { return currentInstr_->FdValue(); } sa()359 inline int32_t sa() const { return currentInstr_->SaValue(); } lsa_sa()360 inline int32_t lsa_sa() const { return currentInstr_->LsaSaValue(); } 361 SetResult(const int32_t rd_reg,const int64_t alu_out)362 inline void SetResult(const int32_t rd_reg, const int64_t alu_out) { 363 set_register(rd_reg, alu_out); 364 TraceRegWr(alu_out); 365 } 366 367 void DecodeTypeImmediate(Instruction* instr); 368 void DecodeTypeJump(Instruction* instr); 369 370 // Used for breakpoints and traps. 371 void SoftwareInterrupt(Instruction* instr); 372 373 // Compact branch guard. CheckForbiddenSlot(int64_t current_pc)374 void CheckForbiddenSlot(int64_t current_pc) { 375 Instruction* instr_after_compact_branch = 376 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize); 377 if (instr_after_compact_branch->IsForbiddenAfterBranch()) { 378 V8_Fatal(__FILE__, __LINE__, 379 "Error: Unexpected instruction 0x%08x immediately after a " 380 "compact branch instruction.", 381 *reinterpret_cast<uint32_t*>(instr_after_compact_branch)); 382 } 383 } 384 385 // Stop helper functions. 386 bool IsWatchpoint(uint64_t code); 387 void PrintWatchpoint(uint64_t code); 388 void HandleStop(uint64_t code, Instruction* instr); 389 bool IsStopInstruction(Instruction* instr); 390 bool IsEnabledStop(uint64_t code); 391 void EnableStop(uint64_t code); 392 void DisableStop(uint64_t code); 393 void IncreaseStopCounter(uint64_t code); 394 void PrintStopInfo(uint64_t code); 395 396 397 // Executes one instruction. 398 void InstructionDecode(Instruction* instr); 399 // Execute one instruction placed in a branch delay slot. BranchDelayInstructionDecode(Instruction * instr)400 void BranchDelayInstructionDecode(Instruction* instr) { 401 if (instr->InstructionBits() == nopInstr) { 402 // Short-cut generic nop instructions. They are always valid and they 403 // never change the simulator state. 404 return; 405 } 406 407 if (instr->IsForbiddenAfterBranch()) { 408 V8_Fatal(__FILE__, __LINE__, 409 "Eror:Unexpected %i opcode in a branch delay slot.", 410 instr->OpcodeValue()); 411 } 412 InstructionDecode(instr); 413 SNPrintF(trace_buf_, " "); 414 } 415 416 // ICache. 417 static void CheckICache(base::HashMap* i_cache, Instruction* instr); 418 static void FlushOnePage(base::HashMap* i_cache, intptr_t start, size_t size); 419 static CachePage* GetCachePage(base::HashMap* i_cache, void* page); 420 421 enum Exception { 422 none, 423 kIntegerOverflow, 424 kIntegerUnderflow, 425 kDivideByZero, 426 kNumExceptions 427 }; 428 429 // Exceptions. 430 void SignalException(Exception e); 431 432 // Runtime call support. 433 static void* RedirectExternalReference(Isolate* isolate, 434 void* external_function, 435 ExternalReference::Type type); 436 437 // Handle arguments and return value for runtime FP functions. 438 void GetFpArgs(double* x, double* y, int32_t* z); 439 void SetFpResult(const double& result); 440 441 void CallInternal(byte* entry); 442 443 // Architecture state. 444 // Registers. 445 int64_t registers_[kNumSimuRegisters]; 446 // Coprocessor Registers. 447 int64_t FPUregisters_[kNumFPURegisters]; 448 // FPU control register. 449 uint32_t FCSR_; 450 451 // Simulator support. 452 // Allocate 1MB for stack. 453 size_t stack_size_; 454 char* stack_; 455 bool pc_modified_; 456 int64_t icount_; 457 int break_count_; 458 EmbeddedVector<char, 128> trace_buf_; 459 460 // Debugger input. 461 char* last_debugger_input_; 462 463 // Icache simulation. 464 base::HashMap* i_cache_; 465 466 v8::internal::Isolate* isolate_; 467 468 // Registered breakpoints. 469 Instruction* break_pc_; 470 Instr break_instr_; 471 472 // Stop is disabled if bit 31 is set. 473 static const uint32_t kStopDisabledBit = 1 << 31; 474 475 // A stop is enabled, meaning the simulator will stop when meeting the 476 // instruction, if bit 31 of watched_stops_[code].count is unset. 477 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times 478 // the breakpoint was hit or gone through. 479 struct StopCountAndDesc { 480 uint32_t count; 481 char* desc; 482 }; 483 StopCountAndDesc watched_stops_[kMaxStopCode + 1]; 484 }; 485 486 487 // When running with the simulator transition into simulated execution at this 488 // point. 489 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \ 490 reinterpret_cast<Object*>(Simulator::current(isolate)->Call( \ 491 FUNCTION_ADDR(entry), 5, reinterpret_cast<int64_t*>(p0), \ 492 reinterpret_cast<int64_t*>(p1), reinterpret_cast<int64_t*>(p2), \ 493 reinterpret_cast<int64_t*>(p3), reinterpret_cast<int64_t*>(p4))) 494 495 496 #define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \ 497 p7, p8) \ 498 static_cast<int>(Simulator::current(isolate)->Call( \ 499 entry, 10, p0, p1, p2, p3, p4, reinterpret_cast<int64_t*>(p5), p6, p7, \ 500 NULL, p8)) 501 502 503 // The simulator has its own stack. Thus it has a different stack limit from 504 // the C-based native code. The JS-based limit normally points near the end of 505 // the simulator stack. When the C-based limit is exhausted we reflect that by 506 // lowering the JS-based limit as well, to make stack checks trigger. 507 class SimulatorStack : public v8::internal::AllStatic { 508 public: JsLimitFromCLimit(Isolate * isolate,uintptr_t c_limit)509 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate, 510 uintptr_t c_limit) { 511 return Simulator::current(isolate)->StackLimit(c_limit); 512 } 513 RegisterCTryCatch(Isolate * isolate,uintptr_t try_catch_address)514 static inline uintptr_t RegisterCTryCatch(Isolate* isolate, 515 uintptr_t try_catch_address) { 516 Simulator* sim = Simulator::current(isolate); 517 return sim->PushAddress(try_catch_address); 518 } 519 UnregisterCTryCatch(Isolate * isolate)520 static inline void UnregisterCTryCatch(Isolate* isolate) { 521 Simulator::current(isolate)->PopAddress(); 522 } 523 }; 524 525 } // namespace internal 526 } // namespace v8 527 528 #endif // !defined(USE_SIMULATOR) 529 #endif // V8_MIPS_SIMULATOR_MIPS_H_ 530