simulator-mips.h revision 3fb3ca8c7ca439d408449a395897395c0faae8d1
1// Copyright 2011 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 29// Declares a Simulator for MIPS instructions if we are not generating a native 30// MIPS binary. This Simulator allows us to run and debug MIPS code generation 31// on regular desktop machines. 32// V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro, 33// which will start execution in the Simulator or forwards to the real entry 34// on a MIPS HW platform. 35 36#ifndef V8_MIPS_SIMULATOR_MIPS_H_ 37#define V8_MIPS_SIMULATOR_MIPS_H_ 38 39#include "allocation.h" 40#include "constants-mips.h" 41 42#if !defined(USE_SIMULATOR) 43// Running without a simulator on a native mips platform. 44 45namespace v8 { 46namespace internal { 47 48// When running without a simulator we call the entry directly. 49#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ 50 entry(p0, p1, p2, p3, p4) 51 52typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*, 53 void*, int*, Address, int, Isolate*); 54 55 56// Call the generated regexp code directly. The code at the entry address 57// should act as a function matching the type arm_regexp_matcher. 58// The fifth argument is a dummy that reserves the space used for 59// the return address added by the ExitFrame in native calls. 60#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \ 61 (FUNCTION_CAST<mips_regexp_matcher>(entry)( \ 62 p0, p1, p2, p3, NULL, p4, p5, p6, p7)) 63 64#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ 65 reinterpret_cast<TryCatch*>(try_catch_address) 66 67// The stack limit beyond which we will throw stack overflow errors in 68// generated code. Because generated code on mips uses the C stack, we 69// just use the C stack limit. 70class SimulatorStack : public v8::internal::AllStatic { 71 public: 72 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate, 73 uintptr_t c_limit) { 74 return c_limit; 75 } 76 77 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { 78 return try_catch_address; 79 } 80 81 static inline void UnregisterCTryCatch() { } 82}; 83 84} } // namespace v8::internal 85 86// Calculated the stack limit beyond which we will throw stack overflow errors. 87// This macro must be called from a C++ method. It relies on being able to take 88// the address of "this" to get a value on the current execution stack and then 89// calculates the stack limit based on that value. 90// NOTE: The check for overflow is not safe as there is no guarantee that the 91// running thread has its stack in all memory up to address 0x00000000. 92#define GENERATED_CODE_STACK_LIMIT(limit) \ 93 (reinterpret_cast<uintptr_t>(this) >= limit ? \ 94 reinterpret_cast<uintptr_t>(this) - limit : 0) 95 96#else // !defined(USE_SIMULATOR) 97// Running with a simulator. 98 99#include "hashmap.h" 100#include "assembler.h" 101 102namespace v8 { 103namespace internal { 104 105// ----------------------------------------------------------------------------- 106// Utility functions 107 108class CachePage { 109 public: 110 static const int LINE_VALID = 0; 111 static const int LINE_INVALID = 1; 112 113 static const int kPageShift = 12; 114 static const int kPageSize = 1 << kPageShift; 115 static const int kPageMask = kPageSize - 1; 116 static const int kLineShift = 2; // The cache line is only 4 bytes right now. 117 static const int kLineLength = 1 << kLineShift; 118 static const int kLineMask = kLineLength - 1; 119 120 CachePage() { 121 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); 122 } 123 124 char* ValidityByte(int offset) { 125 return &validity_map_[offset >> kLineShift]; 126 } 127 128 char* CachedData(int offset) { 129 return &data_[offset]; 130 } 131 132 private: 133 char data_[kPageSize]; // The cached data. 134 static const int kValidityMapSize = kPageSize >> kLineShift; 135 char validity_map_[kValidityMapSize]; // One byte per line. 136}; 137 138class Simulator { 139 public: 140 friend class MipsDebugger; 141 142 // Registers are declared in order. See SMRL chapter 2. 143 enum Register { 144 no_reg = -1, 145 zero_reg = 0, 146 at, 147 v0, v1, 148 a0, a1, a2, a3, 149 t0, t1, t2, t3, t4, t5, t6, t7, 150 s0, s1, s2, s3, s4, s5, s6, s7, 151 t8, t9, 152 k0, k1, 153 gp, 154 sp, 155 s8, 156 ra, 157 // LO, HI, and pc. 158 LO, 159 HI, 160 pc, // pc must be the last register. 161 kNumSimuRegisters, 162 // aliases 163 fp = s8 164 }; 165 166 // Coprocessor registers. 167 // Generated code will always use doubles. So we will only use even registers. 168 enum FPURegister { 169 f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, 170 f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters. 171 f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, 172 f26, f27, f28, f29, f30, f31, 173 kNumFPURegisters 174 }; 175 176 explicit Simulator(Isolate* isolate); 177 ~Simulator(); 178 179 // The currently executing Simulator instance. Potentially there can be one 180 // for each native thread. 181 static Simulator* current(v8::internal::Isolate* isolate); 182 183 // Accessors for register state. Reading the pc value adheres to the MIPS 184 // architecture specification and is off by a 8 from the currently executing 185 // instruction. 186 void set_register(int reg, int32_t value); 187 int32_t get_register(int reg) const; 188 // Same for FPURegisters. 189 void set_fpu_register(int fpureg, int32_t value); 190 void set_fpu_register_float(int fpureg, float value); 191 void set_fpu_register_double(int fpureg, double value); 192 int32_t get_fpu_register(int fpureg) const; 193 int64_t get_fpu_register_long(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 200 // Special case of set_register and get_register to access the raw PC value. 201 void set_pc(int32_t value); 202 int32_t get_pc() const; 203 204 // Accessor to the internal simulator stack area. 205 uintptr_t StackLimit() const; 206 207 // Executes MIPS instructions until the PC reaches end_sim_pc. 208 void Execute(); 209 210 // Call on program start. 211 static void Initialize(Isolate* isolate); 212 213 // V8 generally calls into generated JS code with 5 parameters and into 214 // generated RegExp code with 7 parameters. This is a convenience function, 215 // which sets up the simulator state and grabs the result on return. 216 int32_t Call(byte* entry, int argument_count, ...); 217 218 // Push an address onto the JS stack. 219 uintptr_t PushAddress(uintptr_t address); 220 221 // Pop an address from the JS stack. 222 uintptr_t PopAddress(); 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_ra, end_sim_pc). 230 bool has_bad_pc() const; 231 232 private: 233 enum special_values { 234 // Known bad pc value to ensure that the simulator does not execute 235 // without being properly setup. 236 bad_ra = -1, 237 // A pc value used to signal the simulator to stop execution. Generally 238 // the ra is set to this value on transition from native C code to 239 // simulated execution, so that the simulator can "return" to the native 240 // C code. 241 end_sim_pc = -2, 242 // Unpredictable value. 243 Unpredictable = 0xbadbeaf 244 }; 245 246 // Unsupported instructions use Format to print an error and stop execution. 247 void Format(Instruction* instr, const char* format); 248 249 // Read and write memory. 250 inline uint32_t ReadBU(int32_t addr); 251 inline int32_t ReadB(int32_t addr); 252 inline void WriteB(int32_t addr, uint8_t value); 253 inline void WriteB(int32_t addr, int8_t value); 254 255 inline uint16_t ReadHU(int32_t addr, Instruction* instr); 256 inline int16_t ReadH(int32_t addr, Instruction* instr); 257 // Note: Overloaded on the sign of the value. 258 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr); 259 inline void WriteH(int32_t addr, int16_t value, Instruction* instr); 260 261 inline int ReadW(int32_t addr, Instruction* instr); 262 inline void WriteW(int32_t addr, int value, Instruction* instr); 263 264 inline double ReadD(int32_t addr, Instruction* instr); 265 inline void WriteD(int32_t addr, double value, Instruction* instr); 266 267 // Operations depending on endianness. 268 // Get Double Higher / Lower word. 269 inline int32_t GetDoubleHIW(double* addr); 270 inline int32_t GetDoubleLOW(double* addr); 271 // Set Double Higher / Lower word. 272 inline int32_t SetDoubleHIW(double* addr); 273 inline int32_t SetDoubleLOW(double* addr); 274 275 // Executing is handled based on the instruction type. 276 void DecodeTypeRegister(Instruction* instr); 277 278 // Helper function for DecodeTypeRegister. 279 void ConfigureTypeRegister(Instruction* instr, 280 int32_t& alu_out, 281 int64_t& i64hilo, 282 uint64_t& u64hilo, 283 int32_t& next_pc, 284 bool& do_interrupt); 285 286 void DecodeTypeImmediate(Instruction* instr); 287 void DecodeTypeJump(Instruction* instr); 288 289 // Used for breakpoints and traps. 290 void SoftwareInterrupt(Instruction* instr); 291 292 // Stop helper functions. 293 bool IsWatchpoint(uint32_t code); 294 void PrintWatchpoint(uint32_t code); 295 void HandleStop(uint32_t code, Instruction* instr); 296 bool IsStopInstruction(Instruction* instr); 297 bool IsEnabledStop(uint32_t code); 298 void EnableStop(uint32_t code); 299 void DisableStop(uint32_t code); 300 void IncreaseStopCounter(uint32_t code); 301 void PrintStopInfo(uint32_t code); 302 303 304 // Executes one instruction. 305 void InstructionDecode(Instruction* instr); 306 // Execute one instruction placed in a branch delay slot. 307 void BranchDelayInstructionDecode(Instruction* instr) { 308 if (instr->IsForbiddenInBranchDelay()) { 309 V8_Fatal(__FILE__, __LINE__, 310 "Eror:Unexpected %i opcode in a branch delay slot.", 311 instr->OpcodeValue()); 312 } 313 InstructionDecode(instr); 314 } 315 316 // ICache. 317 static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr); 318 static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start, 319 int size); 320 static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page); 321 322 enum Exception { 323 none, 324 kIntegerOverflow, 325 kIntegerUnderflow, 326 kDivideByZero, 327 kNumExceptions 328 }; 329 int16_t exceptions[kNumExceptions]; 330 331 // Exceptions. 332 void SignalExceptions(); 333 334 // Runtime call support. 335 static void* RedirectExternalReference(void* external_function, 336 ExternalReference::Type type); 337 338 // For use in calls that take double value arguments. 339 void GetFpArgs(double* x, double* y); 340 void GetFpArgs(double* x); 341 void GetFpArgs(double* x, int32_t* y); 342 void SetFpResult(const double& result); 343 344 345 // Architecture state. 346 // Registers. 347 int32_t registers_[kNumSimuRegisters]; 348 // Coprocessor Registers. 349 int32_t FPUregisters_[kNumFPURegisters]; 350 // FPU control register. 351 uint32_t FCSR_; 352 353 // Simulator support. 354 // Allocate 1MB for stack. 355 static const size_t stack_size_ = 1 * 1024*1024; 356 char* stack_; 357 bool pc_modified_; 358 int icount_; 359 int break_count_; 360 361 // Icache simulation. 362 v8::internal::HashMap* i_cache_; 363 364 v8::internal::Isolate* isolate_; 365 366 // Registered breakpoints. 367 Instruction* break_pc_; 368 Instr break_instr_; 369 370 // Stop is disabled if bit 31 is set. 371 static const uint32_t kStopDisabledBit = 1 << 31; 372 373 // A stop is enabled, meaning the simulator will stop when meeting the 374 // instruction, if bit 31 of watched_stops[code].count is unset. 375 // The value watched_stops[code].count & ~(1 << 31) indicates how many times 376 // the breakpoint was hit or gone through. 377 struct StopCountAndDesc { 378 uint32_t count; 379 char* desc; 380 }; 381 StopCountAndDesc watched_stops[kMaxStopCode + 1]; 382}; 383 384 385// When running with the simulator transition into simulated execution at this 386// point. 387#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ 388 reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \ 389 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4)) 390 391#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \ 392 Simulator::current(Isolate::Current())->Call( \ 393 entry, 9, p0, p1, p2, p3, NULL, p4, p5, p6, p7) 394 395#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ 396 try_catch_address == NULL ? \ 397 NULL : *(reinterpret_cast<TryCatch**>(try_catch_address)) 398 399 400// The simulator has its own stack. Thus it has a different stack limit from 401// the C-based native code. Setting the c_limit to indicate a very small 402// stack cause stack overflow errors, since the simulator ignores the input. 403// This is unlikely to be an issue in practice, though it might cause testing 404// trouble down the line. 405class SimulatorStack : public v8::internal::AllStatic { 406 public: 407 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate, 408 uintptr_t c_limit) { 409 return Simulator::current(isolate)->StackLimit(); 410 } 411 412 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { 413 Simulator* sim = Simulator::current(Isolate::Current()); 414 return sim->PushAddress(try_catch_address); 415 } 416 417 static inline void UnregisterCTryCatch() { 418 Simulator::current(Isolate::Current())->PopAddress(); 419 } 420}; 421 422} } // namespace v8::internal 423 424#endif // !defined(USE_SIMULATOR) 425#endif // V8_MIPS_SIMULATOR_MIPS_H_ 426