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