blob: 2c6f76634240e902ccf1f019630e2782acdc84c6 [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"
TDYa1273d71d802012-08-15 03:47:03 -070019#include "runtime_support.h"
Ian Rogers00f7d0e2012-07-19 15:28:27 -070020#include "scoped_thread_state_change.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070021#include "thread.h"
22
23namespace art {
24
25// Used by the JNI dlsym stub to find the native method to invoke if none is registered.
Ian Rogersb726dcb2012-09-05 08:57:23 -070026extern void* FindNativeMethod(Thread* self) LOCKS_EXCLUDED(Locks::mutator_lock_) {
27 Locks::mutator_lock_->AssertNotHeld(); // We come here as Native.
Ian Rogers57b86d42012-03-27 16:05:41 -070028 DCHECK(Thread::Current() == self);
Ian Rogers00f7d0e2012-07-19 15:28:27 -070029 ScopedObjectAccess soa(self);
Ian Rogers57b86d42012-03-27 16:05:41 -070030
Ian Rogers00f7d0e2012-07-19 15:28:27 -070031 Method* method = self->GetCurrentMethod();
Ian Rogers57b86d42012-03-27 16:05:41 -070032 DCHECK(method != NULL);
33
34 // Lookup symbol address for method, on failure we'll return NULL with an
35 // exception set, otherwise we return the address of the method we found.
Ian Rogers00f7d0e2012-07-19 15:28:27 -070036 void* native_code = soa.Vm()->FindCodeForNativeMethod(method);
Ian Rogers57b86d42012-03-27 16:05:41 -070037 if (native_code == NULL) {
38 DCHECK(self->IsExceptionPending());
39 return NULL;
40 } else {
41 // Register so that future calls don't come here
42 method->RegisterNative(self, native_code);
43 return native_code;
44 }
45}
46
Ian Rogers00f7d0e2012-07-19 15:28:27 -070047// Called on entry to JNI, transition out of Runnable and release share of mutator_lock_.
48extern uint32_t JniMethodStart(Thread* self) UNLOCK_FUNCTION(GlobalSynchronizatio::mutator_lock_) {
49 JNIEnvExt* env = self->GetJniEnv();
50 uint32_t saved_local_ref_cookie = env->local_ref_cookie;
51 env->local_ref_cookie = env->locals.GetSegmentState();
52 self->TransitionFromRunnableToSuspended(kNative);
53 return saved_local_ref_cookie;
54}
Elliott Hughesb264f082012-04-06 17:10:10 -070055
Ian Rogers00f7d0e2012-07-19 15:28:27 -070056extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self)
Ian Rogersb726dcb2012-09-05 08:57:23 -070057 UNLOCK_FUNCTION(Locks::mutator_lock_) {
Ian Rogers00f7d0e2012-07-19 15:28:27 -070058 self->DecodeJObject(to_lock)->MonitorEnter(self);
59 return JniMethodStart(self);
60}
61
62static void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self) {
63 JNIEnvExt* env = self->GetJniEnv();
64 env->locals.SetSegmentState(env->local_ref_cookie);
65 env->local_ref_cookie = saved_local_ref_cookie;
66 self->PopSirt();
67}
68
Ian Rogers00f7d0e2012-07-19 15:28:27 -070069extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self)
Ian Rogersb726dcb2012-09-05 08:57:23 -070070 SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
Ian Rogers00f7d0e2012-07-19 15:28:27 -070071 self->TransitionFromSuspendedToRunnable();
72 PopLocalReferences(saved_local_ref_cookie, self);
73}
74
75
76extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked, Thread* self)
Ian Rogersb726dcb2012-09-05 08:57:23 -070077 SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
Ian Rogers00f7d0e2012-07-19 15:28:27 -070078 self->TransitionFromSuspendedToRunnable();
79 UnlockJniSynchronizedMethod(locked, self); // Must decode before pop.
80 PopLocalReferences(saved_local_ref_cookie, self);
81}
82
83extern Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie,
84 Thread* self)
Ian Rogersb726dcb2012-09-05 08:57:23 -070085 SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
Ian Rogers00f7d0e2012-07-19 15:28:27 -070086 self->TransitionFromSuspendedToRunnable();
87 Object* o = self->DecodeJObject(result); // Must decode before pop.
88 PopLocalReferences(saved_local_ref_cookie, self);
89 // Process result.
90 if (UNLIKELY(self->GetJniEnv()->check_jni)) {
91 if (self->IsExceptionPending()) {
92 return NULL;
93 }
94 CheckReferenceResult(o, self);
95 }
96 return o;
97}
98
99extern Object* JniMethodEndWithReferenceSynchronized(jobject result,
100 uint32_t saved_local_ref_cookie,
101 jobject locked, Thread* self)
Ian Rogersb726dcb2012-09-05 08:57:23 -0700102 SHARED_LOCK_FUNCTION(Locks::mutator_lock_) {
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700103 self->TransitionFromSuspendedToRunnable();
104 UnlockJniSynchronizedMethod(locked, self); // Must decode before pop.
105 Object* o = self->DecodeJObject(result);
106 PopLocalReferences(saved_local_ref_cookie, self);
107 // Process result.
108 if (UNLIKELY(self->GetJniEnv()->check_jni)) {
109 if (self->IsExceptionPending()) {
110 return NULL;
111 }
112 CheckReferenceResult(o, self);
113 }
Elliott Hughesb264f082012-04-06 17:10:10 -0700114 return o;
Ian Rogers57b86d42012-03-27 16:05:41 -0700115}
116
117static void WorkAroundJniBugsForJobject(intptr_t* arg_ptr) {
118 intptr_t value = *arg_ptr;
119 Object** value_as_jni_rep = reinterpret_cast<Object**>(value);
120 Object* value_as_work_around_rep = value_as_jni_rep != NULL ? *value_as_jni_rep : NULL;
121 CHECK(Runtime::Current()->GetHeap()->IsHeapAddress(value_as_work_around_rep)) << value_as_work_around_rep;
122 *arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep);
123}
124
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700125extern "C" const void* artWorkAroundAppJniBugs(Thread* self, intptr_t* sp)
Ian Rogersb726dcb2012-09-05 08:57:23 -0700126 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_){
Ian Rogers57b86d42012-03-27 16:05:41 -0700127 DCHECK(Thread::Current() == self);
128 // TODO: this code is specific to ARM
129 // On entry the stack pointed by sp is:
130 // | arg3 | <- Calling JNI method's frame (and extra bit for out args)
131 // | LR |
132 // | R3 | arg2
133 // | R2 | arg1
134 // | R1 | jclass/jobject
135 // | R0 | JNIEnv
136 // | unused |
137 // | unused |
138 // | unused | <- sp
Ian Rogers0399dde2012-06-06 17:09:28 -0700139 Method* jni_method = self->GetCurrentMethod();
Ian Rogers57b86d42012-03-27 16:05:41 -0700140 DCHECK(jni_method->IsNative()) << PrettyMethod(jni_method);
141 intptr_t* arg_ptr = sp + 4; // pointer to r1 on stack
142 // Fix up this/jclass argument
143 WorkAroundJniBugsForJobject(arg_ptr);
144 arg_ptr++;
145 // Fix up jobject arguments
146 MethodHelper mh(jni_method);
147 int reg_num = 2; // Current register being processed, -1 for stack arguments.
148 for (uint32_t i = 1; i < mh.GetShortyLength(); i++) {
149 char shorty_char = mh.GetShorty()[i];
150 if (shorty_char == 'L') {
151 WorkAroundJniBugsForJobject(arg_ptr);
152 }
153 if (shorty_char == 'J' || shorty_char == 'D') {
154 if (reg_num == 2) {
155 arg_ptr = sp + 8; // skip to out arguments
156 reg_num = -1;
157 } else if (reg_num == 3) {
158 arg_ptr = sp + 10; // skip to out arguments plus 2 slots as long must be aligned
159 reg_num = -1;
160 } else {
Elliott Hughes74847412012-06-20 18:10:21 -0700161 DCHECK_EQ(reg_num, -1);
Ian Rogers57b86d42012-03-27 16:05:41 -0700162 if ((reinterpret_cast<intptr_t>(arg_ptr) & 7) == 4) {
163 arg_ptr += 3; // unaligned, pad and move through stack arguments
164 } else {
165 arg_ptr += 2; // aligned, move through stack arguments
166 }
167 }
168 } else {
169 if (reg_num == 2) {
170 arg_ptr++; // move through register arguments
171 reg_num++;
172 } else if (reg_num == 3) {
173 arg_ptr = sp + 8; // skip to outgoing stack arguments
174 reg_num = -1;
175 } else {
Elliott Hughes74847412012-06-20 18:10:21 -0700176 DCHECK_EQ(reg_num, -1);
Ian Rogers57b86d42012-03-27 16:05:41 -0700177 arg_ptr++; // move through stack arguments
178 }
179 }
180 }
181 // Load expected destination, see Method::RegisterNative
Ian Rogers0c7abda2012-09-19 13:33:42 -0700182 const void* code = reinterpret_cast<const void*>(jni_method->GetNativeGcMap());
Ian Rogers57b86d42012-03-27 16:05:41 -0700183 if (UNLIKELY(code == NULL)) {
184 code = Runtime::Current()->GetJniDlsymLookupStub()->GetData();
185 jni_method->RegisterNative(self, code);
186 }
187 return code;
188}
189
190} // namespace art