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