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 41 #if defined(__mips) 42 43 // When running without a simulator we call the entry directly. 44 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ 45 entry(p0, p1, p2, p3, p4); 46 47 // The stack limit beyond which we will throw stack overflow errors in 48 // generated code. Because generated code on mips uses the C stack, we 49 // just use the C stack limit. 50 class SimulatorStack : public v8::internal::AllStatic { 51 public: 52 static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) { 53 return c_limit; 54 } 55 56 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { 57 return try_catch_address; 58 } 59 60 static inline void UnregisterCTryCatch() { } 61 }; 62 63 // Calculated the stack limit beyond which we will throw stack overflow errors. 64 // This macro must be called from a C++ method. It relies on being able to take 65 // the address of "this" to get a value on the current execution stack and then 66 // calculates the stack limit based on that value. 67 // NOTE: The check for overflow is not safe as there is no guarantee that the 68 // running thread has its stack in all memory up to address 0x00000000. 69 #define GENERATED_CODE_STACK_LIMIT(limit) \ 70 (reinterpret_cast<uintptr_t>(this) >= limit ? \ 71 reinterpret_cast<uintptr_t>(this) - limit : 0) 72 73 // Call the generated regexp code directly. The entry function pointer should 74 // expect seven int/pointer sized arguments and return an int. 75 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ 76 entry(p0, p1, p2, p3, p4, p5, p6) 77 78 #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ 79 reinterpret_cast<TryCatch*>(try_catch_address) 80 81 82 #else // #if defined(__mips) 83 84 // When running with the simulator transition into simulated execution at this 85 // point. 86 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ 87 reinterpret_cast<Object*>(\ 88 assembler::mips::Simulator::current()->Call(FUNCTION_ADDR(entry), 5, \ 89 p0, p1, p2, p3, p4)) 90 91 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ 92 assembler::mips::Simulator::current()->Call(\ 93 FUNCTION_ADDR(entry), 7, p0, p1, p2, p3, p4, p5, p6) 94 95 #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ 96 try_catch_address == NULL ? \ 97 NULL : *(reinterpret_cast<TryCatch**>(try_catch_address)) 98 99 100 namespace assembler { 101 namespace mips { 102 103 class Simulator { 104 public: 105 friend class Debugger; 106 107 // Registers are declared in order. See SMRL chapter 2. 108 enum Register { 109 no_reg = -1, 110 zero_reg = 0, 111 at, 112 v0, v1, 113 a0, a1, a2, a3, 114 t0, t1, t2, t3, t4, t5, t6, t7, 115 s0, s1, s2, s3, s4, s5, s6, s7, 116 t8, t9, 117 k0, k1, 118 gp, 119 sp, 120 s8, 121 ra, 122 // LO, HI, and pc 123 LO, 124 HI, 125 pc, // pc must be the last register. 126 kNumSimuRegisters, 127 // aliases 128 fp = s8 129 }; 130 131 // Coprocessor registers. 132 // Generated code will always use doubles. So we will only use even registers. 133 enum FPURegister { 134 f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, 135 f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters 136 f16, f17, f18, f19, f20, f21, f22, f23, f24, f25, 137 f26, f27, f28, f29, f30, f31, 138 kNumFPURegisters 139 }; 140 141 Simulator(); 142 ~Simulator(); 143 144 // The currently executing Simulator instance. Potentially there can be one 145 // for each native thread. 146 static Simulator* current(); 147 148 // Accessors for register state. Reading the pc value adheres to the MIPS 149 // architecture specification and is off by a 8 from the currently executing 150 // instruction. 151 void set_register(int reg, int32_t value); 152 int32_t get_register(int reg) const; 153 // Same for FPURegisters 154 void set_fpu_register(int fpureg, int32_t value); 155 void set_fpu_register_double(int fpureg, double value); 156 int32_t get_fpu_register(int fpureg) const; 157 double get_fpu_register_double(int fpureg) const; 158 159 // Special case of set_register and get_register to access the raw PC value. 160 void set_pc(int32_t value); 161 int32_t get_pc() const; 162 163 // Accessor to the internal simulator stack area. 164 uintptr_t StackLimit() const; 165 166 // Executes MIPS instructions until the PC reaches end_sim_pc. 167 void Execute(); 168 169 // Call on program start. 170 static void Initialize(); 171 172 // V8 generally calls into generated JS code with 5 parameters and into 173 // generated RegExp code with 7 parameters. This is a convenience function, 174 // which sets up the simulator state and grabs the result on return. 175 int32_t Call(byte_* entry, int argument_count, ...); 176 177 // Push an address onto the JS stack. 178 uintptr_t PushAddress(uintptr_t address); 179 180 // Pop an address from the JS stack. 181 uintptr_t PopAddress(); 182 183 private: 184 enum special_values { 185 // Known bad pc value to ensure that the simulator does not execute 186 // without being properly setup. 187 bad_ra = -1, 188 // A pc value used to signal the simulator to stop execution. Generally 189 // the ra is set to this value on transition from native C code to 190 // simulated execution, so that the simulator can "return" to the native 191 // C code. 192 end_sim_pc = -2, 193 // Unpredictable value. 194 Unpredictable = 0xbadbeaf 195 }; 196 197 // Unsupported instructions use Format to print an error and stop execution. 198 void Format(Instruction* instr, const char* format); 199 200 // Read and write memory. 201 inline uint32_t ReadBU(int32_t addr); 202 inline int32_t ReadB(int32_t addr); 203 inline void WriteB(int32_t addr, uint8_t value); 204 inline void WriteB(int32_t addr, int8_t value); 205 206 inline uint16_t ReadHU(int32_t addr, Instruction* instr); 207 inline int16_t ReadH(int32_t addr, Instruction* instr); 208 // Note: Overloaded on the sign of the value. 209 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr); 210 inline void WriteH(int32_t addr, int16_t value, Instruction* instr); 211 212 inline int ReadW(int32_t addr, Instruction* instr); 213 inline void WriteW(int32_t addr, int value, Instruction* instr); 214 215 inline double ReadD(int32_t addr, Instruction* instr); 216 inline void WriteD(int32_t addr, double value, Instruction* instr); 217 218 // Operations depending on endianness. 219 // Get Double Higher / Lower word. 220 inline int32_t GetDoubleHIW(double* addr); 221 inline int32_t GetDoubleLOW(double* addr); 222 // Set Double Higher / Lower word. 223 inline int32_t SetDoubleHIW(double* addr); 224 inline int32_t SetDoubleLOW(double* addr); 225 226 227 // Executing is handled based on the instruction type. 228 void DecodeTypeRegister(Instruction* instr); 229 void DecodeTypeImmediate(Instruction* instr); 230 void DecodeTypeJump(Instruction* instr); 231 232 // Used for breakpoints and traps. 233 void SoftwareInterrupt(Instruction* instr); 234 235 // Executes one instruction. 236 void InstructionDecode(Instruction* instr); 237 // Execute one instruction placed in a branch delay slot. 238 void BranchDelayInstructionDecode(Instruction* instr) { 239 if (instr->IsForbiddenInBranchDelay()) { 240 V8_Fatal(__FILE__, __LINE__, 241 "Eror:Unexpected %i opcode in a branch delay slot.", 242 instr->OpcodeField()); 243 } 244 InstructionDecode(instr); 245 } 246 247 enum Exception { 248 none, 249 kIntegerOverflow, 250 kIntegerUnderflow, 251 kDivideByZero, 252 kNumExceptions 253 }; 254 int16_t exceptions[kNumExceptions]; 255 256 // Exceptions. 257 void SignalExceptions(); 258 259 // Runtime call support. 260 static void* RedirectExternalReference(void* external_function, 261 bool fp_return); 262 263 // Used for real time calls that takes two double values as arguments and 264 // returns a double. 265 void SetFpResult(double result); 266 267 // Architecture state. 268 // Registers. 269 int32_t registers_[kNumSimuRegisters]; 270 // Coprocessor Registers. 271 int32_t FPUregisters_[kNumFPURegisters]; 272 273 // Simulator support. 274 char* stack_; 275 bool pc_modified_; 276 int icount_; 277 static bool initialized_; 278 279 // Registered breakpoints. 280 Instruction* break_pc_; 281 Instr break_instr_; 282 }; 283 284 } } // namespace assembler::mips 285 286 287 // The simulator has its own stack. Thus it has a different stack limit from 288 // the C-based native code. Setting the c_limit to indicate a very small 289 // stack cause stack overflow errors, since the simulator ignores the input. 290 // This is unlikely to be an issue in practice, though it might cause testing 291 // trouble down the line. 292 class SimulatorStack : public v8::internal::AllStatic { 293 public: 294 static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) { 295 return assembler::mips::Simulator::current()->StackLimit(); 296 } 297 298 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { 299 assembler::mips::Simulator* sim = assembler::mips::Simulator::current(); 300 return sim->PushAddress(try_catch_address); 301 } 302 303 static inline void UnregisterCTryCatch() { 304 assembler::mips::Simulator::current()->PopAddress(); 305 } 306 }; 307 308 #endif // defined(__mips) 309 310 #endif // V8_MIPS_SIMULATOR_MIPS_H_ 311 312