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 |