blob: 26f61cf6dd85eb8d32dcc51749ad181cbf8ff8bf [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"
Elliott Hugheseac76672012-05-24 21:56:51 -070022#include "well_known_classes.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070023
24#include "ScopedLocalRef.h"
25
jeffhaod66a8752012-05-22 15:30:16 -070026#if defined(__arm__)
jeffhao5d05c752012-05-23 10:57:48 -070027#define SP_OFFSET_IN_BYTES 12
jeffhaod66a8752012-05-22 15:30:16 -070028#define FRAME_SIZE_IN_BYTES 48u
jeffhao5d05c752012-05-23 10:57:48 -070029#define ARG2_OFFSET_IN_WORDS 11 // offset to 3rd arg; skip callee saves, LR, Method* and out arg spills for OUT0 to OUT2
jeffhaod66a8752012-05-22 15:30:16 -070030#elif defined(__i386__)
jeffhao5d05c752012-05-23 10:57:48 -070031#define SP_OFFSET_IN_BYTES 8
jeffhaod66a8752012-05-22 15:30:16 -070032#define FRAME_SIZE_IN_BYTES 32u
jeffhao5d05c752012-05-23 10:57:48 -070033#define ARG2_OFFSET_IN_WORDS 8 // offset to 3rd arg; skip callee saves, LR, Method* and out arg spills for OUT0 to OUT2
jeffhaod66a8752012-05-22 15:30:16 -070034#else
jeffhao5d05c752012-05-23 10:57:48 -070035#error "Unsupported architecture"
jeffhaod66a8752012-05-22 15:30:16 -070036#endif
37
Ian Rogers57b86d42012-03-27 16:05:41 -070038namespace art {
39
Ian Rogers57b86d42012-03-27 16:05:41 -070040// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
41// which is responsible for recording callee save registers. We explicitly handlerize incoming
42// reference arguments (so they survive GC) and create a boxed argument array. Finally we invoke
43// the invocation handler which is a field within the proxy object receiver.
44extern "C" void artProxyInvokeHandler(Method* proxy_method, Object* receiver,
45 Thread* self, byte* stack_args) {
46 // Register the top of the managed stack
jeffhao5d05c752012-05-23 10:57:48 -070047 Method** proxy_sp = reinterpret_cast<Method**>(stack_args - SP_OFFSET_IN_BYTES);
Ian Rogers57b86d42012-03-27 16:05:41 -070048 DCHECK_EQ(*proxy_sp, proxy_method);
49 self->SetTopOfStack(proxy_sp, 0);
jeffhaod66a8752012-05-22 15:30:16 -070050 DCHECK_EQ(proxy_method->GetFrameSizeInBytes(), FRAME_SIZE_IN_BYTES);
Ian Rogers57b86d42012-03-27 16:05:41 -070051 // Start new JNI local reference state
52 JNIEnvExt* env = self->GetJniEnv();
53 ScopedJniEnvLocalRefState env_state(env);
54 // Create local ref. copies of proxy method and the receiver
55 jobject rcvr_jobj = AddLocalReference<jobject>(env, receiver);
56 jobject proxy_method_jobj = AddLocalReference<jobject>(env, proxy_method);
57
58 // Placing into local references incoming arguments from the caller's register arguments,
59 // replacing original Object* with jobject
60 MethodHelper proxy_mh(proxy_method);
61 const size_t num_params = proxy_mh.NumArgs();
62 size_t args_in_regs = 0;
63 for (size_t i = 1; i < num_params; i++) { // skip receiver
64 args_in_regs = args_in_regs + (proxy_mh.IsParamALongOrDouble(i) ? 2 : 1);
65 if (args_in_regs > 2) {
66 args_in_regs = 2;
67 break;
68 }
69 }
70 size_t cur_arg = 0; // current stack location to read
71 size_t param_index = 1; // skip receiver
72 while (cur_arg < args_in_regs && param_index < num_params) {
73 if (proxy_mh.IsParamAReference(param_index)) {
74 Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
75 jobject jobj = AddLocalReference<jobject>(env, obj);
76 *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
77 }
78 cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
79 param_index++;
80 }
81 // Placing into local references incoming arguments from the caller's stack arguments
jeffhao5d05c752012-05-23 10:57:48 -070082 cur_arg += ARG2_OFFSET_IN_WORDS;
Ian Rogers57b86d42012-03-27 16:05:41 -070083 while (param_index < num_params) {
84 if (proxy_mh.IsParamAReference(param_index)) {
85 Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
86 jobject jobj = AddLocalReference<jobject>(env, obj);
87 *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
88 }
89 cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
90 param_index++;
91 }
92 // Set up arguments array and place in local IRT during boxing (which may allocate/GC)
93 jvalue args_jobj[3];
94 args_jobj[0].l = rcvr_jobj;
95 args_jobj[1].l = proxy_method_jobj;
96 // Args array, if no arguments then NULL (don't include receiver in argument count)
97 args_jobj[2].l = NULL;
98 ObjectArray<Object>* args = NULL;
99 if ((num_params - 1) > 0) {
100 args = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(num_params - 1);
101 if (args == NULL) {
102 CHECK(self->IsExceptionPending());
103 return;
104 }
105 args_jobj[2].l = AddLocalReference<jobjectArray>(env, args);
106 }
107 // Convert proxy method into expected interface method
108 Method* interface_method = proxy_method->FindOverriddenMethod();
109 DCHECK(interface_method != NULL);
110 DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
111 args_jobj[1].l = AddLocalReference<jobject>(env, interface_method);
112 // Box arguments
113 cur_arg = 0; // reset stack location to read to start
114 // reset index, will index into param type array which doesn't include the receiver
115 param_index = 0;
116 ObjectArray<Class>* param_types = proxy_mh.GetParameterTypes();
117 if (param_types == NULL) {
118 CHECK(self->IsExceptionPending());
119 return;
120 }
121 // Check number of parameter types agrees with number from the Method - less 1 for the receiver.
122 DCHECK_EQ(static_cast<size_t>(param_types->GetLength()), num_params - 1);
123 while (cur_arg < args_in_regs && param_index < (num_params - 1)) {
124 Class* param_type = param_types->Get(param_index);
125 Object* obj;
126 if (!param_type->IsPrimitive()) {
127 obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
128 } else {
129 JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
130 if (cur_arg == 1 && (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble())) {
131 // long/double split over regs and stack, mask in high half from stack arguments
jeffhao5d05c752012-05-23 10:57:48 -0700132 uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args + ((ARG2_OFFSET_IN_WORDS + 2) * kPointerSize));
Elliott Hughesf24d3ce2012-04-11 17:43:37 -0700133 val.SetJ((val.GetJ() & 0xffffffffULL) | (high_half << 32));
Ian Rogers57b86d42012-03-27 16:05:41 -0700134 }
135 BoxPrimitive(param_type->GetPrimitiveType(), val);
136 if (self->IsExceptionPending()) {
137 return;
138 }
Elliott Hughesf24d3ce2012-04-11 17:43:37 -0700139 obj = val.GetL();
Ian Rogers57b86d42012-03-27 16:05:41 -0700140 }
141 args->Set(param_index, obj);
142 cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
143 param_index++;
144 }
145 // Placing into local references incoming arguments from the caller's stack arguments
jeffhao5d05c752012-05-23 10:57:48 -0700146 cur_arg += ARG2_OFFSET_IN_WORDS;
Ian Rogers57b86d42012-03-27 16:05:41 -0700147 while (param_index < (num_params - 1)) {
148 Class* param_type = param_types->Get(param_index);
149 Object* obj;
150 if (!param_type->IsPrimitive()) {
151 obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
152 } else {
153 JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
154 BoxPrimitive(param_type->GetPrimitiveType(), val);
155 if (self->IsExceptionPending()) {
156 return;
157 }
Elliott Hughesf24d3ce2012-04-11 17:43:37 -0700158 obj = val.GetL();
Ian Rogers57b86d42012-03-27 16:05:41 -0700159 }
160 args->Set(param_index, obj);
161 cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
162 param_index++;
163 }
164 // Get the InvocationHandler method and the field that holds it within the Proxy object
Elliott Hugheseac76672012-05-24 21:56:51 -0700165 DCHECK(env->IsInstanceOf(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy));
166 jobject inv_hand = env->GetObjectField(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy_h);
Ian Rogers57b86d42012-03-27 16:05:41 -0700167 // Call InvocationHandler.invoke
Elliott Hugheseac76672012-05-24 21:56:51 -0700168 jobject result = env->CallObjectMethodA(inv_hand, WellKnownClasses::java_lang_reflect_InvocationHandler_invoke, args_jobj);
Ian Rogers57b86d42012-03-27 16:05:41 -0700169 // Place result in stack args
170 if (!self->IsExceptionPending()) {
171 Object* result_ref = self->DecodeJObject(result);
172 if (result_ref != NULL) {
173 JValue result_unboxed;
Elliott Hughesaaa5edc2012-05-16 15:54:30 -0700174 bool unboxed_okay = UnboxPrimitiveForResult(result_ref, proxy_mh.GetReturnType(), result_unboxed);
Ian Rogers57b86d42012-03-27 16:05:41 -0700175 if (!unboxed_okay) {
176 self->ClearException();
177 self->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
178 "Couldn't convert result of type %s to %s",
179 PrettyTypeOf(result_ref).c_str(),
180 PrettyDescriptor(proxy_mh.GetReturnType()).c_str());
181 return;
182 }
183 *reinterpret_cast<JValue*>(stack_args) = result_unboxed;
184 } else {
185 *reinterpret_cast<jobject*>(stack_args) = NULL;
186 }
187 } else {
188 // In the case of checked exceptions that aren't declared, the exception must be wrapped by
189 // a UndeclaredThrowableException.
190 Throwable* exception = self->GetException();
191 self->ClearException();
192 if (!exception->IsCheckedException()) {
193 self->SetException(exception);
194 } else {
195 SynthesizedProxyClass* proxy_class =
196 down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
197 int throws_index = -1;
198 size_t num_virt_methods = proxy_class->NumVirtualMethods();
199 for (size_t i = 0; i < num_virt_methods; i++) {
200 if (proxy_class->GetVirtualMethod(i) == proxy_method) {
201 throws_index = i;
202 break;
203 }
204 }
205 CHECK_NE(throws_index, -1);
206 ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
207 Class* exception_class = exception->GetClass();
208 bool declares_exception = false;
209 for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
210 Class* declared_exception = declared_exceptions->Get(i);
211 declares_exception = declared_exception->IsAssignableFrom(exception_class);
212 }
213 if (declares_exception) {
214 self->SetException(exception);
215 } else {
216 ThrowNewUndeclaredThrowableException(self, env, exception);
217 }
218 }
219 }
220}
221
222} // namespace art