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