// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef RUNTIME_VM_COMPILER_ASSEMBLER_ASSEMBLER_IA32_H_ #define RUNTIME_VM_COMPILER_ASSEMBLER_ASSEMBLER_IA32_H_ #ifndef RUNTIME_VM_COMPILER_ASSEMBLER_ASSEMBLER_H_ #error Do not include assembler_ia32.h directly; use assembler.h instead. #endif #include "platform/assert.h" #include "platform/utils.h" #include "vm/constants_ia32.h" #include "vm/constants_x86.h" namespace dart { // Forward declarations. class RuntimeEntry; class StubEntry; class Immediate : public ValueObject { public: explicit Immediate(int32_t value) : value_(value) {} Immediate(const Immediate& other) : ValueObject(), value_(other.value_) {} int32_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_); } private: const int32_t value_; // TODO(5411081): Add DISALLOW_COPY_AND_ASSIGN(Immediate) once the mac // build issue is resolved. // And remove the unnecessary copy constructor. }; class Operand : public ValueObject { public: uint8_t mod() const { return (encoding_at(0) >> 6) & 3; } Register rm() const { return static_cast(encoding_at(0) & 7); } ScaleFactor scale() const { return static_cast((encoding_at(1) >> 6) & 3); } Register index() const { return static_cast((encoding_at(1) >> 3) & 7); } Register base() const { return static_cast(encoding_at(1) & 7); } int8_t disp8() const { ASSERT(length_ >= 2); return static_cast(encoding_[length_ - 1]); } int32_t disp32() const { ASSERT(length_ >= 5); return bit_copy(encoding_[length_ - 4]); } Operand(const Operand& other) : ValueObject(), length_(other.length_) { memmove(&encoding_[0], &other.encoding_[0], other.length_); } Operand& operator=(const Operand& other) { length_ = other.length_; memmove(&encoding_[0], &other.encoding_[0], other.length_); return *this; } bool Equals(const Operand& other) const { if (length_ != other.length_) return false; for (uint8_t i = 0; i < length_; i++) { if (encoding_[i] != other.encoding_[i]) return false; } return true; } protected: Operand() : length_(0) {} // Needed by subclass Address. void SetModRM(int mod, Register rm) { ASSERT((mod & ~3) == 0); encoding_[0] = (mod << 6) | rm; length_ = 1; } void SetSIB(ScaleFactor scale, Register index, Register base) { ASSERT(length_ == 1); ASSERT((scale & ~3) == 0); encoding_[1] = (scale << 6) | (index << 3) | base; length_ = 2; } void SetDisp8(int8_t disp) { ASSERT(length_ == 1 || length_ == 2); encoding_[length_++] = static_cast(disp); } void SetDisp32(int32_t disp) { ASSERT(length_ == 1 || length_ == 2); intptr_t disp_size = sizeof(disp); memmove(&encoding_[length_], &disp, disp_size); length_ += disp_size; } private: uint8_t length_; uint8_t encoding_[6]; uint8_t padding_; explicit Operand(Register reg) { SetModRM(3, reg); } // Get the operand encoding byte at the given index. uint8_t encoding_at(intptr_t 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 ((encoding_[0] & 0xF8) == 0xC0) // Addressing mode is register only. && ((encoding_[0] & 0x07) == reg); // Register codes match. } friend class Assembler; }; class Address : public Operand { public: Address(Register base, int32_t disp) { if (disp == 0 && base != EBP) { SetModRM(0, base); if (base == ESP) SetSIB(TIMES_1, ESP, base); } else if (Utils::IsInt(8, disp)) { SetModRM(1, base); if (base == ESP) SetSIB(TIMES_1, ESP, base); SetDisp8(disp); } else { SetModRM(2, base); if (base == ESP) SetSIB(TIMES_1, ESP, base); SetDisp32(disp); } } Address(Register index, ScaleFactor scale, int32_t disp) { ASSERT(index != ESP); // Illegal addressing mode. SetModRM(0, ESP); SetSIB(scale, index, EBP); SetDisp32(disp); } // This addressing mode does not exist. Address(Register index, ScaleFactor scale, Register r); Address(Register base, Register index, ScaleFactor scale, int32_t disp) { ASSERT(index != ESP); // Illegal addressing mode. if (disp == 0 && base != EBP) { SetModRM(0, ESP); SetSIB(scale, index, base); } else if (Utils::IsInt(8, disp)) { SetModRM(1, ESP); SetSIB(scale, index, base); SetDisp8(disp); } else { SetModRM(2, ESP); SetSIB(scale, index, base); SetDisp32(disp); } } // This addressing mode does not exist. Address(Register base, Register index, ScaleFactor scale, Register r); Address(const Address& other) : Operand(other) {} Address& operator=(const Address& other) { Operand::operator=(other); return *this; } static Address Absolute(const uword addr) { Address result; result.SetModRM(0, EBP); result.SetDisp32(addr); return result; } private: Address() {} // Needed by Address::Absolute. }; class FieldAddress : public Address { public: FieldAddress(Register base, int32_t disp) : Address(base, disp - kHeapObjectTag) {} // This addressing mode does not exist. FieldAddress(Register base, Register r); FieldAddress(Register base, Register index, ScaleFactor scale, int32_t disp) : Address(base, index, scale, disp - kHeapObjectTag) {} // This addressing mode does not exist. FieldAddress(Register base, Register index, ScaleFactor scale, Register r); FieldAddress(const FieldAddress& other) : Address(other) {} FieldAddress& operator=(const FieldAddress& other) { Address::operator=(other); return *this; } }; class Assembler : public ValueObject { public: explicit Assembler(bool use_far_branches = false) : buffer_(), prologue_offset_(-1), jit_cookie_(0), comments_(), code_(Code::ZoneHandle()) { // This mode is only needed and implemented for ARM. ASSERT(!use_far_branches); } ~Assembler() {} 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 pushl(Register reg); void pushl(const Address& address); void pushl(const Immediate& imm); void popl(Register reg); void popl(const Address& address); void pushal(); void popal(); void setcc(Condition condition, ByteRegister dst); void movl(Register dst, const Immediate& src); void movl(Register dst, Register src); void movl(Register dst, const Address& src); void movl(const Address& dst, Register src); void movl(const Address& dst, const Immediate& imm); void movzxb(Register dst, ByteRegister src); void movzxb(Register dst, const Address& src); void movsxb(Register dst, ByteRegister src); void movsxb(Register dst, const Address& src); void movb(Register dst, const Address& src); void movb(const Address& dst, ByteRegister 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 movw(const Address& dst, const Immediate& imm); void leal(Register dst, const Address& src); void cmovno(Register dst, Register src); void cmove(Register dst, Register src); void cmovne(Register dst, Register src); void cmovs(Register dst, Register src); void cmovns(Register dst, Register src); void cmovgel(Register dst, Register src); void cmovlessl(Register dst, Register src); void rep_movsb(); 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 movq(const Address& dst, XmmRegister src); void movq(XmmRegister dst, const Address& src); void addss(XmmRegister dst, XmmRegister src); void addss(XmmRegister dst, const Address& src); void subss(XmmRegister dst, XmmRegister src); void subss(XmmRegister dst, const Address& src); void mulss(XmmRegister dst, XmmRegister src); void mulss(XmmRegister dst, const Address& src); void divss(XmmRegister dst, XmmRegister src); void divss(XmmRegister dst, const Address& src); void movsd(XmmRegister dst, const Address& src); void movsd(const Address& dst, XmmRegister src); void movsd(XmmRegister dst, XmmRegister src); void movaps(XmmRegister dst, XmmRegister src); void movups(XmmRegister dst, const Address& src); void movups(const Address& dst, XmmRegister src); void addsd(XmmRegister dst, XmmRegister src); void addsd(XmmRegister dst, const Address& src); void subsd(XmmRegister dst, XmmRegister src); void subsd(XmmRegister dst, const Address& src); void mulsd(XmmRegister dst, XmmRegister src); void mulsd(XmmRegister dst, const Address& src); void divsd(XmmRegister dst, XmmRegister src); void divsd(XmmRegister dst, const Address& src); void addpl(XmmRegister dst, XmmRegister src); void subpl(XmmRegister dst, XmmRegister src); void addps(XmmRegister dst, XmmRegister src); void subps(XmmRegister dst, XmmRegister src); void divps(XmmRegister dst, XmmRegister src); void mulps(XmmRegister dst, XmmRegister src); void minps(XmmRegister dst, XmmRegister src); void maxps(XmmRegister dst, XmmRegister src); void andps(XmmRegister dst, XmmRegister src); void andps(XmmRegister dst, const Address& src); void orps(XmmRegister dst, XmmRegister src); void notps(XmmRegister dst); void negateps(XmmRegister dst); void absps(XmmRegister dst); void zerowps(XmmRegister dst); void cmppseq(XmmRegister dst, XmmRegister src); void cmppsneq(XmmRegister dst, XmmRegister src); void cmppslt(XmmRegister dst, XmmRegister src); void cmppsle(XmmRegister dst, XmmRegister src); void cmppsnlt(XmmRegister dst, XmmRegister src); void cmppsnle(XmmRegister dst, XmmRegister src); void sqrtps(XmmRegister dst); void rsqrtps(XmmRegister dst); void reciprocalps(XmmRegister dst); void movhlps(XmmRegister dst, XmmRegister src); void movlhps(XmmRegister dst, XmmRegister src); void unpcklps(XmmRegister dst, XmmRegister src); void unpckhps(XmmRegister dst, XmmRegister src); void unpcklpd(XmmRegister dst, XmmRegister src); void unpckhpd(XmmRegister dst, XmmRegister src); void set1ps(XmmRegister dst, Register tmp, const Immediate& imm); void shufps(XmmRegister dst, XmmRegister src, const Immediate& mask); void addpd(XmmRegister dst, XmmRegister src); void negatepd(XmmRegister dst); void subpd(XmmRegister dst, XmmRegister src); void mulpd(XmmRegister dst, XmmRegister src); void divpd(XmmRegister dst, XmmRegister src); void abspd(XmmRegister dst); void minpd(XmmRegister dst, XmmRegister src); void maxpd(XmmRegister dst, XmmRegister src); void sqrtpd(XmmRegister dst); void cvtps2pd(XmmRegister dst, XmmRegister src); void cvtpd2ps(XmmRegister dst, XmmRegister src); void shufpd(XmmRegister dst, XmmRegister src, const Immediate& mask); void cvtsi2ss(XmmRegister dst, Register src); void cvtsi2sd(XmmRegister dst, Register src); void cvtss2si(Register dst, XmmRegister src); void cvtss2sd(XmmRegister dst, XmmRegister src); void cvtsd2si(Register dst, XmmRegister src); void cvtsd2ss(XmmRegister dst, XmmRegister src); void cvttss2si(Register dst, XmmRegister src); void cvttsd2si(Register dst, XmmRegister src); void cvtdq2pd(XmmRegister dst, XmmRegister src); void comiss(XmmRegister a, XmmRegister b); void comisd(XmmRegister a, XmmRegister b); void movmskpd(Register dst, XmmRegister src); void movmskps(Register dst, XmmRegister src); void sqrtsd(XmmRegister dst, XmmRegister src); void sqrtss(XmmRegister dst, XmmRegister src); void xorpd(XmmRegister dst, const Address& src); void xorpd(XmmRegister dst, XmmRegister src); void xorps(XmmRegister dst, const Address& src); void xorps(XmmRegister dst, XmmRegister src); void andpd(XmmRegister dst, const Address& src); void andpd(XmmRegister dst, XmmRegister src); void orpd(XmmRegister dst, XmmRegister src); void pextrd(Register dst, XmmRegister src, const Immediate& imm); void pmovsxdq(XmmRegister dst, XmmRegister src); void pcmpeqq(XmmRegister dst, XmmRegister src); void pxor(XmmRegister dst, XmmRegister src); enum RoundingMode { kRoundToNearest = 0x0, kRoundDown = 0x1, kRoundUp = 0x2, kRoundToZero = 0x3 }; void roundsd(XmmRegister dst, XmmRegister src, RoundingMode mode); void flds(const Address& src); void fstps(const Address& dst); void fldl(const Address& src); void fstpl(const Address& dst); void fnstcw(const Address& dst); void fldcw(const Address& src); void fistpl(const Address& dst); void fistps(const Address& dst); void fildl(const Address& src); void filds(const Address& src); void fincstp(); void ffree(intptr_t value); void fsin(); void fcos(); void fsincos(); void fptan(); void xchgl(Register dst, Register src); void cmpw(const Address& address, const Immediate& imm); void cmpb(const Address& address, const Immediate& imm); void testl(Register reg1, Register reg2); void testl(Register reg, const Immediate& imm); void testb(const Address& address, const Immediate& imm); // clang-format off // Macro for handling common ALU instructions. Arguments to F: // name, opcode, reversed opcode, opcode for the reg field of the modrm byte. #define ALU_OPS(F) \ F(and, 0x23, 0x21, 4) \ F(or, 0x0b, 0x09, 1) \ F(xor, 0x33, 0x31, 6) \ F(add, 0x03, 0x01, 0) \ F(adc, 0x13, 0x11, 2) \ F(sub, 0x2b, 0x29, 5) \ F(sbb, 0x1b, 0x19, 3) \ F(cmp, 0x3b, 0x39, 7) // clang-format on #define DECLARE_ALU(op, opcode, opcode2, modrm_opcode) \ void op##l(Register dst, Register src) { Alu(4, opcode, dst, src); } \ void op##w(Register dst, Register src) { Alu(2, opcode, dst, src); } \ void op##l(Register dst, const Address& src) { Alu(4, opcode, dst, src); } \ void op##w(Register dst, const Address& src) { Alu(2, opcode, dst, src); } \ void op##l(const Address& dst, Register src) { Alu(4, opcode2, dst, src); } \ void op##w(const Address& dst, Register src) { Alu(2, opcode2, dst, src); } \ void op##l(Register dst, const Immediate& imm) { \ Alu(modrm_opcode, dst, imm); \ } \ void op##l(const Address& dst, const Immediate& imm) { \ Alu(modrm_opcode, dst, imm); \ } ALU_OPS(DECLARE_ALU); #undef DECLARE_ALU #undef ALU_OPS void cdq(); void idivl(Register reg); void divl(Register reg); void imull(Register dst, Register src); void imull(Register reg, const Immediate& imm); void imull(Register reg, const Address& address); void imull(Register reg); void imull(const Address& address); void mull(Register reg); void mull(const Address& address); void incl(Register reg); void incl(const Address& address); void decl(Register reg); void decl(const Address& address); void shll(Register reg, const Immediate& imm); void shll(Register operand, Register shifter); void shll(const Address& 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 sarl(const Address& address, Register shifter); void shldl(Register dst, Register src, Register shifter); void shldl(Register dst, Register src, const Immediate& imm); void shldl(const Address& operand, Register src, Register shifter); void shrdl(Register dst, Register src, Register shifter); void shrdl(Register dst, Register src, const Immediate& imm); void shrdl(const Address& dst, Register src, Register shifter); void negl(Register reg); void notl(Register reg); void bsrl(Register dst, Register src); void bt(Register base, Register offset); void bt(Register base, int bit); void enter(const Immediate& imm); void leave(); void ret(); void ret(const Immediate& imm); // 'size' indicates size in bytes and must be in the range 1..8. void nop(int size = 1); void int3(); void hlt(); static uword GetBreakInstructionFiller() { return 0xCCCCCCCC; } void j(Condition condition, Label* label, bool near = kFarJump); void j(Condition condition, const ExternalLabel* label); 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 cpuid(); /* * Macros for High-level operations and implemented on all architectures. */ void CompareRegisters(Register a, Register b); void BranchIf(Condition condition, Label* label) { j(condition, label); } void LoadField(Register dst, FieldAddress address) { movw(dst, address); } // Issues a move instruction if 'to' is not the same as 'from'. void MoveRegister(Register to, Register from); void PushRegister(Register r); void PopRegister(Register r); void AddImmediate(Register reg, const Immediate& imm); void SubImmediate(Register reg, const Immediate& imm); void CompareImmediate(Register reg, int32_t immediate) { cmpl(reg, Immediate(immediate)); } void Drop(intptr_t stack_elements); void LoadIsolate(Register dst); void LoadObject(Register dst, const Object& object, bool movable_referent = false); // If 'object' is a large Smi, xor it with a per-assembler cookie value to // prevent user-controlled immediates from appearing in the code stream. void LoadObjectSafely(Register dst, const Object& object); void PushObject(const Object& object); void CompareObject(Register reg, const Object& object); void LoadDoubleConstant(XmmRegister dst, double value); enum CanBeSmi { kValueIsNotSmi, kValueCanBeSmi, }; void StoreIntoObject(Register object, // Object we are storing into. const Address& dest, // Where we are storing into. Register value, // Value we are storing. CanBeSmi can_value_be_smi = kValueCanBeSmi); void StoreIntoObjectNoBarrier(Register object, const Address& dest, Register value); void StoreIntoObjectNoBarrier(Register object, const Address& dest, const Object& value); // Stores a Smi value into a heap object field that always contains a Smi. void StoreIntoSmiField(const Address& dest, Register value); void ZeroInitSmiField(const Address& dest); // Increments a Smi field. Leaves flags in same state as an 'addl'. void IncrementSmiField(const Address& dest, int32_t increment); 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 ReserveAlignedFrameSpace(intptr_t frame_space); // Create a frame for calling into runtime that preserves all volatile // registers. Frame's RSP is guaranteed to be correctly aligned and // frame_space bytes are reserved under it. void EnterCallRuntimeFrame(intptr_t frame_space); void LeaveCallRuntimeFrame(); void CallRuntime(const RuntimeEntry& entry, intptr_t argument_count); void Call(const StubEntry& stub_entry, bool movable_target = false); void CallToRuntime(); void Jmp(const StubEntry& stub_entry); void J(Condition condition, const StubEntry& stub_entry); /* * Loading and comparing classes of objects. */ void LoadClassId(Register result, Register object); void LoadClassById(Register result, Register class_id); void LoadClass(Register result, Register object, Register scratch); void CompareClassId(Register object, intptr_t class_id, Register scratch); void LoadClassIdMayBeSmi(Register result, Register object); void LoadTaggedClassIdMayBeSmi(Register result, Register object); void SmiUntagOrCheckClass(Register object, intptr_t class_id, Register scratch, Label* is_smi); static Address ElementAddressForIntIndex(bool is_external, intptr_t cid, intptr_t index_scale, Register array, intptr_t index); static Address ElementAddressForRegIndex(bool is_external, intptr_t cid, intptr_t index_scale, Register array, Register index); static Address VMTagAddress() { return Address(THR, Thread::vm_tag_offset()); } /* * Misc. functionality */ void SmiTag(Register reg) { addl(reg, reg); } void SmiUntag(Register reg) { sarl(reg, Immediate(kSmiTagSize)); } void BranchIfNotSmi(Register reg, Label* label) { testl(reg, Immediate(kSmiTagMask)); j(NOT_ZERO, label); } void BranchIfSmi(Register reg, Label* label) { testl(reg, Immediate(kSmiTagMask)); j(ZERO, label); } void Align(intptr_t alignment, intptr_t offset); void Bind(Label* label); void Jump(Label* label) { jmp(label); } // Address of code at offset. uword CodeAddress(intptr_t offset) { return buffer_.Address(offset); } intptr_t CodeSize() const { return buffer_.Size(); } intptr_t prologue_offset() const { return prologue_offset_; } bool has_single_entry_point() const { return true; } // Count the fixups that produce a pointer offset, without processing // the fixups. intptr_t CountPointerOffsets() const { return buffer_.CountPointerOffsets(); } const ZoneGrowableArray& GetPointerOffsets() const { return buffer_.pointer_offsets(); } ObjectPoolWrapper& object_pool_wrapper() { return object_pool_wrapper_; } RawObjectPool* MakeObjectPool() { return object_pool_wrapper_.MakeObjectPool(); } void FinalizeInstructions(const MemoryRegion& region) { buffer_.FinalizeInstructions(region); } // Set up a Dart frame on entry with a frame pointer and PC information to // enable easy access to the RawInstruction object of code corresponding // to this frame. // The dart frame layout is as follows: // .... // ret PC // saved EBP <=== EBP // pc (used to derive the RawInstruction Object of the dart code) // locals space <=== ESP // ..... // This code sets this up with the sequence: // pushl ebp // movl ebp, esp // call L // L: // ..... void EnterDartFrame(intptr_t frame_size); // Set up a Dart frame for a function compiled for on-stack replacement. // The frame layout is a normal Dart frame, but the frame is partially set // up on entry (it is the frame of the unoptimized code). void EnterOsrFrame(intptr_t extra_size); // Set up a stub frame so that the stack traversal code can easily identify // a stub frame. // The stub frame layout is as follows: // .... // ret PC // saved EBP // 0 (used to indicate frame is a stub frame) // ..... // This code sets this up with the sequence: // pushl ebp // movl ebp, esp // pushl immediate(0) // ..... void EnterStubFrame(); static const intptr_t kEnterStubFramePushedWords = 2; // Instruction pattern from entrypoint is used in dart frame prologs // to set up the frame and save a PC which can be used to figure out the // RawInstruction object corresponding to the code running in the frame. // entrypoint: // pushl ebp (size is 1 byte) // movl ebp, esp (size is 2 bytes) // call L (size is 5 bytes) // L: static const intptr_t kEntryPointToPcMarkerOffset = 8; static intptr_t EntryPointToPcMarkerOffset() { return kEntryPointToPcMarkerOffset; } // If allocation tracing for |cid| is enabled, will jump to |trace| label, // which will allocate in the runtime where tracing occurs. void MaybeTraceAllocation(intptr_t cid, Register temp_reg, Label* trace, bool near_jump); void UpdateAllocationStats(intptr_t cid, Register temp_reg, Heap::Space space); void UpdateAllocationStatsWithSize(intptr_t cid, Register size_reg, Register temp_reg, Heap::Space space); void UpdateAllocationStatsWithSize(intptr_t cid, intptr_t instance_size, Register temp_reg, Heap::Space space); // Inlined allocation of an instance of class 'cls', code has no runtime // calls. Jump to 'failure' if the instance cannot be allocated here. // Allocated instance is returned in 'instance_reg'. // Only the tags field of the object is initialized. void TryAllocate(const Class& cls, Label* failure, bool near_jump, Register instance_reg, Register temp_reg); void TryAllocateArray(intptr_t cid, intptr_t instance_size, Label* failure, bool near_jump, Register instance, Register end_address, Register temp); // Debugging and bringup support. void Breakpoint() { int3(); } 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, intptr_t length); void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); static bool EmittingComments(); const Code::Comments& GetCodeComments() const; static const char* RegisterName(Register reg); static const char* FpuRegisterName(FpuRegister reg); // Smis that do not fit into 17 bits (16 bits of payload) are unsafe. static bool IsSafeSmi(const Object& object) { if (!object.IsSmi()) { return false; } if (Utils::IsInt(17, reinterpret_cast(object.raw()))) { return true; } // Single bit smis (powers of two) and corresponding masks are safe. const intptr_t value = Smi::Cast(object).Value(); if (Utils::IsPowerOfTwo(value) || Utils::IsPowerOfTwo(value + 1)) { return true; } return false; } static bool IsSafe(const Object& object) { return !object.IsSmi() || IsSafeSmi(object); } void set_code_object(const Code& code) { code_ ^= code.raw(); } void PushCodeObject(); private: class CodeComment : public ZoneAllocated { public: CodeComment(intptr_t pc_offset, const String& comment) : pc_offset_(pc_offset), comment_(comment) {} intptr_t pc_offset() const { return pc_offset_; } const String& comment() const { return comment_; } private: intptr_t pc_offset_; const String& comment_; DISALLOW_COPY_AND_ASSIGN(CodeComment); }; void Alu(int bytes, uint8_t opcode, Register dst, Register src); void Alu(uint8_t modrm_opcode, Register dst, const Immediate& imm); void Alu(int bytes, uint8_t opcode, Register dst, const Address& src); void Alu(int bytes, uint8_t opcode, const Address& dst, Register src); void Alu(uint8_t modrm_opcode, const Address& dst, const Immediate& imm); inline void EmitUint8(uint8_t value); inline void EmitInt32(int32_t value); inline void EmitRegisterOperand(int rm, int reg); 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, intptr_t instruction_size); void EmitLabelLink(Label* label); void EmitNearLabelLink(Label* label); void EmitGenericShift(int rm, Register reg, const Immediate& imm); void EmitGenericShift(int rm, const Operand& operand, Register shifter); enum BarrierFilterMode { // Filter falls through into the barrier update code. Target label // is a "after-store" label. kJumpToNoUpdate, // Filter falls through to the "after-store" code. Target label // is barrier update code label. kJumpToBarrier, }; void StoreIntoObjectFilter(Register object, Register value, Label* label, CanBeSmi can_be_smi, BarrierFilterMode barrier_filter_mode); void UnverifiedStoreOldObject(const Address& dest, const Object& value); int32_t jit_cookie(); AssemblerBuffer buffer_; ObjectPoolWrapper object_pool_wrapper_; intptr_t prologue_offset_; int32_t jit_cookie_; GrowableArray comments_; Code& code_; DISALLOW_ALLOCATION(); DISALLOW_COPY_AND_ASSIGN(Assembler); }; inline void Assembler::EmitUint8(uint8_t value) { buffer_.Emit(value); } inline void Assembler::EmitInt32(int32_t value) { buffer_.Emit(value); } inline void Assembler::EmitRegisterOperand(int rm, int reg) { ASSERT(rm >= 0 && rm < 8); buffer_.Emit(0xC0 + (rm << 3) + reg); } inline void Assembler::EmitXmmRegisterOperand(int rm, XmmRegister reg) { EmitRegisterOperand(rm, static_cast(reg)); } inline void Assembler::EmitFixup(AssemblerFixup* fixup) { buffer_.EmitFixup(fixup); } inline void Assembler::EmitOperandSizeOverride() { EmitUint8(0x66); } } // namespace dart #endif // RUNTIME_VM_COMPILER_ASSEMBLER_ASSEMBLER_IA32_H_