blob: 0a1cf8f50b34aebf625dcf67c233c93380b77e7a [file] [log] [blame]
Shih-wei Liao2d831012011-09-28 22:06:53 -07001/*
Elliott Hughes0f3c5532012-03-30 14:51:51 -07002 * Copyright (C) 2012 The Android Open Source Project
Shih-wei Liao2d831012011-09-28 22:06:53 -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 "runtime_support.h"
18
19namespace art {
20
Ian Rogers57b86d42012-03-27 16:05:41 -070021void ThrowNewIllegalAccessErrorClass(Thread* self,
22 Class* referrer,
23 Class* accessed) {
24 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
25 "illegal class access: '%s' -> '%s'",
26 PrettyDescriptor(referrer).c_str(),
27 PrettyDescriptor(accessed).c_str());
Shih-wei Liaoddbd01a2012-03-09 14:42:12 -080028}
29
Ian Rogers57b86d42012-03-27 16:05:41 -070030void ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self,
31 Class* referrer,
32 Class* accessed,
33 const Method* caller,
34 const Method* called,
35 InvokeType type) {
36 std::ostringstream type_stream;
37 type_stream << type;
38 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
39 "illegal class access ('%s' -> '%s')"
40 "in attempt to invoke %s method '%s' from '%s'",
41 PrettyDescriptor(referrer).c_str(),
42 PrettyDescriptor(accessed).c_str(),
43 type_stream.str().c_str(),
44 PrettyMethod(called).c_str(),
45 PrettyMethod(caller).c_str());
buzbee44b412b2012-02-04 08:50:53 -080046}
47
Ian Rogers57b86d42012-03-27 16:05:41 -070048void ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(Thread* self,
49 const Method* referrer,
50 const Method* interface_method,
51 Object* this_object) {
52 self->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
53 "class '%s' does not implement interface '%s' in call to '%s' from '%s'",
54 PrettyDescriptor(this_object->GetClass()).c_str(),
55 PrettyDescriptor(interface_method->GetDeclaringClass()).c_str(),
56 PrettyMethod(interface_method).c_str(), PrettyMethod(referrer).c_str());
Shih-wei Liao2d831012011-09-28 22:06:53 -070057}
58
Ian Rogers57b86d42012-03-27 16:05:41 -070059void ThrowNewIllegalAccessErrorField(Thread* self,
60 Class* referrer,
61 Field* accessed) {
62 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
63 "Field '%s' is inaccessible to class '%s'",
64 PrettyField(accessed, false).c_str(),
65 PrettyDescriptor(referrer).c_str());
Shih-wei Liao2d831012011-09-28 22:06:53 -070066}
67
Ian Rogers57b86d42012-03-27 16:05:41 -070068void ThrowNewIllegalAccessErrorFinalField(Thread* self,
69 const Method* referrer,
70 Field* accessed) {
71 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
72 "Final field '%s' cannot be written to by method '%s'",
73 PrettyField(accessed, false).c_str(),
74 PrettyMethod(referrer).c_str());
Shih-wei Liao2d831012011-09-28 22:06:53 -070075}
76
Ian Rogers57b86d42012-03-27 16:05:41 -070077void ThrowNewIllegalAccessErrorMethod(Thread* self,
78 Class* referrer,
79 Method* accessed) {
80 self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
81 "Method '%s' is inaccessible to class '%s'",
82 PrettyMethod(accessed).c_str(),
83 PrettyDescriptor(referrer).c_str());
Shih-wei Liao2d831012011-09-28 22:06:53 -070084}
85
Ian Rogers57b86d42012-03-27 16:05:41 -070086void ThrowNullPointerExceptionForFieldAccess(Thread* self,
87 Field* field,
88 bool is_read) {
89 self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
90 "Attempt to %s field '%s' on a null object reference",
91 is_read ? "read from" : "write to",
92 PrettyField(field, true).c_str());
Shih-wei Liao2d831012011-09-28 22:06:53 -070093}
94
Ian Rogers57b86d42012-03-27 16:05:41 -070095void ThrowNullPointerExceptionForMethodAccess(Thread* self,
96 Method* caller,
97 uint32_t method_idx,
98 InvokeType type) {
99 const DexFile& dex_file =
100 Runtime::Current()->GetClassLinker()->FindDexFile(caller->GetDeclaringClass()->GetDexCache());
101 std::ostringstream type_stream;
102 type_stream << type;
103 self->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
104 "Attempt to invoke %s method '%s' on a null object reference",
105 type_stream.str().c_str(),
106 PrettyMethod(method_idx, dex_file, true).c_str());
Shih-wei Liao2d831012011-09-28 22:06:53 -0700107}
108
TDYa1273f9137d2012-04-08 15:59:19 -0700109void ThrowNullPointerExceptionFromDexPC(Thread* self, Method* throw_method, uint32_t dex_pc) {
110 const DexFile::CodeItem* code = MethodHelper(throw_method).GetCodeItem();
111 CHECK_LT(dex_pc, code->insns_size_in_code_units_);
112 const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
113 DecodedInstruction dec_insn(instr);
114 switch (instr->Opcode()) {
115 case Instruction::INVOKE_DIRECT:
116 case Instruction::INVOKE_DIRECT_RANGE:
117 ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kDirect);
118 break;
119 case Instruction::INVOKE_VIRTUAL:
120 case Instruction::INVOKE_VIRTUAL_RANGE:
121 ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kVirtual);
122 break;
123 case Instruction::IGET:
124 case Instruction::IGET_WIDE:
125 case Instruction::IGET_OBJECT:
126 case Instruction::IGET_BOOLEAN:
127 case Instruction::IGET_BYTE:
128 case Instruction::IGET_CHAR:
129 case Instruction::IGET_SHORT: {
130 Field* field =
131 Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
132 ThrowNullPointerExceptionForFieldAccess(self, field, true /* read */);
133 break;
134 }
135 case Instruction::IPUT:
136 case Instruction::IPUT_WIDE:
137 case Instruction::IPUT_OBJECT:
138 case Instruction::IPUT_BOOLEAN:
139 case Instruction::IPUT_BYTE:
140 case Instruction::IPUT_CHAR:
141 case Instruction::IPUT_SHORT: {
142 Field* field =
143 Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false);
144 ThrowNullPointerExceptionForFieldAccess(self, field, false /* write */);
145 break;
146 }
147 case Instruction::AGET:
148 case Instruction::AGET_WIDE:
149 case Instruction::AGET_OBJECT:
150 case Instruction::AGET_BOOLEAN:
151 case Instruction::AGET_BYTE:
152 case Instruction::AGET_CHAR:
153 case Instruction::AGET_SHORT:
154 self->ThrowNewException("Ljava/lang/NullPointerException;",
155 "Attempt to read from null array");
156 break;
157 case Instruction::APUT:
158 case Instruction::APUT_WIDE:
159 case Instruction::APUT_OBJECT:
160 case Instruction::APUT_BOOLEAN:
161 case Instruction::APUT_BYTE:
162 case Instruction::APUT_CHAR:
163 case Instruction::APUT_SHORT:
164 self->ThrowNewException("Ljava/lang/NullPointerException;",
165 "Attempt to write to null array");
166 break;
167 default: {
168 const DexFile& dex_file = Runtime::Current()->GetClassLinker()
169 ->FindDexFile(throw_method->GetDeclaringClass()->GetDexCache());
170 std::string message("Null pointer exception during instruction '");
171 message += instr->DumpString(&dex_file);
172 message += "'";
173 self->ThrowNewException("Ljava/lang/NullPointerException;", message.c_str());
174 break;
175 }
176 }
177}
178
Ian Rogers57b86d42012-03-27 16:05:41 -0700179std::string FieldNameFromIndex(const Method* method, uint32_t ref,
180 verifier::VerifyErrorRefType ref_type, bool access) {
Ian Rogersd81871c2011-10-03 13:57:23 -0700181 CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_FIELD));
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700182
183 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
184 const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
185
186 const DexFile::FieldId& id = dex_file.GetFieldId(ref);
Brian Carlstrom6b4ef022011-10-23 14:59:04 -0700187 std::string class_name(PrettyDescriptor(dex_file.GetFieldDeclaringClassDescriptor(id)));
Ian Rogers0571d352011-11-03 19:51:38 -0700188 const char* field_name = dex_file.StringDataByIdx(id.name_idx_);
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700189 if (!access) {
190 return class_name + "." + field_name;
191 }
192
193 std::string result;
194 result += "tried to access field ";
195 result += class_name + "." + field_name;
196 result += " from class ";
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800197 result += PrettyDescriptor(method->GetDeclaringClass());
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700198 return result;
199}
200
Ian Rogers57b86d42012-03-27 16:05:41 -0700201std::string MethodNameFromIndex(const Method* method, uint32_t ref,
202 verifier::VerifyErrorRefType ref_type, bool access) {
Ian Rogersd81871c2011-10-03 13:57:23 -0700203 CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_METHOD));
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700204
205 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
206 const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
207
208 const DexFile::MethodId& id = dex_file.GetMethodId(ref);
Brian Carlstrom6b4ef022011-10-23 14:59:04 -0700209 std::string class_name(PrettyDescriptor(dex_file.GetMethodDeclaringClassDescriptor(id)));
Ian Rogers0571d352011-11-03 19:51:38 -0700210 const char* method_name = dex_file.StringDataByIdx(id.name_idx_);
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700211 if (!access) {
212 return class_name + "." + method_name;
213 }
214
215 std::string result;
216 result += "tried to access method ";
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700217 result += class_name + "." + method_name + ":" +
Ian Rogers0571d352011-11-03 19:51:38 -0700218 dex_file.CreateMethodSignature(id.proto_idx_, NULL);
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700219 result += " from class ";
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800220 result += PrettyDescriptor(method->GetDeclaringClass());
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700221 return result;
222}
223
Logan Chien9e5f5c12012-04-10 13:51:45 +0800224static inline std::string ClassNameFromIndex(const Method* method, uint32_t ref,
225 verifier::VerifyErrorRefType ref_type, bool access) {
226 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
227 const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
228
229 uint16_t type_idx = 0;
230 if (ref_type == verifier::VERIFY_ERROR_REF_FIELD) {
231 const DexFile::FieldId& id = dex_file.GetFieldId(ref);
232 type_idx = id.class_idx_;
233 } else if (ref_type == verifier::VERIFY_ERROR_REF_METHOD) {
234 const DexFile::MethodId& id = dex_file.GetMethodId(ref);
235 type_idx = id.class_idx_;
236 } else if (ref_type == verifier::VERIFY_ERROR_REF_CLASS) {
237 type_idx = ref;
238 } else {
239 CHECK(false) << static_cast<int>(ref_type);
240 }
241
242 std::string class_name(PrettyDescriptor(dex_file.StringByTypeIdx(type_idx)));
243 if (!access) {
244 return class_name;
245 }
246
247 std::string result;
248 result += "tried to access class ";
249 result += class_name;
250 result += " from class ";
251 result += PrettyDescriptor(method->GetDeclaringClass());
252 return result;
253}
254
255void ThrowVerificationError(Thread* self, const Method* method,
256 int32_t kind, int32_t ref) {
257 verifier::VerifyErrorRefType ref_type =
258 static_cast<verifier::VerifyErrorRefType>(kind >> verifier::kVerifyErrorRefTypeShift);
259
260 const char* exception_class = "Ljava/lang/VerifyError;";
261 std::string msg;
262
263 switch (static_cast<verifier::VerifyError>(kind & ~(0xff << verifier::kVerifyErrorRefTypeShift))) {
264 case verifier::VERIFY_ERROR_NO_CLASS:
265 exception_class = "Ljava/lang/NoClassDefFoundError;";
266 msg = ClassNameFromIndex(method, ref, ref_type, false);
267 break;
268 case verifier::VERIFY_ERROR_NO_FIELD:
269 exception_class = "Ljava/lang/NoSuchFieldError;";
270 msg = FieldNameFromIndex(method, ref, ref_type, false);
271 break;
272 case verifier::VERIFY_ERROR_NO_METHOD:
273 exception_class = "Ljava/lang/NoSuchMethodError;";
274 msg = MethodNameFromIndex(method, ref, ref_type, false);
275 break;
276 case verifier::VERIFY_ERROR_ACCESS_CLASS:
277 exception_class = "Ljava/lang/IllegalAccessError;";
278 msg = ClassNameFromIndex(method, ref, ref_type, true);
279 break;
280 case verifier::VERIFY_ERROR_ACCESS_FIELD:
281 exception_class = "Ljava/lang/IllegalAccessError;";
282 msg = FieldNameFromIndex(method, ref, ref_type, true);
283 break;
284 case verifier::VERIFY_ERROR_ACCESS_METHOD:
285 exception_class = "Ljava/lang/IllegalAccessError;";
286 msg = MethodNameFromIndex(method, ref, ref_type, true);
287 break;
288 case verifier::VERIFY_ERROR_CLASS_CHANGE:
289 exception_class = "Ljava/lang/IncompatibleClassChangeError;";
290 msg = ClassNameFromIndex(method, ref, ref_type, false);
291 break;
292 case verifier::VERIFY_ERROR_INSTANTIATION:
293 exception_class = "Ljava/lang/InstantiationError;";
294 msg = ClassNameFromIndex(method, ref, ref_type, false);
295 break;
296 case verifier::VERIFY_ERROR_BAD_CLASS_SOFT:
297 case verifier::VERIFY_ERROR_BAD_CLASS_HARD:
298 // Generic VerifyError; use default exception, no message.
299 break;
300 case verifier::VERIFY_ERROR_NONE:
301 CHECK(false);
302 break;
303 }
304
305 self->ThrowNewException(exception_class, msg.c_str());
306}
307
Ian Rogers57b86d42012-03-27 16:05:41 -0700308// Helper function to allocate array for FILLED_NEW_ARRAY.
309Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
310 Thread* self, bool access_check) {
311 if (UNLIKELY(component_count < 0)) {
312 self->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", component_count);
313 return NULL; // Failure
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700314 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700315 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
316 if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
317 klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
318 if (klass == NULL) { // Error
319 DCHECK(Thread::Current()->IsExceptionPending());
320 return NULL; // Failure
Ian Rogers19846512012-02-24 11:42:47 -0800321 }
Ian Rogersea2a11d2011-10-11 16:48:51 -0700322 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700323 if (UNLIKELY(klass->IsPrimitive() && !klass->IsPrimitiveInt())) {
324 if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
325 Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
326 "Bad filled array request for type %s",
327 PrettyDescriptor(klass).c_str());
Ian Rogers573db4a2011-12-13 15:30:50 -0800328 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700329 Thread::Current()->ThrowNewExceptionF("Ljava/lang/InternalError;",
330 "Found type %s; filled-new-array not implemented for anything but \'int\'",
331 PrettyDescriptor(klass).c_str());
Ian Rogers573db4a2011-12-13 15:30:50 -0800332 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700333 return NULL; // Failure
Ian Rogersad25ac52011-10-04 19:13:33 -0700334 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700335 if (access_check) {
336 Class* referrer = method->GetDeclaringClass();
337 if (UNLIKELY(!referrer->CanAccess(klass))) {
338 ThrowNewIllegalAccessErrorClass(self, referrer, klass);
339 return NULL; // Failure
340 }
Ian Rogers60db5ab2012-02-20 17:02:00 -0800341 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700342 DCHECK(klass->IsArrayClass()) << PrettyClass(klass);
343 return Array::Alloc(klass, component_count);
344 }
345}
346
347// Slow path field resolution and declaring class initialization
348Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
349 bool is_static, bool is_primitive, bool is_set, size_t expected_size) {
350 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
351 Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
352 if (UNLIKELY(resolved_field == NULL)) {
353 DCHECK(self->IsExceptionPending()); // Throw exception and unwind
354 return NULL; // failure
355 } else {
356 Class* fields_class = resolved_field->GetDeclaringClass();
357 Class* referring_class = referrer->GetDeclaringClass();
358 if (UNLIKELY(!referring_class->CanAccess(fields_class))) {
359 ThrowNewIllegalAccessErrorClass(self, referring_class, fields_class);
360 return NULL; // failure
361 } else if (UNLIKELY(!referring_class->CanAccessMember(fields_class,
362 resolved_field->GetAccessFlags()))) {
363 ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
364 return NULL; // failure
365 } else if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
366 ThrowNewIllegalAccessErrorFinalField(self, referrer, resolved_field);
367 return NULL; // failure
368 } else {
369 FieldHelper fh(resolved_field);
370 if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
371 fh.FieldSize() != expected_size)) {
372 self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
373 "Attempted read of %zd-bit %s on field '%s'",
374 expected_size * (32 / sizeof(int32_t)),
375 is_primitive ? "primitive" : "non-primitive",
376 PrettyField(resolved_field, true).c_str());
377 return NULL; // failure
378 } else if (!is_static) {
379 // instance fields must be being accessed on an initialized class
380 return resolved_field;
Ian Rogers60db5ab2012-02-20 17:02:00 -0800381 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700382 // If the class is already initializing, we must be inside <clinit>, or
383 // we'd still be waiting for the lock.
384 if (fields_class->IsInitializing()) {
385 return resolved_field;
Ian Rogers0045a292012-03-31 21:08:41 -0700386 } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700387 return resolved_field;
Ian Rogers60db5ab2012-02-20 17:02:00 -0800388 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700389 DCHECK(self->IsExceptionPending()); // Throw exception and unwind
390 return NULL; // failure
Ian Rogers60db5ab2012-02-20 17:02:00 -0800391 }
392 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700393 }
394 }
395}
396
397// Slow path method resolution
398Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
399 Thread* self, bool access_check, InvokeType type) {
400 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
401 bool is_direct = type == kStatic || type == kDirect;
402 Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, is_direct);
403 if (UNLIKELY(resolved_method == NULL)) {
404 DCHECK(self->IsExceptionPending()); // Throw exception and unwind
405 return NULL; // failure
406 } else {
407 if (!access_check) {
408 if (is_direct) {
409 return resolved_method;
410 } else if (type == kInterface) {
411 Method* interface_method =
412 this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
413 if (UNLIKELY(interface_method == NULL)) {
414 ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
415 resolved_method,
416 this_object);
417 return NULL; // failure
418 } else {
419 return interface_method;
420 }
Ian Rogers60db5ab2012-02-20 17:02:00 -0800421 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700422 ObjectArray<Method>* vtable;
423 uint16_t vtable_index = resolved_method->GetMethodIndex();
424 if (type == kSuper) {
425 vtable = referrer->GetDeclaringClass()->GetSuperClass()->GetVTable();
426 } else {
427 vtable = this_object->GetClass()->GetVTable();
428 }
429 // TODO: eliminate bounds check?
430 return vtable->Get(vtable_index);
431 }
432 } else {
433 Class* methods_class = resolved_method->GetDeclaringClass();
434 Class* referring_class = referrer->GetDeclaringClass();
435 if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
436 !referring_class->CanAccessMember(methods_class,
437 resolved_method->GetAccessFlags()))) {
438 // The referring class can't access the resolved method, this may occur as a result of a
439 // protected method being made public by implementing an interface that re-declares the
440 // method public. Resort to the dex file to determine the correct class for the access check
441 const DexFile& dex_file = class_linker->FindDexFile(referring_class->GetDexCache());
442 methods_class = class_linker->ResolveType(dex_file,
443 dex_file.GetMethodId(method_idx).class_idx_,
444 referring_class);
445 if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
446 ThrowNewIllegalAccessErrorClassForMethodDispatch(self, referring_class, methods_class,
447 referrer, resolved_method, type);
448 return NULL; // failure
449 } else if (UNLIKELY(!referring_class->CanAccessMember(methods_class,
450 resolved_method->GetAccessFlags()))) {
451 ThrowNewIllegalAccessErrorMethod(self, referring_class, resolved_method);
452 return NULL; // failure
453 }
454 }
455 if (is_direct) {
456 return resolved_method;
457 } else if (type == kInterface) {
458 Method* interface_method =
459 this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
460 if (UNLIKELY(interface_method == NULL)) {
461 ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
462 resolved_method,
463 this_object);
464 return NULL; // failure
465 } else {
466 return interface_method;
467 }
468 } else {
469 ObjectArray<Method>* vtable;
470 uint16_t vtable_index = resolved_method->GetMethodIndex();
471 if (type == kSuper) {
472 Class* super_class = referring_class->GetSuperClass();
473 if (LIKELY(super_class != NULL)) {
474 vtable = referring_class->GetSuperClass()->GetVTable();
475 } else {
476 vtable = NULL;
477 }
478 } else {
479 vtable = this_object->GetClass()->GetVTable();
480 }
481 if (LIKELY(vtable != NULL &&
482 vtable_index < static_cast<uint32_t>(vtable->GetLength()))) {
483 return vtable->GetWithoutChecks(vtable_index);
484 } else {
485 // Behavior to agree with that of the verifier
486 self->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
487 "attempt to invoke %s method '%s' from '%s'"
488 " using incorrect form of method dispatch",
489 (type == kSuper ? "super class" : "virtual"),
490 PrettyMethod(resolved_method).c_str(),
491 PrettyMethod(referrer).c_str());
492 return NULL; // failure
493 }
Ian Rogers60db5ab2012-02-20 17:02:00 -0800494 }
495 }
496 }
Ian Rogers60db5ab2012-02-20 17:02:00 -0800497}
498
Ian Rogers57b86d42012-03-27 16:05:41 -0700499Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
500 bool can_run_clinit, bool verify_access) {
501 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
502 Class* klass = class_linker->ResolveType(type_idx, referrer);
503 if (UNLIKELY(klass == NULL)) {
jeffhao441d9122012-03-21 17:29:10 -0700504 CHECK(self->IsExceptionPending());
Ian Rogers57b86d42012-03-27 16:05:41 -0700505 return NULL; // Failure - Indicate to caller to deliver exception
jeffhao441d9122012-03-21 17:29:10 -0700506 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700507 // Perform access check if necessary.
508 Class* referring_class = referrer->GetDeclaringClass();
509 if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) {
510 ThrowNewIllegalAccessErrorClass(self, referring_class, klass);
511 return NULL; // Failure - Indicate to caller to deliver exception
Ian Rogers14b1b242011-10-11 18:54:34 -0700512 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700513 // If we're just implementing const-class, we shouldn't call <clinit>.
514 if (!can_run_clinit) {
515 return klass;
Ian Rogersdfcdf1a2011-10-10 17:50:35 -0700516 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700517 // If we are the <clinit> of this class, just return our storage.
518 //
519 // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
520 // running.
521 if (klass == referring_class && MethodHelper(referrer).IsClassInitializer()) {
522 return klass;
Ian Rogersdfcdf1a2011-10-10 17:50:35 -0700523 }
Ian Rogers0045a292012-03-31 21:08:41 -0700524 if (!class_linker->EnsureInitialized(klass, true, true)) {
Ian Rogers57b86d42012-03-27 16:05:41 -0700525 CHECK(self->IsExceptionPending());
526 return NULL; // Failure - Indicate to caller to deliver exception
Ian Rogersdfcdf1a2011-10-10 17:50:35 -0700527 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700528 referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass);
529 return klass;
Shih-wei Liao2d831012011-09-28 22:06:53 -0700530}
531
532} // namespace art