| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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 #ifndef V8_A64_SIMULATOR_A64_H_ | |
| 29 #define V8_A64_SIMULATOR_A64_H_ | |
| 30 | |
| 31 #include <stdarg.h> | |
| 32 #include <vector> | |
| 33 | |
| 34 #include "v8.h" | |
| 35 | |
| 36 #include "globals.h" | |
| 37 #include "utils.h" | |
| 38 #include "allocation.h" | |
| 39 #include "assembler.h" | |
| 40 #include "a64/assembler-a64.h" | |
| 41 #include "a64/decoder-a64.h" | |
| 42 #include "a64/disasm-a64.h" | |
| 43 #include "a64/instrument-a64.h" | |
| 44 | |
| 45 #define REGISTER_CODE_LIST(R) \ | |
| 46 R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ | |
| 47 R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \ | |
| 48 R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \ | |
| 49 R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31) | |
| 50 | |
| 51 namespace v8 { | |
| 52 namespace internal { | |
| 53 | |
| 54 #if !defined(USE_SIMULATOR) | |
| 55 | |
| 56 // Running without a simulator on a native A64 platform. | |
| 57 // When running without a simulator we call the entry directly. | |
| 58 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ | |
| 59 (entry(p0, p1, p2, p3, p4)) | |
| 60 | |
| 61 typedef int (*a64_regexp_matcher)(String* input, | |
| 62 int64_t start_offset, | |
| 63 const byte* input_start, | |
| 64 const byte* input_end, | |
| 65 int* output, | |
| 66 int64_t output_size, | |
| 67 Address stack_base, | |
| 68 int64_t direct_call, | |
| 69 void* return_address, | |
| 70 Isolate* isolate); | |
| 71 | |
| 72 // Call the generated regexp code directly. The code at the entry address | |
| 73 // should act as a function matching the type a64_regexp_matcher. | |
| 74 // The ninth argument is a dummy that reserves the space used for | |
| 75 // the return address added by the ExitFrame in native calls. | |
| 76 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \ | |
| 77 (FUNCTION_CAST<a64_regexp_matcher>(entry)( \ | |
| 78 p0, p1, p2, p3, p4, p5, p6, p7, NULL, p8)) | |
| 79 | |
| 80 #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ | |
| 81 reinterpret_cast<TryCatch*>(try_catch_address) | |
| 82 | |
| 83 // Running without a simulator there is nothing to do. | |
| 84 class SimulatorStack : public v8::internal::AllStatic { | |
| 85 public: | |
| 86 static uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate, | |
| 87 uintptr_t c_limit) { | |
| 88 USE(isolate); | |
| 89 return c_limit; | |
| 90 } | |
| 91 | |
| 92 static uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { | |
| 93 return try_catch_address; | |
| 94 } | |
| 95 | |
| 96 static void UnregisterCTryCatch() { } | |
| 97 }; | |
| 98 | |
| 99 #else // !defined(USE_SIMULATOR) | |
| 100 | |
| 101 enum ReverseByteMode { | |
| 102 Reverse16 = 0, | |
| 103 Reverse32 = 1, | |
| 104 Reverse64 = 2 | |
| 105 }; | |
| 106 | |
| 107 | |
| 108 // The proper way to initialize a simulated system register (such as NZCV) is as | |
| 109 // follows: | |
| 110 // SimSystemRegister nzcv = SimSystemRegister::DefaultValueFor(NZCV); | |
| 111 class SimSystemRegister { | |
| 112 public: | |
| 113 // The default constructor represents a register which has no writable bits. | |
| 114 // It is not possible to set its value to anything other than 0. | |
| 115 SimSystemRegister() : value_(0), write_ignore_mask_(0xffffffff) { } | |
| 116 | |
| 117 uint32_t RawValue() const { | |
| 118 return value_; | |
| 119 } | |
| 120 | |
| 121 void SetRawValue(uint32_t new_value) { | |
| 122 value_ = (value_ & write_ignore_mask_) | (new_value & ~write_ignore_mask_); | |
| 123 } | |
| 124 | |
| 125 uint32_t Bits(int msb, int lsb) const { | |
| 126 return unsigned_bitextract_32(msb, lsb, value_); | |
| 127 } | |
| 128 | |
| 129 int32_t SignedBits(int msb, int lsb) const { | |
| 130 return signed_bitextract_32(msb, lsb, value_); | |
| 131 } | |
| 132 | |
| 133 void SetBits(int msb, int lsb, uint32_t bits); | |
| 134 | |
| 135 // Default system register values. | |
| 136 static SimSystemRegister DefaultValueFor(SystemRegister id); | |
| 137 | |
| 138 #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \ | |
| 139 uint32_t Name() const { return Func(HighBit, LowBit); } \ | |
| 140 void Set##Name(uint32_t bits) { SetBits(HighBit, LowBit, bits); } | |
| 141 #define DEFINE_WRITE_IGNORE_MASK(Name, Mask) \ | |
| 142 static const uint32_t Name##WriteIgnoreMask = ~static_cast<uint32_t>(Mask); | |
| 143 | |
| 144 SYSTEM_REGISTER_FIELDS_LIST(DEFINE_GETTER, DEFINE_WRITE_IGNORE_MASK) | |
| 145 | |
| 146 #undef DEFINE_ZERO_BITS | |
| 147 #undef DEFINE_GETTER | |
| 148 | |
| 149 protected: | |
| 150 // Most system registers only implement a few of the bits in the word. Other | |
| 151 // bits are "read-as-zero, write-ignored". The write_ignore_mask argument | |
| 152 // describes the bits which are not modifiable. | |
| 153 SimSystemRegister(uint32_t value, uint32_t write_ignore_mask) | |
| 154 : value_(value), write_ignore_mask_(write_ignore_mask) { } | |
| 155 | |
| 156 uint32_t value_; | |
| 157 uint32_t write_ignore_mask_; | |
| 158 }; | |
| 159 | |
| 160 | |
| 161 // Represent a register (r0-r31, v0-v31). | |
| 162 template<int kSizeInBytes> | |
| 163 class SimRegisterBase { | |
| 164 public: | |
| 165 template<typename T> | |
| 166 void Set(T new_value, unsigned size = sizeof(T)) { | |
| 167 ASSERT(size <= kSizeInBytes); | |
| 168 ASSERT(size <= sizeof(new_value)); | |
| 169 // All AArch64 registers are zero-extending; Writing a W register clears the | |
| 170 // top bits of the corresponding X register. | |
| 171 memset(value_, 0, kSizeInBytes); | |
| 172 memcpy(value_, &new_value, size); | |
| 173 } | |
| 174 | |
| 175 // Copy 'size' bytes of the register to the result, and zero-extend to fill | |
| 176 // the result. | |
| 177 template<typename T> | |
| 178 T Get(unsigned size = sizeof(T)) const { | |
| 179 ASSERT(size <= kSizeInBytes); | |
| 180 T result; | |
| 181 memset(&result, 0, sizeof(result)); | |
| 182 memcpy(&result, value_, size); | |
| 183 return result; | |
| 184 } | |
| 185 | |
| 186 protected: | |
| 187 uint8_t value_[kSizeInBytes]; | |
| 188 }; | |
| 189 typedef SimRegisterBase<kXRegSizeInBytes> SimRegister; // r0-r31 | |
| 190 typedef SimRegisterBase<kDRegSizeInBytes> SimFPRegister; // v0-v31 | |
| 191 | |
| 192 | |
| 193 class Simulator : public DecoderVisitor { | |
| 194 public: | |
| 195 explicit Simulator(Decoder* decoder, | |
| 196 Isolate* isolate = NULL, | |
| 197 FILE* stream = stderr); | |
| 198 ~Simulator(); | |
| 199 | |
| 200 // System functions. | |
| 201 | |
| 202 static void Initialize(Isolate* isolate); | |
| 203 | |
| 204 static Simulator* current(v8::internal::Isolate* isolate); | |
| 205 | |
| 206 class CallArgument; | |
| 207 | |
| 208 // Call an arbitrary function taking an arbitrary number of arguments. The | |
| 209 // varargs list must be a set of arguments with type CallArgument, and | |
| 210 // terminated by CallArgument::End(). | |
| 211 void CallVoid(byte* entry, CallArgument* args); | |
| 212 | |
| 213 // Like CallVoid, but expect a return value. | |
| 214 int64_t CallInt64(byte* entry, CallArgument* args); | |
| 215 double CallDouble(byte* entry, CallArgument* args); | |
| 216 | |
| 217 // V8 calls into generated JS code with 5 parameters and into | |
| 218 // generated RegExp code with 10 parameters. These are convenience functions, | |
| 219 // which set up the simulator state and grab the result on return. | |
| 220 int64_t CallJS(byte* entry, | |
| 221 byte* function_entry, | |
| 222 JSFunction* func, | |
| 223 Object* revc, | |
| 224 int64_t argc, | |
| 225 Object*** argv); | |
| 226 int64_t CallRegExp(byte* entry, | |
| 227 String* input, | |
| 228 int64_t start_offset, | |
| 229 const byte* input_start, | |
| 230 const byte* input_end, | |
| 231 int* output, | |
| 232 int64_t output_size, | |
| 233 Address stack_base, | |
| 234 int64_t direct_call, | |
| 235 void* return_address, | |
| 236 Isolate* isolate); | |
| 237 | |
| 238 // A wrapper class that stores an argument for one of the above Call | |
| 239 // functions. | |
| 240 // | |
| 241 // Only arguments up to 64 bits in size are supported. | |
| 242 class CallArgument { | |
| 243 public: | |
| 244 template<typename T> | |
| 245 explicit CallArgument(T argument) { | |
| 246 ASSERT(sizeof(argument) <= sizeof(bits_)); | |
| 247 memcpy(&bits_, &argument, sizeof(argument)); | |
| 248 type_ = X_ARG; | |
| 249 } | |
| 250 | |
| 251 explicit CallArgument(double argument) { | |
| 252 ASSERT(sizeof(argument) == sizeof(bits_)); | |
| 253 memcpy(&bits_, &argument, sizeof(argument)); | |
| 254 type_ = D_ARG; | |
| 255 } | |
| 256 | |
| 257 explicit CallArgument(float argument) { | |
| 258 // TODO(all): CallArgument(float) is untested, remove this check once | |
| 259 // tested. | |
| 260 UNIMPLEMENTED(); | |
| 261 // Make the D register a NaN to try to trap errors if the callee expects a | |
| 262 // double. If it expects a float, the callee should ignore the top word. | |
| 263 ASSERT(sizeof(kFP64SignallingNaN) == sizeof(bits_)); | |
| 264 memcpy(&bits_, &kFP64SignallingNaN, sizeof(kFP64SignallingNaN)); | |
| 265 // Write the float payload to the S register. | |
| 266 ASSERT(sizeof(argument) <= sizeof(bits_)); | |
| 267 memcpy(&bits_, &argument, sizeof(argument)); | |
| 268 type_ = D_ARG; | |
| 269 } | |
| 270 | |
| 271 // This indicates the end of the arguments list, so that CallArgument | |
| 272 // objects can be passed into varargs functions. | |
| 273 static CallArgument End() { return CallArgument(); } | |
| 274 | |
| 275 int64_t bits() const { return bits_; } | |
| 276 bool IsEnd() const { return type_ == NO_ARG; } | |
| 277 bool IsX() const { return type_ == X_ARG; } | |
| 278 bool IsD() const { return type_ == D_ARG; } | |
| 279 | |
| 280 private: | |
| 281 enum CallArgumentType { X_ARG, D_ARG, NO_ARG }; | |
| 282 | |
| 283 // All arguments are aligned to at least 64 bits and we don't support | |
| 284 // passing bigger arguments, so the payload size can be fixed at 64 bits. | |
| 285 int64_t bits_; | |
| 286 CallArgumentType type_; | |
| 287 | |
| 288 CallArgument() { type_ = NO_ARG; } | |
| 289 }; | |
| 290 | |
| 291 | |
| 292 // Start the debugging command line. | |
| 293 void Debug(); | |
| 294 | |
| 295 bool GetValue(const char* desc, int64_t* value); | |
| 296 | |
| 297 bool PrintValue(const char* desc); | |
| 298 | |
| 299 // Push an address onto the JS stack. | |
| 300 uintptr_t PushAddress(uintptr_t address); | |
| 301 | |
| 302 // Pop an address from the JS stack. | |
| 303 uintptr_t PopAddress(); | |
| 304 | |
| 305 // Accessor to the internal simulator stack area. | |
| 306 uintptr_t StackLimit() const; | |
| 307 | |
| 308 void ResetState(); | |
| 309 | |
| 310 // Runtime call support. | |
| 311 static void* RedirectExternalReference(void* external_function, | |
| 312 ExternalReference::Type type); | |
| 313 | |
| 314 // Run the simulator. | |
| 315 static const Instruction* kEndOfSimAddress; | |
| 316 void DecodeInstruction(); | |
| 317 void Run(); | |
| 318 void RunFrom(Instruction* start); | |
| 319 | |
| 320 // Simulation helpers. | |
| 321 template <typename T> | |
| 322 void set_pc(T new_pc) { | |
| 323 ASSERT(sizeof(T) == sizeof(pc_)); | |
| 324 memcpy(&pc_, &new_pc, sizeof(T)); | |
| 325 pc_modified_ = true; | |
| 326 } | |
| 327 Instruction* pc() { return pc_; } | |
| 328 | |
| 329 void increment_pc() { | |
| 330 if (!pc_modified_) { | |
| 331 pc_ = pc_->NextInstruction(); | |
| 332 } | |
| 333 | |
| 334 pc_modified_ = false; | |
| 335 } | |
| 336 | |
| 337 void ExecuteInstruction() { | |
| 338 ASSERT(IsAligned(reinterpret_cast<uintptr_t>(pc_), kInstructionSize)); | |
| 339 CheckBreakNext(); | |
| 340 decoder_->Decode(pc_); | |
| 341 LogProcessorState(); | |
| 342 increment_pc(); | |
| 343 CheckBreakpoints(); | |
| 344 } | |
| 345 | |
| 346 // Declare all Visitor functions. | |
| 347 #define DECLARE(A) void Visit##A(Instruction* instr); | |
| 348 VISITOR_LIST(DECLARE) | |
| 349 #undef DECLARE | |
| 350 | |
| 351 // Register accessors. | |
| 352 | |
| 353 // Return 'size' bits of the value of an integer register, as the specified | |
| 354 // type. The value is zero-extended to fill the result. | |
| 355 // | |
| 356 // The only supported values of 'size' are kXRegSize and kWRegSize. | |
| 357 template<typename T> | |
| 358 T reg(unsigned size, unsigned code, | |
| 359 Reg31Mode r31mode = Reg31IsZeroRegister) const { | |
| 360 unsigned size_in_bytes = size / 8; | |
| 361 ASSERT(size_in_bytes <= sizeof(T)); | |
| 362 ASSERT((size == kXRegSize) || (size == kWRegSize)); | |
| 363 ASSERT(code < kNumberOfRegisters); | |
| 364 | |
| 365 if ((code == 31) && (r31mode == Reg31IsZeroRegister)) { | |
| 366 T result; | |
| 367 memset(&result, 0, sizeof(result)); | |
| 368 return result; | |
| 369 } | |
| 370 return registers_[code].Get<T>(size_in_bytes); | |
| 371 } | |
| 372 | |
| 373 // Like reg(), but infer the access size from the template type. | |
| 374 template<typename T> | |
| 375 T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { | |
| 376 return reg<T>(sizeof(T) * 8, code, r31mode); | |
| 377 } | |
| 378 | |
| 379 // Common specialized accessors for the reg() template. | |
| 380 int32_t wreg(unsigned code, | |
| 381 Reg31Mode r31mode = Reg31IsZeroRegister) const { | |
| 382 return reg<int32_t>(code, r31mode); | |
| 383 } | |
| 384 | |
| 385 int64_t xreg(unsigned code, | |
| 386 Reg31Mode r31mode = Reg31IsZeroRegister) const { | |
| 387 return reg<int64_t>(code, r31mode); | |
| 388 } | |
| 389 | |
| 390 int64_t reg(unsigned size, unsigned code, | |
| 391 Reg31Mode r31mode = Reg31IsZeroRegister) const { | |
| 392 return reg<int64_t>(size, code, r31mode); | |
| 393 } | |
| 394 | |
| 395 // Write 'size' bits of 'value' into an integer register. The value is | |
| 396 // zero-extended. This behaviour matches AArch64 register writes. | |
| 397 // | |
| 398 // The only supported values of 'size' are kXRegSize and kWRegSize. | |
| 399 template<typename T> | |
| 400 void set_reg(unsigned size, unsigned code, T value, | |
| 401 Reg31Mode r31mode = Reg31IsZeroRegister) { | |
| 402 unsigned size_in_bytes = size / 8; | |
| 403 ASSERT(size_in_bytes <= sizeof(T)); | |
| 404 ASSERT((size == kXRegSize) || (size == kWRegSize)); | |
| 405 ASSERT(code < kNumberOfRegisters); | |
| 406 | |
| 407 if ((code == 31) && (r31mode == Reg31IsZeroRegister)) { | |
| 408 return; | |
| 409 } | |
| 410 return registers_[code].Set(value, size_in_bytes); | |
| 411 } | |
| 412 | |
| 413 // Like set_reg(), but infer the access size from the template type. | |
| 414 template<typename T> | |
| 415 void set_reg(unsigned code, T value, | |
| 416 Reg31Mode r31mode = Reg31IsZeroRegister) { | |
| 417 set_reg(sizeof(value) * 8, code, value, r31mode); | |
| 418 } | |
| 419 | |
| 420 // Common specialized accessors for the set_reg() template. | |
| 421 void set_wreg(unsigned code, int32_t value, | |
| 422 Reg31Mode r31mode = Reg31IsZeroRegister) { | |
| 423 set_reg(kWRegSize, code, value, r31mode); | |
| 424 } | |
| 425 | |
| 426 void set_xreg(unsigned code, int64_t value, | |
| 427 Reg31Mode r31mode = Reg31IsZeroRegister) { | |
| 428 set_reg(kXRegSize, code, value, r31mode); | |
| 429 } | |
| 430 | |
| 431 // Commonly-used special cases. | |
| 432 template<typename T> | |
| 433 void set_lr(T value) { | |
| 434 ASSERT(sizeof(T) == kPointerSize); | |
| 435 set_reg(kLinkRegCode, value); | |
| 436 } | |
| 437 | |
| 438 template<typename T> | |
| 439 void set_sp(T value) { | |
| 440 ASSERT(sizeof(T) == kPointerSize); | |
| 441 set_reg(31, value, Reg31IsStackPointer); | |
| 442 } | |
| 443 | |
| 444 int64_t sp() { return xreg(31, Reg31IsStackPointer); } | |
| 445 int64_t jssp() { return xreg(kJSSPCode, Reg31IsStackPointer); } | |
| 446 int64_t fp() { | |
| 447 return xreg(kFramePointerRegCode, Reg31IsStackPointer); | |
| 448 } | |
| 449 Instruction* lr() { return reg<Instruction*>(kLinkRegCode); } | |
| 450 | |
| 451 Address get_sp() { return reg<Address>(31, Reg31IsStackPointer); } | |
| 452 | |
| 453 // Return 'size' bits of the value of a floating-point register, as the | |
| 454 // specified type. The value is zero-extended to fill the result. | |
| 455 // | |
| 456 // The only supported values of 'size' are kDRegSize and kSRegSize. | |
| 457 template<typename T> | |
| 458 T fpreg(unsigned size, unsigned code) const { | |
| 459 unsigned size_in_bytes = size / 8; | |
| 460 ASSERT(size_in_bytes <= sizeof(T)); | |
| 461 ASSERT((size == kDRegSize) || (size == kSRegSize)); | |
| 462 ASSERT(code < kNumberOfFPRegisters); | |
| 463 return fpregisters_[code].Get<T>(size_in_bytes); | |
| 464 } | |
| 465 | |
| 466 // Like fpreg(), but infer the access size from the template type. | |
| 467 template<typename T> | |
| 468 T fpreg(unsigned code) const { | |
| 469 return fpreg<T>(sizeof(T) * 8, code); | |
| 470 } | |
| 471 | |
| 472 // Common specialized accessors for the fpreg() template. | |
| 473 float sreg(unsigned code) const { | |
| 474 return fpreg<float>(code); | |
| 475 } | |
| 476 | |
| 477 uint32_t sreg_bits(unsigned code) const { | |
| 478 return fpreg<uint32_t>(code); | |
| 479 } | |
| 480 | |
| 481 double dreg(unsigned code) const { | |
| 482 return fpreg<double>(code); | |
| 483 } | |
| 484 | |
| 485 uint64_t dreg_bits(unsigned code) const { | |
| 486 return fpreg<uint64_t>(code); | |
| 487 } | |
| 488 | |
| 489 double fpreg(unsigned size, unsigned code) const { | |
| 490 switch (size) { | |
| 491 case kSRegSize: return sreg(code); | |
| 492 case kDRegSize: return dreg(code); | |
| 493 default: | |
| 494 UNREACHABLE(); | |
| 495 return 0.0; | |
| 496 } | |
| 497 } | |
| 498 | |
| 499 // Write 'value' into a floating-point register. The value is zero-extended. | |
| 500 // This behaviour matches AArch64 register writes. | |
| 501 template<typename T> | |
| 502 void set_fpreg(unsigned code, T value) { | |
| 503 ASSERT((sizeof(value) == kDRegSizeInBytes) || | |
| 504 (sizeof(value) == kSRegSizeInBytes)); | |
| 505 ASSERT(code < kNumberOfFPRegisters); | |
| 506 fpregisters_[code].Set(value, sizeof(value)); | |
| 507 } | |
| 508 | |
| 509 // Common specialized accessors for the set_fpreg() template. | |
| 510 void set_sreg(unsigned code, float value) { | |
| 511 set_fpreg(code, value); | |
| 512 } | |
| 513 | |
| 514 void set_sreg_bits(unsigned code, uint32_t value) { | |
| 515 set_fpreg(code, value); | |
| 516 } | |
| 517 | |
| 518 void set_dreg(unsigned code, double value) { | |
| 519 set_fpreg(code, value); | |
| 520 } | |
| 521 | |
| 522 void set_dreg_bits(unsigned code, uint64_t value) { | |
| 523 set_fpreg(code, value); | |
| 524 } | |
| 525 | |
| 526 bool N() { return nzcv_.N() != 0; } | |
| 527 bool Z() { return nzcv_.Z() != 0; } | |
| 528 bool C() { return nzcv_.C() != 0; } | |
| 529 bool V() { return nzcv_.V() != 0; } | |
| 530 SimSystemRegister& nzcv() { return nzcv_; } | |
| 531 | |
| 532 // TODO(jbramley): Find a way to make the fpcr_ members return the proper | |
| 533 // types, so this accessor is not necessary. | |
| 534 FPRounding RMode() { return static_cast<FPRounding>(fpcr_.RMode()); } | |
| 535 SimSystemRegister& fpcr() { return fpcr_; } | |
| 536 | |
| 537 // Debug helpers | |
| 538 | |
| 539 // Simulator breakpoints. | |
| 540 struct Breakpoint { | |
| 541 Instruction* location; | |
| 542 bool enabled; | |
| 543 }; | |
| 544 std::vector<Breakpoint> breakpoints_; | |
| 545 void SetBreakpoint(Instruction* breakpoint); | |
| 546 void ListBreakpoints(); | |
| 547 void CheckBreakpoints(); | |
| 548 | |
| 549 // Helpers for the 'next' command. | |
| 550 // When this is set, the Simulator will insert a breakpoint after the next BL | |
| 551 // instruction it meets. | |
| 552 bool break_on_next_; | |
| 553 // Check if the Simulator should insert a break after the current instruction | |
| 554 // for the 'next' command. | |
| 555 void CheckBreakNext(); | |
| 556 | |
| 557 // Disassemble instruction at the given address. | |
| 558 void PrintInstructionsAt(Instruction* pc, uint64_t count); | |
| 559 | |
| 560 void PrintSystemRegisters(bool print_all = false); | |
| 561 void PrintRegisters(bool print_all_regs = false); | |
| 562 void PrintFPRegisters(bool print_all_regs = false); | |
| 563 void PrintProcessorState(); | |
| 564 void PrintWrite(uint8_t* address, uint64_t value, unsigned num_bytes); | |
| 565 void LogSystemRegisters() { | |
| 566 if (log_parameters_ & LOG_SYS_REGS) PrintSystemRegisters(); | |
| 567 } | |
| 568 void LogRegisters() { | |
| 569 if (log_parameters_ & LOG_REGS) PrintRegisters(); | |
| 570 } | |
| 571 void LogFPRegisters() { | |
| 572 if (log_parameters_ & LOG_FP_REGS) PrintFPRegisters(); | |
| 573 } | |
| 574 void LogProcessorState() { | |
| 575 LogSystemRegisters(); | |
| 576 LogRegisters(); | |
| 577 LogFPRegisters(); | |
| 578 } | |
| 579 void LogWrite(uint8_t* address, uint64_t value, unsigned num_bytes) { | |
| 580 if (log_parameters_ & LOG_WRITE) PrintWrite(address, value, num_bytes); | |
| 581 } | |
| 582 | |
| 583 int log_parameters() { return log_parameters_; } | |
| 584 void set_log_parameters(int new_parameters) { | |
| 585 if (new_parameters & LOG_DISASM) { | |
| 586 decoder_->InsertVisitorBefore(print_disasm_, this); | |
| 587 } else { | |
| 588 decoder_->RemoveVisitor(print_disasm_); | |
| 589 } | |
| 590 log_parameters_ = new_parameters; | |
| 591 } | |
| 592 | |
| 593 static inline const char* WRegNameForCode(unsigned code, | |
| 594 Reg31Mode mode = Reg31IsZeroRegister); | |
| 595 static inline const char* XRegNameForCode(unsigned code, | |
| 596 Reg31Mode mode = Reg31IsZeroRegister); | |
| 597 static inline const char* SRegNameForCode(unsigned code); | |
| 598 static inline const char* DRegNameForCode(unsigned code); | |
| 599 static inline const char* VRegNameForCode(unsigned code); | |
| 600 static inline int CodeFromName(const char* name); | |
| 601 | |
| 602 protected: | |
| 603 // Simulation helpers ------------------------------------ | |
| 604 bool ConditionPassed(Condition cond) { | |
| 605 switch (cond) { | |
| 606 case eq: | |
| 607 return Z(); | |
| 608 case ne: | |
| 609 return !Z(); | |
| 610 case hs: | |
| 611 return C(); | |
| 612 case lo: | |
| 613 return !C(); | |
| 614 case mi: | |
| 615 return N(); | |
| 616 case pl: | |
| 617 return !N(); | |
| 618 case vs: | |
| 619 return V(); | |
| 620 case vc: | |
| 621 return !V(); | |
| 622 case hi: | |
| 623 return C() && !Z(); | |
| 624 case ls: | |
| 625 return !(C() && !Z()); | |
| 626 case ge: | |
| 627 return N() == V(); | |
| 628 case lt: | |
| 629 return N() != V(); | |
| 630 case gt: | |
| 631 return !Z() && (N() == V()); | |
| 632 case le: | |
| 633 return !(!Z() && (N() == V())); | |
| 634 case nv: // Fall through. | |
| 635 case al: | |
| 636 return true; | |
| 637 default: | |
| 638 UNREACHABLE(); | |
| 639 return false; | |
| 640 } | |
| 641 } | |
| 642 | |
| 643 bool ConditionFailed(Condition cond) { | |
| 644 return !ConditionPassed(cond); | |
| 645 } | |
| 646 | |
| 647 void AddSubHelper(Instruction* instr, int64_t op2); | |
| 648 int64_t AddWithCarry(unsigned reg_size, | |
| 649 bool set_flags, | |
| 650 int64_t src1, | |
| 651 int64_t src2, | |
| 652 int64_t carry_in = 0); | |
| 653 void LogicalHelper(Instruction* instr, int64_t op2); | |
| 654 void ConditionalCompareHelper(Instruction* instr, int64_t op2); | |
| 655 void LoadStoreHelper(Instruction* instr, | |
| 656 int64_t offset, | |
| 657 AddrMode addrmode); | |
| 658 void LoadStorePairHelper(Instruction* instr, AddrMode addrmode); | |
| 659 uint8_t* LoadStoreAddress(unsigned addr_reg, | |
| 660 int64_t offset, | |
| 661 AddrMode addrmode); | |
| 662 void LoadStoreWriteBack(unsigned addr_reg, | |
| 663 int64_t offset, | |
| 664 AddrMode addrmode); | |
| 665 void CheckMemoryAccess(uint8_t* address, uint8_t* stack); | |
| 666 | |
| 667 uint64_t MemoryRead(uint8_t* address, unsigned num_bytes); | |
| 668 uint8_t MemoryRead8(uint8_t* address); | |
| 669 uint16_t MemoryRead16(uint8_t* address); | |
| 670 uint32_t MemoryRead32(uint8_t* address); | |
| 671 float MemoryReadFP32(uint8_t* address); | |
| 672 uint64_t MemoryRead64(uint8_t* address); | |
| 673 double MemoryReadFP64(uint8_t* address); | |
| 674 | |
| 675 void MemoryWrite(uint8_t* address, uint64_t value, unsigned num_bytes); | |
| 676 void MemoryWrite32(uint8_t* address, uint32_t value); | |
| 677 void MemoryWriteFP32(uint8_t* address, float value); | |
| 678 void MemoryWrite64(uint8_t* address, uint64_t value); | |
| 679 void MemoryWriteFP64(uint8_t* address, double value); | |
| 680 | |
| 681 int64_t ShiftOperand(unsigned reg_size, | |
| 682 int64_t value, | |
| 683 Shift shift_type, | |
| 684 unsigned amount); | |
| 685 int64_t Rotate(unsigned reg_width, | |
| 686 int64_t value, | |
| 687 Shift shift_type, | |
| 688 unsigned amount); | |
| 689 int64_t ExtendValue(unsigned reg_width, | |
| 690 int64_t value, | |
| 691 Extend extend_type, | |
| 692 unsigned left_shift = 0); | |
| 693 | |
| 694 uint64_t ReverseBits(uint64_t value, unsigned num_bits); | |
| 695 uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode); | |
| 696 | |
| 697 void FPCompare(double val0, double val1); | |
| 698 double FPRoundInt(double value, FPRounding round_mode); | |
| 699 double FPToDouble(float value); | |
| 700 float FPToFloat(double value, FPRounding round_mode); | |
| 701 double FixedToDouble(int64_t src, int fbits, FPRounding round_mode); | |
| 702 double UFixedToDouble(uint64_t src, int fbits, FPRounding round_mode); | |
| 703 float FixedToFloat(int64_t src, int fbits, FPRounding round_mode); | |
| 704 float UFixedToFloat(uint64_t src, int fbits, FPRounding round_mode); | |
| 705 int32_t FPToInt32(double value, FPRounding rmode); | |
| 706 int64_t FPToInt64(double value, FPRounding rmode); | |
| 707 uint32_t FPToUInt32(double value, FPRounding rmode); | |
| 708 uint64_t FPToUInt64(double value, FPRounding rmode); | |
| 709 | |
| 710 template <typename T> | |
| 711 T FPMax(T a, T b); | |
| 712 | |
| 713 template <typename T> | |
| 714 T FPMin(T a, T b); | |
| 715 | |
| 716 template <typename T> | |
| 717 T FPMaxNM(T a, T b); | |
| 718 | |
| 719 template <typename T> | |
| 720 T FPMinNM(T a, T b); | |
| 721 | |
| 722 void CheckStackAlignment(); | |
| 723 | |
| 724 inline void CheckPCSComplianceAndRun(); | |
| 725 | |
| 726 #ifdef DEBUG | |
| 727 // Corruption values should have their least significant byte cleared to | |
| 728 // allow the code of the register being corrupted to be inserted. | |
| 729 static const uint64_t kCallerSavedRegisterCorruptionValue = | |
| 730 0xca11edc0de000000UL; | |
| 731 // This value is a NaN in both 32-bit and 64-bit FP. | |
| 732 static const uint64_t kCallerSavedFPRegisterCorruptionValue = | |
| 733 0x7ff000007f801000UL; | |
| 734 // This value is a mix of 32/64-bits NaN and "verbose" immediate. | |
| 735 static const uint64_t kDefaultCPURegisterCorruptionValue = | |
| 736 0x7ffbad007f8bad00UL; | |
| 737 | |
| 738 void CorruptRegisters(CPURegList* list, | |
| 739 uint64_t value = kDefaultCPURegisterCorruptionValue); | |
| 740 void CorruptAllCallerSavedCPURegisters(); | |
| 741 #endif | |
| 742 | |
| 743 // Processor state --------------------------------------- | |
| 744 | |
| 745 // Output stream. | |
| 746 FILE* stream_; | |
| 747 PrintDisassembler* print_disasm_; | |
| 748 | |
| 749 // Instrumentation. | |
| 750 Instrument* instrument_; | |
| 751 | |
| 752 // General purpose registers. Register 31 is the stack pointer. | |
| 753 SimRegister registers_[kNumberOfRegisters]; | |
| 754 | |
| 755 // Floating point registers | |
| 756 SimFPRegister fpregisters_[kNumberOfFPRegisters]; | |
| 757 | |
| 758 // Processor state | |
| 759 // bits[31, 27]: Condition flags N, Z, C, and V. | |
| 760 // (Negative, Zero, Carry, Overflow) | |
| 761 SimSystemRegister nzcv_; | |
| 762 | |
| 763 // Floating-Point Control Register | |
| 764 SimSystemRegister fpcr_; | |
| 765 | |
| 766 // Only a subset of FPCR features are supported by the simulator. This helper | |
| 767 // checks that the FPCR settings are supported. | |
| 768 // | |
| 769 // This is checked when floating-point instructions are executed, not when | |
| 770 // FPCR is set. This allows generated code to modify FPCR for external | |
| 771 // functions, or to save and restore it when entering and leaving generated | |
| 772 // code. | |
| 773 void AssertSupportedFPCR() { | |
| 774 ASSERT(fpcr().DN() == 0); // No default-NaN support. | |
| 775 ASSERT(fpcr().FZ() == 0); // No flush-to-zero support. | |
| 776 ASSERT(fpcr().RMode() == FPTieEven); // Ties-to-even rounding only. | |
| 777 | |
| 778 // The simulator does not support half-precision operations so fpcr().AHP() | |
| 779 // is irrelevant, and is not checked here. | |
| 780 } | |
| 781 | |
| 782 static int CalcNFlag(uint64_t result, unsigned reg_size) { | |
| 783 return (result >> (reg_size - 1)) & 1; | |
| 784 } | |
| 785 | |
| 786 static int CalcZFlag(uint64_t result) { | |
| 787 return result == 0; | |
| 788 } | |
| 789 | |
| 790 static const uint32_t kConditionFlagsMask = 0xf0000000; | |
| 791 | |
| 792 // Stack | |
| 793 byte* stack_; | |
| 794 static const intptr_t stack_protection_size_ = KB; | |
| 795 intptr_t stack_size_; | |
| 796 byte* stack_limit_; | |
| 797 // TODO(aleram): protect the stack. | |
| 798 | |
| 799 Decoder* decoder_; | |
| 800 Decoder* disassembler_decoder_; | |
| 801 | |
| 802 // Indicates if the pc has been modified by the instruction and should not be | |
| 803 // automatically incremented. | |
| 804 bool pc_modified_; | |
| 805 Instruction* pc_; | |
| 806 | |
| 807 static const char* xreg_names[]; | |
| 808 static const char* wreg_names[]; | |
| 809 static const char* sreg_names[]; | |
| 810 static const char* dreg_names[]; | |
| 811 static const char* vreg_names[]; | |
| 812 | |
| 813 // Debugger input. | |
| 814 void set_last_debugger_input(char* input) { | |
| 815 DeleteArray(last_debugger_input_); | |
| 816 last_debugger_input_ = input; | |
| 817 } | |
| 818 char* last_debugger_input() { return last_debugger_input_; } | |
| 819 char* last_debugger_input_; | |
| 820 | |
| 821 private: | |
| 822 int log_parameters_; | |
| 823 Isolate* isolate_; | |
| 824 }; | |
| 825 | |
| 826 | |
| 827 // When running with the simulator transition into simulated execution at this | |
| 828 // point. | |
| 829 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ | |
| 830 reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->CallJS( \ | |
| 831 FUNCTION_ADDR(entry), \ | |
| 832 p0, p1, p2, p3, p4)) | |
| 833 | |
| 834 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \ | |
| 835 Simulator::current(Isolate::Current())->CallRegExp( \ | |
| 836 entry, \ | |
| 837 p0, p1, p2, p3, p4, p5, p6, p7, NULL, p8) | |
| 838 | |
| 839 #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ | |
| 840 try_catch_address == NULL ? \ | |
| 841 NULL : *(reinterpret_cast<TryCatch**>(try_catch_address)) | |
| 842 | |
| 843 | |
| 844 // The simulator has its own stack. Thus it has a different stack limit from | |
| 845 // the C-based native code. | |
| 846 // See also 'class SimulatorStack' in arm/simulator-arm.h. | |
| 847 class SimulatorStack : public v8::internal::AllStatic { | |
| 848 public: | |
| 849 static uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate, | |
| 850 uintptr_t c_limit) { | |
| 851 return Simulator::current(isolate)->StackLimit(); | |
| 852 } | |
| 853 | |
| 854 static uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { | |
| 855 Simulator* sim = Simulator::current(Isolate::Current()); | |
| 856 return sim->PushAddress(try_catch_address); | |
| 857 } | |
| 858 | |
| 859 static void UnregisterCTryCatch() { | |
| 860 Simulator::current(Isolate::Current())->PopAddress(); | |
| 861 } | |
| 862 }; | |
| 863 | |
| 864 #endif // !defined(USE_SIMULATOR) | |
| 865 | |
| 866 } } // namespace v8::internal | |
| 867 | |
| 868 #endif // V8_A64_SIMULATOR_A64_H_ | |
| OLD | NEW |