blob: cfa1a11df85d27770f2cabe0039614b58963b313 [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"
19#include "thread.h"
20
21namespace art {
22
23// Used by the JNI dlsym stub to find the native method to invoke if none is registered.
24extern void* FindNativeMethod(Thread* self) {
25 DCHECK(Thread::Current() == self);
26
27 Method* method = const_cast<Method*>(self->GetCurrentMethod());
28 DCHECK(method != NULL);
29
30 // Lookup symbol address for method, on failure we'll return NULL with an
31 // exception set, otherwise we return the address of the method we found.
32 void* native_code = self->GetJniEnv()->vm->FindCodeForNativeMethod(method);
33 if (native_code == NULL) {
34 DCHECK(self->IsExceptionPending());
35 return NULL;
36 } else {
37 // Register so that future calls don't come here
38 method->RegisterNative(self, native_code);
39 return native_code;
40 }
41}
42
43// Return value helper for jobject return types, used for JNI return values.
Elliott Hughesb264f082012-04-06 17:10:10 -070044extern Object* DecodeJObjectInThread(Thread* self, jobject java_object) {
45 if (self->IsExceptionPending()) {
Ian Rogers57b86d42012-03-27 16:05:41 -070046 return NULL;
47 }
Elliott Hughesb264f082012-04-06 17:10:10 -070048 Object* o = self->DecodeJObject(java_object);
49 if (o == NULL || !self->GetJniEnv()->check_jni) {
50 return o;
51 }
52
53 if (o == kInvalidIndirectRefObject) {
Elliott Hughes3f6635a2012-06-19 13:37:49 -070054 JniAbortF(NULL, "invalid reference returned from %s",
55 PrettyMethod(self->GetCurrentMethod()).c_str());
Elliott Hughesb264f082012-04-06 17:10:10 -070056 }
57
58 // Make sure that the result is an instance of the type this
59 // method was expected to return.
60 Method* m = self->GetCurrentMethod();
61 MethodHelper mh(m);
62 Class* return_type = mh.GetReturnType();
63
64 if (!o->InstanceOf(return_type)) {
Elliott Hughes3f6635a2012-06-19 13:37:49 -070065 JniAbortF(NULL, "attempt to return an instance of %s from %s",
66 PrettyTypeOf(o).c_str(), PrettyMethod(m).c_str());
Elliott Hughesb264f082012-04-06 17:10:10 -070067 }
68
69 return o;
Ian Rogers57b86d42012-03-27 16:05:41 -070070}
71
72static void WorkAroundJniBugsForJobject(intptr_t* arg_ptr) {
73 intptr_t value = *arg_ptr;
74 Object** value_as_jni_rep = reinterpret_cast<Object**>(value);
75 Object* value_as_work_around_rep = value_as_jni_rep != NULL ? *value_as_jni_rep : NULL;
76 CHECK(Runtime::Current()->GetHeap()->IsHeapAddress(value_as_work_around_rep)) << value_as_work_around_rep;
77 *arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep);
78}
79
80extern "C" const void* artWorkAroundAppJniBugs(Thread* self, intptr_t* sp) {
81 DCHECK(Thread::Current() == self);
82 // TODO: this code is specific to ARM
83 // On entry the stack pointed by sp is:
84 // | arg3 | <- Calling JNI method's frame (and extra bit for out args)
85 // | LR |
86 // | R3 | arg2
87 // | R2 | arg1
88 // | R1 | jclass/jobject
89 // | R0 | JNIEnv
90 // | unused |
91 // | unused |
92 // | unused | <- sp
Ian Rogers0399dde2012-06-06 17:09:28 -070093 Method* jni_method = self->GetCurrentMethod();
Ian Rogers57b86d42012-03-27 16:05:41 -070094 DCHECK(jni_method->IsNative()) << PrettyMethod(jni_method);
95 intptr_t* arg_ptr = sp + 4; // pointer to r1 on stack
96 // Fix up this/jclass argument
97 WorkAroundJniBugsForJobject(arg_ptr);
98 arg_ptr++;
99 // Fix up jobject arguments
100 MethodHelper mh(jni_method);
101 int reg_num = 2; // Current register being processed, -1 for stack arguments.
102 for (uint32_t i = 1; i < mh.GetShortyLength(); i++) {
103 char shorty_char = mh.GetShorty()[i];
104 if (shorty_char == 'L') {
105 WorkAroundJniBugsForJobject(arg_ptr);
106 }
107 if (shorty_char == 'J' || shorty_char == 'D') {
108 if (reg_num == 2) {
109 arg_ptr = sp + 8; // skip to out arguments
110 reg_num = -1;
111 } else if (reg_num == 3) {
112 arg_ptr = sp + 10; // skip to out arguments plus 2 slots as long must be aligned
113 reg_num = -1;
114 } else {
Elliott Hughes74847412012-06-20 18:10:21 -0700115 DCHECK_EQ(reg_num, -1);
Ian Rogers57b86d42012-03-27 16:05:41 -0700116 if ((reinterpret_cast<intptr_t>(arg_ptr) & 7) == 4) {
117 arg_ptr += 3; // unaligned, pad and move through stack arguments
118 } else {
119 arg_ptr += 2; // aligned, move through stack arguments
120 }
121 }
122 } else {
123 if (reg_num == 2) {
124 arg_ptr++; // move through register arguments
125 reg_num++;
126 } else if (reg_num == 3) {
127 arg_ptr = sp + 8; // skip to outgoing stack arguments
128 reg_num = -1;
129 } else {
Elliott Hughes74847412012-06-20 18:10:21 -0700130 DCHECK_EQ(reg_num, -1);
Ian Rogers57b86d42012-03-27 16:05:41 -0700131 arg_ptr++; // move through stack arguments
132 }
133 }
134 }
135 // Load expected destination, see Method::RegisterNative
136 const void* code = reinterpret_cast<const void*>(jni_method->GetGcMapRaw());
137 if (UNLIKELY(code == NULL)) {
138 code = Runtime::Current()->GetJniDlsymLookupStub()->GetData();
139 jni_method->RegisterNative(self, code);
140 }
141 return code;
142}
143
144} // namespace art