summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nicolas Geoffray <ngeoffray@google.com> 2024-11-05 14:43:07 +0000
committer Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2024-11-28 14:38:30 +0000
commit6963ab426aca2058ab5c4cd575beaf7d1a63547b (patch)
treed88567cb70778f3352eeb5c4043a339b50c2750f
parent2191e733117542a684c7e6c87a5d8d6881ae5936 (diff)
Refactor ResolveMethod.
Introduce ResolveMethodId and ResolveMethodWithChecks to make it more explicit at the call site. This also simplifies the implementation of ResolveMethodWithChecks. Also avoid creating handles in ResolveField when the dex cache already contains the field. Test: test.py Change-Id: Ie722c6d7ecadf7c6dbd780f0fc58dfae89140a01
-rw-r--r--compiler/optimizing/instruction_builder.cc33
-rw-r--r--runtime/class_linker-inl.h245
-rw-r--r--runtime/class_linker.cc48
-rw-r--r--runtime/class_linker.h51
-rw-r--r--runtime/common_throws.cc10
-rw-r--r--runtime/common_throws.h5
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h17
-rw-r--r--runtime/entrypoints/jni/jni_entrypoints.cc3
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc14
-rw-r--r--runtime/interpreter/interpreter_common.cc4
-rw-r--r--runtime/interpreter/mterp/nterp.cc6
-rw-r--r--runtime/jit/small_pattern_matcher.cc6
12 files changed, 168 insertions, 274 deletions
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index b2179e69bb..c66fd3bb26 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -937,13 +937,20 @@ static ArtMethod* ResolveMethod(uint16_t method_idx,
ClassLinker* class_linker = dex_compilation_unit.GetClassLinker();
Handle<mirror::ClassLoader> class_loader = dex_compilation_unit.GetClassLoader();
- ArtMethod* resolved_method =
- class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
+ ArtMethod* resolved_method = nullptr;
+ if (referrer == nullptr) {
+ // The referrer may be unresolved for AOT if we're compiling a class that cannot be
+ // resolved because, for example, we don't find a superclass in the classpath.
+ resolved_method = class_linker->ResolveMethodId(
+ method_idx, dex_compilation_unit.GetDexCache(), class_loader);
+ } else if (referrer->SkipAccessChecks()) {
+ resolved_method = class_linker->ResolveMethodId(method_idx, referrer);
+ } else {
+ resolved_method = class_linker->ResolveMethodWithChecks(
method_idx,
- dex_compilation_unit.GetDexCache(),
- class_loader,
referrer,
*invoke_type);
+ }
if (UNLIKELY(resolved_method == nullptr)) {
// Clean up any exception left by type resolution.
@@ -952,9 +959,18 @@ static ArtMethod* ResolveMethod(uint16_t method_idx,
}
DCHECK(!soa.Self()->IsExceptionPending());
- // The referrer may be unresolved for AOT if we're compiling a class that cannot be
- // resolved because, for example, we don't find a superclass in the classpath.
if (referrer == nullptr) {
+ ObjPtr<mirror::Class> referenced_class = class_linker->LookupResolvedType(
+ dex_compilation_unit.GetDexFile()->GetMethodId(method_idx).class_idx_,
+ dex_compilation_unit.GetDexCache().Get(),
+ class_loader.Get());
+ DCHECK(referenced_class != nullptr); // Must have been resolved when resolving the method.
+ if (class_linker->ThrowIfInvokeClassMismatch(referenced_class,
+ *dex_compilation_unit.GetDexFile(),
+ *invoke_type)) {
+ soa.Self()->ClearException();
+ return nullptr;
+ }
// The class linker cannot check access without a referrer, so we have to do it.
// Check if the declaring class or referencing class is accessible.
SamePackageCompare same_package(dex_compilation_unit);
@@ -963,11 +979,6 @@ static ArtMethod* ResolveMethod(uint16_t method_idx,
if (!declaring_class_accessible) {
// It is possible to access members from an inaccessible superclass
// by referencing them through an accessible subclass.
- ObjPtr<mirror::Class> referenced_class = class_linker->LookupResolvedType(
- dex_compilation_unit.GetDexFile()->GetMethodId(method_idx).class_idx_,
- dex_compilation_unit.GetDexCache().Get(),
- class_loader.Get());
- DCHECK(referenced_class != nullptr); // Must have been resolved when resolving the method.
if (!referenced_class->IsPublic() && !same_package(referenced_class)) {
return nullptr;
}
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 7d84fc1c09..056b26b2d2 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -206,73 +206,6 @@ inline ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(
return type;
}
-template <bool kThrowOnError, typename ClassGetter>
-inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
- InvokeType type,
- ClassGetter class_getter) {
- switch (type) {
- case kStatic:
- case kSuper:
- case kPolymorphic:
- break;
- case kInterface: {
- // We have to check whether the method id really belongs to an interface (dex static bytecode
- // constraints A15, A16). Otherwise you must not invoke-interface on it.
- ObjPtr<mirror::Class> klass = class_getter();
- if (UNLIKELY(!klass->IsInterface())) {
- if (kThrowOnError) {
- ThrowIncompatibleClassChangeError(klass,
- "Found class %s, but interface was expected",
- klass->PrettyDescriptor().c_str());
- }
- return true;
- }
- break;
- }
- case kDirect:
- if (dex_cache->GetDexFile()->SupportsDefaultMethods()) {
- break;
- }
- FALLTHROUGH_INTENDED;
- case kVirtual: {
- // Similarly, invoke-virtual (and invoke-direct without default methods) must reference
- // a non-interface class (dex static bytecode constraint A24, A25).
- ObjPtr<mirror::Class> klass = class_getter();
- if (UNLIKELY(klass->IsInterface())) {
- if (kThrowOnError) {
- ThrowIncompatibleClassChangeError(klass,
- "Found interface %s, but class was expected",
- klass->PrettyDescriptor().c_str());
- }
- return true;
- }
- break;
- }
- default:
- LOG(FATAL) << "Unreachable - invocation type: " << type;
- UNREACHABLE();
- }
- return false;
-}
-
-template <bool kThrow>
-inline bool ClassLinker::CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
- InvokeType type,
- uint32_t method_idx,
- ObjPtr<mirror::ClassLoader> class_loader) {
- DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Ptr());
- return CheckInvokeClassMismatch<kThrow>(
- dex_cache,
- type,
- [this, dex_cache, method_idx, class_loader]() REQUIRES_SHARED(Locks::mutator_lock_) {
- const dex::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(method_idx);
- ObjPtr<mirror::Class> klass =
- LookupResolvedType(method_id.class_idx_, dex_cache, class_loader);
- DCHECK(klass != nullptr) << dex_cache->GetDexFile()->PrettyMethod(method_idx);
- return klass;
- });
-}
-
inline ArtMethod* ClassLinker::LookupResolvedMethod(uint32_t method_idx,
ObjPtr<mirror::DexCache> dex_cache,
ObjPtr<mirror::ClassLoader> class_loader) {
@@ -289,102 +222,88 @@ inline ArtMethod* ClassLinker::LookupResolvedMethod(uint32_t method_idx,
return resolved;
}
-template <ClassLinker::ResolveMode kResolveMode>
-inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,
- uint32_t method_idx,
- ArtMethod* referrer,
- InvokeType type) {
- DCHECK(referrer != nullptr);
- DCHECK_IMPLIES(referrer->IsProxyMethod(), referrer->IsConstructor());
-
- Thread::PoisonObjectPointersIfDebug();
- // 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;
- }
+inline ArtMethod* ClassLinker::ResolveMethodId(uint32_t method_idx, ArtMethod* referrer) {
+ ArtMethod* resolved = referrer->GetDexCache()->GetResolvedMethod(method_idx);
+ if (resolved != nullptr) {
+ DCHECK(!resolved->IsRuntimeMethod());
+ DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
+ return resolved;
}
-
- // For a Proxy constructor, we need to do the lookup in the context of the original method
- // from where it steals the code.
+ // Fail, get the declaring class.
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>
-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 != nullptr);
- DCHECK(dex_cache->GetClassLoader() == class_loader.Get());
- DCHECK(!Thread::Current()->IsExceptionPending()) << Thread::Current()->GetException()->Dump();
- DCHECK(referrer == nullptr || !referrer->IsProxyMethod());
+ const dex::MethodId& method_id = referrer->GetDexFile()->GetMethodId(method_idx);
+ ObjPtr<mirror::Class> klass = ResolveType(method_id.class_idx_, referrer);
+ if (klass == nullptr) {
+ Thread::Current()->AssertPendingException();
+ return nullptr;
+ }
- // 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();
+ resolved =
+ FindResolvedMethod(klass, referrer->GetDexCache(), referrer->GetClassLoader(), method_idx);
+ if (resolved != nullptr) {
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;
- }
+
+ const char* name = referrer->GetDexFile()->GetStringData(method_id.name_idx_);
+ const Signature signature = referrer->GetDexFile()->GetMethodSignature(method_id);
+ ThrowNoSuchMethodError(klass, name, signature);
+ return nullptr;
+}
+
+inline bool ClassLinker::ThrowIfInvokeClassMismatch(ObjPtr<mirror::Class> klass,
+ const DexFile& dex_file,
+ InvokeType type) {
+ if (type == kInterface) {
+ if (UNLIKELY(!klass->IsInterface())) {
+ ThrowIncompatibleClassChangeError(klass,
+ "Found class %s, but interface was expected",
+ klass->PrettyDescriptor().c_str());
+ return true;
}
- } 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;
+ } else if (type == kVirtual) {
+ if (UNLIKELY(klass->IsInterface())) {
+ ThrowIncompatibleClassChangeError(klass,
+ "Found interface %s, but class was expected",
+ klass->PrettyDescriptor().c_str());
+ return true;
}
- // 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;
+ } else if (type == kDirect) {
+ if (UNLIKELY(klass->IsInterface()) && !dex_file.SupportsDefaultMethods()) {
+ ThrowIncompatibleClassChangeError(klass,
+ "Found interface %s, but class was expected",
+ klass->PrettyDescriptor().c_str());
+ return true;
}
}
+ return false;
+}
- // Check if the invoke type matches the class type.
- if (kResolveMode == ResolveMode::kCheckICCEAndIAE &&
- CheckInvokeClassMismatch</* kThrow= */ true>(
- dex_cache.Get(), type, [klass]() { return klass; })) {
+inline ArtMethod* ClassLinker::ResolveMethodWithChecks(uint32_t method_idx,
+ ArtMethod* referrer,
+ InvokeType type) {
+ DCHECK(referrer != nullptr);
+ DCHECK_IMPLIES(referrer->IsProxyMethod(), referrer->IsConstructor());
+
+ // 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_);
+
+ const dex::MethodId& method_id = referrer->GetDexFile()->GetMethodId(method_idx);
+ ObjPtr<mirror::Class> klass = ResolveType(method_id.class_idx_, referrer);
+ if (klass == nullptr || ThrowIfInvokeClassMismatch(klass, *referrer->GetDexFile(), type)) {
DCHECK(Thread::Current()->IsExceptionPending());
return nullptr;
}
- if (!valid_dex_cache_method) {
- resolved = FindResolvedMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx);
+ ArtMethod* resolved = referrer->GetDexCache()->GetResolvedMethod(method_idx);
+ if (resolved == nullptr) {
+ resolved = FindResolvedMethod(klass,
+ referrer->GetDexCache(),
+ referrer->GetDexCache()->GetClassLoader(),
+ method_idx);
}
- // Note: We can check for IllegalAccessError only if we have a referrer.
- if (kResolveMode == ResolveMode::kCheckICCEAndIAE && resolved != nullptr && referrer != nullptr) {
+ if (resolved != nullptr) {
ObjPtr<mirror::Class> methods_class = resolved->GetDeclaringClass();
ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
if (UNLIKELY(!referring_class->CanAccess(methods_class))) {
@@ -403,29 +322,25 @@ inline ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx,
ThrowIllegalAccessErrorMethod(referring_class, resolved);
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;
- }
- // 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 (LIKELY(!resolved->CheckIncompatibleClassChange(type))) {
+ return resolved;
+ }
+ } else {
+ resolved = FindIncompatibleMethod(klass,
+ referrer->GetDexCache(),
+ referrer->GetDexCache()->GetClassLoader(),
+ 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.GetStringData(method_id.name_idx_);
- const Signature signature = dex_file.GetMethodSignature(method_id);
- ThrowNoSuchMethodError(type, klass, name, signature);
+ return nullptr;
}
- Thread::Current()->AssertPendingException();
+
+ // We failed to find the method (using all lookup types), so throw a NoSuchMethodError.
+ const char* name = referrer->GetDexFile()->GetStringData(method_id.name_idx_);
+ const Signature signature = referrer->GetDexFile()->GetMethodSignature(method_id);
+ ThrowNoSuchMethodError(type, klass, name, signature);
return nullptr;
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index eb9e9062cb..0c9b6e2f55 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -10455,21 +10455,17 @@ ObjPtr<mirror::MethodHandle> ClassLinker::ResolveMethodHandleForMethod(
case DexFile::MethodHandleType::kInvokeStatic: {
kind = mirror::MethodHandle::Kind::kInvokeStatic;
receiver_count = 0;
- target_method =
- ResolveMethod<ResolveMode::kCheckICCEAndIAE>(self,
- method_handle.field_or_method_idx_,
- referrer,
- InvokeType::kStatic);
+ target_method = ResolveMethodWithChecks(method_handle.field_or_method_idx_,
+ referrer,
+ InvokeType::kStatic);
break;
}
case DexFile::MethodHandleType::kInvokeInstance: {
kind = mirror::MethodHandle::Kind::kInvokeVirtual;
receiver_count = 1;
- target_method =
- ResolveMethod<ResolveMode::kCheckICCEAndIAE>(self,
- method_handle.field_or_method_idx_,
- referrer,
- InvokeType::kVirtual);
+ target_method = ResolveMethodWithChecks(method_handle.field_or_method_idx_,
+ referrer,
+ InvokeType::kVirtual);
break;
}
case DexFile::MethodHandleType::kInvokeConstructor: {
@@ -10477,11 +10473,9 @@ ObjPtr<mirror::MethodHandle> ClassLinker::ResolveMethodHandleForMethod(
// are special cased later in this method.
kind = mirror::MethodHandle::Kind::kInvokeTransform;
receiver_count = 0;
- target_method =
- ResolveMethod<ResolveMode::kCheckICCEAndIAE>(self,
- method_handle.field_or_method_idx_,
- referrer,
- InvokeType::kDirect);
+ target_method = ResolveMethodWithChecks(method_handle.field_or_method_idx_,
+ referrer,
+ InvokeType::kDirect);
break;
}
case DexFile::MethodHandleType::kInvokeDirect: {
@@ -10503,18 +10497,14 @@ ObjPtr<mirror::MethodHandle> ClassLinker::ResolveMethodHandleForMethod(
if (target_method->IsPrivate()) {
kind = mirror::MethodHandle::Kind::kInvokeDirect;
- target_method =
- ResolveMethod<ResolveMode::kCheckICCEAndIAE>(self,
- method_handle.field_or_method_idx_,
- referrer,
- InvokeType::kDirect);
+ target_method = ResolveMethodWithChecks(method_handle.field_or_method_idx_,
+ referrer,
+ InvokeType::kDirect);
} else {
kind = mirror::MethodHandle::Kind::kInvokeSuper;
- target_method =
- ResolveMethod<ResolveMode::kCheckICCEAndIAE>(self,
- method_handle.field_or_method_idx_,
- referrer,
- InvokeType::kSuper);
+ target_method = ResolveMethodWithChecks(method_handle.field_or_method_idx_,
+ referrer,
+ InvokeType::kSuper);
if (UNLIKELY(target_method == nullptr)) {
break;
}
@@ -10530,11 +10520,9 @@ ObjPtr<mirror::MethodHandle> ClassLinker::ResolveMethodHandleForMethod(
case DexFile::MethodHandleType::kInvokeInterface: {
kind = mirror::MethodHandle::Kind::kInvokeInterface;
receiver_count = 1;
- target_method =
- ResolveMethod<ResolveMode::kCheckICCEAndIAE>(self,
- method_handle.field_or_method_idx_,
- referrer,
- InvokeType::kInterface);
+ target_method = ResolveMethodWithChecks(method_handle.field_or_method_idx_,
+ referrer,
+ InvokeType::kInterface);
break;
}
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index d1c82776cc..4ca6024442 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -334,13 +334,6 @@ class ClassLinker {
ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Determine whether a dex cache result should be trusted, or an IncompatibleClassChangeError
- // check and IllegalAccessError check should be performed even after a hit.
- enum class ResolveMode { // private.
- kNoChecks,
- kCheckICCEAndIAE
- };
-
// Look up a previously resolved method with the given index.
ArtMethod* LookupResolvedMethod(uint32_t method_idx,
ObjPtr<mirror::DexCache> dex_cache,
@@ -363,21 +356,16 @@ class ClassLinker {
uint32_t method_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Resolve a method with a given ID from the DexFile associated with the given DexCache
- // and ClassLoader, storing the result in DexCache. The ClassLinker and ClassLoader are
- // used as in ResolveType. What is unique is the method type argument which is used to
- // determine if this method is a direct, static, or virtual method.
- template <ResolveMode kResolveMode>
- ArtMethod* ResolveMethod(uint32_t method_idx,
- Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader,
- ArtMethod* referrer,
- InvokeType type)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
+ // Check invoke type against the referenced class. Throws IncompatibleClassChangeError
+ // and returns true on mismatch (kInterface on a non-interface class,
+ // kVirtual on interface, kDefault on interface for dex files not supporting default methods),
+ // otherwise returns false.
+ static bool ThrowIfInvokeClassMismatch(ObjPtr<mirror::Class> cls,
+ const DexFile& dex_file,
+ InvokeType type)
+ REQUIRES_SHARED(Locks::mutator_lock_);
- template <ResolveMode kResolveMode>
- ArtMethod* ResolveMethod(Thread* self, uint32_t method_idx, ArtMethod* referrer, InvokeType type)
+ ArtMethod* ResolveMethodWithChecks(uint32_t method_idx, ArtMethod* referrer, InvokeType type)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
@@ -387,6 +375,10 @@ class ClassLinker {
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
+ ArtMethod* ResolveMethodId(uint32_t method_idx, ArtMethod* referrer)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
+
ArtField* LookupResolvedField(uint32_t field_idx, ArtMethod* referrer, bool is_static)
REQUIRES_SHARED(Locks::mutator_lock_);
// Find a field by its field index.
@@ -1408,23 +1400,6 @@ class ClassLinker {
/*out*/bool* new_conflict,
/*out*/ArtMethod** imt) REQUIRES_SHARED(Locks::mutator_lock_);
- // Check invoke type against the referenced class. Throws IncompatibleClassChangeError
- // (if `kThrowOnError`) and returns true on mismatch (kInterface on a non-interface class,
- // kVirtual on interface, kDefault on interface for dex files not supporting default methods),
- // otherwise returns false.
- template <bool kThrowOnError, typename ClassGetter>
- static bool CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
- InvokeType type,
- ClassGetter class_getter)
- REQUIRES_SHARED(Locks::mutator_lock_);
- // Helper that feeds the above function with `ClassGetter` doing `LookupResolvedType()`.
- template <bool kThrow>
- bool CheckInvokeClassMismatch(ObjPtr<mirror::DexCache> dex_cache,
- InvokeType type,
- uint32_t method_idx,
- ObjPtr<mirror::ClassLoader> class_loader)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
ObjPtr<mirror::IfTable> GetArrayIfTable() REQUIRES_SHARED(Locks::mutator_lock_);
bool OpenAndInitImageDexFiles(const gc::space::ImageSpace* space,
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index e1cabbb574..c1d9a00d5d 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -418,6 +418,16 @@ void ThrowNoSuchMethodError(InvokeType type,
ThrowException("Ljava/lang/NoSuchMethodError;", c, msg.str().c_str());
}
+void ThrowNoSuchMethodError(ObjPtr<mirror::Class> c,
+ std::string_view name,
+ const Signature& signature) {
+ std::ostringstream msg;
+ std::string temp;
+ msg << "No method " << name << signature
+ << " in class " << c->GetDescriptor(&temp) << " or its super classes";
+ ThrowException("Ljava/lang/NoSuchMethodError;", c, msg.str().c_str());
+}
+
// NullPointerException
void ThrowNullPointerExceptionForFieldAccess(ArtField* field, ArtMethod* method, bool is_read) {
diff --git a/runtime/common_throws.h b/runtime/common_throws.h
index f6d6891b87..ccf31a3b8b 100644
--- a/runtime/common_throws.h
+++ b/runtime/common_throws.h
@@ -216,6 +216,11 @@ void ThrowNoSuchMethodError(InvokeType type,
const Signature& signature)
REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+void ThrowNoSuchMethodError(ObjPtr<mirror::Class> c,
+ std::string_view name,
+ const Signature& signature)
+ REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+
// NullPointerException
EXPORT
void ThrowNullPointerExceptionForFieldAccess(ArtField* field, ArtMethod* method, bool is_read)
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index fde8043032..7ddf06f5ab 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -387,16 +387,15 @@ inline ArtField* ResolveFieldWithAccessChecks(Thread* self,
}
caller = caller->GetInterfaceMethodIfProxy(class_linker->GetImagePointerSize());
-
- StackHandleScope<2> hs(self);
- Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(caller->GetDexCache()));
- Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(caller->GetClassLoader()));
-
- ArtField* resolved_field = class_linker->ResolveFieldJLS(field_index,
- h_dex_cache,
- h_class_loader);
+ ArtField* resolved_field = caller->GetDexCache()->GetResolvedField(field_index);
if (resolved_field == nullptr) {
- return nullptr;
+ StackHandleScope<2> hs(self);
+ Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(caller->GetDexCache()));
+ Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(caller->GetClassLoader()));
+ resolved_field = class_linker->ResolveFieldJLS(field_index, h_dex_cache, h_class_loader);
+ if (resolved_field == nullptr) {
+ return nullptr;
+ }
}
ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass();
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index fc18269e7b..1167710215 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -60,8 +60,7 @@ extern "C" const void* artFindNativeMethodRunnable(Thread* self)
// We're coming from compiled managed code and the `method` we see here is the caller.
// Resolve target @CriticalNative method for a direct call from compiled managed code.
uint32_t method_idx = GetInvokeStaticMethodIndex(method, dex_pc);
- ArtMethod* target_method = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- self, method_idx, method, kStatic);
+ ArtMethod* target_method = class_linker->ResolveMethodId(method_idx, method);
if (target_method == nullptr) {
self->AssertPendingException();
return nullptr;
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 118e4f3bc0..6c817d5e16 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1297,8 +1297,7 @@ extern "C" const void* artQuickResolutionTrampoline(
HandleWrapper<mirror::Object> h_receiver(
hs.NewHandleWrapper(virtual_or_interface ? &receiver : &fake_receiver));
DCHECK_EQ(caller->GetDexFile(), called_method.dex_file);
- called = linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- self, called_method.index, caller, invoke_type);
+ called = linker->ResolveMethodWithChecks(called_method.index, caller, invoke_type);
}
const void* code = nullptr;
if (LIKELY(!self->IsExceptionPending())) {
@@ -2314,8 +2313,7 @@ extern "C" TwoWordReturn artInvokeInterfaceTrampoline(ArtMethod* interface_metho
RememberForGcArgumentVisitor visitor(sp, false, shorty, &soa);
visitor.VisitArguments();
ClassLinker* class_linker = runtime->GetClassLinker();
- interface_method = class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- self, dex_method_idx, caller_method, kInterface);
+ interface_method = class_linker->ResolveMethodId(dex_method_idx, caller_method);
visitor.FixupReferences();
}
@@ -2429,8 +2427,8 @@ extern "C" uint64_t artInvokePolymorphic(mirror::Object* raw_receiver, Thread* s
// Resolve method.
ClassLinker* linker = Runtime::Current()->GetClassLinker();
- ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- self, inst.VRegB(), caller_method, kVirtual);
+ ArtMethod* resolved_method = linker->ResolveMethodWithChecks(
+ inst.VRegB(), caller_method, kVirtual);
DCHECK_EQ(ArtMethod::NumArgRegisters(shorty) + 1u, (uint32_t)inst.VRegA());
DCHECK_EQ(resolved_method->IsStatic(), kMethodIsStatic);
@@ -2559,8 +2557,8 @@ extern "C" uint64_t artInvokePolymorphicWithHiddenReceiver(mirror::Object* raw_r
ClassLinker* linker = Runtime::Current()->GetClassLinker();
ArtMethod* invoke_exact = WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact;
if (kIsDebugBuild) {
- ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- self, inst.VRegB(), caller_method, kVirtual);
+ ArtMethod* resolved_method = linker->ResolveMethodWithChecks(
+ inst.VRegB(), caller_method, kVirtual);
CHECK_EQ(resolved_method, invoke_exact);
}
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index b6232ec46b..5024b16ba2 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -513,8 +513,8 @@ bool DoInvokePolymorphic(Thread* self,
const int invoke_method_idx = inst->VRegB();
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ArtMethod* invoke_method =
- class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- self, invoke_method_idx, shadow_frame.GetMethod(), kPolymorphic);
+ class_linker->ResolveMethodWithChecks(
+ invoke_method_idx, shadow_frame.GetMethod(), kPolymorphic);
// Ensure intrinsic identifiers are initialized.
DCHECK(invoke_method->IsIntrinsic());
diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc
index aa954d1bdb..141dfae92e 100644
--- a/runtime/interpreter/mterp/nterp.cc
+++ b/runtime/interpreter/mterp/nterp.cc
@@ -332,10 +332,8 @@ extern "C" size_t NterpGetMethod(Thread* self, ArtMethod* caller, const uint16_t
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
ArtMethod* resolved_method = caller->SkipAccessChecks()
- ? class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
- self, method_index, caller, invoke_type)
- : class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- self, method_index, caller, invoke_type);
+ ? class_linker->ResolveMethodId(method_index, caller)
+ : class_linker->ResolveMethodWithChecks(method_index, caller, invoke_type);
if (resolved_method == nullptr) {
DCHECK(self->IsExceptionPending());
return 0;
diff --git a/runtime/jit/small_pattern_matcher.cc b/runtime/jit/small_pattern_matcher.cc
index 5dd116c560..1fc320f780 100644
--- a/runtime/jit/small_pattern_matcher.cc
+++ b/runtime/jit/small_pattern_matcher.cc
@@ -177,11 +177,7 @@ const void* SmallPatternMatcher::TryMatch(ArtMethod* method) REQUIRES_SHARED(Loc
REQUIRES_SHARED(Locks::mutator_lock_) {
uint16_t method_idx = instruction.VRegB_35c();
Thread* self = Thread::Current();
- ArtMethod* target_method =
- class_linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(self,
- method_idx,
- method,
- kDirect);
+ ArtMethod* target_method = class_linker->ResolveMethodId(method_idx, method);
if (target_method == nullptr) {
self->ClearException();
return false;