blob: 29411f02367092a4344cb1c3c4ed6a17e9662705 [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Ian Rogersb033c752011-07-20 12:22:35 -070016
Elliott Hughes07ed66b2012-12-12 18:34:25 -080017#include "base/logging.h"
Ian Rogers2c8f6532011-09-02 17:16:34 -070018#include "calling_convention_arm.h"
Mathieu Chartier3e0acf62015-01-08 09:41:25 -080019#include "handle_scope-inl.h"
Ian Rogers166db042013-07-26 12:05:57 -070020#include "utils/arm/managed_register_arm.h"
Ian Rogersb033c752011-07-20 12:22:35 -070021
22namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -070023namespace arm {
Ian Rogersb033c752011-07-20 12:22:35 -070024
Zheng Xu5667fdb2014-10-23 18:29:55 +080025// Used by hard float.
26static const Register kHFCoreArgumentRegisters[] = {
27 R0, R1, R2, R3
28};
29
30static const SRegister kHFSArgumentRegisters[] = {
31 S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15
32};
33
34static const DRegister kHFDArgumentRegisters[] = {
35 D0, D1, D2, D3, D4, D5, D6, D7
36};
37
Andreas Gampe785d2f22014-11-03 22:57:30 -080038static_assert(arraysize(kHFDArgumentRegisters) * 2 == arraysize(kHFSArgumentRegisters),
39 "ks d argument registers mismatch");
Zheng Xu5667fdb2014-10-23 18:29:55 +080040
Vladimir Marko1cd1b032016-05-19 10:37:24 +010041static constexpr ManagedRegister kCalleeSaveRegisters[] = {
42 // Core registers.
43 ArmManagedRegister::FromCoreRegister(R5),
44 ArmManagedRegister::FromCoreRegister(R6),
45 ArmManagedRegister::FromCoreRegister(R7),
46 ArmManagedRegister::FromCoreRegister(R8),
47 ArmManagedRegister::FromCoreRegister(R10),
48 ArmManagedRegister::FromCoreRegister(R11),
49 // Hard float registers.
50 ArmManagedRegister::FromSRegister(S16),
51 ArmManagedRegister::FromSRegister(S17),
52 ArmManagedRegister::FromSRegister(S18),
53 ArmManagedRegister::FromSRegister(S19),
54 ArmManagedRegister::FromSRegister(S20),
55 ArmManagedRegister::FromSRegister(S21),
56 ArmManagedRegister::FromSRegister(S22),
57 ArmManagedRegister::FromSRegister(S23),
58 ArmManagedRegister::FromSRegister(S24),
59 ArmManagedRegister::FromSRegister(S25),
60 ArmManagedRegister::FromSRegister(S26),
61 ArmManagedRegister::FromSRegister(S27),
62 ArmManagedRegister::FromSRegister(S28),
63 ArmManagedRegister::FromSRegister(S29),
64 ArmManagedRegister::FromSRegister(S30),
65 ArmManagedRegister::FromSRegister(S31)
66};
67
68static constexpr uint32_t CalculateCoreCalleeSpillMask() {
69 // LR is a special callee save which is not reported by CalleeSaveRegisters().
70 uint32_t result = 1 << LR;
71 for (auto&& r : kCalleeSaveRegisters) {
72 if (r.AsArm().IsCoreRegister()) {
73 result |= (1 << r.AsArm().AsCoreRegister());
74 }
75 }
76 return result;
77}
78
79static constexpr uint32_t CalculateFpCalleeSpillMask() {
80 uint32_t result = 0;
81 for (auto&& r : kCalleeSaveRegisters) {
82 if (r.AsArm().IsSRegister()) {
83 result |= (1 << r.AsArm().AsSRegister());
84 }
85 }
86 return result;
87}
88
89static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask();
90static constexpr uint32_t kFpCalleeSpillMask = CalculateFpCalleeSpillMask();
91
Ian Rogers2c8f6532011-09-02 17:16:34 -070092// Calling convention
93
94ManagedRegister ArmManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
95 return ArmManagedRegister::FromCoreRegister(IP); // R12
Ian Rogersb033c752011-07-20 12:22:35 -070096}
97
Ian Rogers2c8f6532011-09-02 17:16:34 -070098ManagedRegister ArmJniCallingConvention::InterproceduralScratchRegister() {
99 return ArmManagedRegister::FromCoreRegister(IP); // R12
Shih-wei Liao668512a2011-09-01 14:18:34 -0700100}
101
Zheng Xu5667fdb2014-10-23 18:29:55 +0800102ManagedRegister ArmManagedRuntimeCallingConvention::ReturnRegister() {
103 if (kArm32QuickCodeUseSoftFloat) {
104 switch (GetShorty()[0]) {
105 case 'V':
106 return ArmManagedRegister::NoRegister();
107 case 'D':
108 case 'J':
109 return ArmManagedRegister::FromRegisterPair(R0_R1);
110 default:
111 return ArmManagedRegister::FromCoreRegister(R0);
112 }
Ian Rogersb033c752011-07-20 12:22:35 -0700113 } else {
Zheng Xu5667fdb2014-10-23 18:29:55 +0800114 switch (GetShorty()[0]) {
115 case 'V':
116 return ArmManagedRegister::NoRegister();
117 case 'D':
118 return ArmManagedRegister::FromDRegister(D0);
119 case 'F':
120 return ArmManagedRegister::FromSRegister(S0);
121 case 'J':
122 return ArmManagedRegister::FromRegisterPair(R0_R1);
123 default:
124 return ArmManagedRegister::FromCoreRegister(R0);
125 }
Ian Rogersb033c752011-07-20 12:22:35 -0700126 }
127}
128
Ian Rogers2c8f6532011-09-02 17:16:34 -0700129ManagedRegister ArmJniCallingConvention::ReturnRegister() {
Zheng Xu5667fdb2014-10-23 18:29:55 +0800130 switch (GetShorty()[0]) {
131 case 'V':
132 return ArmManagedRegister::NoRegister();
133 case 'D':
134 case 'J':
135 return ArmManagedRegister::FromRegisterPair(R0_R1);
136 default:
137 return ArmManagedRegister::FromCoreRegister(R0);
138 }
Ian Rogers2c8f6532011-09-02 17:16:34 -0700139}
140
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700141ManagedRegister ArmJniCallingConvention::IntReturnRegister() {
142 return ArmManagedRegister::FromCoreRegister(R0);
143}
Ian Rogersb033c752011-07-20 12:22:35 -0700144
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700145// Managed runtime calling convention
Ian Rogersb5d09b22012-03-06 22:14:17 -0800146
Ian Rogers2c8f6532011-09-02 17:16:34 -0700147ManagedRegister ArmManagedRuntimeCallingConvention::MethodRegister() {
148 return ArmManagedRegister::FromCoreRegister(R0);
149}
150
151bool ArmManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700152 return false; // Everything moved to stack on entry.
Ian Rogersb033c752011-07-20 12:22:35 -0700153}
154
Ian Rogers2c8f6532011-09-02 17:16:34 -0700155bool ArmManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700156 return true;
Ian Rogersb033c752011-07-20 12:22:35 -0700157}
158
Ian Rogers2c8f6532011-09-02 17:16:34 -0700159ManagedRegister ArmManagedRuntimeCallingConvention::CurrentParamRegister() {
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700160 LOG(FATAL) << "Should not reach here";
161 return ManagedRegister::NoRegister();
Ian Rogersb033c752011-07-20 12:22:35 -0700162}
163
Ian Rogers2c8f6532011-09-02 17:16:34 -0700164FrameOffset ArmManagedRuntimeCallingConvention::CurrentParamStackOffset() {
Ian Rogers7a99c112011-09-07 12:48:27 -0700165 CHECK(IsCurrentParamOnStack());
166 FrameOffset result =
Ian Rogers790a6b72014-04-01 10:36:00 -0700167 FrameOffset(displacement_.Int32Value() + // displacement
168 kFramePointerSize + // Method*
169 (itr_slots_ * kFramePointerSize)); // offset into in args
Ian Rogers7a99c112011-09-07 12:48:27 -0700170 return result;
Ian Rogersb033c752011-07-20 12:22:35 -0700171}
172
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700173const ManagedRegisterEntrySpills& ArmManagedRuntimeCallingConvention::EntrySpills() {
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700174 // We spill the argument registers on ARM to free them up for scratch use, we then assume
175 // all arguments are on the stack.
Zheng Xu5667fdb2014-10-23 18:29:55 +0800176 if (kArm32QuickCodeUseSoftFloat) {
177 if (entry_spills_.size() == 0) {
178 size_t num_spills = NumArgs() + NumLongOrDoubleArgs();
179 if (num_spills > 0) {
180 entry_spills_.push_back(ArmManagedRegister::FromCoreRegister(R1));
181 if (num_spills > 1) {
182 entry_spills_.push_back(ArmManagedRegister::FromCoreRegister(R2));
183 if (num_spills > 2) {
184 entry_spills_.push_back(ArmManagedRegister::FromCoreRegister(R3));
185 }
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700186 }
187 }
188 }
Zheng Xu5667fdb2014-10-23 18:29:55 +0800189 } else {
190 if ((entry_spills_.size() == 0) && (NumArgs() > 0)) {
191 uint32_t gpr_index = 1; // R0 ~ R3. Reserve r0 for ArtMethod*.
192 uint32_t fpr_index = 0; // S0 ~ S15.
193 uint32_t fpr_double_index = 0; // D0 ~ D7.
194
195 ResetIterator(FrameOffset(0));
196 while (HasNext()) {
197 if (IsCurrentParamAFloatOrDouble()) {
198 if (IsCurrentParamADouble()) { // Double.
199 // Double should not overlap with float.
200 fpr_double_index = (std::max(fpr_double_index * 2, RoundUp(fpr_index, 2))) / 2;
201 if (fpr_double_index < arraysize(kHFDArgumentRegisters)) {
202 entry_spills_.push_back(
203 ArmManagedRegister::FromDRegister(kHFDArgumentRegisters[fpr_double_index++]));
204 } else {
205 entry_spills_.push_back(ManagedRegister::NoRegister(), 8);
206 }
207 } else { // Float.
208 // Float should not overlap with double.
209 if (fpr_index % 2 == 0) {
210 fpr_index = std::max(fpr_double_index * 2, fpr_index);
211 }
212 if (fpr_index < arraysize(kHFSArgumentRegisters)) {
213 entry_spills_.push_back(
214 ArmManagedRegister::FromSRegister(kHFSArgumentRegisters[fpr_index++]));
215 } else {
216 entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
217 }
218 }
219 } else {
220 // FIXME: Pointer this returns as both reference and long.
221 if (IsCurrentParamALong() && !IsCurrentParamAReference()) { // Long.
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000222 if (gpr_index < arraysize(kHFCoreArgumentRegisters) - 1) {
223 // Skip R1, and use R2_R3 if the long is the first parameter.
224 if (gpr_index == 1) {
225 gpr_index++;
226 }
227 }
228
Nicolas Geoffray425f2392015-01-08 14:52:29 +0000229 // If it spans register and memory, we must use the value in memory.
230 if (gpr_index < arraysize(kHFCoreArgumentRegisters) - 1) {
Zheng Xu5667fdb2014-10-23 18:29:55 +0800231 entry_spills_.push_back(
232 ArmManagedRegister::FromCoreRegister(kHFCoreArgumentRegisters[gpr_index++]));
Nicolas Geoffray425f2392015-01-08 14:52:29 +0000233 } else if (gpr_index == arraysize(kHFCoreArgumentRegisters) - 1) {
234 gpr_index++;
235 entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
Zheng Xu5667fdb2014-10-23 18:29:55 +0800236 } else {
237 entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
238 }
239 }
240 // High part of long or 32-bit argument.
241 if (gpr_index < arraysize(kHFCoreArgumentRegisters)) {
242 entry_spills_.push_back(
243 ArmManagedRegister::FromCoreRegister(kHFCoreArgumentRegisters[gpr_index++]));
244 } else {
245 entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
246 }
247 }
248 Next();
249 }
250 }
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700251 }
252 return entry_spills_;
253}
Ian Rogersb033c752011-07-20 12:22:35 -0700254// JNI calling convention
255
Ian Rogers169c9a72011-11-13 20:13:17 -0800256ArmJniCallingConvention::ArmJniCallingConvention(bool is_static, bool is_synchronized,
257 const char* shorty)
Ian Rogers790a6b72014-04-01 10:36:00 -0700258 : JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) {
Ian Rogersc7792842012-03-03 15:36:20 -0800259 // Compute padding to ensure longs and doubles are not split in AAPCS. Ignore the 'this' jobject
260 // or jclass for static methods and the JNIEnv. We start at the aligned register r2.
Ian Rogers67375ac2011-09-14 00:55:44 -0700261 size_t padding = 0;
Ian Rogersc7792842012-03-03 15:36:20 -0800262 for (size_t cur_arg = IsStatic() ? 0 : 1, cur_reg = 2; cur_arg < NumArgs(); cur_arg++) {
263 if (IsParamALongOrDouble(cur_arg)) {
264 if ((cur_reg & 1) != 0) {
265 padding += 4;
266 cur_reg++; // additional bump to ensure alignment
267 }
268 cur_reg++; // additional bump to skip extra long word
Ian Rogers67375ac2011-09-14 00:55:44 -0700269 }
Ian Rogersc7792842012-03-03 15:36:20 -0800270 cur_reg++; // bump the iterator for every argument
Ian Rogers2c8f6532011-09-02 17:16:34 -0700271 }
Ian Rogers67375ac2011-09-14 00:55:44 -0700272 padding_ = padding;
Ian Rogers67375ac2011-09-14 00:55:44 -0700273}
274
275uint32_t ArmJniCallingConvention::CoreSpillMask() const {
276 // Compute spill mask to agree with callee saves initialized in the constructor
Vladimir Marko1cd1b032016-05-19 10:37:24 +0100277 return kCoreCalleeSpillMask;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700278}
279
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100280uint32_t ArmJniCallingConvention::FpSpillMask() const {
Vladimir Marko1cd1b032016-05-19 10:37:24 +0100281 return kFpCalleeSpillMask;
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100282}
283
Ian Rogersdc51b792011-09-22 20:41:37 -0700284ManagedRegister ArmJniCallingConvention::ReturnScratchRegister() const {
285 return ArmManagedRegister::FromCoreRegister(R2);
286}
287
Ian Rogers2c8f6532011-09-02 17:16:34 -0700288size_t ArmJniCallingConvention::FrameSize() {
Ian Rogersdc51b792011-09-22 20:41:37 -0700289 // Method*, LR and callee save area size, local reference segment state
Mathieu Chartiere401d142015-04-22 13:56:20 -0700290 size_t frame_data_size = kArmPointerSize + (2 + CalleeSaveRegisters().size()) * kFramePointerSize;
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700291 // References plus 2 words for HandleScope header
Andreas Gampecf4035a2014-05-28 22:43:01 -0700292 size_t handle_scope_size = HandleScope::SizeOf(kFramePointerSize, ReferenceCount());
Ian Rogers0d666d82011-08-14 16:03:46 -0700293 // Plus return value spill area size
Mathieu Chartiereb8167a2014-05-07 15:43:14 -0700294 return RoundUp(frame_data_size + handle_scope_size + SizeOfReturnValue(), kStackAlignment);
Ian Rogers0d666d82011-08-14 16:03:46 -0700295}
296
Ian Rogers2c8f6532011-09-02 17:16:34 -0700297size_t ArmJniCallingConvention::OutArgSize() {
Ian Rogers790a6b72014-04-01 10:36:00 -0700298 return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize + padding_,
Ian Rogers7a99c112011-09-07 12:48:27 -0700299 kStackAlignment);
300}
301
Vladimir Marko1cd1b032016-05-19 10:37:24 +0100302ArrayRef<const ManagedRegister> ArmJniCallingConvention::CalleeSaveRegisters() const {
303 return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters);
304}
305
Ian Rogers67375ac2011-09-14 00:55:44 -0700306// JniCallingConvention ABI follows AAPCS where longs and doubles must occur
307// in even register numbers and stack slots
308void ArmJniCallingConvention::Next() {
309 JniCallingConvention::Next();
Ian Rogers169c9a72011-11-13 20:13:17 -0800310 size_t arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
Ian Rogers67375ac2011-09-14 00:55:44 -0700311 if ((itr_args_ >= 2) &&
Ian Rogers169c9a72011-11-13 20:13:17 -0800312 (arg_pos < NumArgs()) &&
313 IsParamALongOrDouble(arg_pos)) {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700314 // itr_slots_ needs to be an even number, according to AAPCS.
Ian Rogersbdb03912011-09-14 00:55:44 -0700315 if ((itr_slots_ & 0x1u) != 0) {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700316 itr_slots_++;
317 }
318 }
Ian Rogers67375ac2011-09-14 00:55:44 -0700319}
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700320
Ian Rogers67375ac2011-09-14 00:55:44 -0700321bool ArmJniCallingConvention::IsCurrentParamInRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700322 return itr_slots_ < 4;
Ian Rogersb033c752011-07-20 12:22:35 -0700323}
324
Ian Rogers2c8f6532011-09-02 17:16:34 -0700325bool ArmJniCallingConvention::IsCurrentParamOnStack() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700326 return !IsCurrentParamInRegister();
Ian Rogersb033c752011-07-20 12:22:35 -0700327}
328
329static const Register kJniArgumentRegisters[] = {
330 R0, R1, R2, R3
331};
Ian Rogers2c8f6532011-09-02 17:16:34 -0700332ManagedRegister ArmJniCallingConvention::CurrentParamRegister() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700333 CHECK_LT(itr_slots_, 4u);
Ian Rogers169c9a72011-11-13 20:13:17 -0800334 int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni();
335 if ((itr_args_ >= 2) && IsParamALongOrDouble(arg_pos)) {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700336 CHECK_EQ(itr_slots_, 2u);
Ian Rogers2c8f6532011-09-02 17:16:34 -0700337 return ArmManagedRegister::FromRegisterPair(R2_R3);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700338 } else {
339 return
Ian Rogers2c8f6532011-09-02 17:16:34 -0700340 ArmManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700341 }
Ian Rogersb033c752011-07-20 12:22:35 -0700342}
343
Ian Rogers2c8f6532011-09-02 17:16:34 -0700344FrameOffset ArmJniCallingConvention::CurrentParamStackOffset() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700345 CHECK_GE(itr_slots_, 4u);
Ian Rogers790a6b72014-04-01 10:36:00 -0700346 size_t offset = displacement_.Int32Value() - OutArgSize() + ((itr_slots_ - 4) * kFramePointerSize);
Ian Rogersc7792842012-03-03 15:36:20 -0800347 CHECK_LT(offset, OutArgSize());
348 return FrameOffset(offset);
Ian Rogersb033c752011-07-20 12:22:35 -0700349}
350
Ian Rogers2c8f6532011-09-02 17:16:34 -0700351size_t ArmJniCallingConvention::NumberOfOutgoingStackArgs() {
Ian Rogers169c9a72011-11-13 20:13:17 -0800352 size_t static_args = IsStatic() ? 1 : 0; // count jclass
Ian Rogers7a99c112011-09-07 12:48:27 -0700353 // regular argument parameters and this
Ian Rogers169c9a72011-11-13 20:13:17 -0800354 size_t param_args = NumArgs() + NumLongOrDoubleArgs();
Ian Rogers7a99c112011-09-07 12:48:27 -0700355 // count JNIEnv* less arguments in registers
356 return static_args + param_args + 1 - 4;
Ian Rogersb033c752011-07-20 12:22:35 -0700357}
358
Ian Rogers2c8f6532011-09-02 17:16:34 -0700359} // namespace arm
Ian Rogersb033c752011-07-20 12:22:35 -0700360} // namespace art