blob: 83d3a584c55b8560e912b9c52a4417e1489e6935 [file] [log] [blame]
Ian Rogers7655f292013-07-29 11:07:13 -07001/*
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"
Ian Rogers848871b2013-08-05 10:56:33 -070018#include "entrypoints/entrypoint_utils.h"
Brian Carlstromea46f952013-07-30 01:26:50 -070019#include "mirror/art_method-inl.h"
Ian Rogers848871b2013-08-05 10:56:33 -070020#include "mirror/object-inl.h"
21#include "object_utils.h"
Ian Rogers7655f292013-07-29 11:07:13 -070022#include "scoped_thread_state_change.h"
23#include "thread.h"
24
25namespace art {
26
27// Used by the JNI dlsym stub to find the native method to invoke if none is registered.
Ian Rogers848871b2013-08-05 10:56:33 -070028extern "C" void* artFindNativeMethod() {
29 Thread* self = Thread::Current();
Ian Rogers7655f292013-07-29 11:07:13 -070030 Locks::mutator_lock_->AssertNotHeld(self); // We come here as Native.
Ian Rogers7655f292013-07-29 11:07:13 -070031 ScopedObjectAccess soa(self);
32
Brian Carlstromea46f952013-07-30 01:26:50 -070033 mirror::ArtMethod* method = self->GetCurrentMethod(NULL);
Ian Rogers7655f292013-07-29 11:07:13 -070034 DCHECK(method != NULL);
35
Ian Rogers848871b2013-08-05 10:56:33 -070036 // 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.
Ian Rogers7655f292013-07-29 11:07:13 -070038 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
Ian Rogers848871b2013-08-05 10:56:33 -070049static 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
58extern "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
Brian Carlstromea46f952013-07-30 01:26:50 -070072 mirror::ArtMethod* jni_method = self->GetCurrentMethod(NULL);
Ian Rogers848871b2013-08-05 10:56:33 -070073 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
Ian Rogers7655f292013-07-29 11:07:13 -0700123} // namespace art