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 ARM instructions if we are not generating a native 30 // ARM binary. This Simulator allows us to run and debug ARM code generation on 31 // 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 ARM HW platform. 35 36 #ifndef V8_ARM_SIMULATOR_ARM_H_ 37 #define V8_ARM_SIMULATOR_ARM_H_ 38 39 #include "allocation.h" 40 41 #if !defined(USE_SIMULATOR) 42 // Running without a simulator on a native arm platform. 43 44 namespace v8 { 45 namespace internal { 46 47 // When running without a simulator we call the entry directly. 48 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ 49 (entry(p0, p1, p2, p3, p4)) 50 51 typedef int (*arm_regexp_matcher)(String*, int, const byte*, const byte*, 52 void*, int*, Address, int, Isolate*); 53 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<arm_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 arm uses the C stack, we 68 // just use the C stack limit. 69 class SimulatorStack : public v8::internal::AllStatic { 70 public: JsLimitFromCLimit(v8::internal::Isolate * isolate,uintptr_t c_limit)71 static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate, 72 uintptr_t c_limit) { 73 USE(isolate); 74 return c_limit; 75 } 76 RegisterCTryCatch(uintptr_t try_catch_address)77 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { 78 return try_catch_address; 79 } 80 UnregisterCTryCatch()81 static inline void UnregisterCTryCatch() { } 82 }; 83 84 } } // namespace v8::internal 85 86 #else // !defined(USE_SIMULATOR) 87 // Running with a simulator. 88 89 #include "constants-arm.h" 90 #include "hashmap.h" 91 #include "assembler.h" 92 93 namespace v8 { 94 namespace internal { 95 96 class CachePage { 97 public: 98 static const int LINE_VALID = 0; 99 static const int LINE_INVALID = 1; 100 101 static const int kPageShift = 12; 102 static const int kPageSize = 1 << kPageShift; 103 static const int kPageMask = kPageSize - 1; 104 static const int kLineShift = 2; // The cache line is only 4 bytes right now. 105 static const int kLineLength = 1 << kLineShift; 106 static const int kLineMask = kLineLength - 1; 107 CachePage()108 CachePage() { 109 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); 110 } 111 ValidityByte(int offset)112 char* ValidityByte(int offset) { 113 return &validity_map_[offset >> kLineShift]; 114 } 115 CachedData(int offset)116 char* CachedData(int offset) { 117 return &data_[offset]; 118 } 119 120 private: 121 char data_[kPageSize]; // The cached data. 122 static const int kValidityMapSize = kPageSize >> kLineShift; 123 char validity_map_[kValidityMapSize]; // One byte per line. 124 }; 125 126 127 class Simulator { 128 public: 129 friend class ArmDebugger; 130 enum Register { 131 no_reg = -1, 132 r0 = 0, r1, r2, r3, r4, r5, r6, r7, 133 r8, r9, r10, r11, r12, r13, r14, r15, 134 num_registers, 135 sp = 13, 136 lr = 14, 137 pc = 15, 138 s0 = 0, s1, s2, s3, s4, s5, s6, s7, 139 s8, s9, s10, s11, s12, s13, s14, s15, 140 s16, s17, s18, s19, s20, s21, s22, s23, 141 s24, s25, s26, s27, s28, s29, s30, s31, 142 num_s_registers = 32, 143 d0 = 0, d1, d2, d3, d4, d5, d6, d7, 144 d8, d9, d10, d11, d12, d13, d14, d15, 145 num_d_registers = 16 146 }; 147 148 explicit Simulator(Isolate* isolate); 149 ~Simulator(); 150 151 // The currently executing Simulator instance. Potentially there can be one 152 // for each native thread. 153 static Simulator* current(v8::internal::Isolate* isolate); 154 155 // Accessors for register state. Reading the pc value adheres to the ARM 156 // architecture specification and is off by a 8 from the currently executing 157 // instruction. 158 void set_register(int reg, int32_t value); 159 int32_t get_register(int reg) const; 160 double get_double_from_register_pair(int reg); 161 void set_dw_register(int dreg, const int* dbl); 162 163 // Support for VFP. 164 void set_s_register(int reg, unsigned int value); 165 unsigned int get_s_register(int reg) const; 166 void set_d_register_from_double(int dreg, const double& dbl); 167 double get_double_from_d_register(int dreg); 168 void set_s_register_from_float(int sreg, const float dbl); 169 float get_float_from_s_register(int sreg); 170 void set_s_register_from_sinteger(int reg, const int value); 171 int get_sinteger_from_s_register(int reg); 172 173 // Special case of set_register and get_register to access the raw PC value. 174 void set_pc(int32_t value); 175 int32_t get_pc() const; 176 177 // Accessor to the internal simulator stack area. 178 uintptr_t StackLimit() const; 179 180 // Executes ARM instructions until the PC reaches end_sim_pc. 181 void Execute(); 182 183 // Call on program start. 184 static void Initialize(Isolate* isolate); 185 186 // V8 generally calls into generated JS code with 5 parameters and into 187 // generated RegExp code with 7 parameters. This is a convenience function, 188 // which sets up the simulator state and grabs the result on return. 189 int32_t Call(byte* entry, int argument_count, ...); 190 191 // Push an address onto the JS stack. 192 uintptr_t PushAddress(uintptr_t address); 193 194 // Pop an address from the JS stack. 195 uintptr_t PopAddress(); 196 197 // Debugger input. 198 void set_last_debugger_input(char* input); last_debugger_input()199 char* last_debugger_input() { return last_debugger_input_; } 200 201 // ICache checking. 202 static void FlushICache(v8::internal::HashMap* i_cache, void* start, 203 size_t size); 204 205 // Returns true if pc register contains one of the 'special_values' defined 206 // below (bad_lr, end_sim_pc). 207 bool has_bad_pc() const; 208 209 // EABI variant for double arguments in use. use_eabi_hardfloat()210 bool use_eabi_hardfloat() { 211 #if USE_EABI_HARDFLOAT 212 return true; 213 #else 214 return false; 215 #endif 216 } 217 218 private: 219 enum special_values { 220 // Known bad pc value to ensure that the simulator does not execute 221 // without being properly setup. 222 bad_lr = -1, 223 // A pc value used to signal the simulator to stop execution. Generally 224 // the lr is set to this value on transition from native C code to 225 // simulated execution, so that the simulator can "return" to the native 226 // C code. 227 end_sim_pc = -2 228 }; 229 230 // Unsupported instructions use Format to print an error and stop execution. 231 void Format(Instruction* instr, const char* format); 232 233 // Checks if the current instruction should be executed based on its 234 // condition bits. 235 bool ConditionallyExecute(Instruction* instr); 236 237 // Helper functions to set the conditional flags in the architecture state. 238 void SetNZFlags(int32_t val); 239 void SetCFlag(bool val); 240 void SetVFlag(bool val); 241 bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0); 242 bool BorrowFrom(int32_t left, int32_t right); 243 bool OverflowFrom(int32_t alu_out, 244 int32_t left, 245 int32_t right, 246 bool addition); 247 GetCarry()248 inline int GetCarry() { 249 return c_flag_ ? 1 : 0; 250 }; 251 252 // Support for VFP. 253 void Compute_FPSCR_Flags(double val1, double val2); 254 void Copy_FPSCR_to_APSR(); 255 256 // Helper functions to decode common "addressing" modes 257 int32_t GetShiftRm(Instruction* instr, bool* carry_out); 258 int32_t GetImm(Instruction* instr, bool* carry_out); 259 void ProcessPUW(Instruction* instr, 260 int num_regs, 261 int operand_size, 262 intptr_t* start_address, 263 intptr_t* end_address); 264 void HandleRList(Instruction* instr, bool load); 265 void HandleVList(Instruction* inst); 266 void SoftwareInterrupt(Instruction* instr); 267 268 // Stop helper functions. 269 inline bool isStopInstruction(Instruction* instr); 270 inline bool isWatchedStop(uint32_t bkpt_code); 271 inline bool isEnabledStop(uint32_t bkpt_code); 272 inline void EnableStop(uint32_t bkpt_code); 273 inline void DisableStop(uint32_t bkpt_code); 274 inline void IncreaseStopCounter(uint32_t bkpt_code); 275 void PrintStopInfo(uint32_t code); 276 277 // Read and write memory. 278 inline uint8_t ReadBU(int32_t addr); 279 inline int8_t ReadB(int32_t addr); 280 inline void WriteB(int32_t addr, uint8_t value); 281 inline void WriteB(int32_t addr, int8_t value); 282 283 inline uint16_t ReadHU(int32_t addr, Instruction* instr); 284 inline int16_t ReadH(int32_t addr, Instruction* instr); 285 // Note: Overloaded on the sign of the value. 286 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr); 287 inline void WriteH(int32_t addr, int16_t value, Instruction* instr); 288 289 inline int ReadW(int32_t addr, Instruction* instr); 290 inline void WriteW(int32_t addr, int value, Instruction* instr); 291 292 int32_t* ReadDW(int32_t addr); 293 void WriteDW(int32_t addr, int32_t value1, int32_t value2); 294 295 // Executing is handled based on the instruction type. 296 // Both type 0 and type 1 rolled into one. 297 void DecodeType01(Instruction* instr); 298 void DecodeType2(Instruction* instr); 299 void DecodeType3(Instruction* instr); 300 void DecodeType4(Instruction* instr); 301 void DecodeType5(Instruction* instr); 302 void DecodeType6(Instruction* instr); 303 void DecodeType7(Instruction* instr); 304 305 // Support for VFP. 306 void DecodeTypeVFP(Instruction* instr); 307 void DecodeType6CoprocessorIns(Instruction* instr); 308 309 void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instruction* instr); 310 void DecodeVCMP(Instruction* instr); 311 void DecodeVCVTBetweenDoubleAndSingle(Instruction* instr); 312 void DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr); 313 314 // Executes one instruction. 315 void InstructionDecode(Instruction* instr); 316 317 // ICache. 318 static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr); 319 static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start, 320 int size); 321 static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page); 322 323 // Runtime call support. 324 static void* RedirectExternalReference( 325 void* external_function, 326 v8::internal::ExternalReference::Type type); 327 328 // For use in calls that take double value arguments. 329 void GetFpArgs(double* x, double* y); 330 void GetFpArgs(double* x); 331 void GetFpArgs(double* x, int32_t* y); 332 void SetFpResult(const double& result); 333 void TrashCallerSaveRegisters(); 334 335 // Architecture state. 336 // Saturating instructions require a Q flag to indicate saturation. 337 // There is currently no way to read the CPSR directly, and thus read the Q 338 // flag, so this is left unimplemented. 339 int32_t registers_[16]; 340 bool n_flag_; 341 bool z_flag_; 342 bool c_flag_; 343 bool v_flag_; 344 345 // VFP architecture state. 346 unsigned int vfp_register[num_s_registers]; 347 bool n_flag_FPSCR_; 348 bool z_flag_FPSCR_; 349 bool c_flag_FPSCR_; 350 bool v_flag_FPSCR_; 351 352 // VFP rounding mode. See ARM DDI 0406B Page A2-29. 353 VFPRoundingMode FPSCR_rounding_mode_; 354 355 // VFP FP exception flags architecture state. 356 bool inv_op_vfp_flag_; 357 bool div_zero_vfp_flag_; 358 bool overflow_vfp_flag_; 359 bool underflow_vfp_flag_; 360 bool inexact_vfp_flag_; 361 362 // Simulator support. 363 char* stack_; 364 bool pc_modified_; 365 int icount_; 366 367 // Debugger input. 368 char* last_debugger_input_; 369 370 // Icache simulation 371 v8::internal::HashMap* i_cache_; 372 373 // Registered breakpoints. 374 Instruction* break_pc_; 375 Instr break_instr_; 376 377 v8::internal::Isolate* isolate_; 378 379 // A stop is watched if its code is less than kNumOfWatchedStops. 380 // Only watched stops support enabling/disabling and the counter feature. 381 static const uint32_t kNumOfWatchedStops = 256; 382 383 // Breakpoint is disabled if bit 31 is set. 384 static const uint32_t kStopDisabledBit = 1 << 31; 385 386 // A stop is enabled, meaning the simulator will stop when meeting the 387 // instruction, if bit 31 of watched_stops[code].count is unset. 388 // The value watched_stops[code].count & ~(1 << 31) indicates how many times 389 // the breakpoint was hit or gone through. 390 struct StopCountAndDesc { 391 uint32_t count; 392 char* desc; 393 }; 394 StopCountAndDesc watched_stops[kNumOfWatchedStops]; 395 }; 396 397 398 // When running with the simulator transition into simulated execution at this 399 // point. 400 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ 401 reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \ 402 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4)) 403 404 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \ 405 Simulator::current(Isolate::Current())->Call( \ 406 entry, 9, p0, p1, p2, p3, NULL, p4, p5, p6, p7) 407 408 #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ 409 try_catch_address == NULL ? \ 410 NULL : *(reinterpret_cast<TryCatch**>(try_catch_address)) 411 412 413 // The simulator has its own stack. Thus it has a different stack limit from 414 // the C-based native code. Setting the c_limit to indicate a very small 415 // stack cause stack overflow errors, since the simulator ignores the input. 416 // This is unlikely to be an issue in practice, though it might cause testing 417 // trouble down the line. 418 class SimulatorStack : public v8::internal::AllStatic { 419 public: JsLimitFromCLimit(v8::internal::Isolate * isolate,uintptr_t c_limit)420 static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate, 421 uintptr_t c_limit) { 422 return Simulator::current(isolate)->StackLimit(); 423 } 424 RegisterCTryCatch(uintptr_t try_catch_address)425 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { 426 Simulator* sim = Simulator::current(Isolate::Current()); 427 return sim->PushAddress(try_catch_address); 428 } 429 UnregisterCTryCatch()430 static inline void UnregisterCTryCatch() { 431 Simulator::current(Isolate::Current())->PopAddress(); 432 } 433 }; 434 435 } } // namespace v8::internal 436 437 #endif // !defined(USE_SIMULATOR) 438 #endif // V8_ARM_SIMULATOR_ARM_H_ 439