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