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