blob: bbff673b9d1e42b811a1e385159fe9efc616528e [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
17#include "object.h"
18#include "object_utils.h"
Ian Rogers00f7d0e2012-07-19 15:28:27 -070019#include "scoped_thread_state_change.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070020#include "thread.h"
21
22namespace art {
23
24// Used by the JNI dlsym stub to find the native method to invoke if none is registered.
Ian Rogers00f7d0e2012-07-19 15:28:27 -070025extern void* FindNativeMethod(Thread* self) LOCKS_EXCLUDED(GlobalSynchronization::mutator_lock_) {
26 GlobalSynchronization::mutator_lock_->AssertNotHeld(); // We come here as Native.
Ian Rogers57b86d42012-03-27 16:05:41 -070027 DCHECK(Thread::Current() == self);
Ian Rogers00f7d0e2012-07-19 15:28:27 -070028 ScopedObjectAccess soa(self);
Ian Rogers57b86d42012-03-27 16:05:41 -070029
Ian Rogers00f7d0e2012-07-19 15:28:27 -070030 Method* method = self->GetCurrentMethod();
Ian Rogers57b86d42012-03-27 16:05:41 -070031 DCHECK(method != NULL);
32
33 // Lookup symbol address for method, on failure we'll return NULL with an
34 // exception set, otherwise we return the address of the method we found.
Ian Rogers00f7d0e2012-07-19 15:28:27 -070035 void* native_code = soa.Vm()->FindCodeForNativeMethod(method);
Ian Rogers57b86d42012-03-27 16:05:41 -070036 if (native_code == NULL) {
37 DCHECK(self->IsExceptionPending());
38 return NULL;
39 } else {
40 // Register so that future calls don't come here
41 method->RegisterNative(self, native_code);
42 return native_code;
43 }
44}
45
Ian Rogers00f7d0e2012-07-19 15:28:27 -070046// Called on entry to JNI, transition out of Runnable and release share of mutator_lock_.
47extern uint32_t JniMethodStart(Thread* self) UNLOCK_FUNCTION(GlobalSynchronizatio::mutator_lock_) {
48 JNIEnvExt* env = self->GetJniEnv();
49 uint32_t saved_local_ref_cookie = env->local_ref_cookie;
50 env->local_ref_cookie = env->locals.GetSegmentState();
51 self->TransitionFromRunnableToSuspended(kNative);
52 return saved_local_ref_cookie;
53}
Elliott Hughesb264f082012-04-06 17:10:10 -070054
Ian Rogers00f7d0e2012-07-19 15:28:27 -070055extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self)
56 UNLOCK_FUNCTION(GlobalSynchronization::mutator_lock_) {
57 self->DecodeJObject(to_lock)->MonitorEnter(self);
58 return JniMethodStart(self);
59}
60
61static void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self) {
62 JNIEnvExt* env = self->GetJniEnv();
63 env->locals.SetSegmentState(env->local_ref_cookie);
64 env->local_ref_cookie = saved_local_ref_cookie;
65 self->PopSirt();
66}
67
68static void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
69 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_)
70 UNLOCK_FUNCTION(monitor_lock_) {
71 // Save any pending exception over monitor exit call.
72 Throwable* saved_exception = NULL;
73 if (UNLIKELY(self->IsExceptionPending())) {
74 saved_exception = self->GetException();
75 self->ClearException();
76 }
77 // Decode locked object and unlock, before popping local references.
78 self->DecodeJObject(locked)->MonitorExit(self);
79 if (UNLIKELY(self->IsExceptionPending())) {
80 LOG(FATAL) << "Synchronized JNI code returning with an exception:\n"
81 << saved_exception->Dump()
82 << "\nEncountered second exception during implicit MonitorExit:\n"
83 << self->GetException()->Dump();
84 }
85 // Restore pending exception.
86 if (saved_exception != NULL) {
87 self->SetException(saved_exception);
88 }
89}
90
91static void CheckReferenceResult(Object* o, Thread* self)
92 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_) {
93 if (o == NULL) {
94 return;
95 }
Elliott Hughesb264f082012-04-06 17:10:10 -070096 if (o == kInvalidIndirectRefObject) {
Elliott Hughes3f6635a2012-06-19 13:37:49 -070097 JniAbortF(NULL, "invalid reference returned from %s",
98 PrettyMethod(self->GetCurrentMethod()).c_str());
Elliott Hughesb264f082012-04-06 17:10:10 -070099 }
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700100 // Make sure that the result is an instance of the type this method was expected to return.
Elliott Hughesb264f082012-04-06 17:10:10 -0700101 Method* m = self->GetCurrentMethod();
102 MethodHelper mh(m);
103 Class* return_type = mh.GetReturnType();
104
105 if (!o->InstanceOf(return_type)) {
Elliott Hughes3f6635a2012-06-19 13:37:49 -0700106 JniAbortF(NULL, "attempt to return an instance of %s from %s",
107 PrettyTypeOf(o).c_str(), PrettyMethod(m).c_str());
Elliott Hughesb264f082012-04-06 17:10:10 -0700108 }
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700109}
Elliott Hughesb264f082012-04-06 17:10:10 -0700110
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700111extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self)
112 SHARED_LOCK_FUNCTION(GlobalSynchronization::mutator_lock_) {
113 self->TransitionFromSuspendedToRunnable();
114 PopLocalReferences(saved_local_ref_cookie, self);
115}
116
117
118extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked, Thread* self)
119 SHARED_LOCK_FUNCTION(GlobalSynchronization::mutator_lock_) {
120 self->TransitionFromSuspendedToRunnable();
121 UnlockJniSynchronizedMethod(locked, self); // Must decode before pop.
122 PopLocalReferences(saved_local_ref_cookie, self);
123}
124
125extern Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie,
126 Thread* self)
127 SHARED_LOCK_FUNCTION(GlobalSynchronization::mutator_lock_) {
128 self->TransitionFromSuspendedToRunnable();
129 Object* o = self->DecodeJObject(result); // Must decode before pop.
130 PopLocalReferences(saved_local_ref_cookie, self);
131 // Process result.
132 if (UNLIKELY(self->GetJniEnv()->check_jni)) {
133 if (self->IsExceptionPending()) {
134 return NULL;
135 }
136 CheckReferenceResult(o, self);
137 }
138 return o;
139}
140
141extern Object* JniMethodEndWithReferenceSynchronized(jobject result,
142 uint32_t saved_local_ref_cookie,
143 jobject locked, Thread* self)
144 SHARED_LOCK_FUNCTION(GlobalSynchronization::mutator_lock_) {
145 self->TransitionFromSuspendedToRunnable();
146 UnlockJniSynchronizedMethod(locked, self); // Must decode before pop.
147 Object* o = self->DecodeJObject(result);
148 PopLocalReferences(saved_local_ref_cookie, self);
149 // Process result.
150 if (UNLIKELY(self->GetJniEnv()->check_jni)) {
151 if (self->IsExceptionPending()) {
152 return NULL;
153 }
154 CheckReferenceResult(o, self);
155 }
Elliott Hughesb264f082012-04-06 17:10:10 -0700156 return o;
Ian Rogers57b86d42012-03-27 16:05:41 -0700157}
158
159static void WorkAroundJniBugsForJobject(intptr_t* arg_ptr) {
160 intptr_t value = *arg_ptr;
161 Object** value_as_jni_rep = reinterpret_cast<Object**>(value);
162 Object* value_as_work_around_rep = value_as_jni_rep != NULL ? *value_as_jni_rep : NULL;
163 CHECK(Runtime::Current()->GetHeap()->IsHeapAddress(value_as_work_around_rep)) << value_as_work_around_rep;
164 *arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep);
165}
166
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700167extern "C" const void* artWorkAroundAppJniBugs(Thread* self, intptr_t* sp)
168 SHARED_LOCKS_REQUIRED(GlobalSynchronization::mutator_lock_){
Ian Rogers57b86d42012-03-27 16:05:41 -0700169 DCHECK(Thread::Current() == self);
170 // TODO: this code is specific to ARM
171 // On entry the stack pointed by sp is:
172 // | arg3 | <- Calling JNI method's frame (and extra bit for out args)
173 // | LR |
174 // | R3 | arg2
175 // | R2 | arg1
176 // | R1 | jclass/jobject
177 // | R0 | JNIEnv
178 // | unused |
179 // | unused |
180 // | unused | <- sp
Ian Rogers0399dde2012-06-06 17:09:28 -0700181 Method* jni_method = self->GetCurrentMethod();
Ian Rogers57b86d42012-03-27 16:05:41 -0700182 DCHECK(jni_method->IsNative()) << PrettyMethod(jni_method);
183 intptr_t* arg_ptr = sp + 4; // pointer to r1 on stack
184 // Fix up this/jclass argument
185 WorkAroundJniBugsForJobject(arg_ptr);
186 arg_ptr++;
187 // Fix up jobject arguments
188 MethodHelper mh(jni_method);
189 int reg_num = 2; // Current register being processed, -1 for stack arguments.
190 for (uint32_t i = 1; i < mh.GetShortyLength(); i++) {
191 char shorty_char = mh.GetShorty()[i];
192 if (shorty_char == 'L') {
193 WorkAroundJniBugsForJobject(arg_ptr);
194 }
195 if (shorty_char == 'J' || shorty_char == 'D') {
196 if (reg_num == 2) {
197 arg_ptr = sp + 8; // skip to out arguments
198 reg_num = -1;
199 } else if (reg_num == 3) {
200 arg_ptr = sp + 10; // skip to out arguments plus 2 slots as long must be aligned
201 reg_num = -1;
202 } else {
Elliott Hughes74847412012-06-20 18:10:21 -0700203 DCHECK_EQ(reg_num, -1);
Ian Rogers57b86d42012-03-27 16:05:41 -0700204 if ((reinterpret_cast<intptr_t>(arg_ptr) & 7) == 4) {
205 arg_ptr += 3; // unaligned, pad and move through stack arguments
206 } else {
207 arg_ptr += 2; // aligned, move through stack arguments
208 }
209 }
210 } else {
211 if (reg_num == 2) {
212 arg_ptr++; // move through register arguments
213 reg_num++;
214 } else if (reg_num == 3) {
215 arg_ptr = sp + 8; // skip to outgoing stack arguments
216 reg_num = -1;
217 } else {
Elliott Hughes74847412012-06-20 18:10:21 -0700218 DCHECK_EQ(reg_num, -1);
Ian Rogers57b86d42012-03-27 16:05:41 -0700219 arg_ptr++; // move through stack arguments
220 }
221 }
222 }
223 // Load expected destination, see Method::RegisterNative
224 const void* code = reinterpret_cast<const void*>(jni_method->GetGcMapRaw());
225 if (UNLIKELY(code == NULL)) {
226 code = Runtime::Current()->GetJniDlsymLookupStub()->GetData();
227 jni_method->RegisterNative(self, code);
228 }
229 return code;
230}
231
232} // namespace art