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 45 namespace v8 { 46 namespace 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 52 typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*, 53 void*, int*, 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, p8) \ 61 (FUNCTION_CAST<mips_regexp_matcher>(entry)( \ 62 p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)) 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. 70 class 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 102 namespace v8 { 103 namespace internal { 104 105 // ----------------------------------------------------------------------------- 106 // Utility functions 107 108 class 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 138 class 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 void set_dw_register(int dreg, const int* dbl); 188 int32_t get_register(int reg) const; 189 double get_double_from_register_pair(int reg); 190 // Same for FPURegisters. 191 void set_fpu_register(int fpureg, int32_t value); 192 void set_fpu_register_float(int fpureg, float value); 193 void set_fpu_register_double(int fpureg, double value); 194 int32_t get_fpu_register(int fpureg) const; 195 int64_t get_fpu_register_long(int fpureg) const; 196 float get_fpu_register_float(int fpureg) const; 197 double get_fpu_register_double(int fpureg) const; 198 void set_fcsr_bit(uint32_t cc, bool value); 199 bool test_fcsr_bit(uint32_t cc); 200 bool set_fcsr_round_error(double original, double rounded); 201 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 // Accessor to the internal simulator stack area. 207 uintptr_t StackLimit() const; 208 209 // Executes MIPS instructions until the PC reaches end_sim_pc. 210 void Execute(); 211 212 // Call on program start. 213 static void Initialize(Isolate* isolate); 214 215 // V8 generally calls into generated JS code with 5 parameters and into 216 // generated RegExp code with 7 parameters. This is a convenience function, 217 // which sets up the simulator state and grabs the result on return. 218 int32_t Call(byte* entry, int argument_count, ...); 219 // Alternative: call a 2-argument double function. 220 double CallFP(byte* entry, double d0, double d1); 221 222 // Push an address onto the JS stack. 223 uintptr_t PushAddress(uintptr_t address); 224 225 // Pop an address from the JS stack. 226 uintptr_t PopAddress(); 227 228 // Debugger input. 229 void set_last_debugger_input(char* input); 230 char* last_debugger_input() { return last_debugger_input_; } 231 232 // ICache checking. 233 static void FlushICache(v8::internal::HashMap* i_cache, void* start, 234 size_t size); 235 236 // Returns true if pc register contains one of the 'special_values' defined 237 // below (bad_ra, end_sim_pc). 238 bool has_bad_pc() const; 239 240 private: 241 enum special_values { 242 // Known bad pc value to ensure that the simulator does not execute 243 // without being properly setup. 244 bad_ra = -1, 245 // A pc value used to signal the simulator to stop execution. Generally 246 // the ra is set to this value on transition from native C code to 247 // simulated execution, so that the simulator can "return" to the native 248 // C code. 249 end_sim_pc = -2, 250 // Unpredictable value. 251 Unpredictable = 0xbadbeaf 252 }; 253 254 // Unsupported instructions use Format to print an error and stop execution. 255 void Format(Instruction* instr, const char* format); 256 257 // Read and write memory. 258 inline uint32_t ReadBU(int32_t addr); 259 inline int32_t ReadB(int32_t addr); 260 inline void WriteB(int32_t addr, uint8_t value); 261 inline void WriteB(int32_t addr, int8_t value); 262 263 inline uint16_t ReadHU(int32_t addr, Instruction* instr); 264 inline int16_t ReadH(int32_t addr, Instruction* instr); 265 // Note: Overloaded on the sign of the value. 266 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr); 267 inline void WriteH(int32_t addr, int16_t value, Instruction* instr); 268 269 inline int ReadW(int32_t addr, Instruction* instr); 270 inline void WriteW(int32_t addr, int value, Instruction* instr); 271 272 inline double ReadD(int32_t addr, Instruction* instr); 273 inline void WriteD(int32_t addr, double value, Instruction* instr); 274 275 // Operations depending on endianness. 276 // Get Double Higher / Lower word. 277 inline int32_t GetDoubleHIW(double* addr); 278 inline int32_t GetDoubleLOW(double* addr); 279 // Set Double Higher / Lower word. 280 inline int32_t SetDoubleHIW(double* addr); 281 inline int32_t SetDoubleLOW(double* addr); 282 283 // Executing is handled based on the instruction type. 284 void DecodeTypeRegister(Instruction* instr); 285 286 // Helper function for DecodeTypeRegister. 287 void ConfigureTypeRegister(Instruction* instr, 288 int32_t& alu_out, 289 int64_t& i64hilo, 290 uint64_t& u64hilo, 291 int32_t& next_pc, 292 int32_t& return_addr_reg, 293 bool& do_interrupt); 294 295 void DecodeTypeImmediate(Instruction* instr); 296 void DecodeTypeJump(Instruction* instr); 297 298 // Used for breakpoints and traps. 299 void SoftwareInterrupt(Instruction* instr); 300 301 // Stop helper functions. 302 bool IsWatchpoint(uint32_t code); 303 void PrintWatchpoint(uint32_t code); 304 void HandleStop(uint32_t code, Instruction* instr); 305 bool IsStopInstruction(Instruction* instr); 306 bool IsEnabledStop(uint32_t code); 307 void EnableStop(uint32_t code); 308 void DisableStop(uint32_t code); 309 void IncreaseStopCounter(uint32_t code); 310 void PrintStopInfo(uint32_t code); 311 312 313 // Executes one instruction. 314 void InstructionDecode(Instruction* instr); 315 // Execute one instruction placed in a branch delay slot. 316 void BranchDelayInstructionDecode(Instruction* instr) { 317 if (instr->InstructionBits() == nopInstr) { 318 // Short-cut generic nop instructions. They are always valid and they 319 // never change the simulator state. 320 return; 321 } 322 323 if (instr->IsForbiddenInBranchDelay()) { 324 V8_Fatal(__FILE__, __LINE__, 325 "Eror:Unexpected %i opcode in a branch delay slot.", 326 instr->OpcodeValue()); 327 } 328 InstructionDecode(instr); 329 } 330 331 // ICache. 332 static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr); 333 static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start, 334 int size); 335 static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page); 336 337 enum Exception { 338 none, 339 kIntegerOverflow, 340 kIntegerUnderflow, 341 kDivideByZero, 342 kNumExceptions 343 }; 344 int16_t exceptions[kNumExceptions]; 345 346 // Exceptions. 347 void SignalExceptions(); 348 349 // Runtime call support. 350 static void* RedirectExternalReference(void* external_function, 351 ExternalReference::Type type); 352 353 // Handle arguments and return value for runtime FP functions. 354 void GetFpArgs(double* x, double* y, int32_t* z); 355 void SetFpResult(const double& result); 356 357 void CallInternal(byte* entry); 358 359 // Architecture state. 360 // Registers. 361 int32_t registers_[kNumSimuRegisters]; 362 // Coprocessor Registers. 363 int32_t FPUregisters_[kNumFPURegisters]; 364 // FPU control register. 365 uint32_t FCSR_; 366 367 // Simulator support. 368 // Allocate 1MB for stack. 369 static const size_t stack_size_ = 1 * 1024*1024; 370 char* stack_; 371 bool pc_modified_; 372 int icount_; 373 int break_count_; 374 375 // Debugger input. 376 char* last_debugger_input_; 377 378 // Icache simulation. 379 v8::internal::HashMap* i_cache_; 380 381 v8::internal::Isolate* isolate_; 382 383 // Registered breakpoints. 384 Instruction* break_pc_; 385 Instr break_instr_; 386 387 // Stop is disabled if bit 31 is set. 388 static const uint32_t kStopDisabledBit = 1 << 31; 389 390 // A stop is enabled, meaning the simulator will stop when meeting the 391 // instruction, if bit 31 of watched_stops_[code].count is unset. 392 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times 393 // the breakpoint was hit or gone through. 394 struct StopCountAndDesc { 395 uint32_t count; 396 char* desc; 397 }; 398 StopCountAndDesc watched_stops_[kMaxStopCode + 1]; 399 }; 400 401 402 // When running with the simulator transition into simulated execution at this 403 // point. 404 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ 405 reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \ 406 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4)) 407 408 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \ 409 Simulator::current(Isolate::Current())->Call( \ 410 entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8) 411 412 #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ 413 try_catch_address == NULL ? \ 414 NULL : *(reinterpret_cast<TryCatch**>(try_catch_address)) 415 416 417 // The simulator has its own stack. Thus it has a different stack limit from 418 // the C-based native code. Setting the c_limit to indicate a very small 419 // stack cause stack overflow errors, since the simulator ignores the input. 420 // This is unlikely to be an issue in practice, though it might cause testing 421 // trouble down the line. 422 class SimulatorStack : public v8::internal::AllStatic { 423 public: 424 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate, 425 uintptr_t c_limit) { 426 return Simulator::current(isolate)->StackLimit(); 427 } 428 429 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { 430 Simulator* sim = Simulator::current(Isolate::Current()); 431 return sim->PushAddress(try_catch_address); 432 } 433 434 static inline void UnregisterCTryCatch() { 435 Simulator::current(Isolate::Current())->PopAddress(); 436 } 437 }; 438 439 } } // namespace v8::internal 440 441 #endif // !defined(USE_SIMULATOR) 442 #endif // V8_MIPS_SIMULATOR_MIPS_H_ 443