1 /* 2 * Copyright (C) 2012 The Android Open Source Project 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 #ifndef ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_INL_H_ 18 #define ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_INL_H_ 19 20 #include "entrypoint_utils.h" 21 22 #include "class_linker-inl.h" 23 #include "common_throws.h" 24 #include "dex_file.h" 25 #include "indirect_reference_table.h" 26 #include "invoke_type.h" 27 #include "jni_internal.h" 28 #include "mirror/art_method.h" 29 #include "mirror/array.h" 30 #include "mirror/class-inl.h" 31 #include "mirror/object-inl.h" 32 #include "mirror/throwable.h" 33 #include "handle_scope-inl.h" 34 #include "thread.h" 35 36 namespace art { 37 38 // TODO: Fix no thread safety analysis when GCC can handle template specialization. 39 template <const bool kAccessCheck> 40 static inline mirror::Class* CheckObjectAlloc(uint32_t type_idx, 41 mirror::ArtMethod* method, 42 Thread* self, bool* slow_path) { 43 mirror::Class* klass = method->GetDexCacheResolvedType<false>(type_idx); 44 if (UNLIKELY(klass == NULL)) { 45 klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method); 46 *slow_path = true; 47 if (klass == NULL) { 48 DCHECK(self->IsExceptionPending()); 49 return nullptr; // Failure 50 } else { 51 DCHECK(!self->IsExceptionPending()); 52 } 53 } 54 if (kAccessCheck) { 55 if (UNLIKELY(!klass->IsInstantiable())) { 56 ThrowLocation throw_location = self->GetCurrentLocationForThrow(); 57 self->ThrowNewException(throw_location, "Ljava/lang/InstantiationError;", 58 PrettyDescriptor(klass).c_str()); 59 *slow_path = true; 60 return nullptr; // Failure 61 } 62 mirror::Class* referrer = method->GetDeclaringClass(); 63 if (UNLIKELY(!referrer->CanAccess(klass))) { 64 ThrowIllegalAccessErrorClass(referrer, klass); 65 *slow_path = true; 66 return nullptr; // Failure 67 } 68 } 69 if (UNLIKELY(!klass->IsInitialized())) { 70 StackHandleScope<1> hs(self); 71 Handle<mirror::Class> h_klass(hs.NewHandle(klass)); 72 // EnsureInitialized (the class initializer) might cause a GC. 73 // may cause us to suspend meaning that another thread may try to 74 // change the allocator while we are stuck in the entrypoints of 75 // an old allocator. Also, the class initialization may fail. To 76 // handle these cases we mark the slow path boolean as true so 77 // that the caller knows to check the allocator type to see if it 78 // has changed and to null-check the return value in case the 79 // initialization fails. 80 *slow_path = true; 81 if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_klass, true, true)) { 82 DCHECK(self->IsExceptionPending()); 83 return nullptr; // Failure 84 } else { 85 DCHECK(!self->IsExceptionPending()); 86 } 87 return h_klass.Get(); 88 } 89 return klass; 90 } 91 92 // TODO: Fix no thread safety analysis when annotalysis is smarter. 93 static inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class* klass, 94 Thread* self, 95 bool* slow_path) { 96 if (UNLIKELY(!klass->IsInitialized())) { 97 StackHandleScope<1> hs(self); 98 Handle<mirror::Class> h_class(hs.NewHandle(klass)); 99 // EnsureInitialized (the class initializer) might cause a GC. 100 // may cause us to suspend meaning that another thread may try to 101 // change the allocator while we are stuck in the entrypoints of 102 // an old allocator. Also, the class initialization may fail. To 103 // handle these cases we mark the slow path boolean as true so 104 // that the caller knows to check the allocator type to see if it 105 // has changed and to null-check the return value in case the 106 // initialization fails. 107 *slow_path = true; 108 if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) { 109 DCHECK(self->IsExceptionPending()); 110 return nullptr; // Failure 111 } 112 return h_class.Get(); 113 } 114 return klass; 115 } 116 117 // Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it 118 // cannot be resolved, throw an error. If it can, use it to create an instance. 119 // When verification/compiler hasn't been able to verify access, optionally perform an access 120 // check. 121 // TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter. 122 template <bool kAccessCheck, bool kInstrumented> 123 static inline mirror::Object* AllocObjectFromCode(uint32_t type_idx, 124 mirror::ArtMethod* method, 125 Thread* self, 126 gc::AllocatorType allocator_type) { 127 bool slow_path = false; 128 mirror::Class* klass = CheckObjectAlloc<kAccessCheck>(type_idx, method, self, &slow_path); 129 if (UNLIKELY(slow_path)) { 130 if (klass == nullptr) { 131 return nullptr; 132 } 133 return klass->Alloc<kInstrumented>(self, Runtime::Current()->GetHeap()->GetCurrentAllocator()); 134 } 135 DCHECK(klass != nullptr); 136 return klass->Alloc<kInstrumented>(self, allocator_type); 137 } 138 139 // Given the context of a calling Method and a resolved class, create an instance. 140 // TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter. 141 template <bool kInstrumented> 142 static inline mirror::Object* AllocObjectFromCodeResolved(mirror::Class* klass, 143 mirror::ArtMethod* method, 144 Thread* self, 145 gc::AllocatorType allocator_type) { 146 DCHECK(klass != nullptr); 147 bool slow_path = false; 148 klass = CheckClassInitializedForObjectAlloc(klass, self, &slow_path); 149 if (UNLIKELY(slow_path)) { 150 if (klass == nullptr) { 151 return nullptr; 152 } 153 gc::Heap* heap = Runtime::Current()->GetHeap(); 154 // Pass in false since the object can not be finalizable. 155 return klass->Alloc<kInstrumented, false>(self, heap->GetCurrentAllocator()); 156 } 157 // Pass in false since the object can not be finalizable. 158 return klass->Alloc<kInstrumented, false>(self, allocator_type); 159 } 160 161 // Given the context of a calling Method and an initialized class, create an instance. 162 // TODO: Fix NO_THREAD_SAFETY_ANALYSIS when GCC is smarter. 163 template <bool kInstrumented> 164 static inline mirror::Object* AllocObjectFromCodeInitialized(mirror::Class* klass, 165 mirror::ArtMethod* method, 166 Thread* self, 167 gc::AllocatorType allocator_type) { 168 DCHECK(klass != nullptr); 169 // Pass in false since the object can not be finalizable. 170 return klass->Alloc<kInstrumented, false>(self, allocator_type); 171 } 172 173 174 // TODO: Fix no thread safety analysis when GCC can handle template specialization. 175 template <bool kAccessCheck> 176 static inline mirror::Class* CheckArrayAlloc(uint32_t type_idx, 177 mirror::ArtMethod* method, 178 int32_t component_count, 179 bool* slow_path) { 180 if (UNLIKELY(component_count < 0)) { 181 ThrowNegativeArraySizeException(component_count); 182 *slow_path = true; 183 return nullptr; // Failure 184 } 185 mirror::Class* klass = method->GetDexCacheResolvedType<false>(type_idx); 186 if (UNLIKELY(klass == nullptr)) { // Not in dex cache so try to resolve 187 klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method); 188 *slow_path = true; 189 if (klass == nullptr) { // Error 190 DCHECK(Thread::Current()->IsExceptionPending()); 191 return nullptr; // Failure 192 } 193 CHECK(klass->IsArrayClass()) << PrettyClass(klass); 194 } 195 if (kAccessCheck) { 196 mirror::Class* referrer = method->GetDeclaringClass(); 197 if (UNLIKELY(!referrer->CanAccess(klass))) { 198 ThrowIllegalAccessErrorClass(referrer, klass); 199 *slow_path = true; 200 return nullptr; // Failure 201 } 202 } 203 return klass; 204 } 205 206 // Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If 207 // it cannot be resolved, throw an error. If it can, use it to create an array. 208 // When verification/compiler hasn't been able to verify access, optionally perform an access 209 // check. 210 // TODO: Fix no thread safety analysis when GCC can handle template specialization. 211 template <bool kAccessCheck, bool kInstrumented> 212 static inline mirror::Array* AllocArrayFromCode(uint32_t type_idx, 213 mirror::ArtMethod* method, 214 int32_t component_count, 215 Thread* self, 216 gc::AllocatorType allocator_type) { 217 bool slow_path = false; 218 mirror::Class* klass = CheckArrayAlloc<kAccessCheck>(type_idx, method, component_count, 219 &slow_path); 220 if (UNLIKELY(slow_path)) { 221 if (klass == nullptr) { 222 return nullptr; 223 } 224 gc::Heap* heap = Runtime::Current()->GetHeap(); 225 return mirror::Array::Alloc<kInstrumented>(self, klass, component_count, 226 klass->GetComponentSize(), 227 heap->GetCurrentAllocator()); 228 } 229 return mirror::Array::Alloc<kInstrumented>(self, klass, component_count, 230 klass->GetComponentSize(), allocator_type); 231 } 232 233 template <bool kAccessCheck, bool kInstrumented> 234 static inline mirror::Array* AllocArrayFromCodeResolved(mirror::Class* klass, 235 mirror::ArtMethod* method, 236 int32_t component_count, 237 Thread* self, 238 gc::AllocatorType allocator_type) { 239 DCHECK(klass != nullptr); 240 if (UNLIKELY(component_count < 0)) { 241 ThrowNegativeArraySizeException(component_count); 242 return nullptr; // Failure 243 } 244 if (kAccessCheck) { 245 mirror::Class* referrer = method->GetDeclaringClass(); 246 if (UNLIKELY(!referrer->CanAccess(klass))) { 247 ThrowIllegalAccessErrorClass(referrer, klass); 248 return nullptr; // Failure 249 } 250 } 251 // No need to retry a slow-path allocation as the above code won't cause a GC or thread 252 // suspension. 253 return mirror::Array::Alloc<kInstrumented>(self, klass, component_count, 254 klass->GetComponentSize(), allocator_type); 255 } 256 257 template<FindFieldType type, bool access_check> 258 static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, mirror::ArtMethod* referrer, 259 Thread* self, size_t expected_size) { 260 bool is_primitive; 261 bool is_set; 262 bool is_static; 263 switch (type) { 264 case InstanceObjectRead: is_primitive = false; is_set = false; is_static = false; break; 265 case InstanceObjectWrite: is_primitive = false; is_set = true; is_static = false; break; 266 case InstancePrimitiveRead: is_primitive = true; is_set = false; is_static = false; break; 267 case InstancePrimitiveWrite: is_primitive = true; is_set = true; is_static = false; break; 268 case StaticObjectRead: is_primitive = false; is_set = false; is_static = true; break; 269 case StaticObjectWrite: is_primitive = false; is_set = true; is_static = true; break; 270 case StaticPrimitiveRead: is_primitive = true; is_set = false; is_static = true; break; 271 case StaticPrimitiveWrite: // Keep GCC happy by having a default handler, fall-through. 272 default: is_primitive = true; is_set = true; is_static = true; break; 273 } 274 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 275 mirror::ArtField* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static); 276 if (UNLIKELY(resolved_field == nullptr)) { 277 DCHECK(self->IsExceptionPending()); // Throw exception and unwind. 278 return nullptr; // Failure. 279 } 280 mirror::Class* fields_class = resolved_field->GetDeclaringClass(); 281 if (access_check) { 282 if (UNLIKELY(resolved_field->IsStatic() != is_static)) { 283 ThrowIncompatibleClassChangeErrorField(resolved_field, is_static, referrer); 284 return nullptr; 285 } 286 mirror::Class* referring_class = referrer->GetDeclaringClass(); 287 if (UNLIKELY(!referring_class->CheckResolvedFieldAccess(fields_class, resolved_field, 288 field_idx))) { 289 DCHECK(self->IsExceptionPending()); // Throw exception and unwind. 290 return nullptr; // Failure. 291 } 292 if (UNLIKELY(is_set && resolved_field->IsFinal() && (fields_class != referring_class))) { 293 ThrowIllegalAccessErrorFinalField(referrer, resolved_field); 294 return nullptr; // Failure. 295 } else { 296 if (UNLIKELY(resolved_field->IsPrimitiveType() != is_primitive || 297 resolved_field->FieldSize() != expected_size)) { 298 ThrowLocation throw_location = self->GetCurrentLocationForThrow(); 299 DCHECK(throw_location.GetMethod() == referrer); 300 self->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;", 301 "Attempted read of %zd-bit %s on field '%s'", 302 expected_size * (32 / sizeof(int32_t)), 303 is_primitive ? "primitive" : "non-primitive", 304 PrettyField(resolved_field, true).c_str()); 305 return nullptr; // Failure. 306 } 307 } 308 } 309 if (!is_static) { 310 // instance fields must be being accessed on an initialized class 311 return resolved_field; 312 } else { 313 // If the class is initialized we're done. 314 if (LIKELY(fields_class->IsInitialized())) { 315 return resolved_field; 316 } else { 317 StackHandleScope<1> hs(self); 318 Handle<mirror::Class> h_class(hs.NewHandle(fields_class)); 319 if (LIKELY(class_linker->EnsureInitialized(h_class, true, true))) { 320 // Otherwise let's ensure the class is initialized before resolving the field. 321 return resolved_field; 322 } 323 DCHECK(self->IsExceptionPending()); // Throw exception and unwind 324 return nullptr; // Failure. 325 } 326 } 327 } 328 329 // Explicit template declarations of FindFieldFromCode for all field access types. 330 #define EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, _access_check) \ 331 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \ 332 mirror::ArtField* FindFieldFromCode<_type, _access_check>(uint32_t field_idx, \ 333 mirror::ArtMethod* referrer, \ 334 Thread* self, size_t expected_size) \ 335 336 #define EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \ 337 EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, false); \ 338 EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, true) 339 340 EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstanceObjectRead); 341 EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstanceObjectWrite); 342 EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstancePrimitiveRead); 343 EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(InstancePrimitiveWrite); 344 EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticObjectRead); 345 EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticObjectWrite); 346 EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveRead); 347 EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveWrite); 348 349 #undef EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL 350 #undef EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL 351 352 template<InvokeType type, bool access_check> 353 static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, 354 mirror::Object** this_object, 355 mirror::ArtMethod** referrer, Thread* self) { 356 ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); 357 mirror::ArtMethod* resolved_method = class_linker->GetResolvedMethod(method_idx, *referrer, type); 358 if (resolved_method == nullptr) { 359 StackHandleScope<1> hs(self); 360 mirror::Object* null_this = nullptr; 361 HandleWrapper<mirror::Object> h_this( 362 hs.NewHandleWrapper(type == kStatic ? &null_this : this_object)); 363 resolved_method = class_linker->ResolveMethod(self, method_idx, referrer, type); 364 } 365 if (UNLIKELY(resolved_method == nullptr)) { 366 DCHECK(self->IsExceptionPending()); // Throw exception and unwind. 367 return nullptr; // Failure. 368 } else if (UNLIKELY(*this_object == nullptr && type != kStatic)) { 369 // Maintain interpreter-like semantics where NullPointerException is thrown 370 // after potential NoSuchMethodError from class linker. 371 ThrowLocation throw_location = self->GetCurrentLocationForThrow(); 372 DCHECK_EQ(*referrer, throw_location.GetMethod()); 373 ThrowNullPointerExceptionForMethodAccess(throw_location, method_idx, type); 374 return nullptr; // Failure. 375 } else if (access_check) { 376 // Incompatible class change should have been handled in resolve method. 377 if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) { 378 ThrowIncompatibleClassChangeError(type, resolved_method->GetInvokeType(), resolved_method, 379 *referrer); 380 return nullptr; // Failure. 381 } 382 mirror::Class* methods_class = resolved_method->GetDeclaringClass(); 383 mirror::Class* referring_class = (*referrer)->GetDeclaringClass(); 384 bool can_access_resolved_method = 385 referring_class->CheckResolvedMethodAccess<type>(methods_class, resolved_method, 386 method_idx); 387 if (UNLIKELY(!can_access_resolved_method)) { 388 DCHECK(self->IsExceptionPending()); // Throw exception and unwind. 389 return nullptr; // Failure. 390 } 391 } 392 switch (type) { 393 case kStatic: 394 case kDirect: 395 return resolved_method; 396 case kVirtual: { 397 mirror::Class* klass = (*this_object)->GetClass(); 398 uint16_t vtable_index = resolved_method->GetMethodIndex(); 399 if (access_check && 400 (!klass->HasVTable() || 401 vtable_index >= static_cast<uint32_t>(klass->GetVTableLength()))) { 402 // Behavior to agree with that of the verifier. 403 ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(), 404 resolved_method->GetName(), resolved_method->GetSignature()); 405 return nullptr; // Failure. 406 } 407 DCHECK(klass->HasVTable()) << PrettyClass(klass); 408 return klass->GetVTableEntry(vtable_index); 409 } 410 case kSuper: { 411 mirror::Class* super_class = (*referrer)->GetDeclaringClass()->GetSuperClass(); 412 uint16_t vtable_index = resolved_method->GetMethodIndex(); 413 if (access_check) { 414 // Check existence of super class. 415 if (super_class == nullptr || !super_class->HasVTable() || 416 vtable_index >= static_cast<uint32_t>(super_class->GetVTableLength())) { 417 // Behavior to agree with that of the verifier. 418 ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(), 419 resolved_method->GetName(), resolved_method->GetSignature()); 420 return nullptr; // Failure. 421 } 422 } else { 423 // Super class must exist. 424 DCHECK(super_class != nullptr); 425 } 426 DCHECK(super_class->HasVTable()); 427 return super_class->GetVTableEntry(vtable_index); 428 } 429 case kInterface: { 430 uint32_t imt_index = resolved_method->GetDexMethodIndex() % mirror::Class::kImtSize; 431 mirror::ArtMethod* imt_method = (*this_object)->GetClass()->GetEmbeddedImTableEntry(imt_index); 432 if (!imt_method->IsImtConflictMethod() && !imt_method->IsImtUnimplementedMethod()) { 433 if (kIsDebugBuild) { 434 mirror::Class* klass = (*this_object)->GetClass(); 435 mirror::ArtMethod* method = klass->FindVirtualMethodForInterface(resolved_method); 436 CHECK_EQ(imt_method, method) << PrettyMethod(resolved_method) << " / " << 437 PrettyMethod(imt_method) << " / " << PrettyMethod(method) << " / " << 438 PrettyClass(klass); 439 } 440 return imt_method; 441 } else { 442 mirror::ArtMethod* interface_method = 443 (*this_object)->GetClass()->FindVirtualMethodForInterface(resolved_method); 444 if (UNLIKELY(interface_method == nullptr)) { 445 ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method, 446 *this_object, *referrer); 447 return nullptr; // Failure. 448 } 449 return interface_method; 450 } 451 } 452 default: 453 LOG(FATAL) << "Unknown invoke type " << type; 454 return nullptr; // Failure. 455 } 456 } 457 458 // Explicit template declarations of FindMethodFromCode for all invoke types. 459 #define EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, _access_check) \ 460 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \ 461 mirror::ArtMethod* FindMethodFromCode<_type, _access_check>(uint32_t method_idx, \ 462 mirror::Object** this_object, \ 463 mirror::ArtMethod** referrer, \ 464 Thread* self) 465 #define EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \ 466 EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, false); \ 467 EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, true) 468 469 EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kStatic); 470 EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kDirect); 471 EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kVirtual); 472 EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kSuper); 473 EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kInterface); 474 475 #undef EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL 476 #undef EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL 477 478 // Fast path field resolution that can't initialize classes or throw exceptions. 479 static inline mirror::ArtField* FindFieldFast(uint32_t field_idx, 480 mirror::ArtMethod* referrer, 481 FindFieldType type, size_t expected_size) { 482 mirror::ArtField* resolved_field = 483 referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx); 484 if (UNLIKELY(resolved_field == nullptr)) { 485 return nullptr; 486 } 487 // Check for incompatible class change. 488 bool is_primitive; 489 bool is_set; 490 bool is_static; 491 switch (type) { 492 case InstanceObjectRead: is_primitive = false; is_set = false; is_static = false; break; 493 case InstanceObjectWrite: is_primitive = false; is_set = true; is_static = false; break; 494 case InstancePrimitiveRead: is_primitive = true; is_set = false; is_static = false; break; 495 case InstancePrimitiveWrite: is_primitive = true; is_set = true; is_static = false; break; 496 case StaticObjectRead: is_primitive = false; is_set = false; is_static = true; break; 497 case StaticObjectWrite: is_primitive = false; is_set = true; is_static = true; break; 498 case StaticPrimitiveRead: is_primitive = true; is_set = false; is_static = true; break; 499 case StaticPrimitiveWrite: is_primitive = true; is_set = true; is_static = true; break; 500 default: 501 LOG(FATAL) << "UNREACHABLE"; // Assignment below to avoid GCC warnings. 502 is_primitive = true; 503 is_set = true; 504 is_static = true; 505 break; 506 } 507 if (UNLIKELY(resolved_field->IsStatic() != is_static)) { 508 // Incompatible class change. 509 return nullptr; 510 } 511 mirror::Class* fields_class = resolved_field->GetDeclaringClass(); 512 if (is_static) { 513 // Check class is initialized else fail so that we can contend to initialize the class with 514 // other threads that may be racing to do this. 515 if (UNLIKELY(!fields_class->IsInitialized())) { 516 return nullptr; 517 } 518 } 519 mirror::Class* referring_class = referrer->GetDeclaringClass(); 520 if (UNLIKELY(!referring_class->CanAccess(fields_class) || 521 !referring_class->CanAccessMember(fields_class, 522 resolved_field->GetAccessFlags()) || 523 (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) { 524 // Illegal access. 525 return nullptr; 526 } 527 if (UNLIKELY(resolved_field->IsPrimitiveType() != is_primitive || 528 resolved_field->FieldSize() != expected_size)) { 529 return nullptr; 530 } 531 return resolved_field; 532 } 533 534 // Fast path method resolution that can't throw exceptions. 535 static inline mirror::ArtMethod* FindMethodFast(uint32_t method_idx, 536 mirror::Object* this_object, 537 mirror::ArtMethod* referrer, 538 bool access_check, InvokeType type) { 539 if (UNLIKELY(this_object == NULL && type != kStatic)) { 540 return NULL; 541 } 542 mirror::ArtMethod* resolved_method = 543 referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx); 544 if (UNLIKELY(resolved_method == NULL)) { 545 return NULL; 546 } 547 if (access_check) { 548 // Check for incompatible class change errors and access. 549 bool icce = resolved_method->CheckIncompatibleClassChange(type); 550 if (UNLIKELY(icce)) { 551 return NULL; 552 } 553 mirror::Class* methods_class = resolved_method->GetDeclaringClass(); 554 mirror::Class* referring_class = referrer->GetDeclaringClass(); 555 if (UNLIKELY(!referring_class->CanAccess(methods_class) || 556 !referring_class->CanAccessMember(methods_class, 557 resolved_method->GetAccessFlags()))) { 558 // Potential illegal access, may need to refine the method's class. 559 return NULL; 560 } 561 } 562 if (type == kInterface) { // Most common form of slow path dispatch. 563 return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method); 564 } else if (type == kStatic || type == kDirect) { 565 return resolved_method; 566 } else if (type == kSuper) { 567 return referrer->GetDeclaringClass()->GetSuperClass() 568 ->GetVTableEntry(resolved_method->GetMethodIndex()); 569 } else { 570 DCHECK(type == kVirtual); 571 return this_object->GetClass()->GetVTableEntry(resolved_method->GetMethodIndex()); 572 } 573 } 574 575 static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx, 576 mirror::ArtMethod* referrer, 577 Thread* self, bool can_run_clinit, 578 bool verify_access) { 579 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 580 mirror::Class* klass = class_linker->ResolveType(type_idx, referrer); 581 if (UNLIKELY(klass == nullptr)) { 582 CHECK(self->IsExceptionPending()); 583 return nullptr; // Failure - Indicate to caller to deliver exception 584 } 585 // Perform access check if necessary. 586 mirror::Class* referring_class = referrer->GetDeclaringClass(); 587 if (verify_access && UNLIKELY(!referring_class->CanAccess(klass))) { 588 ThrowIllegalAccessErrorClass(referring_class, klass); 589 return nullptr; // Failure - Indicate to caller to deliver exception 590 } 591 // If we're just implementing const-class, we shouldn't call <clinit>. 592 if (!can_run_clinit) { 593 return klass; 594 } 595 // If we are the <clinit> of this class, just return our storage. 596 // 597 // Do not set the DexCache InitializedStaticStorage, since that implies <clinit> has finished 598 // running. 599 if (klass == referring_class && referrer->IsConstructor() && referrer->IsStatic()) { 600 return klass; 601 } 602 StackHandleScope<1> hs(self); 603 Handle<mirror::Class> h_class(hs.NewHandle(klass)); 604 if (!class_linker->EnsureInitialized(h_class, true, true)) { 605 CHECK(self->IsExceptionPending()); 606 return nullptr; // Failure - Indicate to caller to deliver exception 607 } 608 return h_class.Get(); 609 } 610 611 static inline mirror::String* ResolveStringFromCode(mirror::ArtMethod* referrer, 612 uint32_t string_idx) { 613 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 614 return class_linker->ResolveString(string_idx, referrer); 615 } 616 617 static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) { 618 // Save any pending exception over monitor exit call. 619 mirror::Throwable* saved_exception = NULL; 620 ThrowLocation saved_throw_location; 621 bool is_exception_reported = self->IsExceptionReportedToInstrumentation(); 622 if (UNLIKELY(self->IsExceptionPending())) { 623 saved_exception = self->GetException(&saved_throw_location); 624 self->ClearException(); 625 } 626 // Decode locked object and unlock, before popping local references. 627 self->DecodeJObject(locked)->MonitorExit(self); 628 if (UNLIKELY(self->IsExceptionPending())) { 629 LOG(FATAL) << "Synchronized JNI code returning with an exception:\n" 630 << saved_exception->Dump() 631 << "\nEncountered second exception during implicit MonitorExit:\n" 632 << self->GetException(NULL)->Dump(); 633 } 634 // Restore pending exception. 635 if (saved_exception != NULL) { 636 self->SetException(saved_throw_location, saved_exception); 637 self->SetExceptionReportedToInstrumentation(is_exception_reported); 638 } 639 } 640 641 static inline void CheckSuspend(Thread* thread) { 642 for (;;) { 643 if (thread->ReadFlag(kCheckpointRequest)) { 644 thread->RunCheckpointFunction(); 645 } else if (thread->ReadFlag(kSuspendRequest)) { 646 thread->FullSuspendCheck(); 647 } else { 648 break; 649 } 650 } 651 } 652 653 template <typename INT_TYPE, typename FLOAT_TYPE> 654 static inline INT_TYPE art_float_to_integral(FLOAT_TYPE f) { 655 const INT_TYPE kMaxInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::max()); 656 const INT_TYPE kMinInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::min()); 657 const FLOAT_TYPE kMaxIntAsFloat = static_cast<FLOAT_TYPE>(kMaxInt); 658 const FLOAT_TYPE kMinIntAsFloat = static_cast<FLOAT_TYPE>(kMinInt); 659 if (LIKELY(f > kMinIntAsFloat)) { 660 if (LIKELY(f < kMaxIntAsFloat)) { 661 return static_cast<INT_TYPE>(f); 662 } else { 663 return kMaxInt; 664 } 665 } else { 666 return (f != f) ? 0 : kMinInt; // f != f implies NaN 667 } 668 } 669 670 } // namespace art 671 672 #endif // ART_RUNTIME_ENTRYPOINTS_ENTRYPOINT_UTILS_INL_H_ 673