/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "assembler_arm64.h" #include "base/logging.h" #include "entrypoints/quick/quick_entrypoints.h" #include "offsets.h" #include "thread.h" using namespace vixl::aarch64; // NOLINT(build/namespaces) namespace art { namespace arm64 { #ifdef ___ #error "ARM64 Assembler macro already defined." #else #define ___ vixl_masm_. #endif void Arm64Assembler::FinalizeCode() { ___ FinalizeCode(); } size_t Arm64Assembler::CodeSize() const { return vixl_masm_.GetSizeOfCodeGenerated(); } const uint8_t* Arm64Assembler::CodeBufferBaseAddress() const { return vixl_masm_.GetBuffer().GetStartAddress(); } void Arm64Assembler::FinalizeInstructions(const MemoryRegion& region) { // Copy the instructions from the buffer. MemoryRegion from(vixl_masm_.GetBuffer()->GetStartAddress(), CodeSize()); region.CopyFrom(0, from); } void Arm64Assembler::LoadRawPtr(ManagedRegister m_dst, ManagedRegister m_base, Offset offs) { Arm64ManagedRegister dst = m_dst.AsArm64(); Arm64ManagedRegister base = m_base.AsArm64(); CHECK(dst.IsXRegister() && base.IsXRegister()); // Remove dst and base form the temp list - higher level API uses IP1, IP0. UseScratchRegisterScope temps(&vixl_masm_); temps.Exclude(reg_x(dst.AsXRegister()), reg_x(base.AsXRegister())); ___ Ldr(reg_x(dst.AsXRegister()), MEM_OP(reg_x(base.AsXRegister()), offs.Int32Value())); } void Arm64Assembler::JumpTo(ManagedRegister m_base, Offset offs, ManagedRegister m_scratch) { Arm64ManagedRegister base = m_base.AsArm64(); Arm64ManagedRegister scratch = m_scratch.AsArm64(); CHECK(base.IsXRegister()) << base; CHECK(scratch.IsXRegister()) << scratch; // Remove base and scratch form the temp list - higher level API uses IP1, IP0. UseScratchRegisterScope temps(&vixl_masm_); temps.Exclude(reg_x(base.AsXRegister()), reg_x(scratch.AsXRegister())); ___ Ldr(reg_x(scratch.AsXRegister()), MEM_OP(reg_x(base.AsXRegister()), offs.Int32Value())); ___ Br(reg_x(scratch.AsXRegister())); } static inline dwarf::Reg DWARFReg(CPURegister reg) { if (reg.IsFPRegister()) { return dwarf::Reg::Arm64Fp(reg.GetCode()); } else { DCHECK_LT(reg.GetCode(), 31u); // X0 - X30. return dwarf::Reg::Arm64Core(reg.GetCode()); } } void Arm64Assembler::SpillRegisters(CPURegList registers, int offset) { int size = registers.GetRegisterSizeInBytes(); const Register sp = vixl_masm_.StackPointer(); // Since we are operating on register pairs, we would like to align on // double the standard size; on the other hand, we don't want to insert // an extra store, which will happen if the number of registers is even. if (!IsAlignedParam(offset, 2 * size) && registers.GetCount() % 2 != 0) { const CPURegister& dst0 = registers.PopLowestIndex(); ___ Str(dst0, MemOperand(sp, offset)); cfi_.RelOffset(DWARFReg(dst0), offset); offset += size; } while (registers.GetCount() >= 2) { const CPURegister& dst0 = registers.PopLowestIndex(); const CPURegister& dst1 = registers.PopLowestIndex(); ___ Stp(dst0, dst1, MemOperand(sp, offset)); cfi_.RelOffset(DWARFReg(dst0), offset); cfi_.RelOffset(DWARFReg(dst1), offset + size); offset += 2 * size; } if (!registers.IsEmpty()) { const CPURegister& dst0 = registers.PopLowestIndex(); ___ Str(dst0, MemOperand(sp, offset)); cfi_.RelOffset(DWARFReg(dst0), offset); } DCHECK(registers.IsEmpty()); } void Arm64Assembler::UnspillRegisters(CPURegList registers, int offset) { int size = registers.GetRegisterSizeInBytes(); const Register sp = vixl_masm_.StackPointer(); // Be consistent with the logic for spilling registers. if (!IsAlignedParam(offset, 2 * size) && registers.GetCount() % 2 != 0) { const CPURegister& dst0 = registers.PopLowestIndex(); ___ Ldr(dst0, MemOperand(sp, offset)); cfi_.Restore(DWARFReg(dst0)); offset += size; } while (registers.GetCount() >= 2) { const CPURegister& dst0 = registers.PopLowestIndex(); const CPURegister& dst1 = registers.PopLowestIndex(); ___ Ldp(dst0, dst1, MemOperand(sp, offset)); cfi_.Restore(DWARFReg(dst0)); cfi_.Restore(DWARFReg(dst1)); offset += 2 * size; } if (!registers.IsEmpty()) { const CPURegister& dst0 = registers.PopLowestIndex(); ___ Ldr(dst0, MemOperand(sp, offset)); cfi_.Restore(DWARFReg(dst0)); } DCHECK(registers.IsEmpty()); } void Arm64Assembler::PoisonHeapReference(Register reg) { DCHECK(reg.IsW()); // reg = -reg. ___ Neg(reg, Operand(reg)); } void Arm64Assembler::UnpoisonHeapReference(Register reg) { DCHECK(reg.IsW()); // reg = -reg. ___ Neg(reg, Operand(reg)); } void Arm64Assembler::MaybePoisonHeapReference(Register reg) { if (kPoisonHeapReferences) { PoisonHeapReference(reg); } } void Arm64Assembler::MaybeUnpoisonHeapReference(Register reg) { if (kPoisonHeapReferences) { UnpoisonHeapReference(reg); } } #undef ___ } // namespace arm64 } // namespace art