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