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