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