Index: src/DartARM32/assembler_arm.h |
diff --git a/src/DartARM32/assembler_arm.h b/src/DartARM32/assembler_arm.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c686d600433ad1b79e716436ae46a5172d5cf2e7 |
--- /dev/null |
+++ b/src/DartARM32/assembler_arm.h |
@@ -0,0 +1,1214 @@ |
+// 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. |
+// |
+// This is forked from Dart revision df52deea9f25690eb8b66c5995da92b70f7ac1fe |
+// Please update the (git) revision if we merge changes from Dart. |
+// https://code.google.com/p/dart/wiki/GettingTheSource |
+ |
+#ifndef VM_ASSEMBLER_ARM_H_ |
+#define VM_ASSEMBLER_ARM_H_ |
+ |
+#ifndef VM_ASSEMBLER_H_ |
+#error Do not include assembler_arm.h directly; use assembler.h instead. |
+#endif |
+ |
+#include "platform/assert.h" |
+#include "platform/utils.h" |
+#include "vm/constants_arm.h" |
+#include "vm/cpu.h" |
+#include "vm/hash_map.h" |
+#include "vm/object.h" |
+#include "vm/simulator.h" |
+ |
+namespace dart { |
+ |
+// Forward declarations. |
+class RuntimeEntry; |
+class StubEntry; |
+ |
+ |
+// Instruction encoding bits. |
+enum { |
+ H = 1 << 5, // halfword (or byte) |
+ L = 1 << 20, // load (or store) |
+ S = 1 << 20, // set condition code (or leave unchanged) |
+ W = 1 << 21, // writeback base register (or leave unchanged) |
+ A = 1 << 21, // accumulate in multiply instruction (or not) |
+ B = 1 << 22, // unsigned byte (or word) |
+ D = 1 << 22, // high/lo bit of start of s/d register range |
+ N = 1 << 22, // long (or short) |
+ U = 1 << 23, // positive (or negative) offset/index |
+ P = 1 << 24, // offset/pre-indexed addressing (or post-indexed addressing) |
+ I = 1 << 25, // immediate shifter operand (or not) |
+ |
+ B0 = 1, |
+ B1 = 1 << 1, |
+ B2 = 1 << 2, |
+ B3 = 1 << 3, |
+ B4 = 1 << 4, |
+ B5 = 1 << 5, |
+ B6 = 1 << 6, |
+ B7 = 1 << 7, |
+ B8 = 1 << 8, |
+ B9 = 1 << 9, |
+ B10 = 1 << 10, |
+ B11 = 1 << 11, |
+ B12 = 1 << 12, |
+ B16 = 1 << 16, |
+ B17 = 1 << 17, |
+ B18 = 1 << 18, |
+ B19 = 1 << 19, |
+ B20 = 1 << 20, |
+ B21 = 1 << 21, |
+ B22 = 1 << 22, |
+ B23 = 1 << 23, |
+ B24 = 1 << 24, |
+ B25 = 1 << 25, |
+ B26 = 1 << 26, |
+ B27 = 1 << 27, |
+}; |
+ |
+ |
+class Label : public ValueObject { |
+ public: |
+ Label() : position_(0) { } |
+ |
+ ~Label() { |
+ // Assert if label is being destroyed with unresolved branches pending. |
+ ASSERT(!IsLinked()); |
+ } |
+ |
+ // Returns the position for bound and linked labels. Cannot be used |
+ // for unused labels. |
+ intptr_t Position() const { |
+ ASSERT(!IsUnused()); |
+ return IsBound() ? -position_ - kWordSize : position_ - kWordSize; |
+ } |
+ |
+ bool IsBound() const { return position_ < 0; } |
+ bool IsUnused() const { return position_ == 0; } |
+ bool IsLinked() const { return position_ > 0; } |
+ |
+ private: |
+ intptr_t position_; |
+ |
+ void Reinitialize() { |
+ position_ = 0; |
+ } |
+ |
+ void BindTo(intptr_t position) { |
+ ASSERT(!IsBound()); |
+ position_ = -position - kWordSize; |
+ ASSERT(IsBound()); |
+ } |
+ |
+ void LinkTo(intptr_t position) { |
+ ASSERT(!IsBound()); |
+ position_ = position + kWordSize; |
+ ASSERT(IsLinked()); |
+ } |
+ |
+ friend class Assembler; |
+ DISALLOW_COPY_AND_ASSIGN(Label); |
+}; |
+ |
+ |
+// Encodes Addressing Mode 1 - Data-processing operands. |
+class Operand : public ValueObject { |
+ public: |
+ // Data-processing operands - Uninitialized. |
+ Operand() : type_(-1), encoding_(-1) { } |
+ |
+ // Data-processing operands - Copy constructor. |
+ Operand(const Operand& other) |
+ : ValueObject(), type_(other.type_), encoding_(other.encoding_) { } |
+ |
+ // Data-processing operands - Assignment operator. |
+ Operand& operator=(const Operand& other) { |
+ type_ = other.type_; |
+ encoding_ = other.encoding_; |
+ return *this; |
+ } |
+ |
+ // Data-processing operands - Immediate. |
+ explicit Operand(uint32_t immediate) { |
+ ASSERT(immediate < (1 << kImmed8Bits)); |
+ type_ = 1; |
+ encoding_ = immediate; |
+ } |
+ |
+ // Data-processing operands - Rotated immediate. |
+ Operand(uint32_t rotate, uint32_t immed8) { |
+ ASSERT((rotate < (1 << kRotateBits)) && (immed8 < (1 << kImmed8Bits))); |
+ type_ = 1; |
+ encoding_ = (rotate << kRotateShift) | (immed8 << kImmed8Shift); |
+ } |
+ |
+ // Data-processing operands - Register. |
+ explicit Operand(Register rm) { |
+ type_ = 0; |
+ encoding_ = static_cast<uint32_t>(rm); |
+ } |
+ |
+ // Data-processing operands - Logical shift/rotate by immediate. |
+ Operand(Register rm, Shift shift, uint32_t shift_imm) { |
+ ASSERT(shift_imm < (1 << kShiftImmBits)); |
+ type_ = 0; |
+ encoding_ = shift_imm << kShiftImmShift | |
+ static_cast<uint32_t>(shift) << kShiftShift | |
+ static_cast<uint32_t>(rm); |
+ } |
+ |
+ // Data-processing operands - Logical shift/rotate by register. |
+ Operand(Register rm, Shift shift, Register rs) { |
+ type_ = 0; |
+ encoding_ = static_cast<uint32_t>(rs) << kShiftRegisterShift | |
+ static_cast<uint32_t>(shift) << kShiftShift | (1 << 4) | |
+ static_cast<uint32_t>(rm); |
+ } |
+ |
+ static bool CanHold(uint32_t immediate, Operand* o) { |
+ // Avoid the more expensive test for frequent small immediate values. |
+ if (immediate < (1 << kImmed8Bits)) { |
+ o->type_ = 1; |
+ o->encoding_ = (0 << kRotateShift) | (immediate << kImmed8Shift); |
+ return true; |
+ } |
+ // Note that immediate must be unsigned for the test to work correctly. |
+ for (int rot = 0; rot < 16; rot++) { |
+ uint32_t imm8 = (immediate << 2*rot) | (immediate >> (32 - 2*rot)); |
+ if (imm8 < (1 << kImmed8Bits)) { |
+ o->type_ = 1; |
+ o->encoding_ = (rot << kRotateShift) | (imm8 << kImmed8Shift); |
+ return true; |
+ } |
+ } |
+ return false; |
+ } |
+ |
+ private: |
+ bool is_valid() const { return (type_ == 0) || (type_ == 1); } |
+ |
+ uint32_t type() const { |
+ ASSERT(is_valid()); |
+ return type_; |
+ } |
+ |
+ uint32_t encoding() const { |
+ ASSERT(is_valid()); |
+ return encoding_; |
+ } |
+ |
+ uint32_t type_; // Encodes the type field (bits 27-25) in the instruction. |
+ uint32_t encoding_; |
+ |
+ friend class Assembler; |
+ friend class Address; |
+}; |
+ |
+ |
+enum OperandSize { |
+ kByte, |
+ kUnsignedByte, |
+ kHalfword, |
+ kUnsignedHalfword, |
+ kWord, |
+ kUnsignedWord, |
+ kWordPair, |
+ kSWord, |
+ kDWord, |
+ kRegList, |
+}; |
+ |
+ |
+// Load/store multiple addressing mode. |
+enum BlockAddressMode { |
+ // bit encoding P U W |
+ DA = (0|0|0) << 21, // decrement after |
+ IA = (0|4|0) << 21, // increment after |
+ DB = (8|0|0) << 21, // decrement before |
+ IB = (8|4|0) << 21, // increment before |
+ DA_W = (0|0|1) << 21, // decrement after with writeback to base |
+ IA_W = (0|4|1) << 21, // increment after with writeback to base |
+ DB_W = (8|0|1) << 21, // decrement before with writeback to base |
+ IB_W = (8|4|1) << 21 // increment before with writeback to base |
+}; |
+ |
+ |
+class Address : public ValueObject { |
+ public: |
+ enum OffsetKind { |
+ Immediate, |
+ IndexRegister, |
+ ScaledIndexRegister, |
+ }; |
+ |
+ // Memory operand addressing mode |
+ enum Mode { |
+ kModeMask = (8|4|1) << 21, |
+ // bit encoding P U W |
+ Offset = (8|4|0) << 21, // offset (w/o writeback to base) |
+ PreIndex = (8|4|1) << 21, // pre-indexed addressing with writeback |
+ PostIndex = (0|4|0) << 21, // post-indexed addressing with writeback |
+ NegOffset = (8|0|0) << 21, // negative offset (w/o writeback to base) |
+ NegPreIndex = (8|0|1) << 21, // negative pre-indexed with writeback |
+ NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback |
+ }; |
+ |
+ Address(const Address& other) |
+ : ValueObject(), encoding_(other.encoding_), kind_(other.kind_) { |
+ } |
+ |
+ Address& operator=(const Address& other) { |
+ encoding_ = other.encoding_; |
+ kind_ = other.kind_; |
+ return *this; |
+ } |
+ |
+ bool Equals(const Address& other) const { |
+ return (encoding_ == other.encoding_) && (kind_ == other.kind_); |
+ } |
+ |
+ explicit Address(Register rn, int32_t offset = 0, Mode am = Offset) { |
+ ASSERT(Utils::IsAbsoluteUint(12, offset)); |
+ kind_ = Immediate; |
+ if (offset < 0) { |
+ encoding_ = (am ^ (1 << kUShift)) | -offset; // Flip U to adjust sign. |
+ } else { |
+ encoding_ = am | offset; |
+ } |
+ encoding_ |= static_cast<uint32_t>(rn) << kRnShift; |
+ } |
+ |
+ // There is no register offset mode unless Mode is Offset, in which case the |
+ // shifted register case below should be used. |
+ Address(Register rn, Register r, Mode am); |
+ |
+ Address(Register rn, Register rm, |
+ Shift shift = LSL, uint32_t shift_imm = 0, Mode am = Offset) { |
+ Operand o(rm, shift, shift_imm); |
+ |
+ if ((shift == LSL) && (shift_imm == 0)) { |
+ kind_ = IndexRegister; |
+ } else { |
+ kind_ = ScaledIndexRegister; |
+ } |
+ encoding_ = o.encoding() | am | (static_cast<uint32_t>(rn) << kRnShift); |
+ } |
+ |
+ // There is no shifted register mode with a register shift. |
+ Address(Register rn, Register rm, Shift shift, Register r, Mode am = Offset); |
+ |
+ static OperandSize OperandSizeFor(intptr_t cid); |
+ |
+ static bool CanHoldLoadOffset(OperandSize size, |
+ int32_t offset, |
+ int32_t* offset_mask); |
+ static bool CanHoldStoreOffset(OperandSize size, |
+ int32_t offset, |
+ int32_t* offset_mask); |
+ static bool CanHoldImmediateOffset(bool is_load, |
+ intptr_t cid, |
+ int64_t offset); |
+ |
+ private: |
+ Register rn() const { |
+ return Instr::At(reinterpret_cast<uword>(&encoding_))->RnField(); |
+ } |
+ |
+ Register rm() const { |
+ return ((kind() == IndexRegister) || (kind() == ScaledIndexRegister)) ? |
+ Instr::At(reinterpret_cast<uword>(&encoding_))->RmField() : |
+ kNoRegister; |
+ } |
+ |
+ Mode mode() const { return static_cast<Mode>(encoding() & kModeMask); } |
+ |
+ uint32_t encoding() const { return encoding_; } |
+ |
+ // Encoding for addressing mode 3. |
+ uint32_t encoding3() const; |
+ |
+ // Encoding for vfp load/store addressing. |
+ uint32_t vencoding() const; |
+ |
+ OffsetKind kind() const { return kind_; } |
+ |
+ uint32_t encoding_; |
+ |
+ OffsetKind kind_; |
+ |
+ friend class Assembler; |
+}; |
+ |
+ |
+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(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), |
+ use_far_branches_(use_far_branches), |
+ comments_(), |
+ constant_pool_allowed_(false) { } |
+ |
+ ~Assembler() { } |
+ |
+ void PopRegister(Register r) { Pop(r); } |
+ |
+ void Bind(Label* label); |
+ void Jump(Label* label) { b(label); } |
+ |
+ // Misc. functionality |
+ intptr_t CodeSize() const { return buffer_.Size(); } |
+ intptr_t prologue_offset() const { return prologue_offset_; } |
+ |
+ // Count the fixups that produce a pointer offset, without processing |
+ // the fixups. On ARM there are no pointers in code. |
+ intptr_t CountPointerOffsets() const { return 0; } |
+ |
+ const ZoneGrowableArray<intptr_t>& GetPointerOffsets() const { |
+ ASSERT(buffer_.pointer_offsets().length() == 0); // No pointers in code. |
+ return buffer_.pointer_offsets(); |
+ } |
+ |
+ ObjectPoolWrapper& object_pool_wrapper() { return object_pool_wrapper_; } |
+ |
+ RawObjectPool* MakeObjectPool() { |
+ return object_pool_wrapper_.MakeObjectPool(); |
+ } |
+ |
+ bool use_far_branches() const { |
+ return FLAG_use_far_branches || use_far_branches_; |
+ } |
+ |
+#if defined(TESTING) || defined(DEBUG) |
+ // Used in unit tests and to ensure predictable verification code size in |
+ // FlowGraphCompiler::EmitEdgeCounter. |
+ void set_use_far_branches(bool b) { |
+ use_far_branches_ = b; |
+ } |
+#endif // TESTING || DEBUG |
+ |
+ void FinalizeInstructions(const MemoryRegion& region) { |
+ buffer_.FinalizeInstructions(region); |
+ } |
+ |
+ // Debugging and bringup support. |
+ 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); |
+ |
+ // Data-processing instructions. |
+ void and_(Register rd, Register rn, Operand o, Condition cond = AL); |
+ |
+ void eor(Register rd, Register rn, Operand o, Condition cond = AL); |
+ |
+ void sub(Register rd, Register rn, Operand o, Condition cond = AL); |
+ void subs(Register rd, Register rn, Operand o, Condition cond = AL); |
+ |
+ void rsb(Register rd, Register rn, Operand o, Condition cond = AL); |
+ void rsbs(Register rd, Register rn, Operand o, Condition cond = AL); |
+ |
+ void add(Register rd, Register rn, Operand o, Condition cond = AL); |
+ |
+ void adds(Register rd, Register rn, Operand o, Condition cond = AL); |
+ |
+ void adc(Register rd, Register rn, Operand o, Condition cond = AL); |
+ |
+ void adcs(Register rd, Register rn, Operand o, Condition cond = AL); |
+ |
+ void sbc(Register rd, Register rn, Operand o, Condition cond = AL); |
+ |
+ void sbcs(Register rd, Register rn, Operand o, Condition cond = AL); |
+ |
+ void rsc(Register rd, Register rn, Operand o, Condition cond = AL); |
+ |
+ void tst(Register rn, Operand o, Condition cond = AL); |
+ |
+ void teq(Register rn, Operand o, Condition cond = AL); |
+ |
+ void cmp(Register rn, Operand o, Condition cond = AL); |
+ |
+ void cmn(Register rn, Operand o, Condition cond = AL); |
+ |
+ void orr(Register rd, Register rn, Operand o, Condition cond = AL); |
+ void orrs(Register rd, Register rn, Operand o, Condition cond = AL); |
+ |
+ void mov(Register rd, Operand o, Condition cond = AL); |
+ void movs(Register rd, Operand o, Condition cond = AL); |
+ |
+ void bic(Register rd, Register rn, Operand o, Condition cond = AL); |
+ void bics(Register rd, Register rn, Operand o, Condition cond = AL); |
+ |
+ void mvn(Register rd, Operand o, Condition cond = AL); |
+ void mvns(Register rd, Operand o, Condition cond = AL); |
+ |
+ // Miscellaneous data-processing instructions. |
+ void clz(Register rd, Register rm, Condition cond = AL); |
+ |
+ // Multiply instructions. |
+ void mul(Register rd, Register rn, Register rm, Condition cond = AL); |
+ void muls(Register rd, Register rn, Register rm, Condition cond = AL); |
+ void mla(Register rd, Register rn, Register rm, Register ra, |
+ Condition cond = AL); |
+ void mls(Register rd, Register rn, Register rm, Register ra, |
+ Condition cond = AL); |
+ void smull(Register rd_lo, Register rd_hi, Register rn, Register rm, |
+ Condition cond = AL); |
+ void umull(Register rd_lo, Register rd_hi, Register rn, Register rm, |
+ Condition cond = AL); |
+ void smlal(Register rd_lo, Register rd_hi, Register rn, Register rm, |
+ Condition cond = AL); |
+ void umlal(Register rd_lo, Register rd_hi, Register rn, Register rm, |
+ Condition cond = AL); |
+ |
+ // Emulation of this instruction uses IP and the condition codes. Therefore, |
+ // none of the registers can be IP, and the instruction can only be used |
+ // unconditionally. |
+ void umaal(Register rd_lo, Register rd_hi, Register rn, Register rm); |
+ |
+ // Division instructions. |
+ void sdiv(Register rd, Register rn, Register rm, Condition cond = AL); |
+ void udiv(Register rd, Register rn, Register rm, Condition cond = AL); |
+ |
+ // Load/store instructions. |
+ void ldr(Register rd, Address ad, Condition cond = AL); |
+ void str(Register rd, Address ad, Condition cond = AL); |
+ |
+ void ldrb(Register rd, Address ad, Condition cond = AL); |
+ void strb(Register rd, Address ad, Condition cond = AL); |
+ |
+ void ldrh(Register rd, Address ad, Condition cond = AL); |
+ void strh(Register rd, Address ad, Condition cond = AL); |
+ |
+ void ldrsb(Register rd, Address ad, Condition cond = AL); |
+ void ldrsh(Register rd, Address ad, Condition cond = AL); |
+ |
+ // ldrd and strd actually support the full range of addressing modes, but |
+ // we don't use them, and we need to split them up into two instructions for |
+ // ARMv5TE, so we only support the base + offset mode. |
+ void ldrd(Register rd, Register rn, int32_t offset, Condition cond = AL); |
+ void strd(Register rd, Register rn, int32_t offset, Condition cond = AL); |
+ |
+ void ldm(BlockAddressMode am, Register base, |
+ RegList regs, Condition cond = AL); |
+ void stm(BlockAddressMode am, Register base, |
+ RegList regs, Condition cond = AL); |
+ |
+ void ldrex(Register rd, Register rn, Condition cond = AL); |
+ void strex(Register rd, Register rt, Register rn, Condition cond = AL); |
+ |
+ // Miscellaneous instructions. |
+ void clrex(); |
+ void nop(Condition cond = AL); |
+ |
+ // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0. |
+ void bkpt(uint16_t imm16); |
+ |
+ static int32_t BkptEncoding(uint16_t imm16) { |
+ // bkpt requires that the cond field is AL. |
+ return (AL << kConditionShift) | B24 | B21 | |
+ ((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf); |
+ } |
+ |
+ static uword GetBreakInstructionFiller() { |
+ return BkptEncoding(0); |
+ } |
+ |
+ // Floating point instructions (VFPv3-D16 and VFPv3-D32 profiles). |
+ void vmovsr(SRegister sn, Register rt, Condition cond = AL); |
+ void vmovrs(Register rt, SRegister sn, Condition cond = AL); |
+ void vmovsrr(SRegister sm, Register rt, Register rt2, Condition cond = AL); |
+ void vmovrrs(Register rt, Register rt2, SRegister sm, Condition cond = AL); |
+ void vmovdrr(DRegister dm, Register rt, Register rt2, Condition cond = AL); |
+ void vmovrrd(Register rt, Register rt2, DRegister dm, Condition cond = AL); |
+ void vmovdr(DRegister dd, int i, Register rt, Condition cond = AL); |
+ void vmovs(SRegister sd, SRegister sm, Condition cond = AL); |
+ void vmovd(DRegister dd, DRegister dm, Condition cond = AL); |
+ void vmovq(QRegister qd, QRegister qm); |
+ |
+ // Returns false if the immediate cannot be encoded. |
+ bool vmovs(SRegister sd, float s_imm, Condition cond = AL); |
+ bool vmovd(DRegister dd, double d_imm, Condition cond = AL); |
+ |
+ void vldrs(SRegister sd, Address ad, Condition cond = AL); |
+ void vstrs(SRegister sd, Address ad, Condition cond = AL); |
+ void vldrd(DRegister dd, Address ad, Condition cond = AL); |
+ void vstrd(DRegister dd, Address ad, Condition cond = AL); |
+ |
+ void vldms(BlockAddressMode am, Register base, |
+ SRegister first, SRegister last, Condition cond = AL); |
+ void vstms(BlockAddressMode am, Register base, |
+ SRegister first, SRegister last, Condition cond = AL); |
+ |
+ void vldmd(BlockAddressMode am, Register base, |
+ DRegister first, intptr_t count, Condition cond = AL); |
+ void vstmd(BlockAddressMode am, Register base, |
+ DRegister first, intptr_t count, Condition cond = AL); |
+ |
+ void vadds(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); |
+ void vaddd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); |
+ void vaddqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); |
+ void vaddqs(QRegister qd, QRegister qn, QRegister qm); |
+ void vsubs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); |
+ void vsubd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); |
+ void vsubqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); |
+ void vsubqs(QRegister qd, QRegister qn, QRegister qm); |
+ void vmuls(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); |
+ void vmuld(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); |
+ void vmulqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); |
+ void vmulqs(QRegister qd, QRegister qn, QRegister qm); |
+ void vshlqi(OperandSize sz, QRegister qd, QRegister qm, QRegister qn); |
+ void vshlqu(OperandSize sz, QRegister qd, QRegister qm, QRegister qn); |
+ void vmlas(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); |
+ void vmlad(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); |
+ void vmlss(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); |
+ void vmlsd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); |
+ void vdivs(SRegister sd, SRegister sn, SRegister sm, Condition cond = AL); |
+ void vdivd(DRegister dd, DRegister dn, DRegister dm, Condition cond = AL); |
+ void vminqs(QRegister qd, QRegister qn, QRegister qm); |
+ void vmaxqs(QRegister qd, QRegister qn, QRegister qm); |
+ void vrecpeqs(QRegister qd, QRegister qm); |
+ void vrecpsqs(QRegister qd, QRegister qn, QRegister qm); |
+ void vrsqrteqs(QRegister qd, QRegister qm); |
+ void vrsqrtsqs(QRegister qd, QRegister qn, QRegister qm); |
+ |
+ void veorq(QRegister qd, QRegister qn, QRegister qm); |
+ void vorrq(QRegister qd, QRegister qn, QRegister qm); |
+ void vornq(QRegister qd, QRegister qn, QRegister qm); |
+ void vandq(QRegister qd, QRegister qn, QRegister qm); |
+ void vmvnq(QRegister qd, QRegister qm); |
+ |
+ void vceqqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); |
+ void vceqqs(QRegister qd, QRegister qn, QRegister qm); |
+ void vcgeqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); |
+ void vcugeqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); |
+ void vcgeqs(QRegister qd, QRegister qn, QRegister qm); |
+ void vcgtqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); |
+ void vcugtqi(OperandSize sz, QRegister qd, QRegister qn, QRegister qm); |
+ void vcgtqs(QRegister qd, QRegister qn, QRegister qm); |
+ |
+ void vabss(SRegister sd, SRegister sm, Condition cond = AL); |
+ void vabsd(DRegister dd, DRegister dm, Condition cond = AL); |
+ void vabsqs(QRegister qd, QRegister qm); |
+ void vnegs(SRegister sd, SRegister sm, Condition cond = AL); |
+ void vnegd(DRegister dd, DRegister dm, Condition cond = AL); |
+ void vnegqs(QRegister qd, QRegister qm); |
+ void vsqrts(SRegister sd, SRegister sm, Condition cond = AL); |
+ void vsqrtd(DRegister dd, DRegister dm, Condition cond = AL); |
+ |
+ void vcvtsd(SRegister sd, DRegister dm, Condition cond = AL); |
+ void vcvtds(DRegister dd, SRegister sm, Condition cond = AL); |
+ void vcvtis(SRegister sd, SRegister sm, Condition cond = AL); |
+ void vcvtid(SRegister sd, DRegister dm, Condition cond = AL); |
+ void vcvtsi(SRegister sd, SRegister sm, Condition cond = AL); |
+ void vcvtdi(DRegister dd, SRegister sm, Condition cond = AL); |
+ void vcvtus(SRegister sd, SRegister sm, Condition cond = AL); |
+ void vcvtud(SRegister sd, DRegister dm, Condition cond = AL); |
+ void vcvtsu(SRegister sd, SRegister sm, Condition cond = AL); |
+ void vcvtdu(DRegister dd, SRegister sm, Condition cond = AL); |
+ |
+ void vcmps(SRegister sd, SRegister sm, Condition cond = AL); |
+ void vcmpd(DRegister dd, DRegister dm, Condition cond = AL); |
+ void vcmpsz(SRegister sd, Condition cond = AL); |
+ void vcmpdz(DRegister dd, Condition cond = AL); |
+ void vmrs(Register rd, Condition cond = AL); |
+ void vmstat(Condition cond = AL); |
+ |
+ // Duplicates the operand of size sz at index idx from dm to all elements of |
+ // qd. This is a special case of vtbl. |
+ void vdup(OperandSize sz, QRegister qd, DRegister dm, int idx); |
+ |
+ // Each byte of dm is an index into the table of bytes formed by concatenating |
+ // a list of 'length' registers starting with dn. The result is placed in dd. |
+ void vtbl(DRegister dd, DRegister dn, int length, DRegister dm); |
+ |
+ // The words of qd and qm are interleaved with the low words of the result |
+ // in qd and the high words in qm. |
+ void vzipqw(QRegister qd, QRegister qm); |
+ |
+ // Branch instructions. |
+ void b(Label* label, Condition cond = AL); |
+ void bl(Label* label, Condition cond = AL); |
+ void bx(Register rm, Condition cond = AL); |
+ void blx(Register rm, Condition cond = AL); |
+ |
+ void Branch(const StubEntry& stub_entry, |
+ Patchability patchable = kNotPatchable, |
+ Register pp = PP, |
+ Condition cond = AL); |
+ |
+ void BranchLink(const StubEntry& stub_entry, |
+ Patchability patchable = kNotPatchable); |
+ void BranchLink(const Code& code, Patchability patchable); |
+ |
+ // Branch and link to an entry address. Call sequence can be patched. |
+ void BranchLinkPatchable(const StubEntry& stub_entry); |
+ void BranchLinkPatchable(const Code& code); |
+ |
+ // Branch and link to [base + offset]. Call sequence is never patched. |
+ void BranchLinkOffset(Register base, int32_t offset); |
+ |
+ // Add signed immediate value to rd. May clobber IP. |
+ void AddImmediate(Register rd, int32_t value, Condition cond = AL); |
+ void AddImmediate(Register rd, Register rn, int32_t value, |
+ Condition cond = AL); |
+ void AddImmediateSetFlags(Register rd, Register rn, int32_t value, |
+ Condition cond = AL); |
+ void SubImmediateSetFlags(Register rd, Register rn, int32_t value, |
+ Condition cond = AL); |
+ void AndImmediate(Register rd, Register rs, int32_t imm, Condition cond = AL); |
+ |
+ // Test rn and immediate. May clobber IP. |
+ void TestImmediate(Register rn, int32_t imm, Condition cond = AL); |
+ |
+ // Compare rn with signed immediate value. May clobber IP. |
+ void CompareImmediate(Register rn, int32_t value, Condition cond = AL); |
+ |
+ |
+ // Signed integer division of left by right. Checks to see if integer |
+ // division is supported. If not, uses the FPU for division with |
+ // temporary registers tmpl and tmpr. tmpl and tmpr must be different |
+ // registers. |
+ void IntegerDivide(Register result, Register left, Register right, |
+ DRegister tmpl, DRegister tmpr); |
+ |
+ // Load and Store. |
+ // These three do not clobber IP. |
+ void LoadPatchableImmediate(Register rd, int32_t value, Condition cond = AL); |
+ void LoadDecodableImmediate(Register rd, int32_t value, Condition cond = AL); |
+ void LoadImmediate(Register rd, int32_t value, Condition cond = AL); |
+ // These two may clobber IP. |
+ void LoadSImmediate(SRegister sd, float value, Condition cond = AL); |
+ void LoadDImmediate(DRegister dd, double value, |
+ Register scratch, Condition cond = AL); |
+ |
+ void MarkExceptionHandler(Label* label); |
+ |
+ void Drop(intptr_t stack_elements); |
+ |
+ void RestoreCodePointer(); |
+ void LoadPoolPointer(Register reg = PP); |
+ |
+ void LoadIsolate(Register rd); |
+ |
+ void LoadObject(Register rd, const Object& object, Condition cond = AL); |
+ void LoadUniqueObject(Register rd, const Object& object, Condition cond = AL); |
+ void LoadFunctionFromCalleePool(Register dst, |
+ const Function& function, |
+ Register new_pp); |
+ void LoadNativeEntry(Register dst, |
+ const ExternalLabel* label, |
+ Patchability patchable, |
+ Condition cond = AL); |
+ void PushObject(const Object& object); |
+ void CompareObject(Register rn, const Object& object); |
+ |
+ // When storing into a heap object field, knowledge of the previous content |
+ // is expressed through these constants. |
+ enum FieldContent { |
+ kEmptyOrSmiOrNull, // Empty = garbage/zapped in release/debug mode. |
+ kHeapObjectOrSmi, |
+ kOnlySmi, |
+ }; |
+ |
+ void StoreIntoObject(Register object, // Object we are storing into. |
+ const Address& dest, // Where we are storing into. |
+ Register value, // Value we are storing. |
+ bool can_value_be_smi = true); |
+ void StoreIntoObjectOffset(Register object, |
+ int32_t offset, |
+ Register value, |
+ bool can_value_be_smi = true); |
+ |
+ void StoreIntoObjectNoBarrier(Register object, |
+ const Address& dest, |
+ Register value, |
+ FieldContent old_content = kHeapObjectOrSmi); |
+ void InitializeFieldNoBarrier(Register object, |
+ const Address& dest, |
+ Register value) { |
+ StoreIntoObjectNoBarrier(object, dest, value, kEmptyOrSmiOrNull); |
+ } |
+ void StoreIntoObjectNoBarrierOffset( |
+ Register object, |
+ int32_t offset, |
+ Register value, |
+ FieldContent old_content = kHeapObjectOrSmi); |
+ void StoreIntoObjectNoBarrier(Register object, |
+ const Address& dest, |
+ const Object& value, |
+ FieldContent old_content = kHeapObjectOrSmi); |
+ void StoreIntoObjectNoBarrierOffset( |
+ Register object, |
+ int32_t offset, |
+ const Object& value, |
+ FieldContent old_content = kHeapObjectOrSmi); |
+ |
+ // Store value_even, value_odd, value_even, ... into the words in the address |
+ // range [begin, end), assumed to be uninitialized fields in object (tagged). |
+ // The stores must not need a generational store barrier (e.g., smi/null), |
+ // and (value_even, value_odd) must be a valid register pair. |
+ // Destroys register 'begin'. |
+ void InitializeFieldsNoBarrier(Register object, |
+ Register begin, |
+ Register end, |
+ Register value_even, |
+ Register value_odd); |
+ // Like above, for the range [base+begin_offset, base+end_offset), unrolled. |
+ void InitializeFieldsNoBarrierUnrolled(Register object, |
+ Register base, |
+ intptr_t begin_offset, |
+ intptr_t end_offset, |
+ Register value_even, |
+ Register value_odd); |
+ |
+ // Stores a Smi value into a heap object field that always contains a Smi. |
+ void StoreIntoSmiField(const Address& dest, Register value); |
+ |
+ void LoadClassId(Register result, Register object, Condition cond = AL); |
+ 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 ComputeRange(Register result, |
+ Register value, |
+ Register scratch, |
+ Label* miss); |
+ |
+ void UpdateRangeFeedback(Register value, |
+ intptr_t idx, |
+ Register ic_data, |
+ Register scratch1, |
+ Register scratch2, |
+ Label* miss); |
+ |
+ intptr_t FindImmediate(int32_t imm); |
+ bool CanLoadFromObjectPool(const Object& object) const; |
+ void LoadFromOffset(OperandSize type, |
+ Register reg, |
+ Register base, |
+ int32_t offset, |
+ Condition cond = AL); |
+ void LoadFieldFromOffset(OperandSize type, |
+ Register reg, |
+ Register base, |
+ int32_t offset, |
+ Condition cond = AL) { |
+ LoadFromOffset(type, reg, base, offset - kHeapObjectTag, cond); |
+ } |
+ void StoreToOffset(OperandSize type, |
+ Register reg, |
+ Register base, |
+ int32_t offset, |
+ Condition cond = AL); |
+ void LoadSFromOffset(SRegister reg, |
+ Register base, |
+ int32_t offset, |
+ Condition cond = AL); |
+ void StoreSToOffset(SRegister reg, |
+ Register base, |
+ int32_t offset, |
+ Condition cond = AL); |
+ void LoadDFromOffset(DRegister reg, |
+ Register base, |
+ int32_t offset, |
+ Condition cond = AL); |
+ void StoreDToOffset(DRegister reg, |
+ Register base, |
+ int32_t offset, |
+ Condition cond = AL); |
+ |
+ void LoadMultipleDFromOffset(DRegister first, |
+ intptr_t count, |
+ Register base, |
+ int32_t offset); |
+ void StoreMultipleDToOffset(DRegister first, |
+ intptr_t count, |
+ Register base, |
+ int32_t offset); |
+ |
+ void CopyDoubleField(Register dst, Register src, |
+ Register tmp1, Register tmp2, DRegister dtmp); |
+ void CopyFloat32x4Field(Register dst, Register src, |
+ Register tmp1, Register tmp2, DRegister dtmp); |
+ void CopyFloat64x2Field(Register dst, Register src, |
+ Register tmp1, Register tmp2, DRegister dtmp); |
+ |
+ void Push(Register rd, Condition cond = AL); |
+ void Pop(Register rd, Condition cond = AL); |
+ |
+ void PushList(RegList regs, Condition cond = AL); |
+ void PopList(RegList regs, Condition cond = AL); |
+ |
+ void MoveRegister(Register rd, Register rm, Condition cond = AL); |
+ |
+ // Convenience shift instructions. Use mov instruction with shifter operand |
+ // for variants setting the status flags. |
+ void Lsl(Register rd, Register rm, const Operand& shift_imm, |
+ Condition cond = AL); |
+ void Lsl(Register rd, Register rm, Register rs, Condition cond = AL); |
+ void Lsr(Register rd, Register rm, const Operand& shift_imm, |
+ Condition cond = AL); |
+ void Lsr(Register rd, Register rm, Register rs, Condition cond = AL); |
+ void Asr(Register rd, Register rm, const Operand& shift_imm, |
+ Condition cond = AL); |
+ void Asr(Register rd, Register rm, Register rs, Condition cond = AL); |
+ void Asrs(Register rd, Register rm, const Operand& shift_imm, |
+ Condition cond = AL); |
+ void Ror(Register rd, Register rm, const Operand& shift_imm, |
+ Condition cond = AL); |
+ void Ror(Register rd, Register rm, Register rs, Condition cond = AL); |
+ void Rrx(Register rd, Register rm, Condition cond = AL); |
+ |
+ // Fill rd with the sign of rm. |
+ void SignFill(Register rd, Register rm, Condition cond = AL); |
+ |
+ void Vreciprocalqs(QRegister qd, QRegister qm); |
+ void VreciprocalSqrtqs(QRegister qd, QRegister qm); |
+ // If qm must be preserved, then provide a (non-QTMP) temporary. |
+ void Vsqrtqs(QRegister qd, QRegister qm, QRegister temp); |
+ void Vdivqs(QRegister qd, QRegister qn, QRegister qm); |
+ |
+ void SmiTag(Register reg, Condition cond = AL) { |
+ Lsl(reg, reg, Operand(kSmiTagSize), cond); |
+ } |
+ |
+ void SmiTag(Register dst, Register src, Condition cond = AL) { |
+ Lsl(dst, src, Operand(kSmiTagSize), cond); |
+ } |
+ |
+ void SmiUntag(Register reg, Condition cond = AL) { |
+ Asr(reg, reg, Operand(kSmiTagSize), cond); |
+ } |
+ |
+ void SmiUntag(Register dst, Register src, Condition cond = AL) { |
+ Asr(dst, src, Operand(kSmiTagSize), cond); |
+ } |
+ |
+ // Untag the value in the register assuming it is a smi. |
+ // Untagging shifts tag bit into the carry flag - if carry is clear |
+ // assumption was correct. In this case jump to the is_smi label. |
+ // Otherwise fall-through. |
+ void SmiUntag(Register dst, Register src, Label* is_smi) { |
+ ASSERT(kSmiTagSize == 1); |
+ Asrs(dst, src, Operand(kSmiTagSize)); |
+ b(is_smi, CC); |
+ } |
+ |
+ void CheckCodePointer(); |
+ |
+ // Function frame setup and tear down. |
+ void EnterFrame(RegList regs, intptr_t frame_space); |
+ void LeaveFrame(RegList regs); |
+ void Ret(); |
+ void ReserveAlignedFrameSpace(intptr_t frame_space); |
+ |
+ // Create a frame for calling into runtime that preserves all volatile |
+ // registers. Frame's SP 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); |
+ |
+ // 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. |
+ void EnterDartFrame(intptr_t frame_size); |
+ void LeaveDartFrame(RestorePP restore_pp = kRestoreCallerPP); |
+ |
+ // 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. |
+ void EnterStubFrame(); |
+ void LeaveStubFrame(); |
+ |
+ // The register into which the allocation stats table is loaded with |
+ // LoadAllocationStatsAddress should be passed to |
+ // IncrementAllocationStats(WithSize) as stats_addr_reg to update the |
+ // allocation stats. These are separate assembler macros so we can |
+ // avoid a dependent load too nearby the load of the table address. |
+ void LoadAllocationStatsAddress(Register dest, |
+ intptr_t cid, |
+ bool inline_isolate = true); |
+ void IncrementAllocationStats(Register stats_addr, |
+ intptr_t cid, |
+ Heap::Space space); |
+ void IncrementAllocationStatsWithSize(Register stats_addr_reg, |
+ Register size_reg, |
+ Heap::Space space); |
+ |
+ Address ElementAddressForIntIndex(bool is_load, |
+ bool is_external, |
+ intptr_t cid, |
+ intptr_t index_scale, |
+ Register array, |
+ intptr_t index, |
+ Register temp); |
+ |
+ Address ElementAddressForRegIndex(bool is_load, |
+ bool is_external, |
+ intptr_t cid, |
+ intptr_t index_scale, |
+ Register array, |
+ Register index); |
+ |
+ // 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 inline_isolate = true); |
+ |
+ // 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, |
+ Register instance_reg, |
+ Register temp_reg); |
+ |
+ void TryAllocateArray(intptr_t cid, |
+ intptr_t instance_size, |
+ Label* failure, |
+ Register instance, |
+ Register end_address, |
+ Register temp1, |
+ Register temp2); |
+ |
+ // Emit data (e.g encoded instruction or immediate) in instruction stream. |
+ void Emit(int32_t value); |
+ |
+ // On some other platforms, we draw a distinction between safe and unsafe |
+ // smis. |
+ static bool IsSafe(const Object& object) { return true; } |
+ static bool IsSafeSmi(const Object& object) { return object.IsSmi(); } |
+ |
+ bool constant_pool_allowed() const { |
+ return constant_pool_allowed_; |
+ } |
+ void set_constant_pool_allowed(bool b) { |
+ constant_pool_allowed_ = b; |
+ } |
+ |
+ private: |
+ AssemblerBuffer buffer_; // Contains position independent code. |
+ ObjectPoolWrapper object_pool_wrapper_; |
+ |
+ int32_t prologue_offset_; |
+ |
+ bool use_far_branches_; |
+ |
+ // If you are thinking of using one or both of these instructions directly, |
+ // instead LoadImmediate should probably be used. |
+ void movw(Register rd, uint16_t imm16, Condition cond = AL); |
+ void movt(Register rd, uint16_t imm16, Condition cond = AL); |
+ |
+ void BindARMv6(Label* label); |
+ void BindARMv7(Label* label); |
+ |
+ void LoadWordFromPoolOffset(Register rd, |
+ int32_t offset, |
+ Register pp, |
+ Condition cond); |
+ |
+ void BranchLink(const ExternalLabel* label); |
+ |
+ 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); |
+ }; |
+ |
+ GrowableArray<CodeComment*> comments_; |
+ |
+ bool constant_pool_allowed_; |
+ |
+ void LoadObjectHelper(Register rd, |
+ const Object& object, |
+ Condition cond, |
+ bool is_unique, |
+ Register pp); |
+ |
+ void EmitType01(Condition cond, |
+ int type, |
+ Opcode opcode, |
+ int set_cc, |
+ Register rn, |
+ Register rd, |
+ Operand o); |
+ |
+ void EmitType5(Condition cond, int32_t offset, bool link); |
+ |
+ void EmitMemOp(Condition cond, |
+ bool load, |
+ bool byte, |
+ Register rd, |
+ Address ad); |
+ |
+ void EmitMemOpAddressMode3(Condition cond, |
+ int32_t mode, |
+ Register rd, |
+ Address ad); |
+ |
+ void EmitMultiMemOp(Condition cond, |
+ BlockAddressMode am, |
+ bool load, |
+ Register base, |
+ RegList regs); |
+ |
+ void EmitShiftImmediate(Condition cond, |
+ Shift opcode, |
+ Register rd, |
+ Register rm, |
+ Operand o); |
+ |
+ void EmitShiftRegister(Condition cond, |
+ Shift opcode, |
+ Register rd, |
+ Register rm, |
+ Operand o); |
+ |
+ void EmitMulOp(Condition cond, |
+ int32_t opcode, |
+ Register rd, |
+ Register rn, |
+ Register rm, |
+ Register rs); |
+ |
+ void EmitDivOp(Condition cond, |
+ int32_t opcode, |
+ Register rd, |
+ Register rn, |
+ Register rm); |
+ |
+ void EmitMultiVSMemOp(Condition cond, |
+ BlockAddressMode am, |
+ bool load, |
+ Register base, |
+ SRegister start, |
+ uint32_t count); |
+ |
+ void EmitMultiVDMemOp(Condition cond, |
+ BlockAddressMode am, |
+ bool load, |
+ Register base, |
+ DRegister start, |
+ int32_t count); |
+ |
+ void EmitVFPsss(Condition cond, |
+ int32_t opcode, |
+ SRegister sd, |
+ SRegister sn, |
+ SRegister sm); |
+ |
+ void EmitVFPddd(Condition cond, |
+ int32_t opcode, |
+ DRegister dd, |
+ DRegister dn, |
+ DRegister dm); |
+ |
+ void EmitVFPsd(Condition cond, |
+ int32_t opcode, |
+ SRegister sd, |
+ DRegister dm); |
+ |
+ void EmitVFPds(Condition cond, |
+ int32_t opcode, |
+ DRegister dd, |
+ SRegister sm); |
+ |
+ void EmitSIMDqqq(int32_t opcode, OperandSize sz, |
+ QRegister qd, QRegister qn, QRegister qm); |
+ |
+ void EmitSIMDddd(int32_t opcode, OperandSize sz, |
+ DRegister dd, DRegister dn, DRegister dm); |
+ |
+ void EmitFarBranch(Condition cond, int32_t offset, bool link); |
+ void EmitBranch(Condition cond, Label* label, bool link); |
+ int32_t EncodeBranchOffset(int32_t offset, int32_t inst); |
+ static int32_t DecodeBranchOffset(int32_t inst); |
+ int32_t EncodeTstOffset(int32_t offset, int32_t inst); |
+ int32_t DecodeTstOffset(int32_t inst); |
+ |
+ void StoreIntoObjectFilter(Register object, Register value, Label* no_update); |
+ |
+ // Shorter filtering sequence that assumes that value is not a smi. |
+ void StoreIntoObjectFilterNoSmi(Register object, |
+ Register value, |
+ Label* no_update); |
+ |
+ // Helpers for write-barrier verification. |
+ |
+ // Returns VerifiedMemory::offset() as an Operand. |
+ Operand GetVerifiedMemoryShadow(); |
+ // Writes value to [base + offset] and also its shadow location, if enabled. |
+ void WriteShadowedField(Register base, |
+ intptr_t offset, |
+ Register value, |
+ Condition cond = AL); |
+ void WriteShadowedFieldPair(Register base, |
+ intptr_t offset, |
+ Register value_even, |
+ Register value_odd, |
+ Condition cond = AL); |
+ // Writes new_value to address and its shadow location, if enabled, after |
+ // verifying that its old value matches its shadow. |
+ void VerifiedWrite(const Address& address, |
+ Register new_value, |
+ FieldContent old_content); |
+ |
+ DISALLOW_ALLOCATION(); |
+ DISALLOW_COPY_AND_ASSIGN(Assembler); |
+}; |
+ |
+} // namespace dart |
+ |
+#endif // VM_ASSEMBLER_ARM_H_ |