blob: 9072d58712b65900786527fefb1226d751c651bc [file] [log] [blame]
Shih-wei Liao2d831012011-09-28 22:06:53 -07001/*
Ian Rogers57b86d42012-03-27 16:05:41 -07002 * Copyright 2012 Google Inc. All Rights Reserved.
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
Ian Rogers57b86d42012-03-27 16:05:41 -0700109std::string FieldNameFromIndex(const Method* method, uint32_t ref,
110 verifier::VerifyErrorRefType ref_type, bool access) {
Ian Rogersd81871c2011-10-03 13:57:23 -0700111 CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_FIELD));
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700112
113 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
114 const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
115
116 const DexFile::FieldId& id = dex_file.GetFieldId(ref);
Brian Carlstrom6b4ef022011-10-23 14:59:04 -0700117 std::string class_name(PrettyDescriptor(dex_file.GetFieldDeclaringClassDescriptor(id)));
Ian Rogers0571d352011-11-03 19:51:38 -0700118 const char* field_name = dex_file.StringDataByIdx(id.name_idx_);
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700119 if (!access) {
120 return class_name + "." + field_name;
121 }
122
123 std::string result;
124 result += "tried to access field ";
125 result += class_name + "." + field_name;
126 result += " from class ";
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800127 result += PrettyDescriptor(method->GetDeclaringClass());
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700128 return result;
129}
130
Ian Rogers57b86d42012-03-27 16:05:41 -0700131std::string MethodNameFromIndex(const Method* method, uint32_t ref,
132 verifier::VerifyErrorRefType ref_type, bool access) {
Ian Rogersd81871c2011-10-03 13:57:23 -0700133 CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_METHOD));
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700134
135 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
136 const DexFile& dex_file = class_linker->FindDexFile(method->GetDeclaringClass()->GetDexCache());
137
138 const DexFile::MethodId& id = dex_file.GetMethodId(ref);
Brian Carlstrom6b4ef022011-10-23 14:59:04 -0700139 std::string class_name(PrettyDescriptor(dex_file.GetMethodDeclaringClassDescriptor(id)));
Ian Rogers0571d352011-11-03 19:51:38 -0700140 const char* method_name = dex_file.StringDataByIdx(id.name_idx_);
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700141 if (!access) {
142 return class_name + "." + method_name;
143 }
144
145 std::string result;
146 result += "tried to access method ";
Ian Rogers4f0d07c2011-10-06 23:38:47 -0700147 result += class_name + "." + method_name + ":" +
Ian Rogers0571d352011-11-03 19:51:38 -0700148 dex_file.CreateMethodSignature(id.proto_idx_, NULL);
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700149 result += " from class ";
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800150 result += PrettyDescriptor(method->GetDeclaringClass());
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700151 return result;
152}
153
Ian Rogers57b86d42012-03-27 16:05:41 -0700154// Helper function to allocate array for FILLED_NEW_ARRAY.
155Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
156 Thread* self, bool access_check) {
157 if (UNLIKELY(component_count < 0)) {
158 self->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", component_count);
159 return NULL; // Failure
Elliott Hughes6c8867d2011-10-03 16:34:05 -0700160 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700161 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
162 if (UNLIKELY(klass == NULL)) { // Not in dex cache so try to resolve
163 klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
164 if (klass == NULL) { // Error
165 DCHECK(Thread::Current()->IsExceptionPending());
166 return NULL; // Failure
Ian Rogers19846512012-02-24 11:42:47 -0800167 }
Ian Rogersea2a11d2011-10-11 16:48:51 -0700168 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700169 if (UNLIKELY(klass->IsPrimitive() && !klass->IsPrimitiveInt())) {
170 if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
171 Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
172 "Bad filled array request for type %s",
173 PrettyDescriptor(klass).c_str());
Ian Rogers573db4a2011-12-13 15:30:50 -0800174 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700175 Thread::Current()->ThrowNewExceptionF("Ljava/lang/InternalError;",
176 "Found type %s; filled-new-array not implemented for anything but \'int\'",
177 PrettyDescriptor(klass).c_str());
Ian Rogers573db4a2011-12-13 15:30:50 -0800178 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700179 return NULL; // Failure
Ian Rogersad25ac52011-10-04 19:13:33 -0700180 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700181 if (access_check) {
182 Class* referrer = method->GetDeclaringClass();
183 if (UNLIKELY(!referrer->CanAccess(klass))) {
184 ThrowNewIllegalAccessErrorClass(self, referrer, klass);
185 return NULL; // Failure
186 }
Ian Rogers60db5ab2012-02-20 17:02:00 -0800187 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700188 DCHECK(klass->IsArrayClass()) << PrettyClass(klass);
189 return Array::Alloc(klass, component_count);
190 }
191}
192
193// Slow path field resolution and declaring class initialization
194Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
195 bool is_static, bool is_primitive, bool is_set, size_t expected_size) {
196 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
197 Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
198 if (UNLIKELY(resolved_field == NULL)) {
199 DCHECK(self->IsExceptionPending()); // Throw exception and unwind
200 return NULL; // failure
201 } else {
202 Class* fields_class = resolved_field->GetDeclaringClass();
203 Class* referring_class = referrer->GetDeclaringClass();
204 if (UNLIKELY(!referring_class->CanAccess(fields_class))) {
205 ThrowNewIllegalAccessErrorClass(self, referring_class, fields_class);
206 return NULL; // failure
207 } else if (UNLIKELY(!referring_class->CanAccessMember(fields_class,
208 resolved_field->GetAccessFlags()))) {
209 ThrowNewIllegalAccessErrorField(self, referring_class, resolved_field);
210 return NULL; // failure
211 } else if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) {
212 ThrowNewIllegalAccessErrorFinalField(self, referrer, resolved_field);
213 return NULL; // failure
214 } else {
215 FieldHelper fh(resolved_field);
216 if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
217 fh.FieldSize() != expected_size)) {
218 self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
219 "Attempted read of %zd-bit %s on field '%s'",
220 expected_size * (32 / sizeof(int32_t)),
221 is_primitive ? "primitive" : "non-primitive",
222 PrettyField(resolved_field, true).c_str());
223 return NULL; // failure
224 } else if (!is_static) {
225 // instance fields must be being accessed on an initialized class
226 return resolved_field;
Ian Rogers60db5ab2012-02-20 17:02:00 -0800227 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700228 // If the class is already initializing, we must be inside <clinit>, or
229 // we'd still be waiting for the lock.
230 if (fields_class->IsInitializing()) {
231 return resolved_field;
232 } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true)) {
233 return resolved_field;
Ian Rogers60db5ab2012-02-20 17:02:00 -0800234 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700235 DCHECK(self->IsExceptionPending()); // Throw exception and unwind
236 return NULL; // failure
Ian Rogers60db5ab2012-02-20 17:02:00 -0800237 }
238 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700239 }
240 }
241}
242
243// Slow path method resolution
244Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
245 Thread* self, bool access_check, InvokeType type) {
246 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
247 bool is_direct = type == kStatic || type == kDirect;
248 Method* resolved_method = class_linker->ResolveMethod(method_idx, referrer, is_direct);
249 if (UNLIKELY(resolved_method == NULL)) {
250 DCHECK(self->IsExceptionPending()); // Throw exception and unwind
251 return NULL; // failure
252 } else {
253 if (!access_check) {
254 if (is_direct) {
255 return resolved_method;
256 } else if (type == kInterface) {
257 Method* interface_method =
258 this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
259 if (UNLIKELY(interface_method == NULL)) {
260 ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
261 resolved_method,
262 this_object);
263 return NULL; // failure
264 } else {
265 return interface_method;
266 }
Ian Rogers60db5ab2012-02-20 17:02:00 -0800267 } else {
Ian Rogers57b86d42012-03-27 16:05:41 -0700268 ObjectArray<Method>* vtable;
269 uint16_t vtable_index = resolved_method->GetMethodIndex();
270 if (type == kSuper) {
271 vtable = referrer->GetDeclaringClass()->GetSuperClass()->GetVTable();
272 } else {
273 vtable = this_object->GetClass()->GetVTable();
274 }
275 // TODO: eliminate bounds check?
276 return vtable->Get(vtable_index);
277 }
278 } else {
279 Class* methods_class = resolved_method->GetDeclaringClass();
280 Class* referring_class = referrer->GetDeclaringClass();
281 if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
282 !referring_class->CanAccessMember(methods_class,
283 resolved_method->GetAccessFlags()))) {
284 // The referring class can't access the resolved method, this may occur as a result of a
285 // protected method being made public by implementing an interface that re-declares the
286 // method public. Resort to the dex file to determine the correct class for the access check
287 const DexFile& dex_file = class_linker->FindDexFile(referring_class->GetDexCache());
288 methods_class = class_linker->ResolveType(dex_file,
289 dex_file.GetMethodId(method_idx).class_idx_,
290 referring_class);
291 if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
292 ThrowNewIllegalAccessErrorClassForMethodDispatch(self, referring_class, methods_class,
293 referrer, resolved_method, type);
294 return NULL; // failure
295 } else if (UNLIKELY(!referring_class->CanAccessMember(methods_class,
296 resolved_method->GetAccessFlags()))) {
297 ThrowNewIllegalAccessErrorMethod(self, referring_class, resolved_method);
298 return NULL; // failure
299 }
300 }
301 if (is_direct) {
302 return resolved_method;
303 } else if (type == kInterface) {
304 Method* interface_method =
305 this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
306 if (UNLIKELY(interface_method == NULL)) {
307 ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(self, referrer,
308 resolved_method,
309 this_object);
310 return NULL; // failure
311 } else {
312 return interface_method;
313 }
314 } else {
315 ObjectArray<Method>* vtable;
316 uint16_t vtable_index = resolved_method->GetMethodIndex();
317 if (type == kSuper) {
318 Class* super_class = referring_class->GetSuperClass();
319 if (LIKELY(super_class != NULL)) {
320 vtable = referring_class->GetSuperClass()->GetVTable();
321 } else {
322 vtable = NULL;
323 }
324 } else {
325 vtable = this_object->GetClass()->GetVTable();
326 }
327 if (LIKELY(vtable != NULL &&
328 vtable_index < static_cast<uint32_t>(vtable->GetLength()))) {
329 return vtable->GetWithoutChecks(vtable_index);
330 } else {
331 // Behavior to agree with that of the verifier
332 self->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
333 "attempt to invoke %s method '%s' from '%s'"
334 " using incorrect form of method dispatch",
335 (type == kSuper ? "super class" : "virtual"),
336 PrettyMethod(resolved_method).c_str(),
337 PrettyMethod(referrer).c_str());
338 return NULL; // failure
339 }
Ian Rogers60db5ab2012-02-20 17:02:00 -0800340 }
341 }
342 }
Ian Rogers60db5ab2012-02-20 17:02:00 -0800343}
344
Ian Rogers57b86d42012-03-27 16:05:41 -0700345Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
346 bool can_run_clinit, bool verify_access) {
347 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
348 Class* klass = class_linker->ResolveType(type_idx, referrer);
349 if (UNLIKELY(klass == NULL)) {
jeffhao441d9122012-03-21 17:29:10 -0700350 CHECK(self->IsExceptionPending());
Ian Rogers57b86d42012-03-27 16:05:41 -0700351 return NULL; // Failure - Indicate to caller to deliver exception
jeffhao441d9122012-03-21 17:29:10 -0700352 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700353 // Perform access check if necessary.
354 Class* referring_class = referrer->GetDeclaringClass();
355 if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) {
356 ThrowNewIllegalAccessErrorClass(self, referring_class, klass);
357 return NULL; // Failure - Indicate to caller to deliver exception
Ian Rogers14b1b242011-10-11 18:54:34 -0700358 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700359 // If we're just implementing const-class, we shouldn't call <clinit>.
360 if (!can_run_clinit) {
361 return klass;
Ian Rogersdfcdf1a2011-10-10 17:50:35 -0700362 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700363 // If we are the <clinit> of this class, just return our storage.
364 //
365 // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished
366 // running.
367 if (klass == referring_class && MethodHelper(referrer).IsClassInitializer()) {
368 return klass;
Ian Rogersdfcdf1a2011-10-10 17:50:35 -0700369 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700370 if (!class_linker->EnsureInitialized(klass, true)) {
371 CHECK(self->IsExceptionPending());
372 return NULL; // Failure - Indicate to caller to deliver exception
Ian Rogersdfcdf1a2011-10-10 17:50:35 -0700373 }
Ian Rogers57b86d42012-03-27 16:05:41 -0700374 referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass);
375 return klass;
Shih-wei Liao2d831012011-09-28 22:06:53 -0700376}
377
378} // namespace art