Home | History | Annotate | Download | only in arm
      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 
     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 
    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 
    121 ManagedRegister ArmManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
    122   return ArmManagedRegister::FromCoreRegister(IP);  // R12
    123 }
    124 
    125 ManagedRegister ArmJniCallingConvention::InterproceduralScratchRegister() {
    126   return ArmManagedRegister::FromCoreRegister(IP);  // R12
    127 }
    128 
    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 
    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 
    156 ManagedRegister ArmJniCallingConvention::IntReturnRegister() {
    157   return ArmManagedRegister::FromCoreRegister(R0);
    158 }
    159 
    160 // Managed runtime calling convention
    161 
    162 ManagedRegister ArmManagedRuntimeCallingConvention::MethodRegister() {
    163   return ArmManagedRegister::FromCoreRegister(R0);
    164 }
    165 
    166 bool ArmManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
    167   return false;  // Everything moved to stack on entry.
    168 }
    169 
    170 bool ArmManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
    171   return true;
    172 }
    173 
    174 ManagedRegister ArmManagedRuntimeCallingConvention::CurrentParamRegister() {
    175   LOG(FATAL) << "Should not reach here";
    176   return ManagedRegister::NoRegister();
    177 }
    178 
    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 
    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 
    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 
    347 uint32_t ArmJniCallingConvention::CoreSpillMask() const {
    348   // Compute spill mask to agree with callee saves initialized in the constructor
    349   return kCoreCalleeSpillMask;
    350 }
    351 
    352 uint32_t ArmJniCallingConvention::FpSpillMask() const {
    353   return kFpCalleeSpillMask;
    354 }
    355 
    356 ManagedRegister ArmJniCallingConvention::ReturnScratchRegister() const {
    357   return ArmManagedRegister::FromCoreRegister(R2);
    358 }
    359 
    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 
    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 
    394 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
    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 
    413 bool ArmJniCallingConvention::IsCurrentParamInRegister() {
    414   return itr_slots_ < kJniArgumentRegisterCount;
    415 }
    416 
    417 bool ArmJniCallingConvention::IsCurrentParamOnStack() {
    418   return !IsCurrentParamInRegister();
    419 }
    420 
    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 
    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 
    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