blob: 1fdab2a4c6272281d5f8f5303e299ab0066dfffa [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 Rogers00f7d0e2012-07-19 15:28:27 -070021#include "scoped_thread_state_change.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070022#include "thread.h"
Elliott Hugheseac76672012-05-24 21:56:51 -070023#include "well_known_classes.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070024
25#include "ScopedLocalRef.h"
26
jeffhaod66a8752012-05-22 15:30:16 -070027#if defined(__arm__)
jeffhao5d05c752012-05-23 10:57:48 -070028#define SP_OFFSET_IN_BYTES 12
jeffhaod66a8752012-05-22 15:30:16 -070029#define FRAME_SIZE_IN_BYTES 48u
jeffhao5d05c752012-05-23 10:57:48 -070030#define ARG2_OFFSET_IN_WORDS 11 // offset to 3rd arg; skip callee saves, LR, Method* and out arg spills for OUT0 to OUT2
jeffhao7fbee072012-08-24 17:56:54 -070031#elif defined(__mips__)
32#define SP_OFFSET_IN_BYTES 8
jeffhao30a33172012-10-22 18:16:22 -070033#define FRAME_SIZE_IN_BYTES 48u
34#define ARG2_OFFSET_IN_WORDS 12 // offset to 3rd arg; skip callee saves, LR, Method* and out arg spills for OUT0 to OUT2
jeffhaod66a8752012-05-22 15:30:16 -070035#elif defined(__i386__)
jeffhao5d05c752012-05-23 10:57:48 -070036#define SP_OFFSET_IN_BYTES 8
jeffhaod66a8752012-05-22 15:30:16 -070037#define FRAME_SIZE_IN_BYTES 32u
jeffhao5d05c752012-05-23 10:57:48 -070038#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 -070039#else
jeffhao5d05c752012-05-23 10:57:48 -070040#error "Unsupported architecture"
Ian Rogersf58dffd2013-01-13 09:25:49 -080041#define SP_OFFSET_IN_BYTES 0
42#define FRAME_SIZE_IN_BYTES 0
43#define ARG2_OFFSET_IN_WORDS 0
jeffhaod66a8752012-05-22 15:30:16 -070044#endif
45
Ian Rogers57b86d42012-03-27 16:05:41 -070046namespace art {
47
Ian Rogers57b86d42012-03-27 16:05:41 -070048// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
49// which is responsible for recording callee save registers. We explicitly handlerize incoming
50// reference arguments (so they survive GC) and create a boxed argument array. Finally we invoke
51// the invocation handler which is a field within the proxy object receiver.
Mathieu Chartier66f19252012-09-18 08:57:04 -070052extern "C" void artProxyInvokeHandler(AbstractMethod* proxy_method, Object* receiver,
Ian Rogers00f7d0e2012-07-19 15:28:27 -070053 Thread* self, byte* stack_args)
Ian Rogersb726dcb2012-09-05 08:57:23 -070054 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Ian Rogersf58dffd2013-01-13 09:25:49 -080055 // Ensure we don't get thread suspension until the object arguments are safely in jobjects.
56 const char* old_cause =
57 self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
58 // Register the top of the managed stack, making stack crawlable.
Mathieu Chartier66f19252012-09-18 08:57:04 -070059 AbstractMethod** proxy_sp = reinterpret_cast<AbstractMethod**>(stack_args - SP_OFFSET_IN_BYTES);
Ian Rogers57b86d42012-03-27 16:05:41 -070060 DCHECK_EQ(*proxy_sp, proxy_method);
61 self->SetTopOfStack(proxy_sp, 0);
jeffhaod66a8752012-05-22 15:30:16 -070062 DCHECK_EQ(proxy_method->GetFrameSizeInBytes(), FRAME_SIZE_IN_BYTES);
Ian Rogersf58dffd2013-01-13 09:25:49 -080063 self->VerifyStack();
64 // Start new JNI local reference state.
Ian Rogers57b86d42012-03-27 16:05:41 -070065 JNIEnvExt* env = self->GetJniEnv();
Ian Rogers00f7d0e2012-07-19 15:28:27 -070066 ScopedObjectAccessUnchecked soa(env);
Ian Rogers57b86d42012-03-27 16:05:41 -070067 ScopedJniEnvLocalRefState env_state(env);
Ian Rogersf58dffd2013-01-13 09:25:49 -080068 // Create local ref. copies of proxy method and the receiver.
Ian Rogers00f7d0e2012-07-19 15:28:27 -070069 jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);
70 jobject proxy_method_jobj = soa.AddLocalReference<jobject>(proxy_method);
Ian Rogers57b86d42012-03-27 16:05:41 -070071
72 // Placing into local references incoming arguments from the caller's register arguments,
Ian Rogersf58dffd2013-01-13 09:25:49 -080073 // replacing original Object* with jobject.
Ian Rogers57b86d42012-03-27 16:05:41 -070074 MethodHelper proxy_mh(proxy_method);
75 const size_t num_params = proxy_mh.NumArgs();
76 size_t args_in_regs = 0;
77 for (size_t i = 1; i < num_params; i++) { // skip receiver
78 args_in_regs = args_in_regs + (proxy_mh.IsParamALongOrDouble(i) ? 2 : 1);
79 if (args_in_regs > 2) {
80 args_in_regs = 2;
81 break;
82 }
83 }
84 size_t cur_arg = 0; // current stack location to read
85 size_t param_index = 1; // skip receiver
86 while (cur_arg < args_in_regs && param_index < num_params) {
87 if (proxy_mh.IsParamAReference(param_index)) {
88 Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
Ian Rogers00f7d0e2012-07-19 15:28:27 -070089 jobject jobj = soa.AddLocalReference<jobject>(obj);
Ian Rogers57b86d42012-03-27 16:05:41 -070090 *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
91 }
92 cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
93 param_index++;
94 }
Ian Rogersf58dffd2013-01-13 09:25:49 -080095 // Placing into local references incoming arguments from the caller's stack arguments.
jeffhao5d05c752012-05-23 10:57:48 -070096 cur_arg += ARG2_OFFSET_IN_WORDS;
Ian Rogers57b86d42012-03-27 16:05:41 -070097 while (param_index < num_params) {
98 if (proxy_mh.IsParamAReference(param_index)) {
99 Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700100 jobject jobj = soa.AddLocalReference<jobject>(obj);
Ian Rogers57b86d42012-03-27 16:05:41 -0700101 *reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)) = jobj;
102 }
103 cur_arg = cur_arg + (proxy_mh.IsParamALongOrDouble(param_index) ? 2 : 1);
104 param_index++;
105 }
Ian Rogersf58dffd2013-01-13 09:25:49 -0800106 self->EndAssertNoThreadSuspension(old_cause);
107 // Sanity check writing the jobjects over the Object*s in place didn't damage the stack.
108 self->VerifyStack();
109
110 // Set up arguments array and place in local IRT during boxing (which may allocate/GC).
Ian Rogers57b86d42012-03-27 16:05:41 -0700111 jvalue args_jobj[3];
112 args_jobj[0].l = rcvr_jobj;
113 args_jobj[1].l = proxy_method_jobj;
Ian Rogersf58dffd2013-01-13 09:25:49 -0800114 // Args array, if no arguments then NULL (don't include receiver in argument count).
Ian Rogers57b86d42012-03-27 16:05:41 -0700115 args_jobj[2].l = NULL;
116 ObjectArray<Object>* args = NULL;
117 if ((num_params - 1) > 0) {
Ian Rogers50b35e22012-10-04 10:09:15 -0700118 args = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(self, num_params - 1);
Ian Rogers57b86d42012-03-27 16:05:41 -0700119 if (args == NULL) {
120 CHECK(self->IsExceptionPending());
121 return;
122 }
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700123 args_jobj[2].l = soa.AddLocalReference<jobjectArray>(args);
Ian Rogers57b86d42012-03-27 16:05:41 -0700124 }
Ian Rogersf58dffd2013-01-13 09:25:49 -0800125 // Convert proxy method into expected interface method.
Mathieu Chartier66f19252012-09-18 08:57:04 -0700126 AbstractMethod* interface_method = proxy_method->FindOverriddenMethod();
Ian Rogers57b86d42012-03-27 16:05:41 -0700127 DCHECK(interface_method != NULL);
128 DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method);
Ian Rogers00f7d0e2012-07-19 15:28:27 -0700129 args_jobj[1].l = soa.AddLocalReference<jobject>(interface_method);
Ian Rogersf58dffd2013-01-13 09:25:49 -0800130 // Box primitive type arguments.
131 cur_arg = 0; // Stack location to read to start.
132 // Reset index, will index into param type array which doesn't include the receiver.
Ian Rogers57b86d42012-03-27 16:05:41 -0700133 param_index = 0;
Ian Rogers50b35e22012-10-04 10:09:15 -0700134 ObjectArray<Class>* param_types = proxy_mh.GetParameterTypes(self);
Ian Rogers57b86d42012-03-27 16:05:41 -0700135 if (param_types == NULL) {
136 CHECK(self->IsExceptionPending());
137 return;
138 }
139 // Check number of parameter types agrees with number from the Method - less 1 for the receiver.
140 DCHECK_EQ(static_cast<size_t>(param_types->GetLength()), num_params - 1);
141 while (cur_arg < args_in_regs && param_index < (num_params - 1)) {
142 Class* param_type = param_types->Get(param_index);
143 Object* obj;
144 if (!param_type->IsPrimitive()) {
145 obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
146 } else {
147 JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
148 if (cur_arg == 1 && (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble())) {
Ian Rogersf58dffd2013-01-13 09:25:49 -0800149 // long/double split over regs and stack, mask in high half from stack arguments.
150 uint64_t high_half =
151 *reinterpret_cast<uint32_t*>(stack_args + ((ARG2_OFFSET_IN_WORDS + 2) * kPointerSize));
Elliott Hughesf24d3ce2012-04-11 17:43:37 -0700152 val.SetJ((val.GetJ() & 0xffffffffULL) | (high_half << 32));
Ian Rogers57b86d42012-03-27 16:05:41 -0700153 }
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 }
Ian Rogersf58dffd2013-01-13 09:25:49 -0800164 // Placing into local references incoming arguments from the caller's stack arguments.
jeffhao5d05c752012-05-23 10:57:48 -0700165 cur_arg += ARG2_OFFSET_IN_WORDS;
Ian Rogers57b86d42012-03-27 16:05:41 -0700166 while (param_index < (num_params - 1)) {
167 Class* param_type = param_types->Get(param_index);
168 Object* obj;
169 if (!param_type->IsPrimitive()) {
170 obj = self->DecodeJObject(*reinterpret_cast<jobject*>(stack_args + (cur_arg * kPointerSize)));
171 } else {
172 JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
173 BoxPrimitive(param_type->GetPrimitiveType(), val);
174 if (self->IsExceptionPending()) {
175 return;
176 }
Elliott Hughesf24d3ce2012-04-11 17:43:37 -0700177 obj = val.GetL();
Ian Rogers57b86d42012-03-27 16:05:41 -0700178 }
179 args->Set(param_index, obj);
180 cur_arg = cur_arg + (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble() ? 2 : 1);
181 param_index++;
182 }
Ian Rogersf58dffd2013-01-13 09:25:49 -0800183 // Get the InvocationHandler method and the field that holds it within the Proxy object.
Elliott Hugheseac76672012-05-24 21:56:51 -0700184 DCHECK(env->IsInstanceOf(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy));
185 jobject inv_hand = env->GetObjectField(rcvr_jobj, WellKnownClasses::java_lang_reflect_Proxy_h);
Ian Rogersf58dffd2013-01-13 09:25:49 -0800186 // Call InvocationHandler.invoke.
187 jobject result =
188 env->CallObjectMethodA(inv_hand, WellKnownClasses::java_lang_reflect_InvocationHandler_invoke,
189 args_jobj);
190 // Place result in stack args.
Ian Rogers57b86d42012-03-27 16:05:41 -0700191 if (!self->IsExceptionPending()) {
192 Object* result_ref = self->DecodeJObject(result);
193 if (result_ref != NULL) {
194 JValue result_unboxed;
Ian Rogersf58dffd2013-01-13 09:25:49 -0800195 bool unboxed_okay = UnboxPrimitiveForResult(result_ref, proxy_mh.GetReturnType(),
196 result_unboxed);
Ian Rogers57b86d42012-03-27 16:05:41 -0700197 if (!unboxed_okay) {
198 self->ClearException();
199 self->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
200 "Couldn't convert result of type %s to %s",
201 PrettyTypeOf(result_ref).c_str(),
202 PrettyDescriptor(proxy_mh.GetReturnType()).c_str());
203 return;
204 }
205 *reinterpret_cast<JValue*>(stack_args) = result_unboxed;
206 } else {
207 *reinterpret_cast<jobject*>(stack_args) = NULL;
208 }
209 } else {
210 // In the case of checked exceptions that aren't declared, the exception must be wrapped by
211 // a UndeclaredThrowableException.
212 Throwable* exception = self->GetException();
Elliott Hughesa4f94742012-05-29 16:28:38 -0700213 if (exception->IsCheckedException()) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700214 SynthesizedProxyClass* proxy_class =
215 down_cast<SynthesizedProxyClass*>(proxy_method->GetDeclaringClass());
216 int throws_index = -1;
217 size_t num_virt_methods = proxy_class->NumVirtualMethods();
218 for (size_t i = 0; i < num_virt_methods; i++) {
219 if (proxy_class->GetVirtualMethod(i) == proxy_method) {
220 throws_index = i;
221 break;
222 }
223 }
224 CHECK_NE(throws_index, -1);
225 ObjectArray<Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
226 Class* exception_class = exception->GetClass();
227 bool declares_exception = false;
228 for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
229 Class* declared_exception = declared_exceptions->Get(i);
230 declares_exception = declared_exception->IsAssignableFrom(exception_class);
231 }
Elliott Hughesa4f94742012-05-29 16:28:38 -0700232 if (!declares_exception) {
233 self->ThrowNewWrappedException("Ljava/lang/reflect/UndeclaredThrowableException;", NULL);
Ian Rogers57b86d42012-03-27 16:05:41 -0700234 }
235 }
236 }
237}
238
239} // namespace art