blob: dd92fb19f5f5ffa34c40e9cfd9e700eac2744ca1 [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 "reflection.h"
20#include "thread.h"
21
22#include "ScopedLocalRef.h"
23
24namespace art {
25
26static void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception) {
27 ScopedLocalRef<jclass> jlr_UTE_class(env,
28 env->FindClass("java/lang/reflect/UndeclaredThrowableException"));
29 if (jlr_UTE_class.get() == NULL) {
30 LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\"";
31 } else {
32 jmethodID jlre_UTE_constructor = env->GetMethodID(jlr_UTE_class.get(), "<init>",
33 "(Ljava/lang/Throwable;)V");
34 jthrowable jexception = AddLocalReference<jthrowable>(env, exception);
35 ScopedLocalRef<jthrowable> jlr_UTE(env,
36 reinterpret_cast<jthrowable>(env->NewObject(jlr_UTE_class.get(), jlre_UTE_constructor,
37 jexception)));
38 int rc = env->Throw(jlr_UTE.get());
39 if (rc != JNI_OK) {
40 LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\"";
41 }
42 }
43 CHECK(self->IsExceptionPending());
44}
45
46// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
47// which is responsible for recording callee save registers. We explicitly handlerize incoming
48// reference arguments (so they survive GC) and create a boxed argument array. Finally we invoke
49// the invocation handler which is a field within the proxy object receiver.
50extern "C" void artProxyInvokeHandler(Method* proxy_method, Object* receiver,
51 Thread* self, byte* stack_args) {
52 // Register the top of the managed stack
53 Method** proxy_sp = reinterpret_cast<Method**>(stack_args - 12);
54 DCHECK_EQ(*proxy_sp, proxy_method);
55 self->SetTopOfStack(proxy_sp, 0);
56 // TODO: ARM specific
57 DCHECK_EQ(proxy_method->GetFrameSizeInBytes(), 48u);
58 // Start new JNI local reference state
59 JNIEnvExt* env = self->GetJniEnv();
60 ScopedJniEnvLocalRefState env_state(env);
61 // Create local ref. copies of proxy method and the receiver
62 jobject rcvr_jobj = AddLocalReference<jobject>(env, receiver);
63 jobject proxy_method_jobj = AddLocalReference<jobject>(env, proxy_method);
64
65 // Placing into local references incoming arguments from the caller's register arguments,
66 // replacing original Object* with jobject
67 MethodHelper proxy_mh(proxy_method);
68 const size_t num_params = proxy_mh.NumArgs();
69 size_t args_in_regs = 0;
70 for (size_t i = 1; i < num_params; i++) { // skip receiver
71 args_in_regs = args_in_regs + (proxy_mh.IsParamALongOrDouble(i) ? 2 : 1);
72 if (args_in_regs > 2) {
73 args_in_regs = 2;
74 break;
75 }
76 }
77 size_t cur_arg = 0; // current stack location to read
78 size_t param_index = 1; // skip receiver
79 while (cur_arg < args_in_regs && param_index < num_params) {
80 if (proxy_mh.IsParamAReference(param_index)) {
81 Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
82 jobject jobj = AddLocalReference<jobject>(env, obj);
83 *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
84 }
85 cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
86 param_index++;
87 }
88 // Placing into local references incoming arguments from the caller's stack arguments
89 cur_arg += 11; // skip callee saves, LR, Method* and out arg spills for R1 to R3
90 while (param_index < num_params) {
91 if (proxy_mh.IsParamAReference(param_index)) {
92 Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
93 jobject jobj = AddLocalReference<jobject>(env, obj);
94 *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
95 }
96 cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
97 param_index++;
98 }
99 // Set up arguments array and place in local IRT during boxing (which may allocate/GC)
100 jvalue args_jobj[3];
101 args_jobj[0].l = rcvr_jobj;
102 args_jobj[1].l = proxy_method_jobj;
103 // Args array, if no arguments then NULL (don't include receiver in argument count)
104 args_jobj[2].l = NULL;
105 ObjectArray<Object>* args = NULL;
106 if ((num_params - 1) > 0) {
107 args = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(num_params - 1);
108 if (args == NULL) {
109 CHECK(self->IsExceptionPending());
110 return;
111 }
112 args_jobj[2].l = AddLocalReference<jobjectArray>(env, args);
113 }
114 // Convert proxy method into expected interface method
115 Method* interface_method = proxy_method->FindOverriddenMethod();
116 DCHECK(interface_method != NULL);
117 DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
118 args_jobj[1].l = AddLocalReference<jobject>(env, interface_method);
119 // Box arguments
120 cur_arg = 0; // reset stack location to read to start
121 // reset index, will index into param type array which doesn't include the receiver
122 param_index = 0;
123 ObjectArray<Class>* param_types = proxy_mh.GetParameterTypes();
124 if (param_types == NULL) {
125 CHECK(self->IsExceptionPending());
126 return;
127 }
128 // Check number of parameter types agrees with number from the Method - less 1 for the receiver.
129 DCHECK_EQ(static_cast<size_t>(param_types->GetLength()), num_params - 1);
130 while (cur_arg < args_in_regs && param_index < (num_params - 1)) {
131 Class* param_type = param_types->Get(param_index);
132 Object* obj;
133 if (!param_type->IsPrimitive()) {
134 obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
135 } else {
136 JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
137 if (cur_arg == 1 && (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble())) {
138 // long/double split over regs and stack, mask in high half from stack arguments
139 uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args + (13 * kPointerSize));
140 val.j = (val.j & 0xffffffffULL) | (high_half << 32);
141 }
142 BoxPrimitive(param_type->GetPrimitiveType(), val);
143 if (self->IsExceptionPending()) {
144 return;
145 }
146 obj = val.l;
147 }
148 args->Set(param_index, obj);
149 cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
150 param_index++;
151 }
152 // Placing into local references incoming arguments from the caller's stack arguments
153 cur_arg += 11; // skip callee saves, LR, Method* and out arg spills for R1 to R3
154 while (param_index < (num_params - 1)) {
155 Class* param_type = param_types->Get(param_index);
156 Object* obj;
157 if (!param_type->IsPrimitive()) {
158 obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
159 } else {
160 JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
161 BoxPrimitive(param_type->GetPrimitiveType(), val);
162 if (self->IsExceptionPending()) {
163 return;
164 }
165 obj = val.l;
166 }
167 args->Set(param_index, obj);
168 cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
169 param_index++;
170 }
171 // Get the InvocationHandler method and the field that holds it within the Proxy object
172 static jmethodID inv_hand_invoke_mid = NULL;
173 static jfieldID proxy_inv_hand_fid = NULL;
174 if (proxy_inv_hand_fid == NULL) {
175 ScopedLocalRef<jclass> proxy(env, env->FindClass("java/lang/reflect/Proxy"));
176 proxy_inv_hand_fid = env->GetFieldID(proxy.get(), "h", "Ljava/lang/reflect/InvocationHandler;");
177 ScopedLocalRef<jclass> inv_hand_class(env, env->FindClass("java/lang/reflect/InvocationHandler"));
178 inv_hand_invoke_mid = env->GetMethodID(inv_hand_class.get(), "invoke",
179 "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
180 }
181 DCHECK(env->IsInstanceOf(rcvr_jobj, env->FindClass("java/lang/reflect/Proxy")));
182 jobject inv_hand = env->GetObjectField(rcvr_jobj, proxy_inv_hand_fid);
183 // Call InvocationHandler.invoke
184 jobject result = env->CallObjectMethodA(inv_hand, inv_hand_invoke_mid, args_jobj);
185 // Place result in stack args
186 if (!self->IsExceptionPending()) {
187 Object* result_ref = self->DecodeJObject(result);
188 if (result_ref != NULL) {
189 JValue result_unboxed;
190 bool unboxed_okay = UnboxPrimitive(result_ref, proxy_mh.GetReturnType(), result_unboxed, "result");
191 if (!unboxed_okay) {
192 self->ClearException();
193 self->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
194 "Couldn't convert result of type %s to %s",
195 PrettyTypeOf(result_ref).c_str(),
196 PrettyDescriptor(proxy_mh.GetReturnType()).c_str());
197 return;
198 }
199 *reinterpret_cast<JValue*>(stack_args) = result_unboxed;
200 } else {
201 *reinterpret_cast<jobject*>(stack_args) = NULL;
202 }
203 } else {
204 // In the case of checked exceptions that aren't declared, the exception must be wrapped by
205 // a UndeclaredThrowableException.
206 Throwable* exception = self->GetException();
207 self->ClearException();
208 if (!exception->IsCheckedException()) {
209 self->SetException(exception);
210 } else {
211 SynthesizedProxyClass* proxy_class =
212 down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
213 int throws_index = -1;
214 size_t num_virt_methods = proxy_class->NumVirtualMethods();
215 for (size_t i = 0; i < num_virt_methods; i++) {
216 if (proxy_class->GetVirtualMethod(i) == proxy_method) {
217 throws_index = i;
218 break;
219 }
220 }
221 CHECK_NE(throws_index, -1);
222 ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
223 Class* exception_class = exception->GetClass();
224 bool declares_exception = false;
225 for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
226 Class* declared_exception = declared_exceptions->Get(i);
227 declares_exception = declared_exception->IsAssignableFrom(exception_class);
228 }
229 if (declares_exception) {
230 self->SetException(exception);
231 } else {
232 ThrowNewUndeclaredThrowableException(self, env, exception);
233 }
234 }
235 }
236}
237
238} // namespace art