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