1 /*
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  */
16 
17 #include "calling_convention_arm.h"
18 
19 #include <android-base/logging.h>
20 
21 #include "base/macros.h"
22 #include "handle_scope-inl.h"
23 #include "utils/arm/managed_register_arm.h"
24 
25 namespace art {
26 namespace arm {
27 
28 static_assert(kArmPointerSize == PointerSize::k32, "Unexpected ARM pointer size");
29 
30 //
31 // JNI calling convention constants.
32 //
33 
34 // List of parameters passed via registers for JNI.
35 // JNI uses soft-float, so there is only a GPR list.
36 static const Register kJniArgumentRegisters[] = {
37   R0, R1, R2, R3
38 };
39 
40 static const size_t kJniArgumentRegisterCount = arraysize(kJniArgumentRegisters);
41 
42 //
43 // Managed calling convention constants.
44 //
45 
46 // Used by hard float. (General purpose registers.)
47 static const Register kHFCoreArgumentRegisters[] = {
48   R0, R1, R2, R3
49 };
50 
51 // (VFP single-precision registers.)
52 static const SRegister kHFSArgumentRegisters[] = {
53   S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15
54 };
55 
56 // (VFP double-precision registers.)
57 static const DRegister kHFDArgumentRegisters[] = {
58   D0, D1, D2, D3, D4, D5, D6, D7
59 };
60 
61 static_assert(arraysize(kHFDArgumentRegisters) * 2 == arraysize(kHFSArgumentRegisters),
62     "ks d argument registers mismatch");
63 
64 //
65 // Shared managed+JNI calling convention constants.
66 //
67 
68 static constexpr ManagedRegister kCalleeSaveRegisters[] = {
69     // Core registers.
70     ArmManagedRegister::FromCoreRegister(R5),
71     ArmManagedRegister::FromCoreRegister(R6),
72     ArmManagedRegister::FromCoreRegister(R7),
73     ArmManagedRegister::FromCoreRegister(R8),
74     ArmManagedRegister::FromCoreRegister(R10),
75     ArmManagedRegister::FromCoreRegister(R11),
76     // Hard float registers.
77     ArmManagedRegister::FromSRegister(S16),
78     ArmManagedRegister::FromSRegister(S17),
79     ArmManagedRegister::FromSRegister(S18),
80     ArmManagedRegister::FromSRegister(S19),
81     ArmManagedRegister::FromSRegister(S20),
82     ArmManagedRegister::FromSRegister(S21),
83     ArmManagedRegister::FromSRegister(S22),
84     ArmManagedRegister::FromSRegister(S23),
85     ArmManagedRegister::FromSRegister(S24),
86     ArmManagedRegister::FromSRegister(S25),
87     ArmManagedRegister::FromSRegister(S26),
88     ArmManagedRegister::FromSRegister(S27),
89     ArmManagedRegister::FromSRegister(S28),
90     ArmManagedRegister::FromSRegister(S29),
91     ArmManagedRegister::FromSRegister(S30),
92     ArmManagedRegister::FromSRegister(S31)
93 };
94 
CalculateCoreCalleeSpillMask()95 static constexpr uint32_t CalculateCoreCalleeSpillMask() {
96   // LR is a special callee save which is not reported by CalleeSaveRegisters().
97   uint32_t result = 1 << LR;
98   for (auto&& r : kCalleeSaveRegisters) {
99     if (r.AsArm().IsCoreRegister()) {
100       result |= (1 << r.AsArm().AsCoreRegister());
101     }
102   }
103   return result;
104 }
105 
CalculateFpCalleeSpillMask()106 static constexpr uint32_t CalculateFpCalleeSpillMask() {
107   uint32_t result = 0;
108   for (auto&& r : kCalleeSaveRegisters) {
109     if (r.AsArm().IsSRegister()) {
110       result |= (1 << r.AsArm().AsSRegister());
111     }
112   }
113   return result;
114 }
115 
116 static constexpr uint32_t kCoreCalleeSpillMask = CalculateCoreCalleeSpillMask();
117 static constexpr uint32_t kFpCalleeSpillMask = CalculateFpCalleeSpillMask();
118 
119 // Calling convention
120 
InterproceduralScratchRegister()121 ManagedRegister ArmManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
122   return ArmManagedRegister::FromCoreRegister(IP);  // R12
123 }
124 
InterproceduralScratchRegister()125 ManagedRegister ArmJniCallingConvention::InterproceduralScratchRegister() {
126   return ArmManagedRegister::FromCoreRegister(IP);  // R12
127 }
128 
ReturnRegister()129 ManagedRegister ArmManagedRuntimeCallingConvention::ReturnRegister() {
130   switch (GetShorty()[0]) {
131     case 'V':
132       return ArmManagedRegister::NoRegister();
133     case 'D':
134       return ArmManagedRegister::FromDRegister(D0);
135     case 'F':
136       return ArmManagedRegister::FromSRegister(S0);
137     case 'J':
138       return ArmManagedRegister::FromRegisterPair(R0_R1);
139     default:
140       return ArmManagedRegister::FromCoreRegister(R0);
141   }
142 }
143 
ReturnRegister()144 ManagedRegister ArmJniCallingConvention::ReturnRegister() {
145   switch (GetShorty()[0]) {
146   case 'V':
147     return ArmManagedRegister::NoRegister();
148   case 'D':
149   case 'J':
150     return ArmManagedRegister::FromRegisterPair(R0_R1);
151   default:
152     return ArmManagedRegister::FromCoreRegister(R0);
153   }
154 }
155 
IntReturnRegister()156 ManagedRegister ArmJniCallingConvention::IntReturnRegister() {
157   return ArmManagedRegister::FromCoreRegister(R0);
158 }
159 
160 // Managed runtime calling convention
161 
MethodRegister()162 ManagedRegister ArmManagedRuntimeCallingConvention::MethodRegister() {
163   return ArmManagedRegister::FromCoreRegister(R0);
164 }
165 
IsCurrentParamInRegister()166 bool ArmManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
167   return false;  // Everything moved to stack on entry.
168 }
169 
IsCurrentParamOnStack()170 bool ArmManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
171   return true;
172 }
173 
CurrentParamRegister()174 ManagedRegister ArmManagedRuntimeCallingConvention::CurrentParamRegister() {
175   LOG(FATAL) << "Should not reach here";
176   return ManagedRegister::NoRegister();
177 }
178 
CurrentParamStackOffset()179 FrameOffset ArmManagedRuntimeCallingConvention::CurrentParamStackOffset() {
180   CHECK(IsCurrentParamOnStack());
181   FrameOffset result =
182       FrameOffset(displacement_.Int32Value() +        // displacement
183                   kFramePointerSize +                 // Method*
184                   (itr_slots_ * kFramePointerSize));  // offset into in args
185   return result;
186 }
187 
EntrySpills()188 const ManagedRegisterEntrySpills& ArmManagedRuntimeCallingConvention::EntrySpills() {
189   // We spill the argument registers on ARM to free them up for scratch use, we then assume
190   // all arguments are on the stack.
191   if ((entry_spills_.size() == 0) && (NumArgs() > 0)) {
192     uint32_t gpr_index = 1;  // R0 ~ R3. Reserve r0 for ArtMethod*.
193     uint32_t fpr_index = 0;  // S0 ~ S15.
194     uint32_t fpr_double_index = 0;  // D0 ~ D7.
195 
196     ResetIterator(FrameOffset(0));
197     while (HasNext()) {
198       if (IsCurrentParamAFloatOrDouble()) {
199         if (IsCurrentParamADouble()) {  // Double.
200           // Double should not overlap with float.
201           fpr_double_index = (std::max(fpr_double_index * 2, RoundUp(fpr_index, 2))) / 2;
202           if (fpr_double_index < arraysize(kHFDArgumentRegisters)) {
203             entry_spills_.push_back(
204                 ArmManagedRegister::FromDRegister(kHFDArgumentRegisters[fpr_double_index++]));
205           } else {
206             entry_spills_.push_back(ManagedRegister::NoRegister(), 8);
207           }
208         } else {  // Float.
209           // Float should not overlap with double.
210           if (fpr_index % 2 == 0) {
211             fpr_index = std::max(fpr_double_index * 2, fpr_index);
212           }
213           if (fpr_index < arraysize(kHFSArgumentRegisters)) {
214             entry_spills_.push_back(
215                 ArmManagedRegister::FromSRegister(kHFSArgumentRegisters[fpr_index++]));
216           } else {
217             entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
218           }
219         }
220       } else {
221         // FIXME: Pointer this returns as both reference and long.
222         if (IsCurrentParamALong() && !IsCurrentParamAReference()) {  // Long.
223           if (gpr_index < arraysize(kHFCoreArgumentRegisters) - 1) {
224             // Skip R1, and use R2_R3 if the long is the first parameter.
225             if (gpr_index == 1) {
226               gpr_index++;
227             }
228           }
229 
230           // If it spans register and memory, we must use the value in memory.
231           if (gpr_index < arraysize(kHFCoreArgumentRegisters) - 1) {
232             entry_spills_.push_back(
233                 ArmManagedRegister::FromCoreRegister(kHFCoreArgumentRegisters[gpr_index++]));
234           } else if (gpr_index == arraysize(kHFCoreArgumentRegisters) - 1) {
235             gpr_index++;
236             entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
237           } else {
238             entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
239           }
240         }
241         // High part of long or 32-bit argument.
242         if (gpr_index < arraysize(kHFCoreArgumentRegisters)) {
243           entry_spills_.push_back(
244               ArmManagedRegister::FromCoreRegister(kHFCoreArgumentRegisters[gpr_index++]));
245         } else {
246           entry_spills_.push_back(ManagedRegister::NoRegister(), 4);
247         }
248       }
249       Next();
250     }
251   }
252   return entry_spills_;
253 }
254 // JNI calling convention
255 
ArmJniCallingConvention(bool is_static,bool is_synchronized,bool is_critical_native,const char * shorty)256 ArmJniCallingConvention::ArmJniCallingConvention(bool is_static,
257                                                  bool is_synchronized,
258                                                  bool is_critical_native,
259                                                  const char* shorty)
260     : JniCallingConvention(is_static,
261                            is_synchronized,
262                            is_critical_native,
263                            shorty,
264                            kArmPointerSize) {
265   // AAPCS 4.1 specifies fundamental alignments for each type. All of our stack arguments are
266   // usually 4-byte aligned, however longs and doubles must be 8 bytes aligned. Add padding to
267   // maintain 8-byte alignment invariant.
268   //
269   // Compute padding to ensure longs and doubles are not split in AAPCS.
270   size_t shift = 0;
271 
272   size_t cur_arg, cur_reg;
273   if (LIKELY(HasExtraArgumentsForJni())) {
274     // Ignore the 'this' jobject or jclass for static methods and the JNIEnv.
275     // We start at the aligned register r2.
276     //
277     // Ignore the first 2 parameters because they are guaranteed to be aligned.
278     cur_arg = NumImplicitArgs();  // skip the "this" arg.
279     cur_reg = 2;  // skip {r0=JNIEnv, r1=jobject} / {r0=JNIEnv, r1=jclass} parameters (start at r2).
280   } else {
281     // Check every parameter.
282     cur_arg = 0;
283     cur_reg = 0;
284   }
285 
286   // TODO: Maybe should just use IsCurrentParamALongOrDouble instead to be cleaner?
287   // (this just seems like an unnecessary micro-optimization).
288 
289   // Shift across a logical register mapping that looks like:
290   //
291   //   | r0 | r1 | r2 | r3 | SP | SP+4| SP+8 | SP+12 | ... | SP+n | SP+n+4 |
292   //
293   //   (where SP is some arbitrary stack pointer that our 0th stack arg would go into).
294   //
295   // Any time there would normally be a long/double in an odd logical register,
296   // we have to push out the rest of the mappings by 4 bytes to maintain an 8-byte alignment.
297   //
298   // This works for both physical register pairs {r0, r1}, {r2, r3} and for when
299   // the value is on the stack.
300   //
301   // For example:
302   // (a) long would normally go into r1, but we shift it into r2
303   //  | INT | (PAD) | LONG      |
304   //  | r0  |  r1   |  r2  | r3 |
305   //
306   // (b) long would normally go into r3, but we shift it into SP
307   //  | INT | INT | INT | (PAD) | LONG     |
308   //  | r0  |  r1 |  r2 |  r3   | SP+4 SP+8|
309   //
310   // where INT is any <=4 byte arg, and LONG is any 8-byte arg.
311   for (; cur_arg < NumArgs(); cur_arg++) {
312     if (IsParamALongOrDouble(cur_arg)) {
313       if ((cur_reg & 1) != 0) {  // check that it's in a logical contiguous register pair
314         shift += 4;
315         cur_reg++;  // additional bump to ensure alignment
316       }
317       cur_reg += 2;  // bump the iterator twice for every long argument
318     } else {
319       cur_reg++;  // bump the iterator for every non-long argument
320     }
321   }
322 
323   if (cur_reg < kJniArgumentRegisterCount) {
324     // As a special case when, as a result of shifting (or not) there are no arguments on the stack,
325     // we actually have 0 stack padding.
326     //
327     // For example with @CriticalNative and:
328     // (int, long) -> shifts the long but doesn't need to pad the stack
329     //
330     //          shift
331     //           \/
332     //  | INT | (PAD) | LONG      | (EMPTY) ...
333     //  | r0  |  r1   |  r2  | r3 |   SP    ...
334     //                                /\
335     //                          no stack padding
336     padding_ = 0;
337   } else {
338     padding_ = shift;
339   }
340 
341   // TODO: add some new JNI tests for @CriticalNative that introduced new edge cases
342   // (a) Using r0,r1 pair = f(long,...)
343   // (b) Shifting r1 long into r2,r3 pair = f(int, long, int, ...);
344   // (c) Shifting but not introducing a stack padding = f(int, long);
345 }
346 
CoreSpillMask() const347 uint32_t ArmJniCallingConvention::CoreSpillMask() const {
348   // Compute spill mask to agree with callee saves initialized in the constructor
349   return kCoreCalleeSpillMask;
350 }
351 
FpSpillMask() const352 uint32_t ArmJniCallingConvention::FpSpillMask() const {
353   return kFpCalleeSpillMask;
354 }
355 
ReturnScratchRegister() const356 ManagedRegister ArmJniCallingConvention::ReturnScratchRegister() const {
357   return ArmManagedRegister::FromCoreRegister(R2);
358 }
359 
FrameSize()360 size_t ArmJniCallingConvention::FrameSize() {
361   // Method*, LR and callee save area size, local reference segment state
362   const size_t method_ptr_size = static_cast<size_t>(kArmPointerSize);
363   const size_t lr_return_addr_size = kFramePointerSize;
364   const size_t callee_save_area_size = CalleeSaveRegisters().size() * kFramePointerSize;
365   size_t frame_data_size = method_ptr_size + lr_return_addr_size + callee_save_area_size;
366 
367   if (LIKELY(HasLocalReferenceSegmentState())) {
368     // local reference segment state
369     frame_data_size += kFramePointerSize;
370     // TODO: Probably better to use sizeof(IRTSegmentState) here...
371   }
372 
373   // References plus link_ (pointer) and number_of_references_ (uint32_t) for HandleScope header
374   const size_t handle_scope_size = HandleScope::SizeOf(kArmPointerSize, ReferenceCount());
375 
376   size_t total_size = frame_data_size;
377   if (LIKELY(HasHandleScope())) {
378     // HandleScope is sometimes excluded.
379     total_size += handle_scope_size;                                 // handle scope size
380   }
381 
382   // Plus return value spill area size
383   total_size += SizeOfReturnValue();
384 
385   return RoundUp(total_size, kStackAlignment);
386 }
387 
OutArgSize()388 size_t ArmJniCallingConvention::OutArgSize() {
389   // TODO: Identical to x86_64 except for also adding additional padding.
390   return RoundUp(NumberOfOutgoingStackArgs() * kFramePointerSize + padding_,
391                  kStackAlignment);
392 }
393 
CalleeSaveRegisters() const394 ArrayRef<const ManagedRegister> ArmJniCallingConvention::CalleeSaveRegisters() const {
395   return ArrayRef<const ManagedRegister>(kCalleeSaveRegisters);
396 }
397 
398 // JniCallingConvention ABI follows AAPCS where longs and doubles must occur
399 // in even register numbers and stack slots
Next()400 void ArmJniCallingConvention::Next() {
401   // Update the iterator by usual JNI rules.
402   JniCallingConvention::Next();
403 
404   if (LIKELY(HasNext())) {  // Avoid CHECK failure for IsCurrentParam
405     // Ensure slot is 8-byte aligned for longs/doubles (AAPCS).
406     if (IsCurrentParamALongOrDouble() && ((itr_slots_ & 0x1u) != 0)) {
407       // itr_slots_ needs to be an even number, according to AAPCS.
408       itr_slots_++;
409     }
410   }
411 }
412 
IsCurrentParamInRegister()413 bool ArmJniCallingConvention::IsCurrentParamInRegister() {
414   return itr_slots_ < kJniArgumentRegisterCount;
415 }
416 
IsCurrentParamOnStack()417 bool ArmJniCallingConvention::IsCurrentParamOnStack() {
418   return !IsCurrentParamInRegister();
419 }
420 
CurrentParamRegister()421 ManagedRegister ArmJniCallingConvention::CurrentParamRegister() {
422   CHECK_LT(itr_slots_, kJniArgumentRegisterCount);
423   if (IsCurrentParamALongOrDouble()) {
424     // AAPCS 5.1.1 requires 64-bit values to be in a consecutive register pair:
425     // "A double-word sized type is passed in two consecutive registers (e.g., r0 and r1, or r2 and
426     // r3). The content of the registers is as if the value had been loaded from memory
427     // representation with a single LDM instruction."
428     if (itr_slots_ == 0u) {
429       return ArmManagedRegister::FromRegisterPair(R0_R1);
430     } else if (itr_slots_ == 2u) {
431       return ArmManagedRegister::FromRegisterPair(R2_R3);
432     } else {
433       // The register can either be R0 (+R1) or R2 (+R3). Cannot be other values.
434       LOG(FATAL) << "Invalid iterator register position for a long/double " << itr_args_;
435       UNREACHABLE();
436     }
437   } else {
438     // All other types can fit into one register.
439     return ArmManagedRegister::FromCoreRegister(kJniArgumentRegisters[itr_slots_]);
440   }
441 }
442 
CurrentParamStackOffset()443 FrameOffset ArmJniCallingConvention::CurrentParamStackOffset() {
444   CHECK_GE(itr_slots_, kJniArgumentRegisterCount);
445   size_t offset =
446       displacement_.Int32Value()
447           - OutArgSize()
448           + ((itr_slots_ - kJniArgumentRegisterCount) * kFramePointerSize);
449   CHECK_LT(offset, OutArgSize());
450   return FrameOffset(offset);
451 }
452 
NumberOfOutgoingStackArgs()453 size_t ArmJniCallingConvention::NumberOfOutgoingStackArgs() {
454   size_t static_args = HasSelfClass() ? 1 : 0;  // count jclass
455   // regular argument parameters and this
456   size_t param_args = NumArgs() + NumLongOrDoubleArgs();  // twice count 8-byte args
457   // XX: Why is the long/ordouble counted twice but not JNIEnv* ???
458   // count JNIEnv* less arguments in registers
459   size_t internal_args = (HasJniEnv() ? 1 : 0 /* jni env */);
460   size_t total_args = static_args + param_args + internal_args;
461 
462   return total_args - std::min(kJniArgumentRegisterCount, static_cast<size_t>(total_args));
463 
464   // TODO: Very similar to x86_64 except for the return pc.
465 }
466 
467 }  // namespace arm
468 }  // namespace art
469