blob: ee19d4e9699549d7a28501767b55e6079ce1984b [file] [log] [blame]
Ian Rogers57b86d42012-03-27 16:05:41 -07001/*
Elliott Hughes0f3c5532012-03-30 14:51:51 -07002 * Copyright (C) 2012 The Android Open Source Project
Ian Rogers57b86d42012-03-27 16:05:41 -07003 *
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
Ian Rogers4f6ad8a2013-03-18 15:27:28 -070017#include "dex_file-inl.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080018#include "mirror/class-inl.h"
19#include "mirror/abstract_method-inl.h"
20#include "mirror/object.h"
21#include "mirror/object-inl.h"
22#include "mirror/object_array-inl.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070023#include "object_utils.h"
TDYa1273d71d802012-08-15 03:47:03 -070024#include "runtime_support.h"
Ian Rogers00f7d0e2012-07-19 15:28:27 -070025#include "scoped_thread_state_change.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070026#include "thread.h"
27
28namespace art {
29
30// Used by the JNI dlsym stub to find the native method to invoke if none is registered.
Ian Rogers693ff612013-02-01 10:56:12 -080031extern void* FindNativeMethod(Thread* self) {
Ian Rogers81d425b2012-09-27 16:03:43 -070032 Locks::mutator_lock_->AssertNotHeld(self); // We come here as Native.
Ian Rogers57b86d42012-03-27 16:05:41 -070033 DCHECK(Thread::Current() == self);
Ian Rogers00f7d0e2012-07-19 15:28:27 -070034 ScopedObjectAccess soa(self);
Ian Rogers57b86d42012-03-27 16:05:41 -070035
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080036 mirror::AbstractMethod* method = self->GetCurrentMethod();
Ian Rogers57b86d42012-03-27 16:05:41 -070037 DCHECK(method != NULL);
38
39 // Lookup symbol address for method, on failure we'll return NULL with an
40 // exception set, otherwise we return the address of the method we found.
Ian Rogers00f7d0e2012-07-19 15:28:27 -070041 void* native_code = soa.Vm()->FindCodeForNativeMethod(method);
Ian Rogers57b86d42012-03-27 16:05:41 -070042 if (native_code == NULL) {
43 DCHECK(self->IsExceptionPending());
44 return NULL;
45 } else {
46 // Register so that future calls don't come here
47 method->RegisterNative(self, native_code);
48 return native_code;
49 }
50}
51
Ian Rogers00f7d0e2012-07-19 15:28:27 -070052// Called on entry to JNI, transition out of Runnable and release share of mutator_lock_.
Ian Rogers693ff612013-02-01 10:56:12 -080053extern uint32_t JniMethodStart(Thread* self) {
Ian Rogers00f7d0e2012-07-19 15:28:27 -070054 JNIEnvExt* env = self->GetJniEnv();
Ian Rogers120f1c72012-09-28 17:17:10 -070055 DCHECK(env != NULL);
Ian Rogers00f7d0e2012-07-19 15:28:27 -070056 uint32_t saved_local_ref_cookie = env->local_ref_cookie;
57 env->local_ref_cookie = env->locals.GetSegmentState();
58 self->TransitionFromRunnableToSuspended(kNative);
59 return saved_local_ref_cookie;
60}
Elliott Hughesb264f082012-04-06 17:10:10 -070061
Ian Rogers693ff612013-02-01 10:56:12 -080062extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self) {
Ian Rogers00f7d0e2012-07-19 15:28:27 -070063 self->DecodeJObject(to_lock)->MonitorEnter(self);
64 return JniMethodStart(self);
65}
66
67static void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self) {
68 JNIEnvExt* env = self->GetJniEnv();
69 env->locals.SetSegmentState(env->local_ref_cookie);
70 env->local_ref_cookie = saved_local_ref_cookie;
71 self->PopSirt();
72}
73
Ian Rogers693ff612013-02-01 10:56:12 -080074extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self) {
Ian Rogers00f7d0e2012-07-19 15:28:27 -070075 self->TransitionFromSuspendedToRunnable();
76 PopLocalReferences(saved_local_ref_cookie, self);
77}
78
79
Ian Rogers693ff612013-02-01 10:56:12 -080080extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked,
81 Thread* self) {
Ian Rogers00f7d0e2012-07-19 15:28:27 -070082 self->TransitionFromSuspendedToRunnable();
83 UnlockJniSynchronizedMethod(locked, self); // Must decode before pop.
84 PopLocalReferences(saved_local_ref_cookie, self);
85}
86
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080087extern mirror::Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie,
Ian Rogers693ff612013-02-01 10:56:12 -080088 Thread* self) {
Ian Rogers00f7d0e2012-07-19 15:28:27 -070089 self->TransitionFromSuspendedToRunnable();
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080090 mirror::Object* o = self->DecodeJObject(result); // Must decode before pop.
Ian Rogers00f7d0e2012-07-19 15:28:27 -070091 PopLocalReferences(saved_local_ref_cookie, self);
92 // Process result.
93 if (UNLIKELY(self->GetJniEnv()->check_jni)) {
94 if (self->IsExceptionPending()) {
95 return NULL;
96 }
97 CheckReferenceResult(o, self);
98 }
99 return o;
100}
101
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800102extern mirror::Object* JniMethodEndWithReferenceSynchronized(jobject result,
103 uint32_t saved_local_ref_cookie,
Ian Rogers693ff612013-02-01 10:56:12 -0800104 jobject locked, Thread* self) {
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700105 self->TransitionFromSuspendedToRunnable();
106 UnlockJniSynchronizedMethod(locked, self); // Must decode before pop.
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800107 mirror::Object* o = self->DecodeJObject(result);
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700108 PopLocalReferences(saved_local_ref_cookie, self);
109 // Process result.
110 if (UNLIKELY(self->GetJniEnv()->check_jni)) {
111 if (self->IsExceptionPending()) {
112 return NULL;
113 }
114 CheckReferenceResult(o, self);
115 }
Elliott Hughesb264f082012-04-06 17:10:10 -0700116 return o;
Ian Rogers57b86d42012-03-27 16:05:41 -0700117}
118
119static void WorkAroundJniBugsForJobject(intptr_t* arg_ptr) {
120 intptr_t value = *arg_ptr;
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800121 mirror::Object** value_as_jni_rep = reinterpret_cast<mirror::Object**>(value);
122 mirror::Object* value_as_work_around_rep = value_as_jni_rep != NULL ? *value_as_jni_rep : NULL;
123 CHECK(Runtime::Current()->GetHeap()->IsHeapAddress(value_as_work_around_rep))
124 << value_as_work_around_rep;
Ian Rogers57b86d42012-03-27 16:05:41 -0700125 *arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep);
126}
127
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700128extern "C" const void* artWorkAroundAppJniBugs(Thread* self, intptr_t* sp)
Ian Rogersb726dcb2012-09-05 08:57:23 -0700129 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_){
Ian Rogers57b86d42012-03-27 16:05:41 -0700130 DCHECK(Thread::Current() == self);
131 // TODO: this code is specific to ARM
132 // On entry the stack pointed by sp is:
133 // | arg3 | <- Calling JNI method's frame (and extra bit for out args)
134 // | LR |
135 // | R3 | arg2
136 // | R2 | arg1
137 // | R1 | jclass/jobject
138 // | R0 | JNIEnv
139 // | unused |
140 // | unused |
141 // | unused | <- sp
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800142 mirror::AbstractMethod* jni_method = self->GetCurrentMethod();
Ian Rogers57b86d42012-03-27 16:05:41 -0700143 DCHECK(jni_method->IsNative()) << PrettyMethod(jni_method);
144 intptr_t* arg_ptr = sp + 4; // pointer to r1 on stack
145 // Fix up this/jclass argument
146 WorkAroundJniBugsForJobject(arg_ptr);
147 arg_ptr++;
148 // Fix up jobject arguments
149 MethodHelper mh(jni_method);
150 int reg_num = 2; // Current register being processed, -1 for stack arguments.
151 for (uint32_t i = 1; i < mh.GetShortyLength(); i++) {
152 char shorty_char = mh.GetShorty()[i];
153 if (shorty_char == 'L') {
154 WorkAroundJniBugsForJobject(arg_ptr);
155 }
156 if (shorty_char == 'J' || shorty_char == 'D') {
157 if (reg_num == 2) {
158 arg_ptr = sp + 8; // skip to out arguments
159 reg_num = -1;
160 } else if (reg_num == 3) {
161 arg_ptr = sp + 10; // skip to out arguments plus 2 slots as long must be aligned
162 reg_num = -1;
163 } else {
Elliott Hughes74847412012-06-20 18:10:21 -0700164 DCHECK_EQ(reg_num, -1);
Ian Rogers57b86d42012-03-27 16:05:41 -0700165 if ((reinterpret_cast<intptr_t>(arg_ptr) & 7) == 4) {
166 arg_ptr += 3; // unaligned, pad and move through stack arguments
167 } else {
168 arg_ptr += 2; // aligned, move through stack arguments
169 }
170 }
171 } else {
172 if (reg_num == 2) {
173 arg_ptr++; // move through register arguments
174 reg_num++;
175 } else if (reg_num == 3) {
176 arg_ptr = sp + 8; // skip to outgoing stack arguments
177 reg_num = -1;
178 } else {
Elliott Hughes74847412012-06-20 18:10:21 -0700179 DCHECK_EQ(reg_num, -1);
Ian Rogers57b86d42012-03-27 16:05:41 -0700180 arg_ptr++; // move through stack arguments
181 }
182 }
183 }
184 // Load expected destination, see Method::RegisterNative
Ian Rogers0c7abda2012-09-19 13:33:42 -0700185 const void* code = reinterpret_cast<const void*>(jni_method->GetNativeGcMap());
Ian Rogers57b86d42012-03-27 16:05:41 -0700186 if (UNLIKELY(code == NULL)) {
187 code = Runtime::Current()->GetJniDlsymLookupStub()->GetData();
188 jni_method->RegisterNative(self, code);
189 }
190 return code;
191}
192
193} // namespace art