diff options
author | 2023-01-06 12:06:13 +0000 | |
---|---|---|
committer | 2023-01-16 12:14:00 +0000 | |
commit | ae12f96965dd1fb1cf5fefb0188b749e921ba88b (patch) | |
tree | 802eb68fb823189f39cb1d7e57ed9e035568f4b9 /runtime/class_linker-inl.h | |
parent | e52e4fb74e9f13009af4ffbfb2e5103ce035a94b (diff) |
Refactor code aroud method resolution.
- Make unresolved AOT entrypoints use the tls cache
- Remove duplicate code
- Inline method access checks logic in its only use.
- Fix in ClassLinker::ResolveMethodWithoutInvokeType() by calling shared
helper.
Test: test.py
Change-Id: I1f42b5d0ac1dcd9c5eb483db9c5c5eefc9b2f4d1
Diffstat (limited to 'runtime/class_linker-inl.h')
-rw-r--r-- | runtime/class_linker-inl.h | 182 |
1 files changed, 47 insertions, 135 deletions
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 8f3692dd39..8b6d45da39 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -305,129 +305,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> @@ -436,10 +339,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(); @@ -499,12 +403,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; } } @@ -514,23 +426,23 @@ 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, |