diff options
Diffstat (limited to 'runtime/class_linker-inl.h')
| -rw-r--r-- | runtime/class_linker-inl.h | 259 |
1 files changed, 83 insertions, 176 deletions
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 02b2778f4f..c4f3b15d7c 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -24,6 +24,7 @@ #include "art_method-inl.h" #include "base/mutex.h" #include "class_linker.h" +#include "class_table-inl.h" #include "dex/dex_file.h" #include "dex/dex_file_structs.h" #include "gc_root-inl.h" @@ -70,12 +71,10 @@ inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string ArtField* referrer) { Thread::PoisonObjectPointersIfDebug(); DCHECK(!Thread::Current()->IsExceptionPending()); - // We do not need the read barrier for getting the DexCache for the initial resolved type - // lookup as both from-space and to-space copies point to the same native resolved types array. - ObjPtr<mirror::String> resolved = - referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx); + ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache(); + ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx); if (resolved == nullptr) { - resolved = DoResolveString(string_idx, referrer->GetDexCache()); + resolved = DoResolveString(string_idx, dex_cache); } return resolved; } @@ -84,12 +83,10 @@ inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string ArtMethod* referrer) { Thread::PoisonObjectPointersIfDebug(); DCHECK(!Thread::Current()->IsExceptionPending()); - // We do not need the read barrier for getting the DexCache for the initial resolved type - // lookup as both from-space and to-space copies point to the same native resolved types array. - ObjPtr<mirror::String> resolved = - referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx); + ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache(); + ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx); if (resolved == nullptr) { - resolved = DoResolveString(string_idx, referrer->GetDexCache()); + resolved = DoResolveString(string_idx, dex_cache); } return resolved; } @@ -122,10 +119,7 @@ inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, Thread::Current()->PoisonObjectPointers(); } DCHECK(!Thread::Current()->IsExceptionPending()); - // We do not need the read barrier for getting the DexCache for the initial resolved type - // lookup as both from-space and to-space copies point to the same native resolved types array. - ObjPtr<mirror::Class> resolved_type = - referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx); + ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx); if (resolved_type == nullptr) { resolved_type = DoResolveType(type_idx, referrer); } @@ -136,10 +130,7 @@ inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtField* referrer) { Thread::PoisonObjectPointersIfDebug(); DCHECK(!Thread::Current()->IsExceptionPending()); - // We do not need the read barrier for getting the DexCache for the initial resolved type - // lookup as both from-space and to-space copies point to the same native resolved types array. - ObjPtr<mirror::Class> resolved_type = - referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx); + ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx); if (UNLIKELY(resolved_type == nullptr)) { resolved_type = DoResolveType(type_idx, referrer); } @@ -150,10 +141,7 @@ inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer) { Thread::PoisonObjectPointersIfDebug(); DCHECK(!Thread::Current()->IsExceptionPending()); - // We do not need the read barrier for getting the DexCache for the initial resolved type - // lookup as both from-space and to-space copies point to the same native resolved types array. - ObjPtr<mirror::Class> resolved_type = - referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx); + ObjPtr<mirror::Class> resolved_type = referrer->GetDexCache()->GetResolvedType(type_idx); if (UNLIKELY(resolved_type == nullptr)) { resolved_type = DoResolveType(type_idx, referrer); } @@ -175,10 +163,7 @@ inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type_idx, ObjPtr<mirror::Class> referrer) { - // We do not need the read barrier for getting the DexCache for the initial resolved type - // lookup as both from-space and to-space copies point to the same native resolved types array. - ObjPtr<mirror::Class> type = - referrer->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetResolvedType(type_idx); + ObjPtr<mirror::Class> type = referrer->GetDexCache()->GetResolvedType(type_idx); if (type == nullptr) { type = DoLookupResolvedType(type_idx, referrer); } @@ -189,8 +174,7 @@ inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type ArtField* referrer) { // We do not need the read barrier for getting the DexCache for the initial resolved type // lookup as both from-space and to-space copies point to the same native resolved types array. - ObjPtr<mirror::Class> type = - referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx); + ObjPtr<mirror::Class> type = referrer->GetDexCache()->GetResolvedType(type_idx); if (type == nullptr) { type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass()); } @@ -201,8 +185,7 @@ inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(dex::TypeIndex type ArtMethod* referrer) { // We do not need the read barrier for getting the DexCache for the initial resolved type // lookup as both from-space and to-space copies point to the same native resolved types array. - ObjPtr<mirror::Class> type = - referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedType(type_idx); + ObjPtr<mirror::Class> type = referrer->GetDexCache()->GetResolvedType(type_idx); if (type == nullptr) { type = DoLookupResolvedType(type_idx, referrer->GetDeclaringClass()); } @@ -304,129 +287,32 @@ inline ArtMethod* ClassLinker::LookupResolvedMethod(uint32_t method_idx, return resolved; } -template <InvokeType type, ClassLinker::ResolveMode kResolveMode> -inline ArtMethod* ClassLinker::GetResolvedMethod(uint32_t method_idx, ArtMethod* referrer) { - DCHECK(referrer != nullptr); - // Note: The referrer can be a Proxy constructor. In that case, we need to do the - // lookup in the context of the original method from where it steals the code. - // However, we delay the GetInterfaceMethodIfProxy() until needed. - DCHECK_IMPLIES(referrer->IsProxyMethod(), referrer->IsConstructor()); - // We do not need the read barrier for getting the DexCache for the initial resolved method - // lookup as both from-space and to-space copies point to the same native resolved methods array. - ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod( - method_idx); - if (resolved_method == nullptr) { - return nullptr; - } - DCHECK(!resolved_method->IsRuntimeMethod()); - if (kResolveMode == ResolveMode::kCheckICCEAndIAE) { - referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_); - // Check if the invoke type matches the class type. - ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache(); - ObjPtr<mirror::ClassLoader> class_loader = referrer->GetClassLoader(); - const dex::MethodId& method_id = referrer->GetDexFile()->GetMethodId(method_idx); - ObjPtr<mirror::Class> cls = LookupResolvedType(method_id.class_idx_, dex_cache, class_loader); - if (cls == nullptr) { - // The verifier breaks the invariant that a resolved method must have its - // class in the class table. Because this method should only lookup and not - // resolve class, return null. The caller is responsible for calling - // `ResolveMethod` afterwards. - // b/73760543 - return nullptr; - } - if (CheckInvokeClassMismatch</* kThrow= */ false>(dex_cache, type, method_idx, class_loader)) { - return nullptr; - } - // Check access. - ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass(); - if (!referring_class->CanAccessResolvedMethod(resolved_method->GetDeclaringClass(), - resolved_method, - dex_cache, - method_idx)) { - return nullptr; - } - // Check if the invoke type matches the method type. - if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) { - return nullptr; - } - } - return resolved_method; -} - template <ClassLinker::ResolveMode kResolveMode> inline ArtMethod* ClassLinker::ResolveMethod(Thread* self, uint32_t method_idx, ArtMethod* referrer, InvokeType type) { DCHECK(referrer != nullptr); - // Note: The referrer can be a Proxy constructor. In that case, we need to do the - // lookup in the context of the original method from where it steals the code. - // However, we delay the GetInterfaceMethodIfProxy() until needed. DCHECK_IMPLIES(referrer->IsProxyMethod(), referrer->IsConstructor()); + Thread::PoisonObjectPointersIfDebug(); - // We do not need the read barrier for getting the DexCache for the initial resolved method - // lookup as both from-space and to-space copies point to the same native resolved methods array. - ArtMethod* resolved_method = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedMethod( - method_idx); - DCHECK(resolved_method == nullptr || !resolved_method->IsRuntimeMethod()); - if (UNLIKELY(resolved_method == nullptr)) { - referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_); - ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass(); - StackHandleScope<2> hs(self); - Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer->GetDexCache())); - Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(declaring_class->GetClassLoader())); - resolved_method = ResolveMethod<kResolveMode>(method_idx, - h_dex_cache, - h_class_loader, - referrer, - type); - } else if (kResolveMode == ResolveMode::kCheckICCEAndIAE) { - referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_); - const dex::MethodId& method_id = referrer->GetDexFile()->GetMethodId(method_idx); - ObjPtr<mirror::Class> cls = - LookupResolvedType(method_id.class_idx_, - referrer->GetDexCache(), - referrer->GetClassLoader()); - if (cls == nullptr) { - // The verifier breaks the invariant that a resolved method must have its - // class in the class table, so resolve the type in case we haven't found it. - // b/73760543 - StackHandleScope<2> hs(Thread::Current()); - Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer->GetDexCache())); - Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(referrer->GetClassLoader())); - cls = ResolveType(method_id.class_idx_, h_dex_cache, h_class_loader); - if (hs.Self()->IsExceptionPending()) { - return nullptr; - } - } - // Check if the invoke type matches the class type. - if (CheckInvokeClassMismatch</* kThrow= */ true>( - referrer->GetDexCache(), type, [cls]() { return cls; })) { - DCHECK(Thread::Current()->IsExceptionPending()); - return nullptr; - } - // Check access. - ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass(); - if (!referring_class->CheckResolvedMethodAccess(resolved_method->GetDeclaringClass(), - resolved_method, - referrer->GetDexCache(), - method_idx, - type)) { - DCHECK(Thread::Current()->IsExceptionPending()); - return nullptr; - } - // Check if the invoke type matches the method type. - if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) { - ThrowIncompatibleClassChangeError(type, - resolved_method->GetInvokeType(), - resolved_method, - referrer); - return nullptr; + // Fast path: no checks and in the dex cache. + if (kResolveMode == ResolveMode::kNoChecks) { + ArtMethod* resolved_method = referrer->GetDexCache()->GetResolvedMethod(method_idx); + if (resolved_method != nullptr) { + DCHECK(!resolved_method->IsRuntimeMethod()); + return resolved_method; } } - // Note: We cannot check here to see whether we added the method to the cache. It - // might be an erroneous class, which results in it being hidden from us. - return resolved_method; + + // For a Proxy constructor, we need to do the lookup in the context of the original method + // from where it steals the code. + referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_); + StackHandleScope<2> hs(self); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); + Handle<mirror::ClassLoader> class_loader( + hs.NewHandle(referrer->GetDeclaringClass()->GetClassLoader())); + return ResolveMethod<kResolveMode>(method_idx, dex_cache, class_loader, referrer, type); } template <ClassLinker::ResolveMode kResolveMode> @@ -435,10 +321,11 @@ inline ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, Handle<mirror::ClassLoader> class_loader, ArtMethod* referrer, InvokeType type) { + DCHECK(dex_cache != nullptr); DCHECK(dex_cache->GetClassLoader() == class_loader.Get()); DCHECK(!Thread::Current()->IsExceptionPending()) << Thread::Current()->GetException()->Dump(); - DCHECK(dex_cache != nullptr); DCHECK(referrer == nullptr || !referrer->IsProxyMethod()); + // Check for hit in the dex cache. ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx); Thread::PoisonObjectPointersIfDebug(); @@ -475,6 +362,11 @@ inline ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, DCHECK(Thread::Current()->IsExceptionPending()); return nullptr; } + // Look for the method again in case the type resolution updated the cache. + resolved = dex_cache->GetResolvedMethod(method_idx); + if (kResolveMode == ResolveMode::kNoChecks && resolved != nullptr) { + return resolved; + } } // Check if the invoke type matches the class type. @@ -493,12 +385,20 @@ inline ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, if (kResolveMode == ResolveMode::kCheckICCEAndIAE && resolved != nullptr && referrer != nullptr) { ObjPtr<mirror::Class> methods_class = resolved->GetDeclaringClass(); ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass(); - if (!referring_class->CheckResolvedMethodAccess(methods_class, - resolved, - dex_cache.Get(), - method_idx, - type)) { - DCHECK(Thread::Current()->IsExceptionPending()); + if (UNLIKELY(!referring_class->CanAccess(methods_class))) { + // The referrer class can't access the method's declaring class but may still be able + // to access the method if the MethodId specifies an accessible subclass of the declaring + // class rather than the declaring class itself. + if (UNLIKELY(!referring_class->CanAccess(klass))) { + ThrowIllegalAccessErrorClassForMethodDispatch(referring_class, + klass, + resolved, + type); + return nullptr; + } + } + if (UNLIKELY(!referring_class->CanAccessMember(methods_class, resolved->GetAccessFlags()))) { + ThrowIllegalAccessErrorMethod(referring_class, resolved); return nullptr; } } @@ -508,36 +408,34 @@ inline ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, LIKELY(kResolveMode == ResolveMode::kNoChecks || !resolved->CheckIncompatibleClassChange(type))) { return resolved; + } + + // If we had a method, or if we can find one with another lookup type, + // it's an incompatible-class-change error. + if (resolved == nullptr) { + resolved = FindIncompatibleMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx); + } + if (resolved != nullptr) { + ThrowIncompatibleClassChangeError(type, resolved->GetInvokeType(), resolved, referrer); } else { - // If we had a method, or if we can find one with another lookup type, - // it's an incompatible-class-change error. - if (resolved == nullptr) { - resolved = FindIncompatibleMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx); - } - if (resolved != nullptr) { - ThrowIncompatibleClassChangeError(type, resolved->GetInvokeType(), resolved, referrer); - } else { - // We failed to find the method (using all lookup types), so throw a NoSuchMethodError. - const char* name = dex_file.StringDataByIdx(method_id.name_idx_); - const Signature signature = dex_file.GetMethodSignature(method_id); - ThrowNoSuchMethodError(type, klass, name, signature); - } - Thread::Current()->AssertPendingException(); - return nullptr; + // We failed to find the method (using all lookup types), so throw a NoSuchMethodError. + const char* name = dex_file.StringDataByIdx(method_id.name_idx_); + const Signature signature = dex_file.GetMethodSignature(method_id); + ThrowNoSuchMethodError(type, klass, name, signature); } + Thread::Current()->AssertPendingException(); + return nullptr; } inline ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx, ArtMethod* referrer, bool is_static) { - // We do not need the read barrier for getting the DexCache for the initial resolved field - // lookup as both from-space and to-space copies point to the same native resolved fields array. - ArtField* field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField( - field_idx); + ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache(); + ArtField* field = dex_cache->GetResolvedField(field_idx); if (field == nullptr) { referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_); ObjPtr<mirror::ClassLoader> class_loader = referrer->GetDeclaringClass()->GetClassLoader(); - field = LookupResolvedField(field_idx, referrer->GetDexCache(), class_loader, is_static); + field = LookupResolvedField(field_idx, dex_cache, class_loader, is_static); } return field; } @@ -546,17 +444,15 @@ inline ArtField* ClassLinker::ResolveField(uint32_t field_idx, ArtMethod* referrer, bool is_static) { Thread::PoisonObjectPointersIfDebug(); - // We do not need the read barrier for getting the DexCache for the initial resolved field - // lookup as both from-space and to-space copies point to the same native resolved fields array. - ArtField* resolved_field = referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedField( - field_idx); + ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache(); + ArtField* resolved_field = dex_cache->GetResolvedField(field_idx); if (UNLIKELY(resolved_field == nullptr)) { StackHandleScope<2> hs(Thread::Current()); referrer = referrer->GetInterfaceMethodIfProxy(image_pointer_size_); ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass(); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); + Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(dex_cache)); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referring_class->GetClassLoader())); - resolved_field = ResolveField(field_idx, dex_cache, class_loader, is_static); + resolved_field = ResolveField(field_idx, h_dex_cache, class_loader, is_static); // Note: We cannot check here to see whether we added the field to the cache. The type // might be an erroneous class, which results in it being hidden from us. } @@ -583,6 +479,12 @@ inline ArtField* ClassLinker::ResolveField(uint32_t field_idx, return nullptr; } + // Look for the field again in case the type resolution updated the cache. + resolved = dex_cache->GetResolvedField(field_idx); + if (resolved != nullptr) { + return resolved; + } + resolved = FindResolvedField(klass, dex_cache.Get(), class_loader.Get(), field_idx, is_static); if (resolved == nullptr) { const char* name = dex_file.GetFieldName(field_id); @@ -592,6 +494,11 @@ inline ArtField* ClassLinker::ResolveField(uint32_t field_idx, return resolved; } +template <typename Visitor> +inline void ClassLinker::VisitBootClasses(Visitor* visitor) { + boot_class_table_->Visit(*visitor); +} + template <class Visitor> inline void ClassLinker::VisitClassTables(const Visitor& visitor) { Thread* const self = Thread::Current(); |