entrypoint_utils.cc revision 57b86d47b66322693a070185fadfb43cb9c12eab
1/* 2 * Copyright 2012 Google Inc. All Rights Reserved. 3 * 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 21void 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()); 28} 29 30void 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()); 46} 47 48void 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()); 57} 58 59void 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()); 66} 67 68void 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()); 75} 76 77void 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()); 84} 85 86void 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()); 93} 94 95void 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()); 107} 108 109std::string FieldNameFromIndex(const Method* method, uint32_t ref, 110 verifier::VerifyErrorRefType ref_type, bool access) { 111 CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_FIELD)); 112 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); 117 std::string class_name(PrettyDescriptor(dex_file.GetFieldDeclaringClassDescriptor(id))); 118 const char* field_name = dex_file.StringDataByIdx(id.name_idx_); 119 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 "; 127 result += PrettyDescriptor(method->GetDeclaringClass()); 128 return result; 129} 130 131std::string MethodNameFromIndex(const Method* method, uint32_t ref, 132 verifier::VerifyErrorRefType ref_type, bool access) { 133 CHECK_EQ(static_cast<int>(ref_type), static_cast<int>(verifier::VERIFY_ERROR_REF_METHOD)); 134 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); 139 std::string class_name(PrettyDescriptor(dex_file.GetMethodDeclaringClassDescriptor(id))); 140 const char* method_name = dex_file.StringDataByIdx(id.name_idx_); 141 if (!access) { 142 return class_name + "." + method_name; 143 } 144 145 std::string result; 146 result += "tried to access method "; 147 result += class_name + "." + method_name + ":" + 148 dex_file.CreateMethodSignature(id.proto_idx_, NULL); 149 result += " from class "; 150 result += PrettyDescriptor(method->GetDeclaringClass()); 151 return result; 152} 153 154// 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 160 } 161 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 167 } 168 } 169 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()); 174 } else { 175 Thread::Current()->ThrowNewExceptionF("Ljava/lang/InternalError;", 176 "Found type %s; filled-new-array not implemented for anything but \'int\'", 177 PrettyDescriptor(klass).c_str()); 178 } 179 return NULL; // Failure 180 } else { 181 if (access_check) { 182 Class* referrer = method->GetDeclaringClass(); 183 if (UNLIKELY(!referrer->CanAccess(klass))) { 184 ThrowNewIllegalAccessErrorClass(self, referrer, klass); 185 return NULL; // Failure 186 } 187 } 188 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; 227 } else { 228 // 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; 234 } else { 235 DCHECK(self->IsExceptionPending()); // Throw exception and unwind 236 return NULL; // failure 237 } 238 } 239 } 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 } 267 } else { 268 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 } 340 } 341 } 342 } 343} 344 345Class* 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)) { 350 CHECK(self->IsExceptionPending()); 351 return NULL; // Failure - Indicate to caller to deliver exception 352 } 353 // 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 358 } 359 // If we're just implementing const-class, we shouldn't call <clinit>. 360 if (!can_run_clinit) { 361 return klass; 362 } 363 // 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; 369 } 370 if (!class_linker->EnsureInitialized(klass, true)) { 371 CHECK(self->IsExceptionPending()); 372 return NULL; // Failure - Indicate to caller to deliver exception 373 } 374 referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass); 375 return klass; 376} 377 378} // namespace art 379