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 <algorithm> 18 #include <memory> 19 #include <vector> 20 #include <fstream> 21 22 #include "base/logging.h" 23 #include "base/macros.h" 24 #include "calling_convention.h" 25 #include "class_linker.h" 26 #include "compiled_method.h" 27 #include "dex_file-inl.h" 28 #include "driver/compiler_driver.h" 29 #include "entrypoints/quick/quick_entrypoints.h" 30 #include "jni_internal.h" 31 #include "mirror/art_method.h" 32 #include "utils/assembler.h" 33 #include "utils/managed_register.h" 34 #include "utils/arm/managed_register_arm.h" 35 #include "utils/arm64/managed_register_arm64.h" 36 #include "utils/mips/managed_register_mips.h" 37 #include "utils/x86/managed_register_x86.h" 38 #include "thread.h" 39 40 #define __ jni_asm-> 41 42 namespace art { 43 44 static void CopyParameter(Assembler* jni_asm, 45 ManagedRuntimeCallingConvention* mr_conv, 46 JniCallingConvention* jni_conv, 47 size_t frame_size, size_t out_arg_size); 48 static void SetNativeParameter(Assembler* jni_asm, 49 JniCallingConvention* jni_conv, 50 ManagedRegister in_reg); 51 52 // Generate the JNI bridge for the given method, general contract: 53 // - Arguments are in the managed runtime format, either on stack or in 54 // registers, a reference to the method object is supplied as part of this 55 // convention. 56 // 57 CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver* driver, 58 uint32_t access_flags, uint32_t method_idx, 59 const DexFile& dex_file) { 60 const bool is_native = (access_flags & kAccNative) != 0; 61 CHECK(is_native); 62 const bool is_static = (access_flags & kAccStatic) != 0; 63 const bool is_synchronized = (access_flags & kAccSynchronized) != 0; 64 const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); 65 InstructionSet instruction_set = driver->GetInstructionSet(); 66 const bool is_64_bit_target = Is64BitInstructionSet(instruction_set); 67 // Calling conventions used to iterate over parameters to method 68 std::unique_ptr<JniCallingConvention> main_jni_conv( 69 JniCallingConvention::Create(is_static, is_synchronized, shorty, instruction_set)); 70 bool reference_return = main_jni_conv->IsReturnAReference(); 71 72 std::unique_ptr<ManagedRuntimeCallingConvention> mr_conv( 73 ManagedRuntimeCallingConvention::Create(is_static, is_synchronized, shorty, instruction_set)); 74 75 // Calling conventions to call into JNI method "end" possibly passing a returned reference, the 76 // method and the current thread. 77 const char* jni_end_shorty; 78 if (reference_return && is_synchronized) { 79 jni_end_shorty = "ILL"; 80 } else if (reference_return) { 81 jni_end_shorty = "IL"; 82 } else if (is_synchronized) { 83 jni_end_shorty = "VL"; 84 } else { 85 jni_end_shorty = "V"; 86 } 87 88 std::unique_ptr<JniCallingConvention> end_jni_conv( 89 JniCallingConvention::Create(is_static, is_synchronized, jni_end_shorty, instruction_set)); 90 91 // Assembler that holds generated instructions 92 std::unique_ptr<Assembler> jni_asm(Assembler::Create(instruction_set)); 93 94 // Offsets into data structures 95 // TODO: if cross compiling these offsets are for the host not the target 96 const Offset functions(OFFSETOF_MEMBER(JNIEnvExt, functions)); 97 const Offset monitor_enter(OFFSETOF_MEMBER(JNINativeInterface, MonitorEnter)); 98 const Offset monitor_exit(OFFSETOF_MEMBER(JNINativeInterface, MonitorExit)); 99 100 // 1. Build the frame saving all callee saves 101 const size_t frame_size(main_jni_conv->FrameSize()); 102 const std::vector<ManagedRegister>& callee_save_regs = main_jni_conv->CalleeSaveRegisters(); 103 __ BuildFrame(frame_size, mr_conv->MethodRegister(), callee_save_regs, mr_conv->EntrySpills()); 104 105 // 2. Set up the HandleScope 106 mr_conv->ResetIterator(FrameOffset(frame_size)); 107 main_jni_conv->ResetIterator(FrameOffset(0)); 108 __ StoreImmediateToFrame(main_jni_conv->HandleScopeNumRefsOffset(), 109 main_jni_conv->ReferenceCount(), 110 mr_conv->InterproceduralScratchRegister()); 111 112 if (is_64_bit_target) { 113 __ CopyRawPtrFromThread64(main_jni_conv->HandleScopeLinkOffset(), 114 Thread::TopHandleScopeOffset<8>(), 115 mr_conv->InterproceduralScratchRegister()); 116 __ StoreStackOffsetToThread64(Thread::TopHandleScopeOffset<8>(), 117 main_jni_conv->HandleScopeOffset(), 118 mr_conv->InterproceduralScratchRegister()); 119 } else { 120 __ CopyRawPtrFromThread32(main_jni_conv->HandleScopeLinkOffset(), 121 Thread::TopHandleScopeOffset<4>(), 122 mr_conv->InterproceduralScratchRegister()); 123 __ StoreStackOffsetToThread32(Thread::TopHandleScopeOffset<4>(), 124 main_jni_conv->HandleScopeOffset(), 125 mr_conv->InterproceduralScratchRegister()); 126 } 127 128 // 3. Place incoming reference arguments into handle scope 129 main_jni_conv->Next(); // Skip JNIEnv* 130 // 3.5. Create Class argument for static methods out of passed method 131 if (is_static) { 132 FrameOffset handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset(); 133 // Check handle scope offset is within frame 134 CHECK_LT(handle_scope_offset.Uint32Value(), frame_size); 135 __ LoadRef(main_jni_conv->InterproceduralScratchRegister(), 136 mr_conv->MethodRegister(), mirror::ArtMethod::DeclaringClassOffset()); 137 __ VerifyObject(main_jni_conv->InterproceduralScratchRegister(), false); 138 __ StoreRef(handle_scope_offset, main_jni_conv->InterproceduralScratchRegister()); 139 main_jni_conv->Next(); // in handle scope so move to next argument 140 } 141 while (mr_conv->HasNext()) { 142 CHECK(main_jni_conv->HasNext()); 143 bool ref_param = main_jni_conv->IsCurrentParamAReference(); 144 CHECK(!ref_param || mr_conv->IsCurrentParamAReference()); 145 // References need placing in handle scope and the entry value passing 146 if (ref_param) { 147 // Compute handle scope entry, note null is placed in the handle scope but its boxed value 148 // must be NULL 149 FrameOffset handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset(); 150 // Check handle scope offset is within frame and doesn't run into the saved segment state 151 CHECK_LT(handle_scope_offset.Uint32Value(), frame_size); 152 CHECK_NE(handle_scope_offset.Uint32Value(), 153 main_jni_conv->SavedLocalReferenceCookieOffset().Uint32Value()); 154 bool input_in_reg = mr_conv->IsCurrentParamInRegister(); 155 bool input_on_stack = mr_conv->IsCurrentParamOnStack(); 156 CHECK(input_in_reg || input_on_stack); 157 158 if (input_in_reg) { 159 ManagedRegister in_reg = mr_conv->CurrentParamRegister(); 160 __ VerifyObject(in_reg, mr_conv->IsCurrentArgPossiblyNull()); 161 __ StoreRef(handle_scope_offset, in_reg); 162 } else if (input_on_stack) { 163 FrameOffset in_off = mr_conv->CurrentParamStackOffset(); 164 __ VerifyObject(in_off, mr_conv->IsCurrentArgPossiblyNull()); 165 __ CopyRef(handle_scope_offset, in_off, 166 mr_conv->InterproceduralScratchRegister()); 167 } 168 } 169 mr_conv->Next(); 170 main_jni_conv->Next(); 171 } 172 173 // 4. Write out the end of the quick frames. 174 if (is_64_bit_target) { 175 __ StoreStackPointerToThread64(Thread::TopOfManagedStackOffset<8>()); 176 __ StoreImmediateToThread64(Thread::TopOfManagedStackPcOffset<8>(), 0, 177 mr_conv->InterproceduralScratchRegister()); 178 } else { 179 __ StoreStackPointerToThread32(Thread::TopOfManagedStackOffset<4>()); 180 __ StoreImmediateToThread32(Thread::TopOfManagedStackPcOffset<4>(), 0, 181 mr_conv->InterproceduralScratchRegister()); 182 } 183 184 // 5. Move frame down to allow space for out going args. 185 const size_t main_out_arg_size = main_jni_conv->OutArgSize(); 186 size_t current_out_arg_size = main_out_arg_size; 187 __ IncreaseFrameSize(main_out_arg_size); 188 189 // 6. Call into appropriate JniMethodStart passing Thread* so that transition out of Runnable 190 // can occur. The result is the saved JNI local state that is restored by the exit call. We 191 // abuse the JNI calling convention here, that is guaranteed to support passing 2 pointer 192 // arguments. 193 ThreadOffset<4> jni_start32 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(4, pJniMethodStartSynchronized) 194 : QUICK_ENTRYPOINT_OFFSET(4, pJniMethodStart); 195 ThreadOffset<8> jni_start64 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(8, pJniMethodStartSynchronized) 196 : QUICK_ENTRYPOINT_OFFSET(8, pJniMethodStart); 197 main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size)); 198 FrameOffset locked_object_handle_scope_offset(0); 199 if (is_synchronized) { 200 // Pass object for locking. 201 main_jni_conv->Next(); // Skip JNIEnv. 202 locked_object_handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset(); 203 main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size)); 204 if (main_jni_conv->IsCurrentParamOnStack()) { 205 FrameOffset out_off = main_jni_conv->CurrentParamStackOffset(); 206 __ CreateHandleScopeEntry(out_off, locked_object_handle_scope_offset, 207 mr_conv->InterproceduralScratchRegister(), 208 false); 209 } else { 210 ManagedRegister out_reg = main_jni_conv->CurrentParamRegister(); 211 __ CreateHandleScopeEntry(out_reg, locked_object_handle_scope_offset, 212 ManagedRegister::NoRegister(), false); 213 } 214 main_jni_conv->Next(); 215 } 216 if (main_jni_conv->IsCurrentParamInRegister()) { 217 __ GetCurrentThread(main_jni_conv->CurrentParamRegister()); 218 if (is_64_bit_target) { 219 __ Call(main_jni_conv->CurrentParamRegister(), Offset(jni_start64), 220 main_jni_conv->InterproceduralScratchRegister()); 221 } else { 222 __ Call(main_jni_conv->CurrentParamRegister(), Offset(jni_start32), 223 main_jni_conv->InterproceduralScratchRegister()); 224 } 225 } else { 226 __ GetCurrentThread(main_jni_conv->CurrentParamStackOffset(), 227 main_jni_conv->InterproceduralScratchRegister()); 228 if (is_64_bit_target) { 229 __ CallFromThread64(jni_start64, main_jni_conv->InterproceduralScratchRegister()); 230 } else { 231 __ CallFromThread32(jni_start32, main_jni_conv->InterproceduralScratchRegister()); 232 } 233 } 234 if (is_synchronized) { // Check for exceptions from monitor enter. 235 __ ExceptionPoll(main_jni_conv->InterproceduralScratchRegister(), main_out_arg_size); 236 } 237 FrameOffset saved_cookie_offset = main_jni_conv->SavedLocalReferenceCookieOffset(); 238 __ Store(saved_cookie_offset, main_jni_conv->IntReturnRegister(), 4); 239 240 // 7. Iterate over arguments placing values from managed calling convention in 241 // to the convention required for a native call (shuffling). For references 242 // place an index/pointer to the reference after checking whether it is 243 // NULL (which must be encoded as NULL). 244 // Note: we do this prior to materializing the JNIEnv* and static's jclass to 245 // give as many free registers for the shuffle as possible 246 mr_conv->ResetIterator(FrameOffset(frame_size + main_out_arg_size)); 247 uint32_t args_count = 0; 248 while (mr_conv->HasNext()) { 249 args_count++; 250 mr_conv->Next(); 251 } 252 253 // Do a backward pass over arguments, so that the generated code will be "mov 254 // R2, R3; mov R1, R2" instead of "mov R1, R2; mov R2, R3." 255 // TODO: A reverse iterator to improve readability. 256 for (uint32_t i = 0; i < args_count; ++i) { 257 mr_conv->ResetIterator(FrameOffset(frame_size + main_out_arg_size)); 258 main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size)); 259 main_jni_conv->Next(); // Skip JNIEnv*. 260 if (is_static) { 261 main_jni_conv->Next(); // Skip Class for now. 262 } 263 // Skip to the argument we're interested in. 264 for (uint32_t j = 0; j < args_count - i - 1; ++j) { 265 mr_conv->Next(); 266 main_jni_conv->Next(); 267 } 268 CopyParameter(jni_asm.get(), mr_conv.get(), main_jni_conv.get(), frame_size, main_out_arg_size); 269 } 270 if (is_static) { 271 // Create argument for Class 272 mr_conv->ResetIterator(FrameOffset(frame_size + main_out_arg_size)); 273 main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size)); 274 main_jni_conv->Next(); // Skip JNIEnv* 275 FrameOffset handle_scope_offset = main_jni_conv->CurrentParamHandleScopeEntryOffset(); 276 if (main_jni_conv->IsCurrentParamOnStack()) { 277 FrameOffset out_off = main_jni_conv->CurrentParamStackOffset(); 278 __ CreateHandleScopeEntry(out_off, handle_scope_offset, 279 mr_conv->InterproceduralScratchRegister(), 280 false); 281 } else { 282 ManagedRegister out_reg = main_jni_conv->CurrentParamRegister(); 283 __ CreateHandleScopeEntry(out_reg, handle_scope_offset, 284 ManagedRegister::NoRegister(), false); 285 } 286 } 287 288 // 8. Create 1st argument, the JNI environment ptr. 289 main_jni_conv->ResetIterator(FrameOffset(main_out_arg_size)); 290 // Register that will hold local indirect reference table 291 if (main_jni_conv->IsCurrentParamInRegister()) { 292 ManagedRegister jni_env = main_jni_conv->CurrentParamRegister(); 293 DCHECK(!jni_env.Equals(main_jni_conv->InterproceduralScratchRegister())); 294 if (is_64_bit_target) { 295 __ LoadRawPtrFromThread64(jni_env, Thread::JniEnvOffset<8>()); 296 } else { 297 __ LoadRawPtrFromThread32(jni_env, Thread::JniEnvOffset<4>()); 298 } 299 } else { 300 FrameOffset jni_env = main_jni_conv->CurrentParamStackOffset(); 301 if (is_64_bit_target) { 302 __ CopyRawPtrFromThread64(jni_env, Thread::JniEnvOffset<8>(), 303 main_jni_conv->InterproceduralScratchRegister()); 304 } else { 305 __ CopyRawPtrFromThread32(jni_env, Thread::JniEnvOffset<4>(), 306 main_jni_conv->InterproceduralScratchRegister()); 307 } 308 } 309 310 // 9. Plant call to native code associated with method. 311 MemberOffset jni_entrypoint_offset = mirror::ArtMethod::EntryPointFromJniOffset( 312 InstructionSetPointerSize(instruction_set)); 313 __ Call(main_jni_conv->MethodStackOffset(), jni_entrypoint_offset, 314 mr_conv->InterproceduralScratchRegister()); 315 316 // 10. Fix differences in result widths. 317 if (main_jni_conv->RequiresSmallResultTypeExtension()) { 318 if (main_jni_conv->GetReturnType() == Primitive::kPrimByte || 319 main_jni_conv->GetReturnType() == Primitive::kPrimShort) { 320 __ SignExtend(main_jni_conv->ReturnRegister(), 321 Primitive::ComponentSize(main_jni_conv->GetReturnType())); 322 } else if (main_jni_conv->GetReturnType() == Primitive::kPrimBoolean || 323 main_jni_conv->GetReturnType() == Primitive::kPrimChar) { 324 __ ZeroExtend(main_jni_conv->ReturnRegister(), 325 Primitive::ComponentSize(main_jni_conv->GetReturnType())); 326 } 327 } 328 329 // 11. Save return value 330 FrameOffset return_save_location = main_jni_conv->ReturnValueSaveLocation(); 331 if (main_jni_conv->SizeOfReturnValue() != 0 && !reference_return) { 332 if (instruction_set == kMips && main_jni_conv->GetReturnType() == Primitive::kPrimDouble && 333 return_save_location.Uint32Value() % 8 != 0) { 334 // Ensure doubles are 8-byte aligned for MIPS 335 return_save_location = FrameOffset(return_save_location.Uint32Value() + kMipsPointerSize); 336 } 337 CHECK_LT(return_save_location.Uint32Value(), frame_size + main_out_arg_size); 338 __ Store(return_save_location, main_jni_conv->ReturnRegister(), main_jni_conv->SizeOfReturnValue()); 339 } 340 341 // Increase frame size for out args if needed by the end_jni_conv. 342 const size_t end_out_arg_size = end_jni_conv->OutArgSize(); 343 if (end_out_arg_size > current_out_arg_size) { 344 size_t out_arg_size_diff = end_out_arg_size - current_out_arg_size; 345 current_out_arg_size = end_out_arg_size; 346 __ IncreaseFrameSize(out_arg_size_diff); 347 saved_cookie_offset = FrameOffset(saved_cookie_offset.SizeValue() + out_arg_size_diff); 348 locked_object_handle_scope_offset = 349 FrameOffset(locked_object_handle_scope_offset.SizeValue() + out_arg_size_diff); 350 return_save_location = FrameOffset(return_save_location.SizeValue() + out_arg_size_diff); 351 } 352 // thread. 353 end_jni_conv->ResetIterator(FrameOffset(end_out_arg_size)); 354 ThreadOffset<4> jni_end32(-1); 355 ThreadOffset<8> jni_end64(-1); 356 if (reference_return) { 357 // Pass result. 358 jni_end32 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEndWithReferenceSynchronized) 359 : QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEndWithReference); 360 jni_end64 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(8, pJniMethodEndWithReferenceSynchronized) 361 : QUICK_ENTRYPOINT_OFFSET(8, pJniMethodEndWithReference); 362 SetNativeParameter(jni_asm.get(), end_jni_conv.get(), end_jni_conv->ReturnRegister()); 363 end_jni_conv->Next(); 364 } else { 365 jni_end32 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEndSynchronized) 366 : QUICK_ENTRYPOINT_OFFSET(4, pJniMethodEnd); 367 jni_end64 = is_synchronized ? QUICK_ENTRYPOINT_OFFSET(8, pJniMethodEndSynchronized) 368 : QUICK_ENTRYPOINT_OFFSET(8, pJniMethodEnd); 369 } 370 // Pass saved local reference state. 371 if (end_jni_conv->IsCurrentParamOnStack()) { 372 FrameOffset out_off = end_jni_conv->CurrentParamStackOffset(); 373 __ Copy(out_off, saved_cookie_offset, end_jni_conv->InterproceduralScratchRegister(), 4); 374 } else { 375 ManagedRegister out_reg = end_jni_conv->CurrentParamRegister(); 376 __ Load(out_reg, saved_cookie_offset, 4); 377 } 378 end_jni_conv->Next(); 379 if (is_synchronized) { 380 // Pass object for unlocking. 381 if (end_jni_conv->IsCurrentParamOnStack()) { 382 FrameOffset out_off = end_jni_conv->CurrentParamStackOffset(); 383 __ CreateHandleScopeEntry(out_off, locked_object_handle_scope_offset, 384 end_jni_conv->InterproceduralScratchRegister(), 385 false); 386 } else { 387 ManagedRegister out_reg = end_jni_conv->CurrentParamRegister(); 388 __ CreateHandleScopeEntry(out_reg, locked_object_handle_scope_offset, 389 ManagedRegister::NoRegister(), false); 390 } 391 end_jni_conv->Next(); 392 } 393 if (end_jni_conv->IsCurrentParamInRegister()) { 394 __ GetCurrentThread(end_jni_conv->CurrentParamRegister()); 395 if (is_64_bit_target) { 396 __ Call(end_jni_conv->CurrentParamRegister(), Offset(jni_end64), 397 end_jni_conv->InterproceduralScratchRegister()); 398 } else { 399 __ Call(end_jni_conv->CurrentParamRegister(), Offset(jni_end32), 400 end_jni_conv->InterproceduralScratchRegister()); 401 } 402 } else { 403 __ GetCurrentThread(end_jni_conv->CurrentParamStackOffset(), 404 end_jni_conv->InterproceduralScratchRegister()); 405 if (is_64_bit_target) { 406 __ CallFromThread64(ThreadOffset<8>(jni_end64), end_jni_conv->InterproceduralScratchRegister()); 407 } else { 408 __ CallFromThread32(ThreadOffset<4>(jni_end32), end_jni_conv->InterproceduralScratchRegister()); 409 } 410 } 411 412 // 13. Reload return value 413 if (main_jni_conv->SizeOfReturnValue() != 0 && !reference_return) { 414 __ Load(mr_conv->ReturnRegister(), return_save_location, mr_conv->SizeOfReturnValue()); 415 } 416 417 // 14. Move frame up now we're done with the out arg space. 418 __ DecreaseFrameSize(current_out_arg_size); 419 420 // 15. Process pending exceptions from JNI call or monitor exit. 421 __ ExceptionPoll(main_jni_conv->InterproceduralScratchRegister(), 0); 422 423 // 16. Remove activation - need to restore callee save registers since the GC may have changed 424 // them. 425 __ RemoveFrame(frame_size, callee_save_regs); 426 427 // 17. Finalize code generation 428 __ EmitSlowPaths(); 429 size_t cs = __ CodeSize(); 430 if (instruction_set == kArm64) { 431 // Test that we do not exceed the buffer size. 432 CHECK(cs < arm64::kBufferSizeArm64); 433 } 434 std::vector<uint8_t> managed_code(cs); 435 MemoryRegion code(&managed_code[0], managed_code.size()); 436 __ FinalizeInstructions(code); 437 return CompiledMethod::SwapAllocCompiledMethod(driver, 438 instruction_set, 439 ArrayRef<const uint8_t>(managed_code), 440 frame_size, 441 main_jni_conv->CoreSpillMask(), 442 main_jni_conv->FpSpillMask()); 443 } 444 445 // Copy a single parameter from the managed to the JNI calling convention 446 static void CopyParameter(Assembler* jni_asm, 447 ManagedRuntimeCallingConvention* mr_conv, 448 JniCallingConvention* jni_conv, 449 size_t frame_size, size_t out_arg_size) { 450 bool input_in_reg = mr_conv->IsCurrentParamInRegister(); 451 bool output_in_reg = jni_conv->IsCurrentParamInRegister(); 452 FrameOffset handle_scope_offset(0); 453 bool null_allowed = false; 454 bool ref_param = jni_conv->IsCurrentParamAReference(); 455 CHECK(!ref_param || mr_conv->IsCurrentParamAReference()); 456 // input may be in register, on stack or both - but not none! 457 CHECK(input_in_reg || mr_conv->IsCurrentParamOnStack()); 458 if (output_in_reg) { // output shouldn't straddle registers and stack 459 CHECK(!jni_conv->IsCurrentParamOnStack()); 460 } else { 461 CHECK(jni_conv->IsCurrentParamOnStack()); 462 } 463 // References need placing in handle scope and the entry address passing 464 if (ref_param) { 465 null_allowed = mr_conv->IsCurrentArgPossiblyNull(); 466 // Compute handle scope offset. Note null is placed in the handle scope but the jobject 467 // passed to the native code must be null (not a pointer into the handle scope 468 // as with regular references). 469 handle_scope_offset = jni_conv->CurrentParamHandleScopeEntryOffset(); 470 // Check handle scope offset is within frame. 471 CHECK_LT(handle_scope_offset.Uint32Value(), (frame_size + out_arg_size)); 472 } 473 if (input_in_reg && output_in_reg) { 474 ManagedRegister in_reg = mr_conv->CurrentParamRegister(); 475 ManagedRegister out_reg = jni_conv->CurrentParamRegister(); 476 if (ref_param) { 477 __ CreateHandleScopeEntry(out_reg, handle_scope_offset, in_reg, null_allowed); 478 } else { 479 if (!mr_conv->IsCurrentParamOnStack()) { 480 // regular non-straddling move 481 __ Move(out_reg, in_reg, mr_conv->CurrentParamSize()); 482 } else { 483 UNIMPLEMENTED(FATAL); // we currently don't expect to see this case 484 } 485 } 486 } else if (!input_in_reg && !output_in_reg) { 487 FrameOffset out_off = jni_conv->CurrentParamStackOffset(); 488 if (ref_param) { 489 __ CreateHandleScopeEntry(out_off, handle_scope_offset, mr_conv->InterproceduralScratchRegister(), 490 null_allowed); 491 } else { 492 FrameOffset in_off = mr_conv->CurrentParamStackOffset(); 493 size_t param_size = mr_conv->CurrentParamSize(); 494 CHECK_EQ(param_size, jni_conv->CurrentParamSize()); 495 __ Copy(out_off, in_off, mr_conv->InterproceduralScratchRegister(), param_size); 496 } 497 } else if (!input_in_reg && output_in_reg) { 498 FrameOffset in_off = mr_conv->CurrentParamStackOffset(); 499 ManagedRegister out_reg = jni_conv->CurrentParamRegister(); 500 // Check that incoming stack arguments are above the current stack frame. 501 CHECK_GT(in_off.Uint32Value(), frame_size); 502 if (ref_param) { 503 __ CreateHandleScopeEntry(out_reg, handle_scope_offset, ManagedRegister::NoRegister(), null_allowed); 504 } else { 505 size_t param_size = mr_conv->CurrentParamSize(); 506 CHECK_EQ(param_size, jni_conv->CurrentParamSize()); 507 __ Load(out_reg, in_off, param_size); 508 } 509 } else { 510 CHECK(input_in_reg && !output_in_reg); 511 ManagedRegister in_reg = mr_conv->CurrentParamRegister(); 512 FrameOffset out_off = jni_conv->CurrentParamStackOffset(); 513 // Check outgoing argument is within frame 514 CHECK_LT(out_off.Uint32Value(), frame_size); 515 if (ref_param) { 516 // TODO: recycle value in in_reg rather than reload from handle scope 517 __ CreateHandleScopeEntry(out_off, handle_scope_offset, mr_conv->InterproceduralScratchRegister(), 518 null_allowed); 519 } else { 520 size_t param_size = mr_conv->CurrentParamSize(); 521 CHECK_EQ(param_size, jni_conv->CurrentParamSize()); 522 if (!mr_conv->IsCurrentParamOnStack()) { 523 // regular non-straddling store 524 __ Store(out_off, in_reg, param_size); 525 } else { 526 // store where input straddles registers and stack 527 CHECK_EQ(param_size, 8u); 528 FrameOffset in_off = mr_conv->CurrentParamStackOffset(); 529 __ StoreSpanning(out_off, in_reg, in_off, mr_conv->InterproceduralScratchRegister()); 530 } 531 } 532 } 533 } 534 535 static void SetNativeParameter(Assembler* jni_asm, 536 JniCallingConvention* jni_conv, 537 ManagedRegister in_reg) { 538 if (jni_conv->IsCurrentParamOnStack()) { 539 FrameOffset dest = jni_conv->CurrentParamStackOffset(); 540 __ StoreRawPtr(dest, in_reg); 541 } else { 542 if (!jni_conv->CurrentParamRegister().Equals(in_reg)) { 543 __ Move(jni_conv->CurrentParamRegister(), in_reg, jni_conv->CurrentParamSize()); 544 } 545 } 546 } 547 548 } // namespace art 549 550 extern "C" art::CompiledMethod* ArtQuickJniCompileMethod(art::CompilerDriver* compiler, 551 uint32_t access_flags, uint32_t method_idx, 552 const art::DexFile& dex_file) { 553 return ArtJniCompileMethodInternal(compiler, access_flags, method_idx, dex_file); 554 } 555