| Index: runtime/vm/assembler_arm64.cc
|
| ===================================================================
|
| --- runtime/vm/assembler_arm64.cc (revision 35070)
|
| +++ runtime/vm/assembler_arm64.cc (working copy)
|
| @@ -24,6 +24,34 @@
|
| DECLARE_FLAG(bool, inline_alloc);
|
|
|
|
|
| +Assembler::Assembler(bool use_far_branches)
|
| + : buffer_(),
|
| + object_pool_(GrowableObjectArray::Handle()),
|
| + patchable_pool_entries_(),
|
| + prologue_offset_(-1),
|
| + use_far_branches_(use_far_branches),
|
| + comments_() {
|
| + if (Isolate::Current() != Dart::vm_isolate()) {
|
| + object_pool_ = GrowableObjectArray::New(Heap::kOld);
|
| +
|
| + // These objects and labels need to be accessible through every pool-pointer
|
| + // at the same index.
|
| + object_pool_.Add(Object::null_object(), Heap::kOld);
|
| + patchable_pool_entries_.Add(kNotPatchable);
|
| + // Not adding Object::null() to the index table. It is at index 0 in the
|
| + // object pool, but the HashMap uses 0 to indicate not found.
|
| +
|
| + object_pool_.Add(Bool::True(), Heap::kOld);
|
| + patchable_pool_entries_.Add(kNotPatchable);
|
| + object_pool_index_table_.Insert(ObjIndexPair(Bool::True().raw(), 1));
|
| +
|
| + object_pool_.Add(Bool::False(), Heap::kOld);
|
| + patchable_pool_entries_.Add(kNotPatchable);
|
| + object_pool_index_table_.Insert(ObjIndexPair(Bool::False().raw(), 2));
|
| + }
|
| +}
|
| +
|
| +
|
| void Assembler::InitializeMemoryWithBreakpoints(uword data, intptr_t length) {
|
| ASSERT(Utils::IsAligned(data, 4));
|
| ASSERT(Utils::IsAligned(length, 4));
|
| @@ -126,7 +154,7 @@
|
| // by the corresponding fields in the logical instruction.
|
| // If it can't be encoded, the function returns false, and the operand is
|
| // undefined.
|
| -bool Assembler::IsImmLogical(uint64_t value, uint8_t width, Operand* imm_op) {
|
| +bool Operand::IsImmLogical(uint64_t value, uint8_t width, Operand* imm_op) {
|
| ASSERT(imm_op != NULL);
|
| ASSERT((width == kWRegSizeInBits) || (width == kXRegSizeInBits));
|
| ASSERT((width == kXRegSizeInBits) || (value <= 0xffffffffUL));
|
| @@ -220,6 +248,193 @@
|
| }
|
| }
|
|
|
| +
|
| +void Assembler::LoadWordFromPoolOffset(Register dst, Register pp,
|
| + uint32_t offset) {
|
| + ASSERT(dst != pp);
|
| + if (Address::CanHoldOffset(offset)) {
|
| + ldr(dst, Address(pp, offset));
|
| + } else {
|
| + const uint16_t offset_low = Utils::Low16Bits(offset);
|
| + const uint16_t offset_high = Utils::High16Bits(offset);
|
| + movz(dst, offset_low, 0);
|
| + if (offset_high != 0) {
|
| + movk(dst, offset_high, 1);
|
| + }
|
| + ldr(dst, Address(pp, dst));
|
| + }
|
| +}
|
| +
|
| +
|
| +intptr_t Assembler::FindObject(const Object& obj, Patchability patchable) {
|
| + // The object pool cannot be used in the vm isolate.
|
| + ASSERT(Isolate::Current() != Dart::vm_isolate());
|
| + ASSERT(!object_pool_.IsNull());
|
| +
|
| + // If the object is not patchable, check if we've already got it in the
|
| + // object pool.
|
| + if (patchable == kNotPatchable) {
|
| + // Special case for Object::null(), which is always at object_pool_ index 0
|
| + // because Lookup() below returns 0 when the object is not mapped in the
|
| + // table.
|
| + if (obj.raw() == Object::null()) {
|
| + return 0;
|
| + }
|
| +
|
| + intptr_t idx = object_pool_index_table_.Lookup(obj.raw());
|
| + if (idx != 0) {
|
| + ASSERT(patchable_pool_entries_[idx] == kNotPatchable);
|
| + return idx;
|
| + }
|
| + }
|
| +
|
| + object_pool_.Add(obj, Heap::kOld);
|
| + patchable_pool_entries_.Add(patchable);
|
| + if (patchable == kNotPatchable) {
|
| + // The object isn't patchable. Record the index for fast lookup.
|
| + object_pool_index_table_.Insert(
|
| + ObjIndexPair(obj.raw(), object_pool_.Length() - 1));
|
| + }
|
| + return object_pool_.Length() - 1;
|
| +}
|
| +
|
| +
|
| +intptr_t Assembler::FindImmediate(int64_t imm) {
|
| + ASSERT(Isolate::Current() != Dart::vm_isolate());
|
| + ASSERT(!object_pool_.IsNull());
|
| + const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(imm));
|
| + return FindObject(smi, kNotPatchable);
|
| +}
|
| +
|
| +
|
| +bool Assembler::CanLoadObjectFromPool(const Object& object) {
|
| + // TODO(zra, kmillikin): Also load other large immediates from the object
|
| + // pool
|
| + if (object.IsSmi()) {
|
| + // If the raw smi does not fit into a 32-bit signed int, then we'll keep
|
| + // the raw value in the object pool.
|
| + return !Utils::IsInt(32, reinterpret_cast<int64_t>(object.raw()));
|
| + }
|
| + ASSERT(object.IsNotTemporaryScopedHandle());
|
| + ASSERT(object.IsOld());
|
| + return (Isolate::Current() != Dart::vm_isolate()) &&
|
| + // Not in the VMHeap, OR is one of the VMHeap objects we put in every
|
| + // object pool.
|
| + // TODO(zra): Evaluate putting all VM heap objects into the pool.
|
| + (!object.InVMHeap() || (object.raw() == Object::null()) ||
|
| + (object.raw() == Bool::True().raw()) ||
|
| + (object.raw() == Bool::False().raw()));
|
| +}
|
| +
|
| +
|
| +bool Assembler::CanLoadImmediateFromPool(int64_t imm, Register pp) {
|
| + return !Utils::IsInt(32, imm) &&
|
| + (pp != kNoRegister) &&
|
| + (Isolate::Current() != Dart::vm_isolate());
|
| +}
|
| +
|
| +
|
| +void Assembler::LoadObject(Register dst, const Object& object, Register pp) {
|
| + if (CanLoadObjectFromPool(object)) {
|
| + const int32_t offset =
|
| + Array::element_offset(FindObject(object, kNotPatchable));
|
| + LoadWordFromPoolOffset(dst, pp, offset - kHeapObjectTag);
|
| + } else {
|
| + ASSERT((Isolate::Current() == Dart::vm_isolate()) ||
|
| + object.IsSmi() ||
|
| + object.InVMHeap());
|
| + LoadImmediate(dst, reinterpret_cast<int64_t>(object.raw()), pp);
|
| + }
|
| +}
|
| +
|
| +
|
| +void Assembler::LoadImmediate(Register reg, int64_t imm, Register pp) {
|
| + Comment("LoadImmediate");
|
| + if (CanLoadImmediateFromPool(imm, pp)) {
|
| + // It's a 64-bit constant and we're not in the VM isolate, so load from
|
| + // object pool.
|
| + // Save the bits that must be masked-off for the SmiTag
|
| + int64_t val_smi_tag = imm & kSmiTagMask;
|
| + imm &= ~kSmiTagMask; // Mask off the tag bits.
|
| + const int32_t offset = Array::element_offset(FindImmediate(imm));
|
| + LoadWordFromPoolOffset(reg, pp, offset - kHeapObjectTag);
|
| + if (val_smi_tag != 0) {
|
| + // Add back the tag bits.
|
| + orri(reg, reg, val_smi_tag);
|
| + }
|
| + } else {
|
| + // 1. Can we use one orri operation?
|
| + Operand op;
|
| + Operand::OperandType ot;
|
| + ot = Operand::CanHold(imm, kXRegSizeInBits, &op);
|
| + if (ot == Operand::BitfieldImm) {
|
| + orri(reg, ZR, imm);
|
| + return;
|
| + }
|
| +
|
| + // 2. Fall back on movz, movk, movn.
|
| + const uint32_t w0 = Utils::Low32Bits(imm);
|
| + const uint32_t w1 = Utils::High32Bits(imm);
|
| + const uint16_t h0 = Utils::Low16Bits(w0);
|
| + const uint16_t h1 = Utils::High16Bits(w0);
|
| + const uint16_t h2 = Utils::Low16Bits(w1);
|
| + const uint16_t h3 = Utils::High16Bits(w1);
|
| +
|
| + // Special case for w1 == 0xffffffff
|
| + if (w1 == 0xffffffff) {
|
| + if (h1 == 0xffff) {
|
| + movn(reg, ~h0, 0);
|
| + } else {
|
| + movn(reg, ~h1, 1);
|
| + movk(reg, h0, 0);
|
| + }
|
| + return;
|
| + }
|
| +
|
| + // Special case for h3 == 0xffff
|
| + if (h3 == 0xffff) {
|
| + // We know h2 != 0xffff.
|
| + movn(reg, ~h2, 2);
|
| + if (h1 != 0xffff) {
|
| + movk(reg, h1, 1);
|
| + }
|
| + if (h0 != 0xffff) {
|
| + movk(reg, h0, 0);
|
| + }
|
| + return;
|
| + }
|
| +
|
| + bool initialized = false;
|
| + if (h0 != 0) {
|
| + movz(reg, h0, 0);
|
| + initialized = true;
|
| + }
|
| + if (h1 != 0) {
|
| + if (initialized) {
|
| + movk(reg, h1, 1);
|
| + } else {
|
| + movz(reg, h1, 1);
|
| + initialized = true;
|
| + }
|
| + }
|
| + if (h2 != 0) {
|
| + if (initialized) {
|
| + movk(reg, h2, 2);
|
| + } else {
|
| + movz(reg, h2, 2);
|
| + initialized = true;
|
| + }
|
| + }
|
| + if (h3 != 0) {
|
| + if (initialized) {
|
| + movk(reg, h3, 3);
|
| + } else {
|
| + movz(reg, h3, 3);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| } // namespace dart
|
|
|
| #endif // defined TARGET_ARCH_ARM64
|
|
|