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