Chromium Code Reviews| Index: runtime/vm/assembler_x64.h |
| =================================================================== |
| --- runtime/vm/assembler_x64.h (revision 1937) |
| +++ runtime/vm/assembler_x64.h (working copy) |
| @@ -11,9 +11,14 @@ |
| #include "vm/assert.h" |
| #include "vm/constants_x64.h" |
| +#include "vm/utils.h" |
| namespace dart { |
| +// Forward declarations. |
| +class RuntimeEntry; |
| + |
| + |
| #if defined(TESTING) || defined(DEBUG) |
| #define CHECK_STACK_ALIGNMENT { \ |
| @@ -27,35 +32,233 @@ |
| #endif |
| +class Immediate : public ValueObject { |
| + public: |
| + explicit Immediate(int64_t value) : value_(value) { } |
| + |
| + int64_t value() const { return value_; } |
| + |
| + bool is_int8() const { return Utils::IsInt(8, value_); } |
| + bool is_uint8() const { return Utils::IsUint(8, value_); } |
| + bool is_uint16() const { return Utils::IsUint(16, value_); } |
| + bool is_int32() const { return Utils::IsInt(32, value_); } |
| + |
| + private: |
| + const int64_t value_; |
| + |
| + // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Immediate) once the mac |
| + // build issue is resolved. |
| +}; |
| + |
| + |
| +class Operand : public ValueObject { |
| + public: |
| + uint8_t rex() const { |
| + return rex_; |
| + } |
| + |
| + uint8_t mod() const { |
| + return (encoding_at(0) >> 6) & 3; |
| + } |
| + |
| + Register rm() const { |
| + int rm_rex = (rex_ & 1) << 3; |
| + return static_cast<Register>(rm_rex + (encoding_at(0) & 7)); |
| + } |
| + |
| + ScaleFactor scale() const { |
| + return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3); |
| + } |
| + |
| + Register index() const { |
| + int index_rex = (rex_ & 2) << 2; |
| + return static_cast<Register>(index_rex + ((encoding_at(1) >> 3) & 7)); |
| + } |
| + |
| + Register base() const { |
| + int base_rex = (rex_ & 1) << 3; |
| + return static_cast<Register>(base_rex + (encoding_at(1) & 7)); |
| + } |
| + |
| + int8_t disp8() const { |
| + ASSERT(length_ >= 2); |
| + return static_cast<int8_t>(encoding_[length_ - 1]); |
| + } |
| + |
| + int32_t disp32() const { |
| + ASSERT(length_ >= 5); |
| + return bit_copy<int32_t>(encoding_[length_ - 4]); |
| + } |
| + |
| + protected: |
| + Operand() : length_(0), rex_(0) { } |
| + |
| + void SetModRM(int mod, Register rm) { |
| + ASSERT((mod & ~3) == 0); |
| + if (rm > 7) rex_ |= 1; |
| + encoding_[0] = (mod << 6) | (rm & 7); |
| + length_ = 1; |
| + } |
| + |
| + void SetSIB(ScaleFactor scale, Register index, Register base) { |
| + ASSERT(length_ == 1); |
| + ASSERT((scale & ~3) == 0); |
| + if (base > 7) { |
| + ASSERT((rex_ & 1) == 0); // Must not have REX.B already set. |
| + rex_ |= 1; |
| + } |
| + if (index > 7) rex_ |= 2; |
| + encoding_[1] = (scale << 6) | ((index & 7) << 3) | (base & 7); |
| + length_ = 2; |
| + } |
| + |
| + void SetDisp8(int8_t disp) { |
| + ASSERT(length_ == 1 || length_ == 2); |
| + encoding_[length_++] = static_cast<uint8_t>(disp); |
| + } |
| + |
| + void SetDisp32(int32_t disp) { |
| + ASSERT(length_ == 1 || length_ == 2); |
| + memmove(&encoding_[length_], &disp, sizeof(disp)); |
| + length_ += sizeof(disp); |
| + } |
| + |
| + private: |
| + uint8_t length_; |
| + uint8_t rex_; |
| + uint8_t encoding_[6]; |
| + |
| + explicit Operand(Register reg) : rex_(0) { SetModRM(3, reg); } |
| + |
| + // Get the operand encoding byte at the given index. |
| + uint8_t encoding_at(int index) const { |
| + ASSERT(index >= 0 && index < length_); |
| + return encoding_[index]; |
| + } |
| + |
| + // Returns whether or not this operand is really the given register in |
| + // disguise. Used from the assembler to generate better encodings. |
| + bool IsRegister(Register reg) const { |
| + return ((reg > 7 ? 1 : 0) == (rex_ & 1)) // REX.B match. |
| + && ((encoding_at(0) & 0xF8) == 0xC0) // Addressing mode is register. |
| + && ((encoding_at(0) & 0x07) == reg); // Register codes match. |
| + } |
| + |
| + |
| + friend class Assembler; |
| + |
| + // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Operand) once the mac |
| + // build issue is resolved. |
| +}; |
| + |
| + |
| +class Address : public Operand { |
| + public: |
| + Address(Register base, int32_t disp) { |
| + if (disp == 0 && base != RBP) { |
| + SetModRM(0, base); |
| + if (base == RSP) SetSIB(TIMES_1, RSP, base); |
| + } else if (Utils::IsInt(8, disp)) { |
| + SetModRM(1, base); |
| + if (base == RSP) SetSIB(TIMES_1, RSP, base); |
| + SetDisp8(disp); |
| + } else { |
| + SetModRM(2, base); |
| + if (base == RSP) SetSIB(TIMES_1, RSP, base); |
| + SetDisp32(disp); |
| + } |
| + } |
| + |
| + Address(Register index, ScaleFactor scale, int32_t disp) { |
| + ASSERT(index != RSP); // Illegal addressing mode. |
| + SetModRM(0, RSP); |
| + SetSIB(scale, index, RBP); |
| + SetDisp32(disp); |
| + } |
| + |
| + Address(Register base, Register index, ScaleFactor scale, int32_t disp) { |
| + ASSERT(index != RSP); // Illegal addressing mode. |
| + if (disp == 0 && base != RBP) { |
| + SetModRM(0, RSP); |
| + SetSIB(scale, index, base); |
| + } else if (Utils::IsInt(8, disp)) { |
| + SetModRM(1, RSP); |
| + SetSIB(scale, index, base); |
| + SetDisp8(disp); |
| + } else { |
| + SetModRM(2, RSP); |
| + SetSIB(scale, index, base); |
| + SetDisp32(disp); |
| + } |
| + } |
| + |
| + static Address Absolute(const uword addr) { |
| + UNIMPLEMENTED(); |
| + Address result; |
| + result.SetModRM(0, RBP); |
| + result.SetDisp32(addr); |
| + return result; |
| + } |
| + |
| + private: |
| + Address() {} |
| + |
| + // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Address) once the mac |
| + // build issue is resolved. |
| +}; |
| + |
| + |
| +class FieldAddress : public Address { |
| + public: |
| + FieldAddress(Register base, int32_t disp) |
| + : Address(base, disp - kHeapObjectTag) {} |
| + FieldAddress(Register base, Register index, ScaleFactor scale, int32_t disp) |
| + : Address(base, index, scale, disp - kHeapObjectTag) {} |
| +}; |
| + |
| + |
| class Label : public ValueObject { |
| public: |
| - Label() : position_(0) { } |
| + Label() : position_(0), unresolved_(0) { |
| +#ifdef DEBUG |
| + for (int i = 0; i < kMaxUnresolvedBranches; i++) { |
| + unresolved_near_positions_[i] = -1; |
| + } |
| +#endif // DEBUG |
| + } |
| ~Label() { |
| // Assert if label is being destroyed with unresolved branches pending. |
| ASSERT(!IsLinked()); |
| + ASSERT(!HasNear()); |
| } |
| - // Returns the position for bound and linked labels. Cannot be used |
| - // for unused labels. |
| + // Returns the position for bound labels. Cannot be used for unused or linked |
| + // labels. |
| int Position() const { |
| - ASSERT(!IsUnused()); |
| - return IsBound() ? -position_ - kWordSize : position_ - kWordSize; |
| + ASSERT(IsBound()); |
| + return -position_ - kWordSize; |
| } |
| + int LinkPosition() const { |
| + ASSERT(IsLinked()); |
| + return position_ - kWordSize; |
| + } |
| + |
| + int NearPosition() { |
| + ASSERT(HasNear()); |
| + return unresolved_near_positions_[--unresolved_]; |
| + } |
| + |
| bool IsBound() const { return position_ < 0; } |
| - bool IsUnused() const { return position_ == 0; } |
| + bool IsUnused() const { return (position_ == 0) && (unresolved_ == 0); } |
| bool IsLinked() const { return position_ > 0; } |
| + bool HasNear() const { return unresolved_ != 0; } |
| private: |
| - int position_; |
| - |
| - void Reinitialize() { |
| - position_ = 0; |
| - } |
| - |
| void BindTo(int position) { |
| ASSERT(!IsBound()); |
| + ASSERT(!HasNear()); |
| position_ = -position - kWordSize; |
| ASSERT(IsBound()); |
| } |
| @@ -66,54 +269,349 @@ |
| ASSERT(IsLinked()); |
| } |
| + void NearLinkTo(int position) { |
| + ASSERT(!IsBound()); |
| + ASSERT(unresolved_ < kMaxUnresolvedBranches); |
| + unresolved_near_positions_[unresolved_++] = position; |
| + } |
| + |
| + static const int kMaxUnresolvedBranches = 20; |
| + |
| + int position_; |
| + int unresolved_; |
| + int unresolved_near_positions_[kMaxUnresolvedBranches]; |
| + |
| friend class Assembler; |
| DISALLOW_COPY_AND_ASSIGN(Label); |
| }; |
| -class Assembler { |
| +class Assembler : public ValueObject { |
| public: |
| - Assembler() { } |
| + Assembler() : buffer_(), prolog_offset_(-1) { } |
| ~Assembler() { } |
| - // Macros for High-level operations. |
| - void AddConstant(Register reg, int value) { |
| - UNIMPLEMENTED(); |
| + static const bool kNearJump = true; |
| + static const bool kFarJump = false; |
| + |
| + /* |
| + * Emit Machine Instructions. |
| + */ |
| + void call(Register reg); |
| + void call(const Address& address); |
| + void call(Label* label); |
| + void call(const ExternalLabel* label); |
| + |
| + static const intptr_t kCallExternalLabelSize = 5; |
| + |
| + void pushq(Register reg); |
| + void pushq(const Address& address); |
| + |
| + void popq(Register reg); |
| + void popq(const Address& address); |
| + |
| + void movl(Register dst, Register src); |
| + void movl(Register dst, const Immediate& imm); |
| + void movl(Register dst, const Address& src); |
| + void movl(const Address& dst, Register src); |
| + |
| + void movzxb(Register dst, Register src); |
| + void movzxb(Register dst, const Address& src); |
| + void movsxb(Register dst, Register src); |
| + void movsxb(Register dst, const Address& src); |
| + void movb(Register dst, const Address& src); |
| + void movb(const Address& dst, Register src); |
| + void movb(const Address& dst, const Immediate& imm); |
| + |
| + void movzxw(Register dst, Register src); |
| + void movzxw(Register dst, const Address& src); |
| + void movsxw(Register dst, Register src); |
| + void movsxw(Register dst, const Address& src); |
| + void movw(Register dst, const Address& src); |
| + void movw(const Address& dst, Register src); |
| + |
| + void movq(Register dst, const Immediate& imm); |
| + void movq(Register dst, Register src); |
| + void movq(Register dst, const Address& src); |
| + void movq(const Address& dst, Register src); |
| + void movq(const Address& dst, const Immediate& imm); |
| + |
| + void movsxl(Register dst, const Address& src); |
| + |
| + void leaq(Register dst, const Address& src); |
| + |
| + void movss(XmmRegister dst, const Address& src); |
| + void movss(const Address& dst, XmmRegister src); |
| + void movss(XmmRegister dst, XmmRegister src); |
| + |
| + void movd(XmmRegister dst, Register src); |
| + void movd(Register dst, XmmRegister src); |
| + |
| + void addss(XmmRegister dst, XmmRegister src); |
| + void subss(XmmRegister dst, XmmRegister src); |
| + void mulss(XmmRegister dst, XmmRegister src); |
| + void divss(XmmRegister dst, XmmRegister src); |
| + |
| + void movsd(XmmRegister dst, const Address& src); |
| + void movsd(const Address& dst, XmmRegister src); |
| + void movsd(XmmRegister dst, XmmRegister src); |
| + |
| + void addsd(XmmRegister dst, XmmRegister src); |
| + void subsd(XmmRegister dst, XmmRegister src); |
| + void mulsd(XmmRegister dst, XmmRegister src); |
| + void divsd(XmmRegister dst, XmmRegister src); |
| + |
| + void xchgl(Register dst, Register src); |
| + void xchgq(Register dst, Register src); |
| + |
| + void cmpl(Register reg, const Immediate& imm); |
| + void cmpl(Register reg0, Register reg1); |
| + void cmpl(Register reg, const Address& address); |
| + void cmpl(const Address& address, const Immediate& imm); |
| + |
| + void cmpq(Register reg, const Immediate& imm); |
| + void cmpq(const Address& address, const Immediate& imm); |
| + void cmpq(Register reg0, Register reg1); |
| + void cmpq(Register reg, const Address& address); |
| + |
| + void testl(Register reg1, Register reg2); |
| + void testl(Register reg, const Immediate& imm); |
| + |
| + void testq(Register reg1, Register reg2); |
| + void testq(Register reg, const Immediate& imm); |
| + |
| + void andl(Register dst, Register src); |
| + void andl(Register dst, const Immediate& imm); |
| + |
| + void orl(Register dst, Register src); |
| + void orl(Register dst, const Immediate& imm); |
| + |
| + void xorl(Register dst, Register src); |
| + |
| + void andq(Register dst, Register src); |
| + void andq(Register dst, const Immediate& imm); |
| + |
| + void orq(Register dst, Register src); |
| + void orq(Register dst, const Immediate& imm); |
| + |
| + void xorq(Register dst, Register src); |
| + |
| + void addl(Register dst, Register src); |
| + void addl(const Address& address, const Immediate& imm); |
| + |
| + void addq(Register dst, Register src); |
| + void addq(Register reg, const Immediate& imm); |
| + void addq(const Address& address, const Immediate& imm); |
| + |
| + void subl(Register dst, Register src); |
| + |
| + void cdq(); |
| + void cqo(); |
| + |
| + void idivl(Register reg); |
| + void idivq(Register reg); |
| + |
| + void imull(Register dst, Register src); |
| + void imull(Register reg, const Immediate& imm); |
| + |
| + void imulq(Register dst, Register src); |
| + |
| + void subq(Register dst, Register src); |
| + void subq(Register reg, const Immediate& imm); |
| + |
| + void shll(Register reg, const Immediate& imm); |
| + void shll(Register operand, Register shifter); |
| + void shrl(Register reg, const Immediate& imm); |
| + void shrl(Register operand, Register shifter); |
| + void sarl(Register reg, const Immediate& imm); |
| + void sarl(Register operand, Register shifter); |
| + |
| + void shlq(Register reg, const Immediate& imm); |
| + void shlq(Register operand, Register shifter); |
| + void shrq(Register reg, const Immediate& imm); |
| + void shrq(Register operand, Register shifter); |
| + void sarq(Register reg, const Immediate& imm); |
| + void sarq(Register operand, Register shifter); |
| + |
| + void incl(const Address& address); |
| + void decl(const Address& address); |
| + |
| + void incq(Register reg); |
| + void incq(const Address& address); |
| + void decq(Register reg); |
| + void decq(const Address& address); |
| + |
| + void negl(Register reg); |
| + void negq(Register reg); |
| + |
| + void enter(const Immediate& imm); |
| + void leave(); |
| + |
| + void ret(); |
| + void nop(); |
| + void int3(); |
| + void hlt(); |
| + |
| + void j(Condition condition, Label* label, bool near = kFarJump); |
| + |
| + void jmp(Register reg); |
| + void jmp(Label* label, bool near = kFarJump); |
| + void jmp(const ExternalLabel* label); |
| + |
| + void lock(); |
| + void cmpxchgl(const Address& address, Register reg); |
| + void lock_cmpxchgl(const Address& address, Register reg) { |
| + lock(); |
| + cmpxchgl(address, reg); |
| } |
| - // Misc. functionality |
| - int CodeSize() const { |
| - UNIMPLEMENTED(); |
| - return 0; |
| + void cmpxchgq(const Address& address, Register reg); |
| + void lock_cmpxchgq(const Address& address, Register reg) { |
| + lock(); |
| + cmpxchgq(address, reg); |
| } |
| - int prolog_offset() const { |
| - UNIMPLEMENTED(); |
| - return 0; |
| + |
| + /* |
| + * Macros for High-level operations. |
| + */ |
| + void AddImmediate(Register reg, const Immediate& imm); |
| + |
| + void LoadObject(Register dst, const Object& object); |
| + void PushObject(const Object& object); |
| + void CompareObject(Register reg, const Object& object); |
| + void LoadDoubleConstant(XmmRegister dst, double value); |
| + |
| + void StoreIntoObject(Register object, // Object we are storing into. |
| + const FieldAddress& dest, // Where we are storing into. |
| + Register value); // Value we are storing. |
| + |
| + void DoubleNegate(XmmRegister d); |
| + void FloatNegate(XmmRegister f); |
| + |
| + void DoubleAbs(XmmRegister reg); |
| + |
| + void LockCmpxchgl(const Address& address, Register reg) { |
| + lock(); |
| + cmpxchgl(address, reg); |
| } |
| + |
| + void EnterFrame(intptr_t frame_space); |
| + void LeaveFrame(); |
| + |
| + void CallRuntimeFromDart(const RuntimeEntry& entry); |
| + void CallRuntimeFromStub(const RuntimeEntry& entry); |
| + |
| + /* |
| + * Misc. functionality |
|
siva
2011/11/30 21:43:43
missing '.'
regis
2011/11/30 22:02:09
Done.
|
| + */ |
| + void SmiTag(Register reg) { |
| + addl(reg, reg); |
| + } |
| + |
| + void SmiUntag(Register reg) { |
| + sarl(reg, Immediate(kSmiTagSize)); |
| + } |
| + |
| + int PreferredLoopAlignment() { return 16; } |
| + void Align(int alignment, int offset); |
| + void Bind(Label* label); |
| + |
| + int CodeSize() const { return buffer_.Size(); } |
| + int prolog_offset() const { return prolog_offset_; } |
| const ZoneGrowableArray<int>& GetPointerOffsets() const { |
| - UNIMPLEMENTED(); |
| - return *pointer_offsets_; |
| + return buffer_.pointer_offsets(); |
| } |
| + |
| void FinalizeInstructions(const MemoryRegion& region) { |
| - UNIMPLEMENTED(); |
| + buffer_.FinalizeInstructions(region); |
| } |
| // Debugging and bringup support. |
| - void Stop(const char* message) { UNIMPLEMENTED(); } |
| + void Stop(const char* message); |
| void Unimplemented(const char* message); |
| void Untested(const char* message); |
| void Unreachable(const char* message); |
| - static void InitializeMemoryWithBreakpoints(uword data, int length) { |
| - UNIMPLEMENTED(); |
| - } |
| + static void InitializeMemoryWithBreakpoints(uword data, int length); |
| private: |
| - ZoneGrowableArray<int>* pointer_offsets_; |
| + AssemblerBuffer buffer_; |
| + int prolog_offset_; |
| + |
| + inline void EmitUint8(uint8_t value); |
| + inline void EmitInt32(int32_t value); |
| + inline void EmitInt64(int64_t value); |
| + |
| + inline void EmitRegisterREX(Register reg, uint8_t rex); |
| + inline void EmitRegisterOperand(int rm, int reg); |
| + inline void EmitOperandREX(int rm, const Operand& operand, uint8_t rex); |
| + inline void EmitXmmRegisterOperand(int rm, XmmRegister reg); |
| + inline void EmitFixup(AssemblerFixup* fixup); |
| + inline void EmitOperandSizeOverride(); |
| + |
| + void EmitOperand(int rm, const Operand& operand); |
| + void EmitImmediate(const Immediate& imm); |
| + void EmitComplex(int rm, const Operand& operand, const Immediate& immediate); |
| + void EmitLabel(Label* label, int instruction_size); |
| + void EmitLabelLink(Label* label); |
| + void EmitNearLabelLink(Label* label); |
| + |
| + void EmitGenericShift(bool wide, int rm, Register reg, const Immediate& imm); |
| + void EmitGenericShift(bool wide, int rm, Register operand, Register shifter); |
| + |
| DISALLOW_ALLOCATION(); |
| DISALLOW_COPY_AND_ASSIGN(Assembler); |
| }; |
| + |
| +enum { |
| + REX_NONE = 0, |
| + REX_B = 1 << 0, |
| + REX_X = 1 << 1, |
| + REX_R = 1 << 2, |
| + REX_W = 1 << 3 |
| +}; |
| + |
| + |
| +inline void Assembler::EmitUint8(uint8_t value) { |
| + buffer_.Emit<uint8_t>(value); |
| +} |
| + |
| + |
| +inline void Assembler::EmitInt32(int32_t value) { |
| + buffer_.Emit<int32_t>(value); |
| +} |
| + |
| + |
| +inline void Assembler::EmitInt64(int64_t value) { |
| + buffer_.Emit<int64_t>(value); |
| +} |
| + |
| + |
| +inline void Assembler::EmitRegisterREX(Register reg, uint8_t rex) { |
| + ASSERT(reg != kNoRegister); |
| + rex |= (reg > 7 ? REX_B : REX_NONE); |
| + if (rex != 0) EmitUint8(0x40 | rex); |
| +} |
| + |
| + |
| +inline void Assembler::EmitOperandREX(int rm, |
| + const Operand& operand, |
| + uint8_t rex) { |
| + rex |= (rm > 7 ? REX_R : REX_NONE) | operand.rex(); |
| + if (rex != 0) EmitUint8(0x40 | rex); |
| +} |
| + |
| + |
| +inline void Assembler::EmitFixup(AssemblerFixup* fixup) { |
| + buffer_.EmitFixup(fixup); |
| +} |
| + |
| + |
| +inline void Assembler::EmitOperandSizeOverride() { |
| + EmitUint8(0x66); |
| +} |
| + |
| } // namespace dart |
| #endif // VM_ASSEMBLER_X64_H_ |