Home | History | Annotate | Download | only in jni
      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