1 /* 2 * Copyright (C) 2012 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 "entrypoints/entrypoint_utils.h" 19 #include "mirror/art_method-inl.h" 20 #include "mirror/object-inl.h" 21 #include "object_utils.h" 22 #include "scoped_thread_state_change.h" 23 #include "thread.h" 24 25 namespace art { 26 27 // Used by the JNI dlsym stub to find the native method to invoke if none is registered. 28 extern "C" void* artFindNativeMethod() { 29 Thread* self = Thread::Current(); 30 Locks::mutator_lock_->AssertNotHeld(self); // We come here as Native. 31 ScopedObjectAccess soa(self); 32 33 mirror::ArtMethod* method = self->GetCurrentMethod(NULL); 34 DCHECK(method != NULL); 35 36 // Lookup symbol address for method, on failure we'll return NULL with an exception set, 37 // otherwise we return the address of the method we found. 38 void* native_code = soa.Vm()->FindCodeForNativeMethod(method); 39 if (native_code == NULL) { 40 DCHECK(self->IsExceptionPending()); 41 return NULL; 42 } else { 43 // Register so that future calls don't come here 44 method->RegisterNative(self, native_code); 45 return native_code; 46 } 47 } 48 49 static void WorkAroundJniBugsForJobject(intptr_t* arg_ptr) { 50 intptr_t value = *arg_ptr; 51 mirror::Object** value_as_jni_rep = reinterpret_cast<mirror::Object**>(value); 52 mirror::Object* value_as_work_around_rep = value_as_jni_rep != NULL ? *value_as_jni_rep : NULL; 53 CHECK(Runtime::Current()->GetHeap()->IsHeapAddress(value_as_work_around_rep)) 54 << value_as_work_around_rep; 55 *arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep); 56 } 57 58 extern "C" const void* artWorkAroundAppJniBugs(Thread* self, intptr_t* sp) 59 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 60 DCHECK(Thread::Current() == self); 61 // TODO: this code is specific to ARM 62 // On entry the stack pointed by sp is: 63 // | arg3 | <- Calling JNI method's frame (and extra bit for out args) 64 // | LR | 65 // | R3 | arg2 66 // | R2 | arg1 67 // | R1 | jclass/jobject 68 // | R0 | JNIEnv 69 // | unused | 70 // | unused | 71 // | unused | <- sp 72 mirror::ArtMethod* jni_method = self->GetCurrentMethod(NULL); 73 DCHECK(jni_method->IsNative()) << PrettyMethod(jni_method); 74 intptr_t* arg_ptr = sp + 4; // pointer to r1 on stack 75 // Fix up this/jclass argument 76 WorkAroundJniBugsForJobject(arg_ptr); 77 arg_ptr++; 78 // Fix up jobject arguments 79 MethodHelper mh(jni_method); 80 int reg_num = 2; // Current register being processed, -1 for stack arguments. 81 for (uint32_t i = 1; i < mh.GetShortyLength(); i++) { 82 char shorty_char = mh.GetShorty()[i]; 83 if (shorty_char == 'L') { 84 WorkAroundJniBugsForJobject(arg_ptr); 85 } 86 if (shorty_char == 'J' || shorty_char == 'D') { 87 if (reg_num == 2) { 88 arg_ptr = sp + 8; // skip to out arguments 89 reg_num = -1; 90 } else if (reg_num == 3) { 91 arg_ptr = sp + 10; // skip to out arguments plus 2 slots as long must be aligned 92 reg_num = -1; 93 } else { 94 DCHECK_EQ(reg_num, -1); 95 if ((reinterpret_cast<intptr_t>(arg_ptr) & 7) == 4) { 96 arg_ptr += 3; // unaligned, pad and move through stack arguments 97 } else { 98 arg_ptr += 2; // aligned, move through stack arguments 99 } 100 } 101 } else { 102 if (reg_num == 2) { 103 arg_ptr++; // move through register arguments 104 reg_num++; 105 } else if (reg_num == 3) { 106 arg_ptr = sp + 8; // skip to outgoing stack arguments 107 reg_num = -1; 108 } else { 109 DCHECK_EQ(reg_num, -1); 110 arg_ptr++; // move through stack arguments 111 } 112 } 113 } 114 // Load expected destination, see Method::RegisterNative 115 const void* code = reinterpret_cast<const void*>(jni_method->GetNativeGcMap()); 116 if (UNLIKELY(code == NULL)) { 117 code = GetJniDlsymLookupStub(); 118 jni_method->RegisterNative(self, code); 119 } 120 return code; 121 } 122 123 } // namespace art 124