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