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 "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 
     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 
    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 
    118 ManagedRegister ArmManagedRuntimeCallingConvention::InterproceduralScratchRegister() {
    119   return ArmManagedRegister::FromCoreRegister(IP);  // R12
    120 }
    121 
    122 ManagedRegister ArmJniCallingConvention::InterproceduralScratchRegister() {
    123   return ArmManagedRegister::FromCoreRegister(IP);  // R12
    124 }
    125 
    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 
    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 
    165 ManagedRegister ArmJniCallingConvention::IntReturnRegister() {
    166   return ArmManagedRegister::FromCoreRegister(R0);
    167 }
    168 
    169 // Managed runtime calling convention
    170 
    171 ManagedRegister ArmManagedRuntimeCallingConvention::MethodRegister() {
    172   return ArmManagedRegister::FromCoreRegister(R0);
    173 }
    174 
    175 bool ArmManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
    176   return false;  // Everything moved to stack on entry.
    177 }
    178 
    179 bool ArmManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
    180   return true;
    181 }
    182 
    183 ManagedRegister ArmManagedRuntimeCallingConvention::CurrentParamRegister() {
    184   LOG(FATAL) << "Should not reach here";
    185   return ManagedRegister::NoRegister();
    186 }
    187 
    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 
    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 
    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 
    371 uint32_t ArmJniCallingConvention::CoreSpillMask() const {
    372   // Compute spill mask to agree with callee saves initialized in the constructor
    373   return kCoreCalleeSpillMask;
    374 }
    375 
    376 uint32_t ArmJniCallingConvention::FpSpillMask() const {
    377   return kFpCalleeSpillMask;
    378 }
    379 
    380 ManagedRegister ArmJniCallingConvention::ReturnScratchRegister() const {
    381   return ArmManagedRegister::FromCoreRegister(R2);
    382 }
    383 
    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 
    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 
    418 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
    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 
    437 bool ArmJniCallingConvention::IsCurrentParamInRegister() {
    438   return itr_slots_ < kJniArgumentRegisterCount;
    439 }
    440 
    441 bool ArmJniCallingConvention::IsCurrentParamOnStack() {
    442   return !IsCurrentParamInRegister();
    443 }
    444 
    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 
    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 
    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