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