| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef VM_ASSEMBLER_X64_H_ | 5 #ifndef VM_ASSEMBLER_X64_H_ |
| 6 #define VM_ASSEMBLER_X64_H_ | 6 #define VM_ASSEMBLER_X64_H_ |
| 7 | 7 |
| 8 #ifndef VM_ASSEMBLER_H_ | 8 #ifndef VM_ASSEMBLER_H_ |
| 9 #error Do not include assembler_x64.h directly; use assembler.h instead. | 9 #error Do not include assembler_x64.h directly; use assembler.h instead. |
| 10 #endif | 10 #endif |
| 11 | 11 |
| 12 #include "vm/assert.h" | 12 #include "vm/assert.h" |
| 13 #include "vm/constants_x64.h" | 13 #include "vm/constants_x64.h" |
| 14 #include "vm/utils.h" | 14 #include "vm/utils.h" |
| 15 | 15 |
| 16 namespace dart { | 16 namespace dart { |
| 17 | 17 |
| 18 // Forward declarations. | 18 // Forward declarations. |
| 19 class RuntimeEntry; | 19 class RuntimeEntry; |
| 20 | 20 |
| 21 | 21 |
| 22 #if defined(TESTING) || defined(DEBUG) | 22 #if defined(TESTING) || defined(DEBUG) |
| 23 | 23 |
| 24 #if defined(TARGET_OS_WINDOWS) |
| 24 #define CHECK_STACK_ALIGNMENT { \ | 25 #define CHECK_STACK_ALIGNMENT { \ |
| 25 UNIMPLEMENTED(); \ | 26 uword current_sp; \ |
| 27 __asm { mov current_sp, rsp } \ |
| 28 ASSERT((OS::ActivationFrameAlignment() == 0) || \ |
| 29 (Utils::IsAligned(current_sp, OS::ActivationFrameAlignment()))); \ |
| 26 } | 30 } |
| 31 #else |
| 32 #define CHECK_STACK_ALIGNMENT { \ |
| 33 uword current_sp; \ |
| 34 asm volatile("mov %%rsp, %[current_sp]" : [current_sp] "=r" (current_sp)); \ |
| 35 ASSERT((OS::ActivationFrameAlignment() == 0) || \ |
| 36 (Utils::IsAligned(current_sp, OS::ActivationFrameAlignment()))); \ |
| 37 } |
| 38 #endif |
| 27 | 39 |
| 28 #else | 40 #else |
| 29 | 41 |
| 30 #define CHECK_STACK_ALIGNMENT { } | 42 #define CHECK_STACK_ALIGNMENT { } |
| 31 | 43 |
| 32 #endif | 44 #endif |
| 33 | 45 |
| 34 | 46 |
| 35 class Immediate : public ValueObject { | 47 class Immediate : public ValueObject { |
| 36 public: | 48 public: |
| (...skipping 18 matching lines...) Expand all Loading... |
| 55 public: | 67 public: |
| 56 uint8_t rex() const { | 68 uint8_t rex() const { |
| 57 return rex_; | 69 return rex_; |
| 58 } | 70 } |
| 59 | 71 |
| 60 uint8_t mod() const { | 72 uint8_t mod() const { |
| 61 return (encoding_at(0) >> 6) & 3; | 73 return (encoding_at(0) >> 6) & 3; |
| 62 } | 74 } |
| 63 | 75 |
| 64 Register rm() const { | 76 Register rm() const { |
| 65 int rm_rex = (rex_ & 1) << 3; | 77 int rm_rex = (rex_ & REX_B) << 3; |
| 66 return static_cast<Register>(rm_rex + (encoding_at(0) & 7)); | 78 return static_cast<Register>(rm_rex + (encoding_at(0) & 7)); |
| 67 } | 79 } |
| 68 | 80 |
| 69 ScaleFactor scale() const { | 81 ScaleFactor scale() const { |
| 70 return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3); | 82 return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3); |
| 71 } | 83 } |
| 72 | 84 |
| 73 Register index() const { | 85 Register index() const { |
| 74 int index_rex = (rex_ & 2) << 2; | 86 int index_rex = (rex_ & REX_X) << 2; |
| 75 return static_cast<Register>(index_rex + ((encoding_at(1) >> 3) & 7)); | 87 return static_cast<Register>(index_rex + ((encoding_at(1) >> 3) & 7)); |
| 76 } | 88 } |
| 77 | 89 |
| 78 Register base() const { | 90 Register base() const { |
| 79 int base_rex = (rex_ & 1) << 3; | 91 int base_rex = (rex_ & REX_B) << 3; |
| 80 return static_cast<Register>(base_rex + (encoding_at(1) & 7)); | 92 return static_cast<Register>(base_rex + (encoding_at(1) & 7)); |
| 81 } | 93 } |
| 82 | 94 |
| 83 int8_t disp8() const { | 95 int8_t disp8() const { |
| 84 ASSERT(length_ >= 2); | 96 ASSERT(length_ >= 2); |
| 85 return static_cast<int8_t>(encoding_[length_ - 1]); | 97 return static_cast<int8_t>(encoding_[length_ - 1]); |
| 86 } | 98 } |
| 87 | 99 |
| 88 int32_t disp32() const { | 100 int32_t disp32() const { |
| 89 ASSERT(length_ >= 5); | 101 ASSERT(length_ >= 5); |
| 90 return bit_copy<int32_t>(encoding_[length_ - 4]); | 102 return bit_copy<int32_t>(encoding_[length_ - 4]); |
| 91 } | 103 } |
| 92 | 104 |
| 93 protected: | 105 protected: |
| 94 Operand() : length_(0), rex_(0) { } | 106 Operand() : length_(0), rex_(REX_NONE) { } |
| 95 | 107 |
| 96 void SetModRM(int mod, Register rm) { | 108 void SetModRM(int mod, Register rm) { |
| 97 ASSERT((mod & ~3) == 0); | 109 ASSERT((mod & ~3) == 0); |
| 98 if (rm > 7) rex_ |= 1; | 110 if ((rm > 7) && !((rm == R12) && (mod != 3))) { |
| 111 rex_ |= REX_B; |
| 112 } |
| 99 encoding_[0] = (mod << 6) | (rm & 7); | 113 encoding_[0] = (mod << 6) | (rm & 7); |
| 100 length_ = 1; | 114 length_ = 1; |
| 101 } | 115 } |
| 102 | 116 |
| 103 void SetSIB(ScaleFactor scale, Register index, Register base) { | 117 void SetSIB(ScaleFactor scale, Register index, Register base) { |
| 104 ASSERT(length_ == 1); | 118 ASSERT(length_ == 1); |
| 105 ASSERT((scale & ~3) == 0); | 119 ASSERT((scale & ~3) == 0); |
| 106 if (base > 7) { | 120 if (base > 7) { |
| 107 ASSERT((rex_ & 1) == 0); // Must not have REX.B already set. | 121 ASSERT((rex_ & REX_B) == 0); // Must not have REX.B already set. |
| 108 rex_ |= 1; | 122 rex_ |= REX_B; |
| 109 } | 123 } |
| 110 if (index > 7) rex_ |= 2; | 124 if (index > 7) rex_ |= REX_X; |
| 111 encoding_[1] = (scale << 6) | ((index & 7) << 3) | (base & 7); | 125 encoding_[1] = (scale << 6) | ((index & 7) << 3) | (base & 7); |
| 112 length_ = 2; | 126 length_ = 2; |
| 113 } | 127 } |
| 114 | 128 |
| 115 void SetDisp8(int8_t disp) { | 129 void SetDisp8(int8_t disp) { |
| 116 ASSERT(length_ == 1 || length_ == 2); | 130 ASSERT(length_ == 1 || length_ == 2); |
| 117 encoding_[length_++] = static_cast<uint8_t>(disp); | 131 encoding_[length_++] = static_cast<uint8_t>(disp); |
| 118 } | 132 } |
| 119 | 133 |
| 120 void SetDisp32(int32_t disp) { | 134 void SetDisp32(int32_t disp) { |
| 121 ASSERT(length_ == 1 || length_ == 2); | 135 ASSERT(length_ == 1 || length_ == 2); |
| 122 memmove(&encoding_[length_], &disp, sizeof(disp)); | 136 memmove(&encoding_[length_], &disp, sizeof(disp)); |
| 123 length_ += sizeof(disp); | 137 length_ += sizeof(disp); |
| 124 } | 138 } |
| 125 | 139 |
| 126 private: | 140 private: |
| 127 uint8_t length_; | 141 uint8_t length_; |
| 128 uint8_t rex_; | 142 uint8_t rex_; |
| 129 uint8_t encoding_[6]; | 143 uint8_t encoding_[6]; |
| 130 | 144 |
| 131 explicit Operand(Register reg) : rex_(0) { SetModRM(3, reg); } | 145 explicit Operand(Register reg) : rex_(REX_NONE) { SetModRM(3, reg); } |
| 132 | 146 |
| 133 // Get the operand encoding byte at the given index. | 147 // Get the operand encoding byte at the given index. |
| 134 uint8_t encoding_at(int index) const { | 148 uint8_t encoding_at(int index) const { |
| 135 ASSERT(index >= 0 && index < length_); | 149 ASSERT(index >= 0 && index < length_); |
| 136 return encoding_[index]; | 150 return encoding_[index]; |
| 137 } | 151 } |
| 138 | 152 |
| 139 // Returns whether or not this operand is really the given register in | 153 // Returns whether or not this operand is really the given register in |
| 140 // disguise. Used from the assembler to generate better encodings. | 154 // disguise. Used from the assembler to generate better encodings. |
| 141 bool IsRegister(Register reg) const { | 155 bool IsRegister(Register reg) const { |
| 142 return ((reg > 7 ? 1 : 0) == (rex_ & 1)) // REX.B match. | 156 return ((reg > 7 ? 1 : 0) == (rex_ & REX_B)) // REX.B match. |
| 143 && ((encoding_at(0) & 0xF8) == 0xC0) // Addressing mode is register. | 157 && ((encoding_at(0) & 0xF8) == 0xC0) // Addressing mode is register. |
| 144 && ((encoding_at(0) & 0x07) == reg); // Register codes match. | 158 && ((encoding_at(0) & 0x07) == reg); // Register codes match. |
| 145 } | 159 } |
| 146 | 160 |
| 147 | 161 |
| 148 friend class Assembler; | 162 friend class Assembler; |
| 149 | 163 |
| 150 // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Operand) once the mac | 164 // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Operand) once the mac |
| 151 // build issue is resolved. | 165 // build issue is resolved. |
| 152 }; | 166 }; |
| 153 | 167 |
| 154 | 168 |
| 155 class Address : public Operand { | 169 class Address : public Operand { |
| 156 public: | 170 public: |
| 157 Address(Register base, int32_t disp) { | 171 Address(Register base, int32_t disp) { |
| 158 if (disp == 0 && base != RBP) { | 172 if ((disp == 0) && ((base & 7) != RBP)) { |
| 159 SetModRM(0, base); | 173 SetModRM(0, base); |
| 160 if (base == RSP) SetSIB(TIMES_1, RSP, base); | 174 if ((base & 7) == RSP) { |
| 175 SetSIB(TIMES_1, RSP, base); |
| 176 } |
| 161 } else if (Utils::IsInt(8, disp)) { | 177 } else if (Utils::IsInt(8, disp)) { |
| 162 SetModRM(1, base); | 178 SetModRM(1, base); |
| 163 if (base == RSP) SetSIB(TIMES_1, RSP, base); | 179 if ((base & 7) == RSP) { |
| 180 SetSIB(TIMES_1, RSP, base); |
| 181 } |
| 164 SetDisp8(disp); | 182 SetDisp8(disp); |
| 165 } else { | 183 } else { |
| 166 SetModRM(2, base); | 184 SetModRM(2, base); |
| 167 if (base == RSP) SetSIB(TIMES_1, RSP, base); | 185 if ((base & 7) == RSP) { |
| 186 SetSIB(TIMES_1, RSP, base); |
| 187 } |
| 168 SetDisp32(disp); | 188 SetDisp32(disp); |
| 169 } | 189 } |
| 170 } | 190 } |
| 171 | 191 |
| 172 Address(Register index, ScaleFactor scale, int32_t disp) { | 192 Address(Register index, ScaleFactor scale, int32_t disp) { |
| 173 ASSERT(index != RSP); // Illegal addressing mode. | 193 ASSERT(index != RSP); // Illegal addressing mode. |
| 174 SetModRM(0, RSP); | 194 SetModRM(0, RSP); |
| 175 SetSIB(scale, index, RBP); | 195 SetSIB(scale, index, RBP); |
| 176 SetDisp32(disp); | 196 SetDisp32(disp); |
| 177 } | 197 } |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 */ | 319 */ |
| 300 void call(Register reg); | 320 void call(Register reg); |
| 301 void call(const Address& address); | 321 void call(const Address& address); |
| 302 void call(Label* label); | 322 void call(Label* label); |
| 303 void call(const ExternalLabel* label); | 323 void call(const ExternalLabel* label); |
| 304 | 324 |
| 305 static const intptr_t kCallExternalLabelSize = 5; | 325 static const intptr_t kCallExternalLabelSize = 5; |
| 306 | 326 |
| 307 void pushq(Register reg); | 327 void pushq(Register reg); |
| 308 void pushq(const Address& address); | 328 void pushq(const Address& address); |
| 329 void pushq(const Immediate& imm); |
| 309 | 330 |
| 310 void popq(Register reg); | 331 void popq(Register reg); |
| 311 void popq(const Address& address); | 332 void popq(const Address& address); |
| 312 | 333 |
| 313 void movl(Register dst, Register src); | 334 void movl(Register dst, Register src); |
| 314 void movl(Register dst, const Immediate& imm); | 335 void movl(Register dst, const Immediate& imm); |
| 315 void movl(Register dst, const Address& src); | 336 void movl(Register dst, const Address& src); |
| 316 void movl(const Address& dst, Register src); | 337 void movl(const Address& dst, Register src); |
| 317 | 338 |
| 318 void movzxb(Register dst, Register src); | 339 void movzxb(Register dst, Register src); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 | 384 |
| 364 void xchgl(Register dst, Register src); | 385 void xchgl(Register dst, Register src); |
| 365 void xchgq(Register dst, Register src); | 386 void xchgq(Register dst, Register src); |
| 366 | 387 |
| 367 void cmpl(Register reg, const Immediate& imm); | 388 void cmpl(Register reg, const Immediate& imm); |
| 368 void cmpl(Register reg0, Register reg1); | 389 void cmpl(Register reg0, Register reg1); |
| 369 void cmpl(Register reg, const Address& address); | 390 void cmpl(Register reg, const Address& address); |
| 370 void cmpl(const Address& address, const Immediate& imm); | 391 void cmpl(const Address& address, const Immediate& imm); |
| 371 | 392 |
| 372 void cmpq(Register reg, const Immediate& imm); | 393 void cmpq(Register reg, const Immediate& imm); |
| 394 void cmpq(const Address& address, Register reg); |
| 373 void cmpq(const Address& address, const Immediate& imm); | 395 void cmpq(const Address& address, const Immediate& imm); |
| 374 void cmpq(Register reg0, Register reg1); | 396 void cmpq(Register reg0, Register reg1); |
| 375 void cmpq(Register reg, const Address& address); | 397 void cmpq(Register reg, const Address& address); |
| 376 | 398 |
| 377 void testl(Register reg1, Register reg2); | 399 void testl(Register reg1, Register reg2); |
| 378 void testl(Register reg, const Immediate& imm); | 400 void testl(Register reg, const Immediate& imm); |
| 379 | 401 |
| 380 void testq(Register reg1, Register reg2); | 402 void testq(Register reg1, Register reg2); |
| 381 void testq(Register reg, const Immediate& imm); | 403 void testq(Register reg, const Immediate& imm); |
| 382 | 404 |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 void EnterFrame(intptr_t frame_space); | 520 void EnterFrame(intptr_t frame_space); |
| 499 void LeaveFrame(); | 521 void LeaveFrame(); |
| 500 | 522 |
| 501 void CallRuntimeFromDart(const RuntimeEntry& entry); | 523 void CallRuntimeFromDart(const RuntimeEntry& entry); |
| 502 void CallRuntimeFromStub(const RuntimeEntry& entry); | 524 void CallRuntimeFromStub(const RuntimeEntry& entry); |
| 503 | 525 |
| 504 /* | 526 /* |
| 505 * Misc. functionality. | 527 * Misc. functionality. |
| 506 */ | 528 */ |
| 507 void SmiTag(Register reg) { | 529 void SmiTag(Register reg) { |
| 508 addl(reg, reg); | 530 addq(reg, reg); |
| 509 } | 531 } |
| 510 | 532 |
| 511 void SmiUntag(Register reg) { | 533 void SmiUntag(Register reg) { |
| 512 sarl(reg, Immediate(kSmiTagSize)); | 534 sarq(reg, Immediate(kSmiTagSize)); |
| 513 } | 535 } |
| 514 | 536 |
| 515 int PreferredLoopAlignment() { return 16; } | 537 int PreferredLoopAlignment() { return 16; } |
| 516 void Align(int alignment, int offset); | 538 void Align(int alignment, int offset); |
| 517 void Bind(Label* label); | 539 void Bind(Label* label); |
| 518 | 540 |
| 519 int CodeSize() const { return buffer_.Size(); } | 541 int CodeSize() const { return buffer_.Size(); } |
| 520 int prolog_offset() const { return prolog_offset_; } | 542 int prolog_offset() const { return prolog_offset_; } |
| 521 const ZoneGrowableArray<int>& GetPointerOffsets() const { | 543 const ZoneGrowableArray<int>& GetPointerOffsets() const { |
| 522 return buffer_.pointer_offsets(); | 544 return buffer_.pointer_offsets(); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 557 void EmitNearLabelLink(Label* label); | 579 void EmitNearLabelLink(Label* label); |
| 558 | 580 |
| 559 void EmitGenericShift(bool wide, int rm, Register reg, const Immediate& imm); | 581 void EmitGenericShift(bool wide, int rm, Register reg, const Immediate& imm); |
| 560 void EmitGenericShift(bool wide, int rm, Register operand, Register shifter); | 582 void EmitGenericShift(bool wide, int rm, Register operand, Register shifter); |
| 561 | 583 |
| 562 DISALLOW_ALLOCATION(); | 584 DISALLOW_ALLOCATION(); |
| 563 DISALLOW_COPY_AND_ASSIGN(Assembler); | 585 DISALLOW_COPY_AND_ASSIGN(Assembler); |
| 564 }; | 586 }; |
| 565 | 587 |
| 566 | 588 |
| 567 enum { | |
| 568 REX_NONE = 0, | |
| 569 REX_B = 1 << 0, | |
| 570 REX_X = 1 << 1, | |
| 571 REX_R = 1 << 2, | |
| 572 REX_W = 1 << 3 | |
| 573 }; | |
| 574 | |
| 575 | |
| 576 inline void Assembler::EmitUint8(uint8_t value) { | 589 inline void Assembler::EmitUint8(uint8_t value) { |
| 577 buffer_.Emit<uint8_t>(value); | 590 buffer_.Emit<uint8_t>(value); |
| 578 } | 591 } |
| 579 | 592 |
| 580 | 593 |
| 581 inline void Assembler::EmitInt32(int32_t value) { | 594 inline void Assembler::EmitInt32(int32_t value) { |
| 582 buffer_.Emit<int32_t>(value); | 595 buffer_.Emit<int32_t>(value); |
| 583 } | 596 } |
| 584 | 597 |
| 585 | 598 |
| 586 inline void Assembler::EmitInt64(int64_t value) { | 599 inline void Assembler::EmitInt64(int64_t value) { |
| 587 buffer_.Emit<int64_t>(value); | 600 buffer_.Emit<int64_t>(value); |
| 588 } | 601 } |
| 589 | 602 |
| 590 | 603 |
| 591 inline void Assembler::EmitRegisterREX(Register reg, uint8_t rex) { | 604 inline void Assembler::EmitRegisterREX(Register reg, uint8_t rex) { |
| 592 ASSERT(reg != kNoRegister); | 605 ASSERT(reg != kNoRegister); |
| 593 rex |= (reg > 7 ? REX_B : REX_NONE); | 606 rex |= (reg > 7 ? REX_B : REX_NONE); |
| 594 if (rex != 0) EmitUint8(0x40 | rex); | 607 if (rex != REX_NONE) EmitUint8(REX_PREFIX | rex); |
| 595 } | 608 } |
| 596 | 609 |
| 597 | 610 |
| 598 inline void Assembler::EmitOperandREX(int rm, | 611 inline void Assembler::EmitOperandREX(int rm, |
| 599 const Operand& operand, | 612 const Operand& operand, |
| 600 uint8_t rex) { | 613 uint8_t rex) { |
| 601 rex |= (rm > 7 ? REX_R : REX_NONE) | operand.rex(); | 614 rex |= (rm > 7 ? REX_R : REX_NONE) | operand.rex(); |
| 602 if (rex != 0) EmitUint8(0x40 | rex); | 615 if (rex != REX_NONE) EmitUint8(REX_PREFIX | rex); |
| 603 } | 616 } |
| 604 | 617 |
| 605 | 618 |
| 606 inline void Assembler::EmitFixup(AssemblerFixup* fixup) { | 619 inline void Assembler::EmitFixup(AssemblerFixup* fixup) { |
| 607 buffer_.EmitFixup(fixup); | 620 buffer_.EmitFixup(fixup); |
| 608 } | 621 } |
| 609 | 622 |
| 610 | 623 |
| 611 inline void Assembler::EmitOperandSizeOverride() { | 624 inline void Assembler::EmitOperandSizeOverride() { |
| 612 EmitUint8(0x66); | 625 EmitUint8(0x66); |
| 613 } | 626 } |
| 614 | 627 |
| 615 } // namespace dart | 628 } // namespace dart |
| 616 | 629 |
| 617 #endif // VM_ASSEMBLER_X64_H_ | 630 #endif // VM_ASSEMBLER_X64_H_ |
| OLD | NEW |