diff options
-rw-r--r-- | runtime/class_linker-inl.h | 127 | ||||
-rw-r--r-- | runtime/class_linker.cc | 141 | ||||
-rw-r--r-- | runtime/interpreter/mterp/nterp.cc | 3 |
3 files changed, 130 insertions, 141 deletions
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 4e8f8edf64..26c422b9eb 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -401,6 +401,104 @@ inline ArtMethod* ClassLinker::ResolveMethod(Thread* self, return resolved_method; } +template <ClassLinker::ResolveMode kResolveMode> +inline ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + ArtMethod* referrer, + InvokeType type) { + 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(); + DCHECK(resolved == nullptr || !resolved->IsRuntimeMethod()); + bool valid_dex_cache_method = resolved != nullptr; + if (kResolveMode == ResolveMode::kNoChecks && valid_dex_cache_method) { + // We have a valid method from the DexCache and no checks to perform. + DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex(); + return resolved; + } + const DexFile& dex_file = *dex_cache->GetDexFile(); + const dex::MethodId& method_id = dex_file.GetMethodId(method_idx); + ObjPtr<mirror::Class> klass = nullptr; + if (valid_dex_cache_method) { + // We have a valid method from the DexCache but we need to perform ICCE and IAE checks. + DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex(); + klass = LookupResolvedType(method_id.class_idx_, dex_cache.Get(), class_loader.Get()); + if (UNLIKELY(klass == nullptr)) { + // We normaly should not end up here. However the verifier currently doesn't guarantee + // the invariant of having the klass in the class table. b/73760543 + klass = ResolveType(method_id.class_idx_, dex_cache, class_loader); + if (klass == nullptr) { + // This can only happen if the current thread is not allowed to load + // classes. + DCHECK(!Thread::Current()->CanLoadClasses()); + DCHECK(Thread::Current()->IsExceptionPending()); + return nullptr; + } + } + } else { + // The method was not in the DexCache, resolve the declaring class. + klass = ResolveType(method_id.class_idx_, dex_cache, class_loader); + if (klass == nullptr) { + DCHECK(Thread::Current()->IsExceptionPending()); + return nullptr; + } + } + + // Check if the invoke type matches the class type. + if (kResolveMode == ResolveMode::kCheckICCEAndIAE && + CheckInvokeClassMismatch</* kThrow= */ true>( + dex_cache.Get(), type, [klass]() { return klass; })) { + DCHECK(Thread::Current()->IsExceptionPending()); + return nullptr; + } + + if (!valid_dex_cache_method) { + resolved = FindResolvedMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx); + } + + // Note: We can check for IllegalAccessError only if we have a referrer. + 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()); + return nullptr; + } + } + + // If we found a method, check for incompatible class changes. + if (LIKELY(resolved != nullptr) && + LIKELY(kResolveMode == ResolveMode::kNoChecks || + !resolved->CheckIncompatibleClassChange(type))) { + return resolved; + } 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; + } +} + inline ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx, ArtMethod* referrer, bool is_static) { @@ -431,6 +529,35 @@ inline ArtField* ClassLinker::ResolveField(uint32_t field_idx, return resolved_field; } +inline ArtField* ClassLinker::ResolveField(uint32_t field_idx, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + bool is_static) { + DCHECK(dex_cache != nullptr); + DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Get()); + DCHECK(!Thread::Current()->IsExceptionPending()) << Thread::Current()->GetException()->Dump(); + ArtField* resolved = dex_cache->GetResolvedField(field_idx); + Thread::PoisonObjectPointersIfDebug(); + if (resolved != nullptr) { + return resolved; + } + const DexFile& dex_file = *dex_cache->GetDexFile(); + const dex::FieldId& field_id = dex_file.GetFieldId(field_idx); + ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader); + if (klass == nullptr) { + DCHECK(Thread::Current()->IsExceptionPending()); + return nullptr; + } + + resolved = FindResolvedField(klass, dex_cache.Get(), class_loader.Get(), field_idx, is_static); + if (resolved == nullptr) { + const char* name = dex_file.GetFieldName(field_id); + const char* type = dex_file.GetFieldTypeDescriptor(field_id); + ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass, type, name); + } + return resolved; +} + template <class Visitor> inline void ClassLinker::VisitClassTables(const Visitor& visitor) { Thread* const self = Thread::Current(); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 69e87d3ba4..8065238c54 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -9054,104 +9054,6 @@ ArtMethod* ClassLinker::FindIncompatibleMethod(ObjPtr<mirror::Class> klass, } } -template <ClassLinker::ResolveMode kResolveMode> -ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - ArtMethod* referrer, - InvokeType type) { - 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(); - DCHECK(resolved == nullptr || !resolved->IsRuntimeMethod()); - bool valid_dex_cache_method = resolved != nullptr; - if (kResolveMode == ResolveMode::kNoChecks && valid_dex_cache_method) { - // We have a valid method from the DexCache and no checks to perform. - DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex(); - return resolved; - } - const DexFile& dex_file = *dex_cache->GetDexFile(); - const dex::MethodId& method_id = dex_file.GetMethodId(method_idx); - ObjPtr<mirror::Class> klass = nullptr; - if (valid_dex_cache_method) { - // We have a valid method from the DexCache but we need to perform ICCE and IAE checks. - DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex(); - klass = LookupResolvedType(method_id.class_idx_, dex_cache.Get(), class_loader.Get()); - if (UNLIKELY(klass == nullptr)) { - // We normaly should not end up here. However the verifier currently doesn't guarantee - // the invariant of having the klass in the class table. b/73760543 - klass = ResolveType(method_id.class_idx_, dex_cache, class_loader); - if (klass == nullptr) { - // This can only happen if the current thread is not allowed to load - // classes. - DCHECK(!Thread::Current()->CanLoadClasses()); - DCHECK(Thread::Current()->IsExceptionPending()); - return nullptr; - } - } - } else { - // The method was not in the DexCache, resolve the declaring class. - klass = ResolveType(method_id.class_idx_, dex_cache, class_loader); - if (klass == nullptr) { - DCHECK(Thread::Current()->IsExceptionPending()); - return nullptr; - } - } - - // Check if the invoke type matches the class type. - if (kResolveMode == ResolveMode::kCheckICCEAndIAE && - CheckInvokeClassMismatch</* kThrow= */ true>( - dex_cache.Get(), type, [klass]() { return klass; })) { - DCHECK(Thread::Current()->IsExceptionPending()); - return nullptr; - } - - if (!valid_dex_cache_method) { - resolved = FindResolvedMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx); - } - - // Note: We can check for IllegalAccessError only if we have a referrer. - 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()); - return nullptr; - } - } - - // If we found a method, check for incompatible class changes. - if (LIKELY(resolved != nullptr) && - LIKELY(kResolveMode == ResolveMode::kNoChecks || - !resolved->CheckIncompatibleClassChange(type))) { - return resolved; - } 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; - } -} - ArtMethod* ClassLinker::ResolveMethodWithoutInvokeType(uint32_t method_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) { @@ -9205,35 +9107,6 @@ ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx, return FindResolvedField(klass, dex_cache, class_loader, field_idx, is_static); } -ArtField* ClassLinker::ResolveField(uint32_t field_idx, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - bool is_static) { - DCHECK(dex_cache != nullptr); - DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Get()); - DCHECK(!Thread::Current()->IsExceptionPending()) << Thread::Current()->GetException()->Dump(); - ArtField* resolved = dex_cache->GetResolvedField(field_idx); - Thread::PoisonObjectPointersIfDebug(); - if (resolved != nullptr) { - return resolved; - } - const DexFile& dex_file = *dex_cache->GetDexFile(); - const dex::FieldId& field_id = dex_file.GetFieldId(field_idx); - ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader); - if (klass == nullptr) { - DCHECK(Thread::Current()->IsExceptionPending()); - return nullptr; - } - - resolved = FindResolvedField(klass, dex_cache.Get(), class_loader.Get(), field_idx, is_static); - if (resolved == nullptr) { - const char* name = dex_file.GetFieldName(field_id); - const char* type = dex_file.GetFieldTypeDescriptor(field_id); - ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass, type, name); - } - return resolved; -} - ArtField* ClassLinker::ResolveFieldJLS(uint32_t field_idx, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader) { @@ -10172,20 +10045,6 @@ void ClassLinker::SetEnablePublicSdkChecks(bool enabled ATTRIBUTE_UNUSED) { UNREACHABLE(); } -// Instantiate ClassLinker::ResolveMethod. -template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>( - uint32_t method_idx, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - ArtMethod* referrer, - InvokeType type); -template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( - uint32_t method_idx, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - ArtMethod* referrer, - InvokeType type); - // Instantiate ClassLinker::AllocClass. template ObjPtr<mirror::Class> ClassLinker::AllocClass</* kMovable= */ true>( Thread* self, diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc index ddef31d792..fd57ece4e4 100644 --- a/runtime/interpreter/mterp/nterp.cc +++ b/runtime/interpreter/mterp/nterp.cc @@ -20,6 +20,7 @@ #include "nterp.h" #include "base/quasi_atomic.h" +#include "class_linker-inl.h" #include "dex/dex_instruction_utils.h" #include "debugger.h" #include "entrypoints/entrypoint_utils-inl.h" @@ -264,6 +265,7 @@ extern "C" const char* NterpGetShortyFromInvokeCustom(ArtMethod* caller, uint16_ return dex_file->GetShorty(proto_idx); } +FLATTEN extern "C" size_t NterpGetMethod(Thread* self, ArtMethod* caller, uint16_t* dex_pc_ptr) REQUIRES_SHARED(Locks::mutator_lock_) { UpdateHotness(caller); @@ -422,6 +424,7 @@ extern "C" size_t NterpGetMethod(Thread* self, ArtMethod* caller, uint16_t* dex_ } } +FLATTEN static ArtField* ResolveFieldWithAccessChecks(Thread* self, ClassLinker* class_linker, uint16_t field_index, |