blob: 7e1ad9fd7bb359df785a730012f2589f842b0a59 [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
Ian Rogers2c8f6532011-09-02 17:16:34 -070017#include "calling_convention_arm.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070018
19#include "base/logging.h"
Mathieu Chartier3e0acf62015-01-08 09:41:25 -080020#include "handle_scope-inl.h"
Ian Rogers166db042013-07-26 12:05:57 -070021#include "utils/arm/managed_register_arm.h"
Ian Rogersb033c752011-07-20 12:22:35 -070022
23namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -070024namespace arm {
Ian Rogersb033c752011-07-20 12:22:35 -070025
Andreas Gampe542451c2016-07-26 09:02:02 -070026static_assert(kArmPointerSize == PointerSize::k32, "Unexpected ARM pointer size");
27
Igor Murashkin367f3dd2016-09-01 17:00:24 -070028//
29// JNI calling convention constants.
30//
31
32// List of parameters passed via registers for JNI.
33// JNI uses soft-float, so there is only a GPR list.
34static const Register kJniArgumentRegisters[] = {
35 R0, R1, R2, R3
36};
37
38static const size_t kJniArgumentRegisterCount = arraysize(kJniArgumentRegisters);
39
40//
41// Managed calling convention constants.
42//
43
44// Used by hard float. (General purpose registers.)
Zheng Xu5667fdb2014-10-23 18:29:55 +080045static const Register kHFCoreArgumentRegisters[] = {
46 R0, R1, R2, R3
47};
48
Igor Murashkin367f3dd2016-09-01 17:00:24 -070049// (VFP single-precision registers.)
Zheng Xu5667fdb2014-10-23 18:29:55 +080050static const SRegister kHFSArgumentRegisters[] = {
51 S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15
52};
53
Igor Murashkin367f3dd2016-09-01 17:00:24 -070054// (VFP double-precision registers.)
Zheng Xu5667fdb2014-10-23 18:29:55 +080055static const DRegister kHFDArgumentRegisters[] = {
56 D0, D1, D2, D3, D4, D5, D6, D7
57};
58
Andreas Gampe785d2f22014-11-03 22:57:30 -080059static_assert(arraysize(kHFDArgumentRegisters) * 2 == arraysize(kHFSArgumentRegisters),
60 "ks d argument registers mismatch");
Zheng Xu5667fdb2014-10-23 18:29:55 +080061
Igor Murashkin367f3dd2016-09-01 17:00:24 -070062//
63// Shared managed+JNI calling convention constants.
64//
65
Vladimir Marko32248382016-05-19 10:37:24 +010066static constexpr ManagedRegister kCalleeSaveRegisters[] = {
67 // Core registers.
68 ArmManagedRegister::FromCoreRegister(R5),
69 ArmManagedRegister::FromCoreRegister(R6),
70 ArmManagedRegister::FromCoreRegister(R7),
71 ArmManagedRegister::FromCoreRegister(R8),
72 ArmManagedRegister::FromCoreRegister(R10),
73 ArmManagedRegister::FromCoreRegister(R11),
74 // Hard float registers.
75 ArmManagedRegister::FromSRegister(S16),
76 ArmManagedRegister::FromSRegister(S17),
77 ArmManagedRegister::FromSRegister(S18),
78 ArmManagedRegister::FromSRegister(S19),
79 ArmManagedRegister::FromSRegister(S20),
80 ArmManagedRegister::FromSRegister(S21),
81 ArmManagedRegister::FromSRegister(S22),
82 ArmManagedRegister::FromSRegister(S23),
83 ArmManagedRegister::FromSRegister(S24),
84 ArmManagedRegister::FromSRegister(S25),
85 ArmManagedRegister::FromSRegister(S26),
86 ArmManagedRegister::FromSRegister(S27),
87 ArmManagedRegister::FromSRegister(S28),
88 ArmManagedRegister::FromSRegister(S29),
89 ArmManagedRegister::FromSRegister(S30),
90 ArmManagedRegister::FromSRegister(S31)
91};
92
93static constexpr uint32_t CalculateCoreCalleeSpillMask() {
94 // LR is a special callee save which is not reported by CalleeSaveRegisters().
95 uint32_t result = 1 << LR;
96 for (auto&& r : kCalleeSaveRegisters) {
97 if (r.AsArm().IsCoreRegister()) {
98 result |= (1 << r.AsArm().AsCoreRegister());
99 }
100 }
101 return result;
102}
103
104static constexpr uint32_t CalculateFpCalleeSpillMask() {
105 uint32_t result = 0;
106 for (auto&& r : kCalleeSaveRegisters) {
107 if (r.AsArm().IsSRegister()) {
108 result |= (1 << r.AsArm().AsSRegister());
109 }
110 }
111 return result;
112}
113
114static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask();
115static constexpr uint32_t kFpCalleeSpillMask = CalculateFpCalleeSpillMask();
116
Ian Rogers2c8f6532011-09-02 17:16:34 -0700117// Calling convention
118
119ManagedRegister ArmManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
120 return ArmManagedRegister::FromCoreRegister(IP); // R12
Ian Rogersb033c752011-07-20 12:22:35 -0700121}
122
Ian Rogers2c8f6532011-09-02 17:16:34 -0700123ManagedRegister ArmJniCallingConvention::InterproceduralScratchRegister() {
124 return ArmManagedRegister::FromCoreRegister(IP); // R12
Shih-wei Liao668512a2011-09-01 14:18:34 -0700125}
126
Zheng Xu5667fdb2014-10-23 18:29:55 +0800127ManagedRegister ArmManagedRuntimeCallingConvention::ReturnRegister() {
128 if (kArm32QuickCodeUseSoftFloat) {
129 switch (GetShorty()[0]) {
130 case 'V':
131 return ArmManagedRegister::NoRegister();
132 case 'D':
133 case 'J':
134 return ArmManagedRegister::FromRegisterPair(R0_R1);
135 default:
136 return ArmManagedRegister::FromCoreRegister(R0);
137 }
Ian Rogersb033c752011-07-20 12:22:35 -0700138 } else {
Zheng Xu5667fdb2014-10-23 18:29:55 +0800139 switch (GetShorty()[0]) {
140 case 'V':
141 return ArmManagedRegister::NoRegister();
142 case 'D':
143 return ArmManagedRegister::FromDRegister(D0);
144 case 'F':
145 return ArmManagedRegister::FromSRegister(S0);
146 case 'J':
147 return ArmManagedRegister::FromRegisterPair(R0_R1);
148 default:
149 return ArmManagedRegister::FromCoreRegister(R0);
150 }
Ian Rogersb033c752011-07-20 12:22:35 -0700151 }
152}
153
Ian Rogers2c8f6532011-09-02 17:16:34 -0700154ManagedRegister ArmJniCallingConvention::ReturnRegister() {
Zheng Xu5667fdb2014-10-23 18:29:55 +0800155 switch (GetShorty()[0]) {
156 case 'V':
157 return ArmManagedRegister::NoRegister();
158 case 'D':
159 case 'J':
160 return ArmManagedRegister::FromRegisterPair(R0_R1);
161 default:
162 return ArmManagedRegister::FromCoreRegister(R0);
163 }
Ian Rogers2c8f6532011-09-02 17:16:34 -0700164}
165
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700166ManagedRegister ArmJniCallingConvention::IntReturnRegister() {
167 return ArmManagedRegister::FromCoreRegister(R0);
168}
Ian Rogersb033c752011-07-20 12:22:35 -0700169
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700170// Managed runtime calling convention
Ian Rogersb5d09b22012-03-06 22:14:17 -0800171
Ian Rogers2c8f6532011-09-02 17:16:34 -0700172ManagedRegister ArmManagedRuntimeCallingConvention::MethodRegister() {
173 return ArmManagedRegister::FromCoreRegister(R0);
174}
175
176bool ArmManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700177 return false; // Everything moved to stack on entry.
Ian Rogersb033c752011-07-20 12:22:35 -0700178}
179
Ian Rogers2c8f6532011-09-02 17:16:34 -0700180bool ArmManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700181 return true;
Ian Rogersb033c752011-07-20 12:22:35 -0700182}
183
Ian Rogers2c8f6532011-09-02 17:16:34 -0700184ManagedRegister ArmManagedRuntimeCallingConvention::CurrentParamRegister() {
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700185 LOG(FATAL) << "Should not reach here";
186 return ManagedRegister::NoRegister();
Ian Rogersb033c752011-07-20 12:22:35 -0700187}
188
Ian Rogers2c8f6532011-09-02 17:16:34 -0700189FrameOffset ArmManagedRuntimeCallingConvention::CurrentParamStackOffset() {
Ian Rogers7a99c112011-09-07 12:48:27 -0700190 CHECK(IsCurrentParamOnStack());
191 FrameOffset result =
Ian Rogers790a6b72014-04-01 10:36:00 -0700192 FrameOffset(displacement_.Int32Value() + // displacement
193 kFramePointerSize + // Method*
194 (itr_slots_ * kFramePointerSize)); // offset into in args
Ian Rogers7a99c112011-09-07 12:48:27 -0700195 return result;
Ian Rogersb033c752011-07-20 12:22:35 -0700196}
197
Dmitry Petrochenkofca82202014-03-21 11:21:37 +0700198const ManagedRegisterEntrySpills& ArmManagedRuntimeCallingConvention::EntrySpills() {
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700199 // We spill the argument registers on ARM to free them up for scratch use, we then assume
200 // all arguments are on the stack.
Zheng Xu5667fdb2014-10-23 18:29:55 +0800201 if (kArm32QuickCodeUseSoftFloat) {
202 if (entry_spills_.size() == 0) {
203 size_t num_spills = NumArgs() + NumLongOrDoubleArgs();
204 if (num_spills > 0) {
205 entry_spills_.push_back(ArmManagedRegister::FromCoreRegister(R1));
206 if (num_spills > 1) {
207 entry_spills_.push_back(ArmManagedRegister::FromCoreRegister(R2));
208 if (num_spills > 2) {
209 entry_spills_.push_back(ArmManagedRegister::FromCoreRegister(R3));
210 }
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700211 }
212 }
213 }
Zheng Xu5667fdb2014-10-23 18:29:55 +0800214 } else {
215 if ((entry_spills_.size() == 0) && (NumArgs() > 0)) {
216 uint32_t gpr_index = 1; // R0 ~ R3. Reserve r0 for ArtMethod*.
217 uint32_t fpr_index = 0; // S0 ~ S15.
218 uint32_t fpr_double_index = 0; // D0 ~ D7.
219
220 ResetIterator(FrameOffset(0));
221 while (HasNext()) {
222 if (IsCurrentParamAFloatOrDouble()) {
223 if (IsCurrentParamADouble()) { // Double.
224 // Double should not overlap with float.
225 fpr_double_index = (std::max(fpr_double_index * 2, RoundUp(fpr_index, 2))) / 2;
226 if (fpr_double_index < arraysize(kHFDArgumentRegisters)) {
227 entry_spills_.push_back(
228 ArmManagedRegister::FromDRegister(kHFDArgumentRegisters[fpr_double_index++]));
229 } else {
230 entry_spills_.push_back(ManagedRegister::NoRegister(), 8);
231 }
232 } else { // Float.
233 // Float should not overlap with double.
234 if (fpr_index % 2 == 0) {
235 fpr_index = std::max(fpr_double_index * 2, fpr_index);
236 }
237 if (fpr_index < arraysize(kHFSArgumentRegisters)) {
238 entry_spills_.push_back(
239 ArmManagedRegister::FromSRegister(kHFSArgumentRegisters[fpr_index++]));
240 } else {
241 entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
242 }
243 }
244 } else {
245 // FIXME: Pointer this returns as both reference and long.
246 if (IsCurrentParamALong() && !IsCurrentParamAReference()) { // Long.
Nicolas Geoffray69c15d32015-01-13 11:42:13 +0000247 if (gpr_index < arraysize(kHFCoreArgumentRegisters) - 1) {
248 // Skip R1, and use R2_R3 if the long is the first parameter.
249 if (gpr_index == 1) {
250 gpr_index++;
251 }
252 }
253
Nicolas Geoffray425f2392015-01-08 14:52:29 +0000254 // If it spans register and memory, we must use the value in memory.
255 if (gpr_index < arraysize(kHFCoreArgumentRegisters) - 1) {
Zheng Xu5667fdb2014-10-23 18:29:55 +0800256 entry_spills_.push_back(
257 ArmManagedRegister::FromCoreRegister(kHFCoreArgumentRegisters[gpr_index++]));
Nicolas Geoffray425f2392015-01-08 14:52:29 +0000258 } else if (gpr_index == arraysize(kHFCoreArgumentRegisters) - 1) {
259 gpr_index++;
260 entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
Zheng Xu5667fdb2014-10-23 18:29:55 +0800261 } else {
262 entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
263 }
264 }
265 // High part of long or 32-bit argument.
266 if (gpr_index < arraysize(kHFCoreArgumentRegisters)) {
267 entry_spills_.push_back(
268 ArmManagedRegister::FromCoreRegister(kHFCoreArgumentRegisters[gpr_index++]));
269 } else {
270 entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
271 }
272 }
273 Next();
274 }
275 }
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700276 }
277 return entry_spills_;
278}
Ian Rogersb033c752011-07-20 12:22:35 -0700279// JNI calling convention
280
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700281ArmJniCallingConvention::ArmJniCallingConvention(bool is_static,
282 bool is_synchronized,
283 bool is_critical_native,
Ian Rogers169c9a72011-11-13 20:13:17 -0800284 const char* shorty)
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700285 : JniCallingConvention(is_static,
286 is_synchronized,
287 is_critical_native,
288 shorty,
289 kArmPointerSize) {
290 // AAPCS 4.1 specifies fundamental alignments for each type. All of our stack arguments are
291 // usually 4-byte aligned, however longs and doubles must be 8 bytes aligned. Add padding to
292 // maintain 8-byte alignment invariant.
293 //
294 // Compute padding to ensure longs and doubles are not split in AAPCS.
295 size_t shift = 0;
296
297 size_t cur_arg, cur_reg;
298 if (LIKELY(HasExtraArgumentsForJni())) {
299 // Ignore the 'this' jobject or jclass for static methods and the JNIEnv.
300 // We start at the aligned register r2.
301 //
302 // Ignore the first 2 parameters because they are guaranteed to be aligned.
303 cur_arg = NumImplicitArgs(); // skip the "this" arg.
304 cur_reg = 2; // skip {r0=JNIEnv, r1=jobject} / {r0=JNIEnv, r1=jclass} parameters (start at r2).
305 } else {
306 // Check every parameter.
307 cur_arg = 0;
308 cur_reg = 0;
309 }
310
311 // TODO: Maybe should just use IsCurrentParamALongOrDouble instead to be cleaner?
312 // (this just seems like an unnecessary micro-optimization).
313
314 // Shift across a logical register mapping that looks like:
315 //
316 // | r0 | r1 | r2 | r3 | SP | SP+4| SP+8 | SP+12 | ... | SP+n | SP+n+4 |
317 //
318 // (where SP is some arbitrary stack pointer that our 0th stack arg would go into).
319 //
320 // Any time there would normally be a long/double in an odd logical register,
321 // we have to push out the rest of the mappings by 4 bytes to maintain an 8-byte alignment.
322 //
323 // This works for both physical register pairs {r0, r1}, {r2, r3} and for when
324 // the value is on the stack.
325 //
326 // For example:
327 // (a) long would normally go into r1, but we shift it into r2
328 // | INT | (PAD) | LONG |
329 // | r0 | r1 | r2 | r3 |
330 //
331 // (b) long would normally go into r3, but we shift it into SP
332 // | INT | INT | INT | (PAD) | LONG |
333 // | r0 | r1 | r2 | r3 | SP+4 SP+8|
334 //
335 // where INT is any <=4 byte arg, and LONG is any 8-byte arg.
336 for (; cur_arg < NumArgs(); cur_arg++) {
Ian Rogersc7792842012-03-03 15:36:20 -0800337 if (IsParamALongOrDouble(cur_arg)) {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700338 if ((cur_reg & 1) != 0) { // check that it's in a logical contiguous register pair
339 shift += 4;
Ian Rogersc7792842012-03-03 15:36:20 -0800340 cur_reg++; // additional bump to ensure alignment
341 }
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700342 cur_reg += 2; // bump the iterator twice for every long argument
343 } else {
344 cur_reg++; // bump the iterator for every non-long argument
Ian Rogers67375ac2011-09-14 00:55:44 -0700345 }
Ian Rogers2c8f6532011-09-02 17:16:34 -0700346 }
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700347
348 if (cur_reg < kJniArgumentRegisterCount) {
349 // As a special case when, as a result of shifting (or not) there are no arguments on the stack,
350 // we actually have 0 stack padding.
351 //
352 // For example with @CriticalNative and:
353 // (int, long) -> shifts the long but doesn't need to pad the stack
354 //
355 // shift
356 // \/
357 // | INT | (PAD) | LONG | (EMPTY) ...
358 // | r0 | r1 | r2 | r3 | SP ...
359 // /\
360 // no stack padding
361 padding_ = 0;
362 } else {
363 padding_ = shift;
364 }
365
366 // TODO: add some new JNI tests for @CriticalNative that introduced new edge cases
367 // (a) Using r0,r1 pair = f(long,...)
368 // (b) Shifting r1 long into r2,r3 pair = f(int, long, int, ...);
369 // (c) Shifting but not introducing a stack padding = f(int, long);
Ian Rogers67375ac2011-09-14 00:55:44 -0700370}
371
372uint32_t ArmJniCallingConvention::CoreSpillMask() const {
373 // Compute spill mask to agree with callee saves initialized in the constructor
Vladimir Marko32248382016-05-19 10:37:24 +0100374 return kCoreCalleeSpillMask;
Ian Rogers2c8f6532011-09-02 17:16:34 -0700375}
376
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100377uint32_t ArmJniCallingConvention::FpSpillMask() const {
Vladimir Marko32248382016-05-19 10:37:24 +0100378 return kFpCalleeSpillMask;
Sebastien Hertz7cde48c2015-01-20 16:06:43 +0100379}
380
Ian Rogersdc51b792011-09-22 20:41:37 -0700381ManagedRegister ArmJniCallingConvention::ReturnScratchRegister() const {
382 return ArmManagedRegister::FromCoreRegister(R2);
383}
384
Ian Rogers2c8f6532011-09-02 17:16:34 -0700385size_t ArmJniCallingConvention::FrameSize() {
Ian Rogersdc51b792011-09-22 20:41:37 -0700386 // Method*, LR and callee save area size, local reference segment state
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700387 const size_t method_ptr_size = static_cast<size_t>(kArmPointerSize);
388 const size_t lr_return_addr_size = kFramePointerSize;
389 const size_t callee_save_area_size = CalleeSaveRegisters().size() * kFramePointerSize;
390 size_t frame_data_size = method_ptr_size + lr_return_addr_size + callee_save_area_size;
391
392 if (LIKELY(HasLocalReferenceSegmentState())) {
393 // local reference segment state
394 frame_data_size += kFramePointerSize;
395 // TODO: Probably better to use sizeof(IRTSegmentState) here...
396 }
397
398 // References plus link_ (pointer) and number_of_references_ (uint32_t) for HandleScope header
399 const size_t handle_scope_size = HandleScope::SizeOf(kArmPointerSize, ReferenceCount());
400
401 size_t total_size = frame_data_size;
402 if (LIKELY(HasHandleScope())) {
403 // HandleScope is sometimes excluded.
404 total_size += handle_scope_size; // handle scope size
405 }
406
Ian Rogers0d666d82011-08-14 16:03:46 -0700407 // Plus return value spill area size
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700408 total_size += SizeOfReturnValue();
409
410 return RoundUp(total_size, kStackAlignment);
Ian Rogers0d666d82011-08-14 16:03:46 -0700411}
412
Ian Rogers2c8f6532011-09-02 17:16:34 -0700413size_t ArmJniCallingConvention::OutArgSize() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700414 // TODO: Identical to x86_64 except for also adding additional padding.
Ian Rogers790a6b72014-04-01 10:36:00 -0700415 return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize + padding_,
Ian Rogers7a99c112011-09-07 12:48:27 -0700416 kStackAlignment);
417}
418
Vladimir Marko32248382016-05-19 10:37:24 +0100419ArrayRef<const ManagedRegister> ArmJniCallingConvention::CalleeSaveRegisters() const {
420 return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters);
421}
422
Ian Rogers67375ac2011-09-14 00:55:44 -0700423// JniCallingConvention ABI follows AAPCS where longs and doubles must occur
424// in even register numbers and stack slots
425void ArmJniCallingConvention::Next() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700426 // Update the iterator by usual JNI rules.
Ian Rogers67375ac2011-09-14 00:55:44 -0700427 JniCallingConvention::Next();
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700428
429 if (LIKELY(HasNext())) { // Avoid CHECK failure for IsCurrentParam
430 // Ensure slot is 8-byte aligned for longs/doubles (AAPCS).
431 if (IsCurrentParamALongOrDouble() && ((itr_slots_ & 0x1u) != 0)) {
432 // itr_slots_ needs to be an even number, according to AAPCS.
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700433 itr_slots_++;
434 }
435 }
Ian Rogers67375ac2011-09-14 00:55:44 -0700436}
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700437
Ian Rogers67375ac2011-09-14 00:55:44 -0700438bool ArmJniCallingConvention::IsCurrentParamInRegister() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700439 return itr_slots_ < kJniArgumentRegisterCount;
Ian Rogersb033c752011-07-20 12:22:35 -0700440}
441
Ian Rogers2c8f6532011-09-02 17:16:34 -0700442bool ArmJniCallingConvention::IsCurrentParamOnStack() {
Shih-wei Liao5381cf92011-07-27 00:28:04 -0700443 return !IsCurrentParamInRegister();
Ian Rogersb033c752011-07-20 12:22:35 -0700444}
445
Ian Rogers2c8f6532011-09-02 17:16:34 -0700446ManagedRegister ArmJniCallingConvention::CurrentParamRegister() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700447 CHECK_LT(itr_slots_, kJniArgumentRegisterCount);
448 if (IsCurrentParamALongOrDouble()) {
449 // AAPCS 5.1.1 requires 64-bit values to be in a consecutive register pair:
450 // "A double-word sized type is passed in two consecutive registers (e.g., r0 and r1, or r2 and
451 // r3). The content of the registers is as if the value had been loaded from memory
452 // representation with a single LDM instruction."
453 if (itr_slots_ == 0u) {
454 return ArmManagedRegister::FromRegisterPair(R0_R1);
455 } else if (itr_slots_ == 2u) {
456 return ArmManagedRegister::FromRegisterPair(R2_R3);
457 } else {
458 // The register can either be R0 (+R1) or R2 (+R3). Cannot be other values.
459 LOG(FATAL) << "Invalid iterator register position for a long/double " << itr_args_;
460 UNREACHABLE();
461 }
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700462 } else {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700463 // All other types can fit into one register.
464 return ArmManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700465 }
Ian Rogersb033c752011-07-20 12:22:35 -0700466}
467
Ian Rogers2c8f6532011-09-02 17:16:34 -0700468FrameOffset ArmJniCallingConvention::CurrentParamStackOffset() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700469 CHECK_GE(itr_slots_, kJniArgumentRegisterCount);
Andreas Gampe542451c2016-07-26 09:02:02 -0700470 size_t offset =
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700471 displacement_.Int32Value()
472 - OutArgSize()
473 + ((itr_slots_ - kJniArgumentRegisterCount) * kFramePointerSize);
Ian Rogersc7792842012-03-03 15:36:20 -0800474 CHECK_LT(offset, OutArgSize());
475 return FrameOffset(offset);
Ian Rogersb033c752011-07-20 12:22:35 -0700476}
477
Ian Rogers2c8f6532011-09-02 17:16:34 -0700478size_t ArmJniCallingConvention::NumberOfOutgoingStackArgs() {
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700479 size_t static_args = HasSelfClass() ? 1 : 0; // count jclass
Ian Rogers7a99c112011-09-07 12:48:27 -0700480 // regular argument parameters and this
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700481 size_t param_args = NumArgs() + NumLongOrDoubleArgs(); // twice count 8-byte args
482 // XX: Why is the long/ordouble counted twice but not JNIEnv* ???
Ian Rogers7a99c112011-09-07 12:48:27 -0700483 // count JNIEnv* less arguments in registers
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700484 size_t internal_args = (HasJniEnv() ? 1 : 0 /* jni env */);
485 size_t total_args = static_args + param_args + internal_args;
486
487 return total_args - std::min(kJniArgumentRegisterCount, static_cast<size_t>(total_args));
488
489 // TODO: Very similar to x86_64 except for the return pc.
Ian Rogersb033c752011-07-20 12:22:35 -0700490}
491
Ian Rogers2c8f6532011-09-02 17:16:34 -0700492} // namespace arm
Ian Rogersb033c752011-07-20 12:22:35 -0700493} // namespace art