1dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe/* 2dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe * Copyright (C) 2016 The Android Open Source Project 3dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe * 4dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe * Licensed under the Apache License, Version 2.0 (the "License"); 5dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe * you may not use this file except in compliance with the License. 6dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe * You may obtain a copy of the License at 7dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe * 8dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe * http://www.apache.org/licenses/LICENSE-2.0 9dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe * 10dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe * Unless required by applicable law or agreed to in writing, software 11dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe * distributed under the License is distributed on an "AS IS" BASIS, 12dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe * See the License for the specific language governing permissions and 14dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe * limitations under the License. 15dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe */ 16dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 17dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#include "jni_macro_assembler_arm64.h" 18dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 19dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#include "base/logging.h" 20dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#include "entrypoints/quick/quick_entrypoints.h" 21dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#include "managed_register_arm64.h" 22dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#include "offsets.h" 23dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#include "thread.h" 24dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 25dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampeusing namespace vixl::aarch64; // NOLINT(build/namespaces) 26dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 27dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampenamespace art { 28dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampenamespace arm64 { 29dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 30dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#ifdef ___ 31dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#error "ARM64 Assembler macro already defined." 32dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#else 33dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#define ___ asm_.GetVIXLAssembler()-> 34dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#endif 35dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 36dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#define reg_x(X) Arm64Assembler::reg_x(X) 37dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#define reg_w(W) Arm64Assembler::reg_w(W) 38dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#define reg_d(D) Arm64Assembler::reg_d(D) 39dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#define reg_s(S) Arm64Assembler::reg_s(S) 40dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 41dcf3014718d9542927a4c8dc93701ce892484c84Andreas GampeArm64JNIMacroAssembler::~Arm64JNIMacroAssembler() { 42dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 43dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 44dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::FinalizeCode() { 45dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe for (const std::unique_ptr<Arm64Exception>& exception : exception_blocks_) { 46dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe EmitExceptionPoll(exception.get()); 47dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 48dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ FinalizeCode(); 49dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 50dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 51dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::GetCurrentThread(ManagedRegister tr) { 52dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Mov(reg_x(tr.AsArm64().AsXRegister()), reg_x(TR)); 53dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 54dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 55dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::GetCurrentThread(FrameOffset offset, ManagedRegister /* scratch */) { 56dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(TR, SP, offset.Int32Value()); 57dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 58dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 59dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe// See Arm64 PCS Section 5.2.2.1. 60dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::IncreaseFrameSize(size_t adjust) { 61dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK_ALIGNED(adjust, kStackAlignment); 62dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe AddConstant(SP, -adjust); 63dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe cfi().AdjustCFAOffset(adjust); 64dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 65dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 66dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe// See Arm64 PCS Section 5.2.2.1. 67dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::DecreaseFrameSize(size_t adjust) { 68dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK_ALIGNED(adjust, kStackAlignment); 69dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe AddConstant(SP, adjust); 70dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe cfi().AdjustCFAOffset(-adjust); 71dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 72dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 73dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::AddConstant(XRegister rd, int32_t value, Condition cond) { 74dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe AddConstant(rd, rd, value, cond); 75dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 76dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 77dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::AddConstant(XRegister rd, 78dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe XRegister rn, 79dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe int32_t value, 80dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Condition cond) { 81dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if ((cond == al) || (cond == nv)) { 82dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // VIXL macro-assembler handles all variants. 83dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Add(reg_x(rd), reg_x(rn), value); 84dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 85dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // temp = rd + value 86dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // rd = cond ? temp : rn 87dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe UseScratchRegisterScope temps(asm_.GetVIXLAssembler()); 88dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe temps.Exclude(reg_x(rd), reg_x(rn)); 89dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Register temp = temps.AcquireX(); 90dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Add(temp, reg_x(rn), value); 91dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Csel(reg_x(rd), temp, reg_x(rd), cond); 92dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 93dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 94dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 95dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::StoreWToOffset(StoreOperandType type, 96dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe WRegister source, 97dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe XRegister base, 98dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe int32_t offset) { 99dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe switch (type) { 100dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe case kStoreByte: 101dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Strb(reg_w(source), MEM_OP(reg_x(base), offset)); 102dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe break; 103dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe case kStoreHalfword: 104dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Strh(reg_w(source), MEM_OP(reg_x(base), offset)); 105dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe break; 106dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe case kStoreWord: 107dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Str(reg_w(source), MEM_OP(reg_x(base), offset)); 108dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe break; 109dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe default: 110dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LOG(FATAL) << "UNREACHABLE"; 111dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 112dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 113dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 114dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::StoreToOffset(XRegister source, XRegister base, int32_t offset) { 115dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK_NE(source, SP); 116dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Str(reg_x(source), MEM_OP(reg_x(base), offset)); 117dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 118dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 119dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::StoreSToOffset(SRegister source, XRegister base, int32_t offset) { 120dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Str(reg_s(source), MEM_OP(reg_x(base), offset)); 121dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 122dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 123dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::StoreDToOffset(DRegister source, XRegister base, int32_t offset) { 124dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Str(reg_d(source), MEM_OP(reg_x(base), offset)); 125dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 126dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 127dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::Store(FrameOffset offs, ManagedRegister m_src, size_t size) { 128dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister src = m_src.AsArm64(); 129dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (src.IsNoRegister()) { 130dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK_EQ(0u, size); 131dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (src.IsWRegister()) { 132dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK_EQ(4u, size); 133dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreWToOffset(kStoreWord, src.AsWRegister(), SP, offs.Int32Value()); 134dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (src.IsXRegister()) { 135dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK_EQ(8u, size); 136dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(src.AsXRegister(), SP, offs.Int32Value()); 137dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (src.IsSRegister()) { 138dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreSToOffset(src.AsSRegister(), SP, offs.Int32Value()); 139dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 140dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(src.IsDRegister()) << src; 141dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreDToOffset(src.AsDRegister(), SP, offs.Int32Value()); 142dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 143dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 144dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 145dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::StoreRef(FrameOffset offs, ManagedRegister m_src) { 146dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister src = m_src.AsArm64(); 147dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(src.IsXRegister()) << src; 148dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreWToOffset(kStoreWord, src.AsOverlappingWRegister(), SP, 149dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe offs.Int32Value()); 150dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 151dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 152dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::StoreRawPtr(FrameOffset offs, ManagedRegister m_src) { 153dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister src = m_src.AsArm64(); 154dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(src.IsXRegister()) << src; 155dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(src.AsXRegister(), SP, offs.Int32Value()); 156dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 157dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 158dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::StoreImmediateToFrame(FrameOffset offs, 159dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe uint32_t imm, 160dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_scratch) { 161dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 162dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(scratch.IsXRegister()) << scratch; 163dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadImmediate(scratch.AsXRegister(), imm); 164dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreWToOffset(kStoreWord, scratch.AsOverlappingWRegister(), SP, 165dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe offs.Int32Value()); 166dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 167dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 168dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::StoreStackOffsetToThread(ThreadOffset64 tr_offs, 169dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe FrameOffset fr_offs, 170dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_scratch) { 171dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 172dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(scratch.IsXRegister()) << scratch; 173dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe AddConstant(scratch.AsXRegister(), SP, fr_offs.Int32Value()); 174dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(scratch.AsXRegister(), TR, tr_offs.Int32Value()); 175dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 176dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 177dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::StoreStackPointerToThread(ThreadOffset64 tr_offs) { 178dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe UseScratchRegisterScope temps(asm_.GetVIXLAssembler()); 179dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Register temp = temps.AcquireX(); 180dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Mov(temp, reg_x(SP)); 181dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Str(temp, MEM_OP(reg_x(TR), tr_offs.Int32Value())); 182dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 183dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 184dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::StoreSpanning(FrameOffset dest_off, 185dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_source, 186dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe FrameOffset in_off, 187dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_scratch) { 188dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister source = m_source.AsArm64(); 189dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 190dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(source.AsXRegister(), SP, dest_off.Int32Value()); 191dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadFromOffset(scratch.AsXRegister(), SP, in_off.Int32Value()); 192dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(scratch.AsXRegister(), SP, dest_off.Int32Value() + 8); 193dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 194dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 195dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe// Load routines. 196dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::LoadImmediate(XRegister dest, int32_t value, Condition cond) { 197dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if ((cond == al) || (cond == nv)) { 198dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Mov(reg_x(dest), value); 199dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 200dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // temp = value 201dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // rd = cond ? temp : rd 202dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (value != 0) { 203dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe UseScratchRegisterScope temps(asm_.GetVIXLAssembler()); 204dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe temps.Exclude(reg_x(dest)); 205dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Register temp = temps.AcquireX(); 206dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Mov(temp, value); 207dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Csel(reg_x(dest), temp, reg_x(dest), cond); 208dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 209dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Csel(reg_x(dest), reg_x(XZR), reg_x(dest), cond); 210dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 211dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 212dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 213dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 214dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::LoadWFromOffset(LoadOperandType type, 215dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe WRegister dest, 216dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe XRegister base, 217dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe int32_t offset) { 218dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe switch (type) { 219dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe case kLoadSignedByte: 220dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldrsb(reg_w(dest), MEM_OP(reg_x(base), offset)); 221dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe break; 222dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe case kLoadSignedHalfword: 223dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldrsh(reg_w(dest), MEM_OP(reg_x(base), offset)); 224dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe break; 225dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe case kLoadUnsignedByte: 226dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldrb(reg_w(dest), MEM_OP(reg_x(base), offset)); 227dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe break; 228dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe case kLoadUnsignedHalfword: 229dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldrh(reg_w(dest), MEM_OP(reg_x(base), offset)); 230dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe break; 231dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe case kLoadWord: 232dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldr(reg_w(dest), MEM_OP(reg_x(base), offset)); 233dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe break; 234dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe default: 235dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LOG(FATAL) << "UNREACHABLE"; 236dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 237dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 238dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 239dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe// Note: We can extend this member by adding load type info - see 240dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe// sign extended A64 load variants. 241dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::LoadFromOffset(XRegister dest, XRegister base, int32_t offset) { 242dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK_NE(dest, SP); 243dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldr(reg_x(dest), MEM_OP(reg_x(base), offset)); 244dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 245dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 246dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::LoadSFromOffset(SRegister dest, XRegister base, int32_t offset) { 247dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldr(reg_s(dest), MEM_OP(reg_x(base), offset)); 248dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 249dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 250dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::LoadDFromOffset(DRegister dest, XRegister base, int32_t offset) { 251dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldr(reg_d(dest), MEM_OP(reg_x(base), offset)); 252dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 253dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 254dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::Load(Arm64ManagedRegister dest, 255dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe XRegister base, 256dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe int32_t offset, 257dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe size_t size) { 258dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (dest.IsNoRegister()) { 259dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK_EQ(0u, size) << dest; 260dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (dest.IsWRegister()) { 261dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK_EQ(4u, size) << dest; 262dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldr(reg_w(dest.AsWRegister()), MEM_OP(reg_x(base), offset)); 263dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (dest.IsXRegister()) { 264dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK_NE(dest.AsXRegister(), SP) << dest; 265ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin 266ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin if (size == 1u) { 267ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin ___ Ldrb(reg_w(dest.AsOverlappingWRegister()), MEM_OP(reg_x(base), offset)); 268ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin } else if (size == 4u) { 269dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldr(reg_w(dest.AsOverlappingWRegister()), MEM_OP(reg_x(base), offset)); 270ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin } else { 271dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK_EQ(8u, size) << dest; 272dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldr(reg_x(dest.AsXRegister()), MEM_OP(reg_x(base), offset)); 273dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 274dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (dest.IsSRegister()) { 275dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldr(reg_s(dest.AsSRegister()), MEM_OP(reg_x(base), offset)); 276dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 277dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(dest.IsDRegister()) << dest; 278dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldr(reg_d(dest.AsDRegister()), MEM_OP(reg_x(base), offset)); 279dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 280dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 281dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 282dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::Load(ManagedRegister m_dst, FrameOffset src, size_t size) { 283dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe return Load(m_dst.AsArm64(), SP, src.Int32Value(), size); 284dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 285dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 286dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::LoadFromThread(ManagedRegister m_dst, 287dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ThreadOffset64 src, 288dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe size_t size) { 289dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe return Load(m_dst.AsArm64(), TR, src.Int32Value(), size); 290dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 291dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 292dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::LoadRef(ManagedRegister m_dst, FrameOffset offs) { 293dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister dst = m_dst.AsArm64(); 294dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(dst.IsXRegister()) << dst; 295dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadWFromOffset(kLoadWord, dst.AsOverlappingWRegister(), SP, offs.Int32Value()); 296dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 297dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 298dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::LoadRef(ManagedRegister m_dst, 299dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_base, 300dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe MemberOffset offs, 301dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe bool unpoison_reference) { 302dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister dst = m_dst.AsArm64(); 303dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister base = m_base.AsArm64(); 304dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(dst.IsXRegister() && base.IsXRegister()); 305dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadWFromOffset(kLoadWord, dst.AsOverlappingWRegister(), base.AsXRegister(), 306dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe offs.Int32Value()); 307dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (unpoison_reference) { 308dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe WRegister ref_reg = dst.AsOverlappingWRegister(); 309dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe asm_.MaybeUnpoisonHeapReference(reg_w(ref_reg)); 310dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 311dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 312dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 313dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::LoadRawPtr(ManagedRegister m_dst, 314dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_base, 315dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Offset offs) { 316dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister dst = m_dst.AsArm64(); 317dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister base = m_base.AsArm64(); 318dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(dst.IsXRegister() && base.IsXRegister()); 319dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Remove dst and base form the temp list - higher level API uses IP1, IP0. 320dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe UseScratchRegisterScope temps(asm_.GetVIXLAssembler()); 321dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe temps.Exclude(reg_x(dst.AsXRegister()), reg_x(base.AsXRegister())); 322dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldr(reg_x(dst.AsXRegister()), MEM_OP(reg_x(base.AsXRegister()), offs.Int32Value())); 323dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 324dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 325dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::LoadRawPtrFromThread(ManagedRegister m_dst, ThreadOffset64 offs) { 326dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister dst = m_dst.AsArm64(); 327dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(dst.IsXRegister()) << dst; 328dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadFromOffset(dst.AsXRegister(), TR, offs.Int32Value()); 329dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 330dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 331dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe// Copying routines. 332dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::Move(ManagedRegister m_dst, ManagedRegister m_src, size_t size) { 333dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister dst = m_dst.AsArm64(); 334dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister src = m_src.AsArm64(); 335dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (!dst.Equals(src)) { 336dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (dst.IsXRegister()) { 337dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (size == 4) { 338dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(src.IsWRegister()); 339dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Mov(reg_w(dst.AsOverlappingWRegister()), reg_w(src.AsWRegister())); 340dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 341dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (src.IsXRegister()) { 342dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Mov(reg_x(dst.AsXRegister()), reg_x(src.AsXRegister())); 343dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 344dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Mov(reg_x(dst.AsXRegister()), reg_x(src.AsOverlappingXRegister())); 345dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 346dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 347dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (dst.IsWRegister()) { 348dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(src.IsWRegister()) << src; 349dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Mov(reg_w(dst.AsWRegister()), reg_w(src.AsWRegister())); 350dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (dst.IsSRegister()) { 351dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(src.IsSRegister()) << src; 352dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Fmov(reg_s(dst.AsSRegister()), reg_s(src.AsSRegister())); 353dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 354dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(dst.IsDRegister()) << dst; 355dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(src.IsDRegister()) << src; 356dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Fmov(reg_d(dst.AsDRegister()), reg_d(src.AsDRegister())); 357dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 358dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 359dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 360dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 361dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::CopyRawPtrFromThread(FrameOffset fr_offs, 362dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ThreadOffset64 tr_offs, 363dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_scratch) { 364dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 365dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(scratch.IsXRegister()) << scratch; 366dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadFromOffset(scratch.AsXRegister(), TR, tr_offs.Int32Value()); 367dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(scratch.AsXRegister(), SP, fr_offs.Int32Value()); 368dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 369dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 370dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::CopyRawPtrToThread(ThreadOffset64 tr_offs, 371dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe FrameOffset fr_offs, 372dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_scratch) { 373dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 374dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(scratch.IsXRegister()) << scratch; 375dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadFromOffset(scratch.AsXRegister(), SP, fr_offs.Int32Value()); 376dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(scratch.AsXRegister(), TR, tr_offs.Int32Value()); 377dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 378dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 379dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister m_scratch) { 380dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 381dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(scratch.IsXRegister()) << scratch; 382dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadWFromOffset(kLoadWord, scratch.AsOverlappingWRegister(), 383dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe SP, src.Int32Value()); 384dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreWToOffset(kStoreWord, scratch.AsOverlappingWRegister(), 385dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe SP, dest.Int32Value()); 386dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 387dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 388dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::Copy(FrameOffset dest, 389dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe FrameOffset src, 390dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_scratch, 391dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe size_t size) { 392dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 393dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(scratch.IsXRegister()) << scratch; 394dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(size == 4 || size == 8) << size; 395dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (size == 4) { 396dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadWFromOffset(kLoadWord, scratch.AsOverlappingWRegister(), SP, src.Int32Value()); 397dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreWToOffset(kStoreWord, scratch.AsOverlappingWRegister(), SP, dest.Int32Value()); 398dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (size == 8) { 399dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadFromOffset(scratch.AsXRegister(), SP, src.Int32Value()); 400dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(scratch.AsXRegister(), SP, dest.Int32Value()); 401dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 402dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; 403dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 404dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 405dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 406dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::Copy(FrameOffset dest, 407dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister src_base, 408dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Offset src_offset, 409dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_scratch, 410dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe size_t size) { 411dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 412dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister base = src_base.AsArm64(); 413dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(base.IsXRegister()) << base; 414dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(scratch.IsXRegister() || scratch.IsWRegister()) << scratch; 415dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(size == 4 || size == 8) << size; 416dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (size == 4) { 417dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadWFromOffset(kLoadWord, scratch.AsWRegister(), base.AsXRegister(), 418dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe src_offset.Int32Value()); 419dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreWToOffset(kStoreWord, scratch.AsWRegister(), SP, dest.Int32Value()); 420dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (size == 8) { 421dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadFromOffset(scratch.AsXRegister(), base.AsXRegister(), src_offset.Int32Value()); 422dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(scratch.AsXRegister(), SP, dest.Int32Value()); 423dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 424dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; 425dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 426dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 427dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 428dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::Copy(ManagedRegister m_dest_base, 429dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Offset dest_offs, 430dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe FrameOffset src, 431dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_scratch, 432dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe size_t size) { 433dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 434dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister base = m_dest_base.AsArm64(); 435dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(base.IsXRegister()) << base; 436dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(scratch.IsXRegister() || scratch.IsWRegister()) << scratch; 437dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(size == 4 || size == 8) << size; 438dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (size == 4) { 439dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadWFromOffset(kLoadWord, scratch.AsWRegister(), SP, src.Int32Value()); 440dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreWToOffset(kStoreWord, scratch.AsWRegister(), base.AsXRegister(), 441dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe dest_offs.Int32Value()); 442dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (size == 8) { 443dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadFromOffset(scratch.AsXRegister(), SP, src.Int32Value()); 444dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(scratch.AsXRegister(), base.AsXRegister(), dest_offs.Int32Value()); 445dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 446dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; 447dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 448dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 449dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 450dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::Copy(FrameOffset /*dst*/, 451dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe FrameOffset /*src_base*/, 452dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Offset /*src_offset*/, 453dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister /*mscratch*/, 454dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe size_t /*size*/) { 455dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe UNIMPLEMENTED(FATAL) << "Unimplemented Copy() variant"; 456dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 457dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 458dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::Copy(ManagedRegister m_dest, 459dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Offset dest_offset, 460dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_src, 461dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Offset src_offset, 462dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_scratch, 463dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe size_t size) { 464dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 465dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister src = m_src.AsArm64(); 466dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister dest = m_dest.AsArm64(); 467dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(dest.IsXRegister()) << dest; 468dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(src.IsXRegister()) << src; 469dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(scratch.IsXRegister() || scratch.IsWRegister()) << scratch; 470dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(size == 4 || size == 8) << size; 471dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (size == 4) { 472dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (scratch.IsWRegister()) { 473dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadWFromOffset(kLoadWord, scratch.AsWRegister(), src.AsXRegister(), 474dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe src_offset.Int32Value()); 475dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreWToOffset(kStoreWord, scratch.AsWRegister(), dest.AsXRegister(), 476dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe dest_offset.Int32Value()); 477dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 478dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadWFromOffset(kLoadWord, scratch.AsOverlappingWRegister(), src.AsXRegister(), 479dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe src_offset.Int32Value()); 480dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreWToOffset(kStoreWord, scratch.AsOverlappingWRegister(), dest.AsXRegister(), 481dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe dest_offset.Int32Value()); 482dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 483dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (size == 8) { 484dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadFromOffset(scratch.AsXRegister(), src.AsXRegister(), src_offset.Int32Value()); 485dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(scratch.AsXRegister(), dest.AsXRegister(), dest_offset.Int32Value()); 486dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 487dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe UNIMPLEMENTED(FATAL) << "We only support Copy() of size 4 and 8"; 488dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 489dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 490dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 491dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::Copy(FrameOffset /*dst*/, 492dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Offset /*dest_offset*/, 493dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe FrameOffset /*src*/, 494dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Offset /*src_offset*/, 495dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister /*scratch*/, 496dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe size_t /*size*/) { 497dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe UNIMPLEMENTED(FATAL) << "Unimplemented Copy() variant"; 498dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 499dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 500dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::MemoryBarrier(ManagedRegister m_scratch ATTRIBUTE_UNUSED) { 501dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // TODO: Should we check that m_scratch is IP? - see arm. 502dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Dmb(InnerShareable, BarrierAll); 503dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 504dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 505dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::SignExtend(ManagedRegister mreg, size_t size) { 506dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister reg = mreg.AsArm64(); 507dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(size == 1 || size == 2) << size; 508dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(reg.IsWRegister()) << reg; 509dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (size == 1) { 510dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Sxtb(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister())); 511dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 512dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Sxth(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister())); 513dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 514dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 515dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 516dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::ZeroExtend(ManagedRegister mreg, size_t size) { 517dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister reg = mreg.AsArm64(); 518dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(size == 1 || size == 2) << size; 519dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(reg.IsWRegister()) << reg; 520dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (size == 1) { 521dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Uxtb(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister())); 522dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 523dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Uxth(reg_w(reg.AsWRegister()), reg_w(reg.AsWRegister())); 524dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 525dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 526dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 527dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::VerifyObject(ManagedRegister /*src*/, bool /*could_be_null*/) { 528dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // TODO: not validating references. 529dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 530dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 531dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::VerifyObject(FrameOffset /*src*/, bool /*could_be_null*/) { 532dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // TODO: not validating references. 533dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 534dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 535dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::Call(ManagedRegister m_base, Offset offs, ManagedRegister m_scratch) { 536dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister base = m_base.AsArm64(); 537dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 538dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(base.IsXRegister()) << base; 539dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(scratch.IsXRegister()) << scratch; 540dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadFromOffset(scratch.AsXRegister(), base.AsXRegister(), offs.Int32Value()); 541dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Blr(reg_x(scratch.AsXRegister())); 542dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 543dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 544dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::Call(FrameOffset base, Offset offs, ManagedRegister m_scratch) { 545dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 546dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(scratch.IsXRegister()) << scratch; 547dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Call *(*(SP + base) + offset) 548dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadFromOffset(scratch.AsXRegister(), SP, base.Int32Value()); 549dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadFromOffset(scratch.AsXRegister(), scratch.AsXRegister(), offs.Int32Value()); 550dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Blr(reg_x(scratch.AsXRegister())); 551dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 552dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 553dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::CallFromThread(ThreadOffset64 offset ATTRIBUTE_UNUSED, 554dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister scratch ATTRIBUTE_UNUSED) { 555dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe UNIMPLEMENTED(FATAL) << "Unimplemented Call() variant"; 556dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 557dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 558dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::CreateHandleScopeEntry(ManagedRegister m_out_reg, 559dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe FrameOffset handle_scope_offs, 560dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_in_reg, 561dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe bool null_allowed) { 562dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister out_reg = m_out_reg.AsArm64(); 563dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister in_reg = m_in_reg.AsArm64(); 564dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // For now we only hold stale handle scope entries in x registers. 565dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(in_reg.IsNoRegister() || in_reg.IsXRegister()) << in_reg; 566dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(out_reg.IsXRegister()) << out_reg; 567dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (null_allowed) { 568dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 569dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // the address in the handle scope holding the reference. 570dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // e.g. out_reg = (handle == 0) ? 0 : (SP+handle_offset) 571dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (in_reg.IsNoRegister()) { 572dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadWFromOffset(kLoadWord, out_reg.AsOverlappingWRegister(), SP, 573dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe handle_scope_offs.Int32Value()); 574dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe in_reg = out_reg; 575dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 576dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Cmp(reg_w(in_reg.AsOverlappingWRegister()), 0); 577dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (!out_reg.Equals(in_reg)) { 578dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadImmediate(out_reg.AsXRegister(), 0, eq); 579dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 580dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe AddConstant(out_reg.AsXRegister(), SP, handle_scope_offs.Int32Value(), ne); 581dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 582dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe AddConstant(out_reg.AsXRegister(), SP, handle_scope_offs.Int32Value(), al); 583dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 584dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 585dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 586dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::CreateHandleScopeEntry(FrameOffset out_off, 587dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe FrameOffset handle_scope_offset, 588dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_scratch, 589dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe bool null_allowed) { 590dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 591dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(scratch.IsXRegister()) << scratch; 592dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (null_allowed) { 593dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadWFromOffset(kLoadWord, scratch.AsOverlappingWRegister(), SP, 594dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe handle_scope_offset.Int32Value()); 595dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is 596dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // the address in the handle scope holding the reference. 597dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // e.g. scratch = (scratch == 0) ? 0 : (SP+handle_scope_offset) 598dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Cmp(reg_w(scratch.AsOverlappingWRegister()), 0); 599dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Move this logic in add constants with flags. 600dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe AddConstant(scratch.AsXRegister(), SP, handle_scope_offset.Int32Value(), ne); 601dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 602dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe AddConstant(scratch.AsXRegister(), SP, handle_scope_offset.Int32Value(), al); 603dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 604dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(scratch.AsXRegister(), SP, out_off.Int32Value()); 605dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 606dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 607dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::LoadReferenceFromHandleScope(ManagedRegister m_out_reg, 608dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister m_in_reg) { 609dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister out_reg = m_out_reg.AsArm64(); 610dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister in_reg = m_in_reg.AsArm64(); 611dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(out_reg.IsXRegister()) << out_reg; 612dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK(in_reg.IsXRegister()) << in_reg; 613dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe vixl::aarch64::Label exit; 614dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (!out_reg.Equals(in_reg)) { 615dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // FIXME: Who sets the flags here? 616dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadImmediate(out_reg.AsXRegister(), 0, eq); 617dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 618dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Cbz(reg_x(in_reg.AsXRegister()), &exit); 619dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadFromOffset(out_reg.AsXRegister(), in_reg.AsXRegister(), 0); 620dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Bind(&exit); 621dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 622dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 623dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::ExceptionPoll(ManagedRegister m_scratch, size_t stack_adjust) { 624dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CHECK_ALIGNED(stack_adjust, kStackAlignment); 625dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister scratch = m_scratch.AsArm64(); 626dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe exception_blocks_.emplace_back(new Arm64Exception(scratch, stack_adjust)); 627dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe LoadFromOffset(scratch.AsXRegister(), 628dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe TR, 629dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Thread::ExceptionOffset<kArm64PointerSize>().Int32Value()); 630dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Cbnz(reg_x(scratch.AsXRegister()), exception_blocks_.back()->Entry()); 631dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 632dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 633ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkinstd::unique_ptr<JNIMacroLabel> Arm64JNIMacroAssembler::CreateLabel() { 634ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin return std::unique_ptr<JNIMacroLabel>(new Arm64JNIMacroLabel()); 635ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin} 636ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin 637ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkinvoid Arm64JNIMacroAssembler::Jump(JNIMacroLabel* label) { 638ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin CHECK(label != nullptr); 639ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin ___ B(Arm64JNIMacroLabel::Cast(label)->AsArm64()); 640ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin} 641ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin 642ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkinvoid Arm64JNIMacroAssembler::Jump(JNIMacroLabel* label, 643ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin JNIMacroUnaryCondition condition, 644ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin ManagedRegister test) { 645ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin CHECK(label != nullptr); 646ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin 647ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin switch (condition) { 648ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin case JNIMacroUnaryCondition::kZero: 649ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin ___ Cbz(reg_x(test.AsArm64().AsXRegister()), Arm64JNIMacroLabel::Cast(label)->AsArm64()); 650ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin break; 651ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin case JNIMacroUnaryCondition::kNotZero: 652ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin ___ Cbnz(reg_x(test.AsArm64().AsXRegister()), Arm64JNIMacroLabel::Cast(label)->AsArm64()); 653ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin break; 654ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin default: 655ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin LOG(FATAL) << "Not implemented unary condition: " << static_cast<int>(condition); 656ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin UNREACHABLE(); 657ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin } 658ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin} 659ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin 660ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkinvoid Arm64JNIMacroAssembler::Bind(JNIMacroLabel* label) { 661ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin CHECK(label != nullptr); 662ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin ___ Bind(Arm64JNIMacroLabel::Cast(label)->AsArm64()); 663ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin} 664ae7ff92c430aa12484ff8258ee4ed13421ac7934Igor Murashkin 665dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::EmitExceptionPoll(Arm64Exception *exception) { 666dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe UseScratchRegisterScope temps(asm_.GetVIXLAssembler()); 667dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe temps.Exclude(reg_x(exception->scratch_.AsXRegister())); 668dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Register temp = temps.AcquireX(); 669dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 670dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Bind exception poll entry. 671dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Bind(exception->Entry()); 672dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (exception->stack_adjust_ != 0) { // Fix up the frame. 673dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe DecreaseFrameSize(exception->stack_adjust_); 674dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 675dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Pass exception object as argument. 676dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Don't care about preserving X0 as this won't return. 677dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Mov(reg_x(X0), reg_x(exception->scratch_.AsXRegister())); 678dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ldr(temp, 679dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe MEM_OP(reg_x(TR), 680dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe QUICK_ENTRYPOINT_OFFSET(kArm64PointerSize, pDeliverException).Int32Value())); 681dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 682dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Blr(temp); 683dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Call should never return. 684dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Brk(); 685dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 686dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 687dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::BuildFrame(size_t frame_size, 688dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegister method_reg, 689dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ArrayRef<const ManagedRegister> callee_save_regs, 690dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe const ManagedRegisterEntrySpills& entry_spills) { 691dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Setup VIXL CPURegList for callee-saves. 692dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CPURegList core_reg_list(CPURegister::kRegister, kXRegSize, 0); 693dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CPURegList fp_reg_list(CPURegister::kFPRegister, kDRegSize, 0); 694dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe for (auto r : callee_save_regs) { 695dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister reg = r.AsArm64(); 696dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (reg.IsXRegister()) { 697dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe core_reg_list.Combine(reg_x(reg.AsXRegister()).GetCode()); 698dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 699dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe DCHECK(reg.IsDRegister()); 700dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe fp_reg_list.Combine(reg_d(reg.AsDRegister()).GetCode()); 701dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 702dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 703dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe size_t core_reg_size = core_reg_list.GetTotalSizeInBytes(); 704dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe size_t fp_reg_size = fp_reg_list.GetTotalSizeInBytes(); 705dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 706dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Increase frame to required size. 707dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe DCHECK_ALIGNED(frame_size, kStackAlignment); 708dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe DCHECK_GE(frame_size, core_reg_size + fp_reg_size + static_cast<size_t>(kArm64PointerSize)); 709dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe IncreaseFrameSize(frame_size); 710dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 711dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Save callee-saves. 712dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe asm_.SpillRegisters(core_reg_list, frame_size - core_reg_size); 713dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe asm_.SpillRegisters(fp_reg_list, frame_size - core_reg_size - fp_reg_size); 714dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 715dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe DCHECK(core_reg_list.IncludesAliasOf(reg_x(TR))); 716dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 717dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Write ArtMethod* 718dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe DCHECK(X0 == method_reg.AsArm64().AsXRegister()); 719dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(X0, SP, 0); 720dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 721dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Write out entry spills 722dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe int32_t offset = frame_size + static_cast<size_t>(kArm64PointerSize); 723dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe for (size_t i = 0; i < entry_spills.size(); ++i) { 724dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister reg = entry_spills.at(i).AsArm64(); 725dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (reg.IsNoRegister()) { 726dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // only increment stack offset. 727dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ManagedRegisterSpill spill = entry_spills.at(i); 728dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe offset += spill.getSize(); 729dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (reg.IsXRegister()) { 730dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreToOffset(reg.AsXRegister(), SP, offset); 731dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe offset += 8; 732dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (reg.IsWRegister()) { 733dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreWToOffset(kStoreWord, reg.AsWRegister(), SP, offset); 734dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe offset += 4; 735dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (reg.IsDRegister()) { 736dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreDToOffset(reg.AsDRegister(), SP, offset); 737dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe offset += 8; 738dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else if (reg.IsSRegister()) { 739dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe StoreSToOffset(reg.AsSRegister(), SP, offset); 740dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe offset += 4; 741dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 742dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 743dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 744dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 745dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampevoid Arm64JNIMacroAssembler::RemoveFrame(size_t frame_size, 746dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ArrayRef<const ManagedRegister> callee_save_regs) { 747dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Setup VIXL CPURegList for callee-saves. 748dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CPURegList core_reg_list(CPURegister::kRegister, kXRegSize, 0); 749dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe CPURegList fp_reg_list(CPURegister::kFPRegister, kDRegSize, 0); 750dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe for (auto r : callee_save_regs) { 751dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe Arm64ManagedRegister reg = r.AsArm64(); 752dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe if (reg.IsXRegister()) { 753dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe core_reg_list.Combine(reg_x(reg.AsXRegister()).GetCode()); 754dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } else { 755dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe DCHECK(reg.IsDRegister()); 756dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe fp_reg_list.Combine(reg_d(reg.AsDRegister()).GetCode()); 757dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 758dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe } 759dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe size_t core_reg_size = core_reg_list.GetTotalSizeInBytes(); 760dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe size_t fp_reg_size = fp_reg_list.GetTotalSizeInBytes(); 761dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 762dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // For now we only check that the size of the frame is large enough to hold spills and method 763dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // reference. 764dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe DCHECK_GE(frame_size, core_reg_size + fp_reg_size + static_cast<size_t>(kArm64PointerSize)); 765dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe DCHECK_ALIGNED(frame_size, kStackAlignment); 766dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 767dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe DCHECK(core_reg_list.IncludesAliasOf(reg_x(TR))); 768dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 769dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe cfi().RememberState(); 770dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 771dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Restore callee-saves. 772dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe asm_.UnspillRegisters(core_reg_list, frame_size - core_reg_size); 773dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe asm_.UnspillRegisters(fp_reg_list, frame_size - core_reg_size - fp_reg_size); 774dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 775dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Decrease frame size to start of callee saved regs. 776dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe DecreaseFrameSize(frame_size); 777dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 778dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // Pop callee saved and return to LR. 779dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe ___ Ret(); 780dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 781dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe // The CFI should be restored for any code that follows the exit block. 782dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe cfi().RestoreState(); 783dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe cfi().DefCFAOffset(frame_size); 784dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} 785dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 786dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe#undef ___ 787dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe 788dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} // namespace arm64 789dcf3014718d9542927a4c8dc93701ce892484c84Andreas Gampe} // namespace art 790