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.h" 18 19 #include "base/logging.h" 20 21 #ifdef ART_ENABLE_CODEGEN_arm 22 #include "jni/quick/arm/calling_convention_arm.h" 23 #endif 24 25 #ifdef ART_ENABLE_CODEGEN_arm64 26 #include "jni/quick/arm64/calling_convention_arm64.h" 27 #endif 28 29 #ifdef ART_ENABLE_CODEGEN_mips 30 #include "jni/quick/mips/calling_convention_mips.h" 31 #endif 32 33 #ifdef ART_ENABLE_CODEGEN_mips64 34 #include "jni/quick/mips64/calling_convention_mips64.h" 35 #endif 36 37 #ifdef ART_ENABLE_CODEGEN_x86 38 #include "jni/quick/x86/calling_convention_x86.h" 39 #endif 40 41 #ifdef ART_ENABLE_CODEGEN_x86_64 42 #include "jni/quick/x86_64/calling_convention_x86_64.h" 43 #endif 44 45 namespace art { 46 47 // Managed runtime calling convention 48 49 std::unique_ptr<ManagedRuntimeCallingConvention> ManagedRuntimeCallingConvention::Create( 50 ArenaAllocator* arena, 51 bool is_static, 52 bool is_synchronized, 53 const char* shorty, 54 InstructionSet instruction_set) { 55 switch (instruction_set) { 56 #ifdef ART_ENABLE_CODEGEN_arm 57 case kArm: 58 case kThumb2: 59 return std::unique_ptr<ManagedRuntimeCallingConvention>( 60 new (arena) arm::ArmManagedRuntimeCallingConvention(is_static, is_synchronized, shorty)); 61 #endif 62 #ifdef ART_ENABLE_CODEGEN_arm64 63 case kArm64: 64 return std::unique_ptr<ManagedRuntimeCallingConvention>( 65 new (arena) arm64::Arm64ManagedRuntimeCallingConvention( 66 is_static, is_synchronized, shorty)); 67 #endif 68 #ifdef ART_ENABLE_CODEGEN_mips 69 case kMips: 70 return std::unique_ptr<ManagedRuntimeCallingConvention>( 71 new (arena) mips::MipsManagedRuntimeCallingConvention( 72 is_static, is_synchronized, shorty)); 73 #endif 74 #ifdef ART_ENABLE_CODEGEN_mips64 75 case kMips64: 76 return std::unique_ptr<ManagedRuntimeCallingConvention>( 77 new (arena) mips64::Mips64ManagedRuntimeCallingConvention( 78 is_static, is_synchronized, shorty)); 79 #endif 80 #ifdef ART_ENABLE_CODEGEN_x86 81 case kX86: 82 return std::unique_ptr<ManagedRuntimeCallingConvention>( 83 new (arena) x86::X86ManagedRuntimeCallingConvention(is_static, is_synchronized, shorty)); 84 #endif 85 #ifdef ART_ENABLE_CODEGEN_x86_64 86 case kX86_64: 87 return std::unique_ptr<ManagedRuntimeCallingConvention>( 88 new (arena) x86_64::X86_64ManagedRuntimeCallingConvention( 89 is_static, is_synchronized, shorty)); 90 #endif 91 default: 92 LOG(FATAL) << "Unknown InstructionSet: " << instruction_set; 93 UNREACHABLE(); 94 } 95 } 96 97 bool ManagedRuntimeCallingConvention::HasNext() { 98 return itr_args_ < NumArgs(); 99 } 100 101 void ManagedRuntimeCallingConvention::Next() { 102 CHECK(HasNext()); 103 if (IsCurrentArgExplicit() && // don't query parameter type of implicit args 104 IsParamALongOrDouble(itr_args_)) { 105 itr_longs_and_doubles_++; 106 itr_slots_++; 107 } 108 if (IsParamAFloatOrDouble(itr_args_)) { 109 itr_float_and_doubles_++; 110 } 111 if (IsCurrentParamAReference()) { 112 itr_refs_++; 113 } 114 itr_args_++; 115 itr_slots_++; 116 } 117 118 bool ManagedRuntimeCallingConvention::IsCurrentArgExplicit() { 119 // Static methods have no implicit arguments, others implicitly pass this 120 return IsStatic() || (itr_args_ != 0); 121 } 122 123 bool ManagedRuntimeCallingConvention::IsCurrentArgPossiblyNull() { 124 return IsCurrentArgExplicit(); // any user parameter may be null 125 } 126 127 size_t ManagedRuntimeCallingConvention::CurrentParamSize() { 128 return ParamSize(itr_args_); 129 } 130 131 bool ManagedRuntimeCallingConvention::IsCurrentParamAReference() { 132 return IsParamAReference(itr_args_); 133 } 134 135 bool ManagedRuntimeCallingConvention::IsCurrentParamAFloatOrDouble() { 136 return IsParamAFloatOrDouble(itr_args_); 137 } 138 139 bool ManagedRuntimeCallingConvention::IsCurrentParamADouble() { 140 return IsParamADouble(itr_args_); 141 } 142 143 bool ManagedRuntimeCallingConvention::IsCurrentParamALong() { 144 return IsParamALong(itr_args_); 145 } 146 147 // JNI calling convention 148 149 std::unique_ptr<JniCallingConvention> JniCallingConvention::Create(ArenaAllocator* arena, 150 bool is_static, 151 bool is_synchronized, 152 bool is_critical_native, 153 const char* shorty, 154 InstructionSet instruction_set) { 155 switch (instruction_set) { 156 #ifdef ART_ENABLE_CODEGEN_arm 157 case kArm: 158 case kThumb2: 159 return std::unique_ptr<JniCallingConvention>( 160 new (arena) arm::ArmJniCallingConvention(is_static, 161 is_synchronized, 162 is_critical_native, 163 shorty)); 164 #endif 165 #ifdef ART_ENABLE_CODEGEN_arm64 166 case kArm64: 167 return std::unique_ptr<JniCallingConvention>( 168 new (arena) arm64::Arm64JniCallingConvention(is_static, 169 is_synchronized, 170 is_critical_native, 171 shorty)); 172 #endif 173 #ifdef ART_ENABLE_CODEGEN_mips 174 case kMips: 175 return std::unique_ptr<JniCallingConvention>( 176 new (arena) mips::MipsJniCallingConvention(is_static, 177 is_synchronized, 178 is_critical_native, 179 shorty)); 180 #endif 181 #ifdef ART_ENABLE_CODEGEN_mips64 182 case kMips64: 183 return std::unique_ptr<JniCallingConvention>( 184 new (arena) mips64::Mips64JniCallingConvention(is_static, 185 is_synchronized, 186 is_critical_native, 187 shorty)); 188 #endif 189 #ifdef ART_ENABLE_CODEGEN_x86 190 case kX86: 191 return std::unique_ptr<JniCallingConvention>( 192 new (arena) x86::X86JniCallingConvention(is_static, 193 is_synchronized, 194 is_critical_native, 195 shorty)); 196 #endif 197 #ifdef ART_ENABLE_CODEGEN_x86_64 198 case kX86_64: 199 return std::unique_ptr<JniCallingConvention>( 200 new (arena) x86_64::X86_64JniCallingConvention(is_static, 201 is_synchronized, 202 is_critical_native, 203 shorty)); 204 #endif 205 default: 206 LOG(FATAL) << "Unknown InstructionSet: " << instruction_set; 207 UNREACHABLE(); 208 } 209 } 210 211 size_t JniCallingConvention::ReferenceCount() const { 212 return NumReferenceArgs() + (IsStatic() ? 1 : 0); 213 } 214 215 FrameOffset JniCallingConvention::SavedLocalReferenceCookieOffset() const { 216 size_t references_size = handle_scope_pointer_size_ * ReferenceCount(); // size excluding header 217 return FrameOffset(HandleReferencesOffset().Int32Value() + references_size); 218 } 219 220 FrameOffset JniCallingConvention::ReturnValueSaveLocation() const { 221 if (LIKELY(HasHandleScope())) { 222 // Initial offset already includes the displacement. 223 // -- Remove the additional local reference cookie offset if we don't have a handle scope. 224 const size_t saved_local_reference_cookie_offset = 225 SavedLocalReferenceCookieOffset().Int32Value(); 226 // Segment state is 4 bytes long 227 const size_t segment_state_size = 4; 228 return FrameOffset(saved_local_reference_cookie_offset + segment_state_size); 229 } else { 230 // Include only the initial Method* as part of the offset. 231 CHECK_LT(displacement_.SizeValue(), 232 static_cast<size_t>(std::numeric_limits<int32_t>::max())); 233 return FrameOffset(displacement_.Int32Value() + static_cast<size_t>(frame_pointer_size_)); 234 } 235 } 236 237 bool JniCallingConvention::HasNext() { 238 if (IsCurrentArgExtraForJni()) { 239 return true; 240 } else { 241 unsigned int arg_pos = GetIteratorPositionWithinShorty(); 242 return arg_pos < NumArgs(); 243 } 244 } 245 246 void JniCallingConvention::Next() { 247 CHECK(HasNext()); 248 if (IsCurrentParamALong() || IsCurrentParamADouble()) { 249 itr_longs_and_doubles_++; 250 itr_slots_++; 251 } 252 if (IsCurrentParamAFloatOrDouble()) { 253 itr_float_and_doubles_++; 254 } 255 if (IsCurrentParamAReference()) { 256 itr_refs_++; 257 } 258 // This default/fallthrough case also covers the extra JNIEnv* argument, 259 // as well as any other single-slot primitives. 260 itr_args_++; 261 itr_slots_++; 262 } 263 264 bool JniCallingConvention::IsCurrentParamAReference() { 265 bool return_value; 266 if (SwitchExtraJniArguments(itr_args_, 267 false, // JNIEnv* 268 true, // jobject or jclass 269 /* out parameters */ 270 &return_value)) { 271 return return_value; 272 } else { 273 int arg_pos = GetIteratorPositionWithinShorty(); 274 return IsParamAReference(arg_pos); 275 } 276 } 277 278 279 bool JniCallingConvention::IsCurrentParamJniEnv() { 280 if (UNLIKELY(!HasJniEnv())) { 281 return false; 282 } 283 return (itr_args_ == kJniEnv); 284 } 285 286 bool JniCallingConvention::IsCurrentParamAFloatOrDouble() { 287 bool return_value; 288 if (SwitchExtraJniArguments(itr_args_, 289 false, // jnienv* 290 false, // jobject or jclass 291 /* out parameters */ 292 &return_value)) { 293 return return_value; 294 } else { 295 int arg_pos = GetIteratorPositionWithinShorty(); 296 return IsParamAFloatOrDouble(arg_pos); 297 } 298 } 299 300 bool JniCallingConvention::IsCurrentParamADouble() { 301 bool return_value; 302 if (SwitchExtraJniArguments(itr_args_, 303 false, // jnienv* 304 false, // jobject or jclass 305 /* out parameters */ 306 &return_value)) { 307 return return_value; 308 } else { 309 int arg_pos = GetIteratorPositionWithinShorty(); 310 return IsParamADouble(arg_pos); 311 } 312 } 313 314 bool JniCallingConvention::IsCurrentParamALong() { 315 bool return_value; 316 if (SwitchExtraJniArguments(itr_args_, 317 false, // jnienv* 318 false, // jobject or jclass 319 /* out parameters */ 320 &return_value)) { 321 return return_value; 322 } else { 323 int arg_pos = GetIteratorPositionWithinShorty(); 324 return IsParamALong(arg_pos); 325 } 326 } 327 328 // Return position of handle scope entry holding reference at the current iterator 329 // position 330 FrameOffset JniCallingConvention::CurrentParamHandleScopeEntryOffset() { 331 CHECK(IsCurrentParamAReference()); 332 CHECK_LT(HandleScopeLinkOffset(), HandleScopeNumRefsOffset()); 333 int result = HandleReferencesOffset().Int32Value() + itr_refs_ * handle_scope_pointer_size_; 334 CHECK_GT(result, HandleScopeNumRefsOffset().Int32Value()); 335 return FrameOffset(result); 336 } 337 338 size_t JniCallingConvention::CurrentParamSize() const { 339 if (IsCurrentArgExtraForJni()) { 340 return static_cast<size_t>(frame_pointer_size_); // JNIEnv or jobject/jclass 341 } else { 342 int arg_pos = GetIteratorPositionWithinShorty(); 343 return ParamSize(arg_pos); 344 } 345 } 346 347 size_t JniCallingConvention::NumberOfExtraArgumentsForJni() const { 348 if (LIKELY(HasExtraArgumentsForJni())) { 349 // The first argument is the JNIEnv*. 350 // Static methods have an extra argument which is the jclass. 351 return IsStatic() ? 2 : 1; 352 } else { 353 // Critical natives exclude the JNIEnv and the jclass/this parameters. 354 return 0; 355 } 356 } 357 358 bool JniCallingConvention::HasHandleScope() const { 359 // Exclude HandleScope for @CriticalNative methods for optimization speed. 360 return is_critical_native_ == false; 361 } 362 363 bool JniCallingConvention::HasLocalReferenceSegmentState() const { 364 // Exclude local reference segment states for @CriticalNative methods for optimization speed. 365 return is_critical_native_ == false; 366 } 367 368 bool JniCallingConvention::HasJniEnv() const { 369 // Exclude "JNIEnv*" parameter for @CriticalNative methods. 370 return HasExtraArgumentsForJni(); 371 } 372 373 bool JniCallingConvention::HasSelfClass() const { 374 if (!IsStatic()) { 375 // Virtual functions: There is never an implicit jclass parameter. 376 return false; 377 } else { 378 // Static functions: There is an implicit jclass parameter unless it's @CriticalNative. 379 return HasExtraArgumentsForJni(); 380 } 381 } 382 383 bool JniCallingConvention::HasExtraArgumentsForJni() const { 384 // @CriticalNative jni implementations exclude both JNIEnv* and the jclass/jobject parameters. 385 return is_critical_native_ == false; 386 } 387 388 unsigned int JniCallingConvention::GetIteratorPositionWithinShorty() const { 389 // We need to subtract out the extra JNI arguments if we want to use this iterator position 390 // with the inherited CallingConvention member functions, which rely on scanning the shorty. 391 // Note that our shorty does *not* include the JNIEnv, jclass/jobject parameters. 392 DCHECK_GE(itr_args_, NumberOfExtraArgumentsForJni()); 393 return itr_args_ - NumberOfExtraArgumentsForJni(); 394 } 395 396 bool JniCallingConvention::IsCurrentArgExtraForJni() const { 397 if (UNLIKELY(!HasExtraArgumentsForJni())) { 398 return false; // If there are no extra args, we can never be an extra. 399 } 400 // Only parameters kJniEnv and kObjectOrClass are considered extra. 401 return itr_args_ <= kObjectOrClass; 402 } 403 404 bool JniCallingConvention::SwitchExtraJniArguments(size_t switch_value, 405 bool case_jni_env, 406 bool case_object_or_class, 407 /* out parameters */ 408 bool* return_value) const { 409 DCHECK(return_value != nullptr); 410 if (UNLIKELY(!HasExtraArgumentsForJni())) { 411 return false; 412 } 413 414 switch (switch_value) { 415 case kJniEnv: 416 *return_value = case_jni_env; 417 return true; 418 case kObjectOrClass: 419 *return_value = case_object_or_class; 420 return true; 421 default: 422 return false; 423 } 424 } 425 426 427 } // namespace art 428