OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 RUNTIME_VM_ASSEMBLER_IA32_H_ | 5 #ifndef RUNTIME_VM_ASSEMBLER_IA32_H_ |
6 #define RUNTIME_VM_ASSEMBLER_IA32_H_ | 6 #define RUNTIME_VM_ASSEMBLER_IA32_H_ |
7 | 7 |
8 #ifndef RUNTIME_VM_ASSEMBLER_H_ | 8 #ifndef RUNTIME_VM_ASSEMBLER_H_ |
9 #error Do not include assembler_ia32.h directly; use assembler.h instead. | 9 #error Do not include assembler_ia32.h directly; use assembler.h instead. |
10 #endif | 10 #endif |
11 | 11 |
12 #include "platform/assert.h" | 12 #include "platform/assert.h" |
13 #include "platform/utils.h" | 13 #include "platform/utils.h" |
14 #include "vm/constants_ia32.h" | 14 #include "vm/constants_ia32.h" |
15 | 15 |
16 namespace dart { | 16 namespace dart { |
17 | 17 |
18 // Forward declarations. | 18 // Forward declarations. |
19 class RuntimeEntry; | 19 class RuntimeEntry; |
20 class StubEntry; | 20 class StubEntry; |
21 | 21 |
22 class Immediate : public ValueObject { | 22 class Immediate : public ValueObject { |
23 public: | 23 public: |
24 explicit Immediate(int32_t value) : value_(value) { } | 24 explicit Immediate(int32_t value) : value_(value) {} |
25 | 25 |
26 Immediate(const Immediate& other) : ValueObject(), value_(other.value_) { } | 26 Immediate(const Immediate& other) : ValueObject(), value_(other.value_) {} |
27 | 27 |
28 int32_t value() const { return value_; } | 28 int32_t value() const { return value_; } |
29 | 29 |
30 bool is_int8() const { return Utils::IsInt(8, value_); } | 30 bool is_int8() const { return Utils::IsInt(8, value_); } |
31 bool is_uint8() const { return Utils::IsUint(8, value_); } | 31 bool is_uint8() const { return Utils::IsUint(8, value_); } |
32 bool is_uint16() const { return Utils::IsUint(16, value_); } | 32 bool is_uint16() const { return Utils::IsUint(16, value_); } |
33 | 33 |
34 private: | 34 private: |
35 const int32_t value_; | 35 const int32_t value_; |
36 | 36 |
37 // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Immediate) once the mac | 37 // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Immediate) once the mac |
38 // build issue is resolved. | 38 // build issue is resolved. |
39 // And remove the unnecessary copy constructor. | 39 // And remove the unnecessary copy constructor. |
40 }; | 40 }; |
41 | 41 |
42 | 42 |
43 class Operand : public ValueObject { | 43 class Operand : public ValueObject { |
44 public: | 44 public: |
45 uint8_t mod() const { | 45 uint8_t mod() const { return (encoding_at(0) >> 6) & 3; } |
46 return (encoding_at(0) >> 6) & 3; | |
47 } | |
48 | 46 |
49 Register rm() const { | 47 Register rm() const { return static_cast<Register>(encoding_at(0) & 7); } |
50 return static_cast<Register>(encoding_at(0) & 7); | |
51 } | |
52 | 48 |
53 ScaleFactor scale() const { | 49 ScaleFactor scale() const { |
54 return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3); | 50 return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3); |
55 } | 51 } |
56 | 52 |
57 Register index() const { | 53 Register index() const { |
58 return static_cast<Register>((encoding_at(1) >> 3) & 7); | 54 return static_cast<Register>((encoding_at(1) >> 3) & 7); |
59 } | 55 } |
60 | 56 |
61 Register base() const { | 57 Register base() const { return static_cast<Register>(encoding_at(1) & 7); } |
62 return static_cast<Register>(encoding_at(1) & 7); | |
63 } | |
64 | 58 |
65 int8_t disp8() const { | 59 int8_t disp8() const { |
66 ASSERT(length_ >= 2); | 60 ASSERT(length_ >= 2); |
67 return static_cast<int8_t>(encoding_[length_ - 1]); | 61 return static_cast<int8_t>(encoding_[length_ - 1]); |
68 } | 62 } |
69 | 63 |
70 int32_t disp32() const { | 64 int32_t disp32() const { |
71 ASSERT(length_ >= 5); | 65 ASSERT(length_ >= 5); |
72 return bit_copy<int32_t>(encoding_[length_ - 4]); | 66 return bit_copy<int32_t>(encoding_[length_ - 4]); |
73 } | 67 } |
(...skipping 10 matching lines...) Expand all Loading... |
84 | 78 |
85 bool Equals(const Operand& other) const { | 79 bool Equals(const Operand& other) const { |
86 if (length_ != other.length_) return false; | 80 if (length_ != other.length_) return false; |
87 for (uint8_t i = 0; i < length_; i++) { | 81 for (uint8_t i = 0; i < length_; i++) { |
88 if (encoding_[i] != other.encoding_[i]) return false; | 82 if (encoding_[i] != other.encoding_[i]) return false; |
89 } | 83 } |
90 return true; | 84 return true; |
91 } | 85 } |
92 | 86 |
93 protected: | 87 protected: |
94 Operand() : length_(0) { } // Needed by subclass Address. | 88 Operand() : length_(0) {} // Needed by subclass Address. |
95 | 89 |
96 void SetModRM(int mod, Register rm) { | 90 void SetModRM(int mod, Register rm) { |
97 ASSERT((mod & ~3) == 0); | 91 ASSERT((mod & ~3) == 0); |
98 encoding_[0] = (mod << 6) | rm; | 92 encoding_[0] = (mod << 6) | rm; |
99 length_ = 1; | 93 length_ = 1; |
100 } | 94 } |
101 | 95 |
102 void SetSIB(ScaleFactor scale, Register index, Register base) { | 96 void SetSIB(ScaleFactor scale, Register index, Register base) { |
103 ASSERT(length_ == 1); | 97 ASSERT(length_ == 1); |
104 ASSERT((scale & ~3) == 0); | 98 ASSERT((scale & ~3) == 0); |
(...skipping 23 matching lines...) Expand all Loading... |
128 // Get the operand encoding byte at the given index. | 122 // Get the operand encoding byte at the given index. |
129 uint8_t encoding_at(intptr_t index) const { | 123 uint8_t encoding_at(intptr_t index) const { |
130 ASSERT(index >= 0 && index < length_); | 124 ASSERT(index >= 0 && index < length_); |
131 return encoding_[index]; | 125 return encoding_[index]; |
132 } | 126 } |
133 | 127 |
134 // Returns whether or not this operand is really the given register in | 128 // Returns whether or not this operand is really the given register in |
135 // disguise. Used from the assembler to generate better encodings. | 129 // disguise. Used from the assembler to generate better encodings. |
136 bool IsRegister(Register reg) const { | 130 bool IsRegister(Register reg) const { |
137 return ((encoding_[0] & 0xF8) == 0xC0) // Addressing mode is register only. | 131 return ((encoding_[0] & 0xF8) == 0xC0) // Addressing mode is register only. |
138 && ((encoding_[0] & 0x07) == reg); // Register codes match. | 132 && ((encoding_[0] & 0x07) == reg); // Register codes match. |
139 } | 133 } |
140 | 134 |
141 friend class Assembler; | 135 friend class Assembler; |
142 }; | 136 }; |
143 | 137 |
144 | 138 |
145 class Address : public Operand { | 139 class Address : public Operand { |
146 public: | 140 public: |
147 Address(Register base, int32_t disp) { | 141 Address(Register base, int32_t disp) { |
148 if (disp == 0 && base != EBP) { | 142 if (disp == 0 && base != EBP) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 } else { | 175 } else { |
182 SetModRM(2, ESP); | 176 SetModRM(2, ESP); |
183 SetSIB(scale, index, base); | 177 SetSIB(scale, index, base); |
184 SetDisp32(disp); | 178 SetDisp32(disp); |
185 } | 179 } |
186 } | 180 } |
187 | 181 |
188 // This addressing mode does not exist. | 182 // This addressing mode does not exist. |
189 Address(Register base, Register index, ScaleFactor scale, Register r); | 183 Address(Register base, Register index, ScaleFactor scale, Register r); |
190 | 184 |
191 Address(const Address& other) : Operand(other) { } | 185 Address(const Address& other) : Operand(other) {} |
192 | 186 |
193 Address& operator=(const Address& other) { | 187 Address& operator=(const Address& other) { |
194 Operand::operator=(other); | 188 Operand::operator=(other); |
195 return *this; | 189 return *this; |
196 } | 190 } |
197 | 191 |
198 static Address Absolute(const uword addr) { | 192 static Address Absolute(const uword addr) { |
199 Address result; | 193 Address result; |
200 result.SetModRM(0, EBP); | 194 result.SetModRM(0, EBP); |
201 result.SetDisp32(addr); | 195 result.SetDisp32(addr); |
202 return result; | 196 return result; |
203 } | 197 } |
204 | 198 |
205 private: | 199 private: |
206 Address() { } // Needed by Address::Absolute. | 200 Address() {} // Needed by Address::Absolute. |
207 }; | 201 }; |
208 | 202 |
209 | 203 |
210 class FieldAddress : public Address { | 204 class FieldAddress : public Address { |
211 public: | 205 public: |
212 FieldAddress(Register base, int32_t disp) | 206 FieldAddress(Register base, int32_t disp) |
213 : Address(base, disp - kHeapObjectTag) { } | 207 : Address(base, disp - kHeapObjectTag) {} |
214 | 208 |
215 // This addressing mode does not exist. | 209 // This addressing mode does not exist. |
216 FieldAddress(Register base, Register r); | 210 FieldAddress(Register base, Register r); |
217 | 211 |
218 FieldAddress(Register base, Register index, ScaleFactor scale, int32_t disp) | 212 FieldAddress(Register base, Register index, ScaleFactor scale, int32_t disp) |
219 : Address(base, index, scale, disp - kHeapObjectTag) { } | 213 : Address(base, index, scale, disp - kHeapObjectTag) {} |
220 | 214 |
221 // This addressing mode does not exist. | 215 // This addressing mode does not exist. |
222 FieldAddress(Register base, Register index, ScaleFactor scale, Register r); | 216 FieldAddress(Register base, Register index, ScaleFactor scale, Register r); |
223 | 217 |
224 FieldAddress(const FieldAddress& other) : Address(other) { } | 218 FieldAddress(const FieldAddress& other) : Address(other) {} |
225 | 219 |
226 FieldAddress& operator=(const FieldAddress& other) { | 220 FieldAddress& operator=(const FieldAddress& other) { |
227 Address::operator=(other); | 221 Address::operator=(other); |
228 return *this; | 222 return *this; |
229 } | 223 } |
230 }; | 224 }; |
231 | 225 |
232 | 226 |
233 class Label : public ValueObject { | 227 class Label : public ValueObject { |
234 public: | 228 public: |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
303 public: | 297 public: |
304 explicit Assembler(bool use_far_branches = false) | 298 explicit Assembler(bool use_far_branches = false) |
305 : buffer_(), | 299 : buffer_(), |
306 prologue_offset_(-1), | 300 prologue_offset_(-1), |
307 jit_cookie_(0), | 301 jit_cookie_(0), |
308 comments_(), | 302 comments_(), |
309 code_(Code::ZoneHandle()) { | 303 code_(Code::ZoneHandle()) { |
310 // This mode is only needed and implemented for MIPS and ARM. | 304 // This mode is only needed and implemented for MIPS and ARM. |
311 ASSERT(!use_far_branches); | 305 ASSERT(!use_far_branches); |
312 } | 306 } |
313 ~Assembler() { } | 307 ~Assembler() {} |
314 | 308 |
315 static const bool kNearJump = true; | 309 static const bool kNearJump = true; |
316 static const bool kFarJump = false; | 310 static const bool kFarJump = false; |
317 | 311 |
318 /* | 312 /* |
319 * Emit Machine Instructions. | 313 * Emit Machine Instructions. |
320 */ | 314 */ |
321 void call(Register reg); | 315 void call(Register reg); |
322 void call(const Address& address); | 316 void call(const Address& address); |
323 void call(Label* label); | 317 void call(Label* label); |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 void orpd(XmmRegister dst, XmmRegister src); | 485 void orpd(XmmRegister dst, XmmRegister src); |
492 | 486 |
493 void pextrd(Register dst, XmmRegister src, const Immediate& imm); | 487 void pextrd(Register dst, XmmRegister src, const Immediate& imm); |
494 void pmovsxdq(XmmRegister dst, XmmRegister src); | 488 void pmovsxdq(XmmRegister dst, XmmRegister src); |
495 void pcmpeqq(XmmRegister dst, XmmRegister src); | 489 void pcmpeqq(XmmRegister dst, XmmRegister src); |
496 | 490 |
497 void pxor(XmmRegister dst, XmmRegister src); | 491 void pxor(XmmRegister dst, XmmRegister src); |
498 | 492 |
499 enum RoundingMode { | 493 enum RoundingMode { |
500 kRoundToNearest = 0x0, | 494 kRoundToNearest = 0x0, |
501 kRoundDown = 0x1, | 495 kRoundDown = 0x1, |
502 kRoundUp = 0x2, | 496 kRoundUp = 0x2, |
503 kRoundToZero = 0x3 | 497 kRoundToZero = 0x3 |
504 }; | 498 }; |
505 void roundsd(XmmRegister dst, XmmRegister src, RoundingMode mode); | 499 void roundsd(XmmRegister dst, XmmRegister src, RoundingMode mode); |
506 | 500 |
507 void flds(const Address& src); | 501 void flds(const Address& src); |
508 void fstps(const Address& dst); | 502 void fstps(const Address& dst); |
509 | 503 |
510 void fldl(const Address& src); | 504 void fldl(const Address& src); |
511 void fstpl(const Address& dst); | 505 void fstpl(const Address& dst); |
512 | 506 |
513 void fnstcw(const Address& dst); | 507 void fnstcw(const Address& dst); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
625 void leave(); | 619 void leave(); |
626 | 620 |
627 void ret(); | 621 void ret(); |
628 void ret(const Immediate& imm); | 622 void ret(const Immediate& imm); |
629 | 623 |
630 // 'size' indicates size in bytes and must be in the range 1..8. | 624 // 'size' indicates size in bytes and must be in the range 1..8. |
631 void nop(int size = 1); | 625 void nop(int size = 1); |
632 void int3(); | 626 void int3(); |
633 void hlt(); | 627 void hlt(); |
634 | 628 |
635 static uword GetBreakInstructionFiller() { | 629 static uword GetBreakInstructionFiller() { return 0xCCCCCCCC; } |
636 return 0xCCCCCCCC; | |
637 } | |
638 | 630 |
639 void j(Condition condition, Label* label, bool near = kFarJump); | 631 void j(Condition condition, Label* label, bool near = kFarJump); |
640 void j(Condition condition, const ExternalLabel* label); | 632 void j(Condition condition, const ExternalLabel* label); |
641 | 633 |
642 void jmp(Register reg); | 634 void jmp(Register reg); |
643 void jmp(Label* label, bool near = kFarJump); | 635 void jmp(Label* label, bool near = kFarJump); |
644 void jmp(const ExternalLabel* label); | 636 void jmp(const ExternalLabel* label); |
645 | 637 |
646 void lock(); | 638 void lock(); |
647 void cmpxchgl(const Address& address, Register reg); | 639 void cmpxchgl(const Address& address, Register reg); |
(...skipping 20 matching lines...) Expand all Loading... |
668 void LoadObject(Register dst, const Object& object); | 660 void LoadObject(Register dst, const Object& object); |
669 | 661 |
670 // If 'object' is a large Smi, xor it with a per-assembler cookie value to | 662 // If 'object' is a large Smi, xor it with a per-assembler cookie value to |
671 // prevent user-controlled immediates from appearing in the code stream. | 663 // prevent user-controlled immediates from appearing in the code stream. |
672 void LoadObjectSafely(Register dst, const Object& object); | 664 void LoadObjectSafely(Register dst, const Object& object); |
673 | 665 |
674 void PushObject(const Object& object); | 666 void PushObject(const Object& object); |
675 void CompareObject(Register reg, const Object& object); | 667 void CompareObject(Register reg, const Object& object); |
676 void LoadDoubleConstant(XmmRegister dst, double value); | 668 void LoadDoubleConstant(XmmRegister dst, double value); |
677 | 669 |
678 void StoreIntoObject(Register object, // Object we are storing into. | 670 void StoreIntoObject(Register object, // Object we are storing into. |
679 const Address& dest, // Where we are storing into. | 671 const Address& dest, // Where we are storing into. |
680 Register value, // Value we are storing. | 672 Register value, // Value we are storing. |
681 bool can_value_be_smi = true); | 673 bool can_value_be_smi = true); |
682 | 674 |
683 void StoreIntoObjectNoBarrier(Register object, | 675 void StoreIntoObjectNoBarrier(Register object, |
684 const Address& dest, | 676 const Address& dest, |
685 Register value); | 677 Register value); |
686 void StoreIntoObjectNoBarrier(Register object, | 678 void StoreIntoObjectNoBarrier(Register object, |
687 const Address& dest, | 679 const Address& dest, |
688 const Object& value); | 680 const Object& value); |
689 | 681 |
690 // Stores a Smi value into a heap object field that always contains a Smi. | 682 // Stores a Smi value into a heap object field that always contains a Smi. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
752 Register array, | 744 Register array, |
753 Register index); | 745 Register index); |
754 | 746 |
755 static Address VMTagAddress() { | 747 static Address VMTagAddress() { |
756 return Address(THR, Thread::vm_tag_offset()); | 748 return Address(THR, Thread::vm_tag_offset()); |
757 } | 749 } |
758 | 750 |
759 /* | 751 /* |
760 * Misc. functionality | 752 * Misc. functionality |
761 */ | 753 */ |
762 void SmiTag(Register reg) { | 754 void SmiTag(Register reg) { addl(reg, reg); } |
763 addl(reg, reg); | |
764 } | |
765 | 755 |
766 void SmiUntag(Register reg) { | 756 void SmiUntag(Register reg) { sarl(reg, Immediate(kSmiTagSize)); } |
767 sarl(reg, Immediate(kSmiTagSize)); | |
768 } | |
769 | 757 |
770 void BranchIfNotSmi(Register reg, Label* label) { | 758 void BranchIfNotSmi(Register reg, Label* label) { |
771 testl(reg, Immediate(kSmiTagMask)); | 759 testl(reg, Immediate(kSmiTagMask)); |
772 j(NOT_ZERO, label); | 760 j(NOT_ZERO, label); |
773 } | 761 } |
774 | 762 |
775 void Align(intptr_t alignment, intptr_t offset); | 763 void Align(intptr_t alignment, intptr_t offset); |
776 void Bind(Label* label); | 764 void Bind(Label* label); |
777 void Jump(Label* label) { jmp(label); } | 765 void Jump(Label* label) { jmp(label); } |
778 | 766 |
779 // Address of code at offset. | 767 // Address of code at offset. |
780 uword CodeAddress(intptr_t offset) { | 768 uword CodeAddress(intptr_t offset) { return buffer_.Address(offset); } |
781 return buffer_.Address(offset); | |
782 } | |
783 | 769 |
784 intptr_t CodeSize() const { return buffer_.Size(); } | 770 intptr_t CodeSize() const { return buffer_.Size(); } |
785 intptr_t prologue_offset() const { return prologue_offset_; } | 771 intptr_t prologue_offset() const { return prologue_offset_; } |
786 bool has_single_entry_point() const { return true; } | 772 bool has_single_entry_point() const { return true; } |
787 | 773 |
788 // Count the fixups that produce a pointer offset, without processing | 774 // Count the fixups that produce a pointer offset, without processing |
789 // the fixups. | 775 // the fixups. |
790 intptr_t CountPointerOffsets() const { | 776 intptr_t CountPointerOffsets() const { return buffer_.CountPointerOffsets(); } |
791 return buffer_.CountPointerOffsets(); | |
792 } | |
793 const ZoneGrowableArray<intptr_t>& GetPointerOffsets() const { | 777 const ZoneGrowableArray<intptr_t>& GetPointerOffsets() const { |
794 return buffer_.pointer_offsets(); | 778 return buffer_.pointer_offsets(); |
795 } | 779 } |
796 | 780 |
797 ObjectPoolWrapper& object_pool_wrapper() { return object_pool_wrapper_; } | 781 ObjectPoolWrapper& object_pool_wrapper() { return object_pool_wrapper_; } |
798 | 782 |
799 RawObjectPool* MakeObjectPool() { | 783 RawObjectPool* MakeObjectPool() { |
800 return object_pool_wrapper_.MakeObjectPool(); | 784 return object_pool_wrapper_.MakeObjectPool(); |
801 } | 785 } |
802 | 786 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
925 if (Utils::IsPowerOfTwo(value) || Utils::IsPowerOfTwo(value + 1)) { | 909 if (Utils::IsPowerOfTwo(value) || Utils::IsPowerOfTwo(value + 1)) { |
926 return true; | 910 return true; |
927 } | 911 } |
928 | 912 |
929 return false; | 913 return false; |
930 } | 914 } |
931 static bool IsSafe(const Object& object) { | 915 static bool IsSafe(const Object& object) { |
932 return !object.IsSmi() || IsSafeSmi(object); | 916 return !object.IsSmi() || IsSafeSmi(object); |
933 } | 917 } |
934 | 918 |
935 void set_code_object(const Code& code) { | 919 void set_code_object(const Code& code) { code_ ^= code.raw(); } |
936 code_ ^= code.raw(); | |
937 } | |
938 | 920 |
939 void PushCodeObject(); | 921 void PushCodeObject(); |
940 | 922 |
941 private: | 923 private: |
942 class CodeComment : public ZoneAllocated { | 924 class CodeComment : public ZoneAllocated { |
943 public: | 925 public: |
944 CodeComment(intptr_t pc_offset, const String& comment) | 926 CodeComment(intptr_t pc_offset, const String& comment) |
945 : pc_offset_(pc_offset), comment_(comment) { } | 927 : pc_offset_(pc_offset), comment_(comment) {} |
946 | 928 |
947 intptr_t pc_offset() const { return pc_offset_; } | 929 intptr_t pc_offset() const { return pc_offset_; } |
948 const String& comment() const { return comment_; } | 930 const String& comment() const { return comment_; } |
949 | 931 |
950 private: | 932 private: |
951 intptr_t pc_offset_; | 933 intptr_t pc_offset_; |
952 const String& comment_; | 934 const String& comment_; |
953 | 935 |
954 DISALLOW_COPY_AND_ASSIGN(CodeComment); | 936 DISALLOW_COPY_AND_ASSIGN(CodeComment); |
955 }; | 937 }; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1020 } | 1002 } |
1021 | 1003 |
1022 | 1004 |
1023 inline void Assembler::EmitOperandSizeOverride() { | 1005 inline void Assembler::EmitOperandSizeOverride() { |
1024 EmitUint8(0x66); | 1006 EmitUint8(0x66); |
1025 } | 1007 } |
1026 | 1008 |
1027 } // namespace dart | 1009 } // namespace dart |
1028 | 1010 |
1029 #endif // RUNTIME_VM_ASSEMBLER_IA32_H_ | 1011 #endif // RUNTIME_VM_ASSEMBLER_IA32_H_ |
OLD | NEW |