ART: Change method lookup to be more consistent to JLS and the RI.
The method lookup for different invoke types was previously
widely different and didn't work well with the dex cache
method array where we have only a single slot for each
MethodId. The new behavior is to perform the same lookup for
all cases, distinguishing only between interface and
non-interface referencing class, and to further align the
behavior with the JLS and the RI. Where the JLS conflicts
with the RI, we follow the JLS semantics.
The new lookup for class methods first searches the methods
declared in the superclass chain (ignoring "copied" methods)
and only then looks in the "copied" methods. If the search
in the superclass chain finds a method that has not been
inherited (i.e. either a private method or a package-access
method where one of the classes in the chain does not belong
to the same package, see JLS 8.4.8), we still search the
"copied" methods as there may actually be a method inherited
from an interface. This follows the JLS semantics where
inherited methods are included in the search (JLS 15.12.2.1)
but conflicts with the RI where the private or
package-access method takes precedence over methods
inherited from interfaces.
Note that this search can find an accessible method that is
not inherited by the qualifying type, either for a package
access method when the referrer is in the same package but
the qualifying type is in another package, or for a private
method where the referrer is in the same class but the
qualifying type is actually a subclass. For the moment we
allow such calls and we shall consider whether to throw
an IncompatibleClassChangeError in this situation in future
to comply with JLS 15.12.4.3.
The new lookup for interface methods searches the interface
class, then all the superinterfaces and then the
java.lang.Object class, see implicitly declared methods in
interfaces, JLS 9.2. The search for the maximally-specific
non-abstract superinterface method is not yet implemented,
but the difference should be difficult to observe as the
usual subsequent call to FindVirtualMethodForInterface()
should yield the same result for any matching method.
The new test 162-method-idx-clash exposes several cases
where we previously completely messed up due to the effects
of the DexCache, or where we were out of line with the RI.
It also tests a case where the JLS and the RI disagree and
we follow the JLS.
Test: art/test/run-test --host --jvm 162-method-resolution
Test: m test-art-host-gtest
Test: testrunner.py --host
Test: testrunner.py --host --interp-ac
Test: Nexus 6P boots.
Test: testrunner.py --target
Bug: 62855082
Bug: 30627598
Change-Id: If450c8cff2751369011d649c25d28a482a2c61a3
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 45dd596..ef9c457 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -67,9 +67,10 @@
return this;
} else {
mirror::Class* declaring_class = GetDeclaringClass();
- ArtMethod* ret = declaring_class->FindDeclaredVirtualMethod(declaring_class->GetDexCache(),
- GetDexMethodIndex(),
- pointer_size);
+ DCHECK(declaring_class->IsInterface());
+ ArtMethod* ret = declaring_class->FindInterfaceMethod(declaring_class->GetDexCache(),
+ GetDexMethodIndex(),
+ pointer_size);
DCHECK(ret != nullptr);
return ret;
}
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 3c51f52..d29db15 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -90,33 +90,105 @@
return resolved_type.Ptr();
}
+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:
+ 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()->GetVersion() >= DexFile::kDefaultMethodsVersion) {
+ 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) {
+ return CheckInvokeClassMismatch<kThrow>(
+ dex_cache,
+ type,
+ [this, dex_cache, method_idx, class_loader]() REQUIRES_SHARED(Locks::mutator_lock_) {
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
+ ObjPtr<mirror::Class> klass =
+ LookupResolvedType(dex_file, method_id.class_idx_, dex_cache, class_loader);
+ DCHECK(klass != nullptr);
+ return klass;
+ });
+}
+
+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(!referrer->IsProxyMethod() || referrer->IsConstructor());
ArtMethod* resolved_method = referrer->GetDexCacheResolvedMethod(method_idx, image_pointer_size_);
if (resolved_method == nullptr || resolved_method->IsRuntimeMethod()) {
return nullptr;
}
- return resolved_method;
-}
-
-inline mirror::Class* ClassLinker::ResolveReferencedClassOfMethod(
- uint32_t method_idx,
- Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader) {
- // NB: We cannot simply use `GetResolvedMethod(method_idx, ...)->GetDeclaringClass()`. This is
- // because if we did so than an invoke-super could be incorrectly dispatched in cases where
- // GetMethodId(method_idx).class_idx_ refers to a non-interface, non-direct-superclass
- // (super*-class?) of the referrer and the direct superclass of the referrer contains a concrete
- // implementation of the method. If this class's implementation of the method is copied from an
- // interface (either miranda, default or conflict) we would incorrectly assume that is what we
- // want to invoke on, instead of the 'concrete' implementation that the direct superclass
- // contains.
- const DexFile* dex_file = dex_cache->GetDexFile();
- const DexFile::MethodId& method = dex_file->GetMethodId(method_idx);
- ObjPtr<mirror::Class> resolved_type = dex_cache->GetResolvedType(method.class_idx_);
- if (UNLIKELY(resolved_type == nullptr)) {
- resolved_type = ResolveType(*dex_file, method.class_idx_, dex_cache, class_loader);
+ 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();
+ 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_type.Ptr();
+ return resolved_method;
}
template <ClassLinker::ResolveMode kResolveMode>
@@ -124,9 +196,15 @@
uint32_t method_idx,
ArtMethod* referrer,
InvokeType type) {
- ArtMethod* resolved_method = GetResolvedMethod(method_idx, 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(!referrer->IsProxyMethod() || referrer->IsConstructor());
Thread::PoisonObjectPointersIfDebug();
- if (UNLIKELY(resolved_method == nullptr)) {
+ ArtMethod* resolved_method = referrer->GetDexCacheResolvedMethod(method_idx, image_pointer_size_);
+ if (UNLIKELY(resolved_method == nullptr || resolved_method->IsRuntimeMethod())) {
+ 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()));
@@ -138,6 +216,33 @@
h_class_loader,
referrer,
type);
+ } else 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();
+ if (CheckInvokeClassMismatch</* kThrow */ true>(dex_cache, type, method_idx, class_loader)) {
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return nullptr;
+ }
+ // Check access.
+ ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
+ if (!referring_class->CheckResolvedMethodAccess(resolved_method->GetDeclaringClass(),
+ resolved_method,
+ dex_cache,
+ 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;
+ }
}
// 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.
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 41adae4..07a40c4 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -149,8 +149,8 @@
return false;
}
- ArtMethod* exception_init_method = exception_class->FindDeclaredDirectMethod(
- "<init>", "(Ljava/lang/String;)V", class_linker->GetImagePointerSize());
+ ArtMethod* exception_init_method = exception_class->FindConstructor(
+ "(Ljava/lang/String;)V", class_linker->GetImagePointerSize());
return exception_init_method != nullptr;
}
@@ -4658,10 +4658,8 @@
// Find the <init>(InvocationHandler)V method. The exact method offset varies depending
// on which front-end compiler was used to build the libcore DEX files.
- ArtMethod* proxy_constructor = GetClassRoot(kJavaLangReflectProxy)->
- FindDeclaredDirectMethod("<init>",
- "(Ljava/lang/reflect/InvocationHandler;)V",
- image_pointer_size_);
+ ArtMethod* proxy_constructor = GetClassRoot(kJavaLangReflectProxy)->FindConstructor(
+ "(Ljava/lang/reflect/InvocationHandler;)V", image_pointer_size_);
DCHECK(proxy_constructor != nullptr)
<< "Could not find <init> method in java.lang.reflect.Proxy";
@@ -4673,8 +4671,9 @@
// code_ too)
DCHECK(out != nullptr);
out->CopyFrom(proxy_constructor, image_pointer_size_);
- // Make this constructor public and fix the class to be our Proxy version
+ // Make this constructor public and fix the class to be our Proxy version.
// Mark kAccCompileDontBother so that we don't take JIT samples for the method. b/62349349
+ // Note that the compiler calls a ResolveMethod() overload that does not handle a Proxy referrer.
out->SetAccessFlags((out->GetAccessFlags() & ~kAccProtected) |
kAccPublic |
kAccCompileDontBother);
@@ -7383,10 +7382,8 @@
// defaults. This means we don't need to do any trickery when creating the Miranda methods, since
// they will already be null. This has the additional benefit that the declarer of a miranda
// method will actually declare an abstract method.
- for (size_t i = ifcount; i != 0; ) {
+ for (size_t i = ifcount; i != 0u; ) {
--i;
-
- DCHECK_GE(i, 0u);
DCHECK_LT(i, ifcount);
size_t num_methods = iftable->GetInterface(i)->NumDeclaredVirtualMethods();
@@ -7967,201 +7964,95 @@
ArtMethod* referrer,
InvokeType type) {
DCHECK(dex_cache != nullptr);
+ DCHECK(referrer == nullptr || !referrer->IsProxyMethod());
// Check for hit in the dex cache.
- ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, image_pointer_size_);
+ PointerSize pointer_size = image_pointer_size_;
+ ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, pointer_size);
Thread::PoisonObjectPointersIfDebug();
- if (resolved != nullptr && !resolved->IsRuntimeMethod()) {
+ bool valid_dex_cache_method = resolved != nullptr && !resolved->IsRuntimeMethod();
+ 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();
- if (kResolveMode == ClassLinker::kForceICCECheck) {
- if (resolved->CheckIncompatibleClassChange(type)) {
- ThrowIncompatibleClassChangeError(type, resolved->GetInvokeType(), resolved, referrer);
- return nullptr;
- }
- }
return resolved;
}
- // Fail, get the declaring class.
const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
- ObjPtr<mirror::Class> klass = ResolveType(dex_file, method_id.class_idx_, dex_cache, class_loader);
- if (klass == nullptr) {
+ 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(dex_file, method_id.class_idx_, dex_cache.Get(), class_loader.Get());
+ DCHECK(klass != nullptr);
+ } else {
+ // The method was not in the DexCache, resolve the declaring class.
+ klass = ResolveType(dex_file, 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;
}
- // Scan using method_idx, this saves string compares but will only hit for matching dex
- // caches/files.
- switch (type) {
- case kDirect: // Fall-through.
- case kStatic:
- resolved = klass->FindDirectMethod(dex_cache.Get(), method_idx, image_pointer_size_);
- DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr);
- break;
- case kInterface:
- // We have to check whether the method id really belongs to an interface (dex static bytecode
- // constraint A15). Otherwise you must not invoke-interface on it.
- //
- // This is not symmetric to A12-A14 (direct, static, virtual), as using FindInterfaceMethod
- // assumes that the given type is an interface, and will check the interface table if the
- // method isn't declared in the class. So it may find an interface method (usually by name
- // in the handling below, but we do the constraint check early). In that case,
- // CheckIncompatibleClassChange will succeed (as it is called on an interface method)
- // unexpectedly.
- // Example:
- // interface I {
- // foo()
- // }
- // class A implements I {
- // ...
- // }
- // class B extends A {
- // ...
- // }
- // invoke-interface B.foo
- // -> FindInterfaceMethod finds I.foo (interface method), not A.foo (miranda method)
- if (UNLIKELY(!klass->IsInterface())) {
- ThrowIncompatibleClassChangeError(klass,
- "Found class %s, but interface was expected",
- klass->PrettyDescriptor().c_str());
- return nullptr;
- } else {
- resolved = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, image_pointer_size_);
- DCHECK(resolved == nullptr || resolved->GetDeclaringClass()->IsInterface());
- }
- break;
- case kSuper:
- if (klass->IsInterface()) {
- resolved = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, image_pointer_size_);
- } else {
- resolved = klass->FindVirtualMethod(dex_cache.Get(), method_idx, image_pointer_size_);
- }
- break;
- case kVirtual:
- resolved = klass->FindVirtualMethod(dex_cache.Get(), method_idx, image_pointer_size_);
- break;
- default:
- LOG(FATAL) << "Unreachable - invocation type: " << type;
- UNREACHABLE();
- }
- if (resolved == nullptr) {
- // Search by name, which works across dex files.
- const char* name = dex_file.StringDataByIdx(method_id.name_idx_);
- const Signature signature = dex_file.GetMethodSignature(method_id);
- switch (type) {
- case kDirect: // Fall-through.
- case kStatic:
- resolved = klass->FindDirectMethod(name, signature, image_pointer_size_);
- DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr);
- break;
- case kInterface:
- resolved = klass->FindInterfaceMethod(name, signature, image_pointer_size_);
- DCHECK(resolved == nullptr || resolved->GetDeclaringClass()->IsInterface());
- break;
- case kSuper:
- if (klass->IsInterface()) {
- resolved = klass->FindInterfaceMethod(name, signature, image_pointer_size_);
- } else {
- resolved = klass->FindVirtualMethod(name, signature, image_pointer_size_);
- }
- break;
- case kVirtual:
- resolved = klass->FindVirtualMethod(name, signature, image_pointer_size_);
- break;
+
+ if (!valid_dex_cache_method) {
+ // Search for the method using dex_cache and method_idx. The Class::Find*Method()
+ // functions can optimize the search if the dex_cache is the same as the DexCache
+ // of the class, with fall-back to name and signature search otherwise.
+ if (klass->IsInterface()) {
+ resolved = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, pointer_size);
+ } else {
+ resolved = klass->FindClassMethod(dex_cache.Get(), method_idx, pointer_size);
+ }
+ DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr);
+ if (resolved != nullptr) {
+ // Be a good citizen and update the dex cache to speed subsequent calls.
+ dex_cache->SetResolvedMethod(method_idx, resolved, pointer_size);
}
}
+
+ // 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 && !resolved->CheckIncompatibleClassChange(type))) {
- // Be a good citizen and update the dex cache to speed subsequent calls.
- dex_cache->SetResolvedMethod(method_idx, resolved, image_pointer_size_);
+ if (LIKELY(resolved != nullptr) &&
+ LIKELY(kResolveMode == ResolveMode::kNoChecks ||
+ !resolved->CheckIncompatibleClassChange(type))) {
return resolved;
} else {
- // If we had a method, it's an incompatible-class-change error.
+ // 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) {
+ if (klass->IsInterface()) {
+ resolved = klass->FindClassMethod(dex_cache.Get(), method_idx, pointer_size);
+ } else {
+ // If there was an interface method with the same signature,
+ // we would have found it also in the "copied" methods.
+ DCHECK(klass->FindInterfaceMethod(dex_cache.Get(), method_idx, pointer_size) == nullptr);
+ }
+ }
if (resolved != nullptr) {
ThrowIncompatibleClassChangeError(type, resolved->GetInvokeType(), resolved, referrer);
} else {
- // We failed to find the method which means either an access error, an incompatible class
- // change, or no such method. First try to find the method among direct and virtual methods.
+ // 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);
- switch (type) {
- case kDirect:
- case kStatic:
- resolved = klass->FindVirtualMethod(name, signature, image_pointer_size_);
- // Note: kDirect and kStatic are also mutually exclusive, but in that case we would
- // have had a resolved method before, which triggers the "true" branch above.
- break;
- case kInterface:
- case kVirtual:
- case kSuper:
- resolved = klass->FindDirectMethod(name, signature, image_pointer_size_);
- break;
- }
-
- // If we found something, check that it can be accessed by the referrer.
- bool exception_generated = false;
- if (resolved != nullptr && referrer != nullptr) {
- ObjPtr<mirror::Class> methods_class = resolved->GetDeclaringClass();
- ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
- if (!referring_class->CanAccess(methods_class)) {
- ThrowIllegalAccessErrorClassForMethodDispatch(referring_class,
- methods_class,
- resolved,
- type);
- exception_generated = true;
- } else if (!referring_class->CanAccessMember(methods_class, resolved->GetAccessFlags())) {
- ThrowIllegalAccessErrorMethod(referring_class, resolved);
- exception_generated = true;
- }
- }
- if (!exception_generated) {
- // Otherwise, throw an IncompatibleClassChangeError if we found something, and check
- // interface methods and throw if we find the method there. If we find nothing, throw a
- // NoSuchMethodError.
- switch (type) {
- case kDirect:
- case kStatic:
- if (resolved != nullptr) {
- ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer);
- } else {
- resolved = klass->FindInterfaceMethod(name, signature, image_pointer_size_);
- if (resolved != nullptr) {
- ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer);
- } else {
- ThrowNoSuchMethodError(type, klass, name, signature);
- }
- }
- break;
- case kInterface:
- if (resolved != nullptr) {
- ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer);
- } else {
- resolved = klass->FindVirtualMethod(name, signature, image_pointer_size_);
- if (resolved != nullptr) {
- ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer);
- } else {
- ThrowNoSuchMethodError(type, klass, name, signature);
- }
- }
- break;
- case kSuper:
- if (resolved != nullptr) {
- ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer);
- } else {
- ThrowNoSuchMethodError(type, klass, name, signature);
- }
- break;
- case kVirtual:
- if (resolved != nullptr) {
- ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer);
- } else {
- resolved = klass->FindInterfaceMethod(name, signature, image_pointer_size_);
- if (resolved != nullptr) {
- ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer);
- } else {
- ThrowNoSuchMethodError(type, klass, name, signature);
- }
- }
- break;
- }
- }
+ ThrowNoSuchMethodError(type, klass, name, signature);
}
Thread::Current()->AssertPendingException();
return nullptr;
@@ -8180,21 +8071,16 @@
}
// Fail, get the declaring class.
const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
- ObjPtr<mirror::Class> klass = ResolveType(dex_file, method_id.class_idx_, dex_cache, class_loader);
+ ObjPtr<mirror::Class> klass =
+ ResolveType(dex_file, method_id.class_idx_, dex_cache, class_loader);
if (klass == nullptr) {
Thread::Current()->AssertPendingException();
return nullptr;
}
if (klass->IsInterface()) {
- LOG(FATAL) << "ResolveAmbiguousMethod: unexpected method in interface: "
- << klass->PrettyClass();
- return nullptr;
- }
-
- // Search both direct and virtual methods
- resolved = klass->FindDirectMethod(dex_cache.Get(), method_idx, image_pointer_size_);
- if (resolved == nullptr) {
- resolved = klass->FindVirtualMethod(dex_cache.Get(), method_idx, image_pointer_size_);
+ resolved = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, image_pointer_size_);
+ } else {
+ resolved = klass->FindClassMethod(dex_cache.Get(), method_idx, image_pointer_size_);
}
return resolved;
@@ -8509,19 +8395,19 @@
case DexFile::MethodHandleType::kInvokeStatic: {
kind = mirror::MethodHandle::Kind::kInvokeStatic;
receiver_count = 0;
- target_method = ResolveMethod<kNoICCECheckForCache>(self,
- method_handle.field_or_method_idx_,
- referrer,
- InvokeType::kStatic);
+ target_method = ResolveMethod<ResolveMode::kNoChecks>(self,
+ 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<kNoICCECheckForCache>(self,
- method_handle.field_or_method_idx_,
- referrer,
- InvokeType::kVirtual);
+ target_method = ResolveMethod<ResolveMode::kNoChecks>(self,
+ method_handle.field_or_method_idx_,
+ referrer,
+ InvokeType::kVirtual);
break;
}
case DexFile::MethodHandleType::kInvokeConstructor: {
@@ -8529,10 +8415,10 @@
// are special cased later in this method.
kind = mirror::MethodHandle::Kind::kInvokeTransform;
receiver_count = 0;
- target_method = ResolveMethod<kNoICCECheckForCache>(self,
- method_handle.field_or_method_idx_,
- referrer,
- InvokeType::kDirect);
+ target_method = ResolveMethod<ResolveMode::kNoChecks>(self,
+ method_handle.field_or_method_idx_,
+ referrer,
+ InvokeType::kDirect);
break;
}
case DexFile::MethodHandleType::kInvokeDirect: {
@@ -8555,16 +8441,16 @@
if (target_method->IsPrivate()) {
kind = mirror::MethodHandle::Kind::kInvokeDirect;
- target_method = ResolveMethod<kNoICCECheckForCache>(self,
- method_handle.field_or_method_idx_,
- referrer,
- InvokeType::kDirect);
+ target_method = ResolveMethod<ResolveMode::kNoChecks>(self,
+ method_handle.field_or_method_idx_,
+ referrer,
+ InvokeType::kDirect);
} else {
kind = mirror::MethodHandle::Kind::kInvokeSuper;
- target_method = ResolveMethod<kNoICCECheckForCache>(self,
- method_handle.field_or_method_idx_,
- referrer,
- InvokeType::kSuper);
+ target_method = ResolveMethod<ResolveMode::kNoChecks>(self,
+ method_handle.field_or_method_idx_,
+ referrer,
+ InvokeType::kSuper);
if (UNLIKELY(target_method == nullptr)) {
break;
}
@@ -8580,10 +8466,10 @@
case DexFile::MethodHandleType::kInvokeInterface: {
kind = mirror::MethodHandle::Kind::kInvokeInterface;
receiver_count = 1;
- target_method = ResolveMethod<kNoICCECheckForCache>(self,
- method_handle.field_or_method_idx_,
- referrer,
- InvokeType::kInterface);
+ target_method = ResolveMethod<ResolveMode::kNoChecks>(self,
+ method_handle.field_or_method_idx_,
+ referrer,
+ InvokeType::kInterface);
break;
}
}
@@ -9200,14 +9086,14 @@
}
// Instantiate ResolveMethod.
-template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::kForceICCECheck>(
+template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
const DexFile& dex_file,
uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader,
ArtMethod* referrer,
InvokeType type);
-template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::kNoICCECheckForCache>(
+template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
const DexFile& dex_file,
uint32_t method_idx,
Handle<mirror::DexCache> dex_cache,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 864d37f..3cf59f0 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -281,10 +281,10 @@
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
// Determine whether a dex cache result should be trusted, or an IncompatibleClassChangeError
- // check should be performed even after a hit.
- enum ResolveMode { // private.
- kNoICCECheckForCache,
- kForceICCECheck
+ // check and IllegalAccessError check should be performed even after a hit.
+ enum class ResolveMode { // private.
+ kNoChecks,
+ kCheckICCEAndIAE
};
// Resolve a method with a given ID from the DexFile, storing the
@@ -302,17 +302,10 @@
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
+ template <InvokeType type, ResolveMode kResolveMode>
ArtMethod* GetResolvedMethod(uint32_t method_idx, ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_);
- // This returns the class referred to by GetMethodId(method_idx).class_idx_. This might be
- // different then the declaring class of the resolved method due to copied
- // miranda/default/conflict methods.
- mirror::Class* ResolveReferencedClassOfMethod(uint32_t method_idx,
- Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
template <ResolveMode kResolveMode>
ArtMethod* ResolveMethod(Thread* self, uint32_t method_idx, ArtMethod* referrer, InvokeType type)
REQUIRES_SHARED(Locks::mutator_lock_)
@@ -1205,6 +1198,23 @@
bool* new_conflict,
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_);
+
std::vector<const DexFile*> boot_class_path_;
std::vector<std::unique_ptr<const DexFile>> boot_dex_files_;
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 03cc6c5..98d7c7c 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -1121,7 +1121,7 @@
// Static final primitives that are initialized by a compile-time constant
// expression resolve to a copy of a constant value from the constant pool.
// So <clinit> should be null.
- ArtMethod* clinit = statics->FindDirectMethod("<clinit>", "()V", kRuntimePointerSize);
+ ArtMethod* clinit = statics->FindClassMethod("<clinit>", "()V", kRuntimePointerSize);
EXPECT_TRUE(clinit == nullptr);
EXPECT_EQ(9U, statics->NumStaticFields());
@@ -1208,24 +1208,30 @@
EXPECT_TRUE(J->IsAssignableFrom(B.Get()));
const Signature void_sig = I->GetDexCache()->GetDexFile()->CreateSignature("()V");
- ArtMethod* Ii = I->FindVirtualMethod("i", void_sig, kRuntimePointerSize);
- ArtMethod* Jj1 = J->FindVirtualMethod("j1", void_sig, kRuntimePointerSize);
- ArtMethod* Jj2 = J->FindVirtualMethod("j2", void_sig, kRuntimePointerSize);
+ ArtMethod* Ii = I->FindClassMethod("i", void_sig, kRuntimePointerSize);
+ ArtMethod* Jj1 = J->FindClassMethod("j1", void_sig, kRuntimePointerSize);
+ ArtMethod* Jj2 = J->FindClassMethod("j2", void_sig, kRuntimePointerSize);
ArtMethod* Kj1 = K->FindInterfaceMethod("j1", void_sig, kRuntimePointerSize);
ArtMethod* Kj2 = K->FindInterfaceMethod("j2", void_sig, kRuntimePointerSize);
ArtMethod* Kk = K->FindInterfaceMethod("k", void_sig, kRuntimePointerSize);
- ArtMethod* Ai = A->FindVirtualMethod("i", void_sig, kRuntimePointerSize);
- ArtMethod* Aj1 = A->FindVirtualMethod("j1", void_sig, kRuntimePointerSize);
- ArtMethod* Aj2 = A->FindVirtualMethod("j2", void_sig, kRuntimePointerSize);
+ ArtMethod* Ai = A->FindClassMethod("i", void_sig, kRuntimePointerSize);
+ ArtMethod* Aj1 = A->FindClassMethod("j1", void_sig, kRuntimePointerSize);
+ ArtMethod* Aj2 = A->FindClassMethod("j2", void_sig, kRuntimePointerSize);
ASSERT_TRUE(Ii != nullptr);
+ ASSERT_FALSE(Ii->IsDirect());
ASSERT_TRUE(Jj1 != nullptr);
+ ASSERT_FALSE(Jj1->IsDirect());
ASSERT_TRUE(Jj2 != nullptr);
+ ASSERT_FALSE(Jj2->IsDirect());
ASSERT_TRUE(Kj1 != nullptr);
ASSERT_TRUE(Kj2 != nullptr);
ASSERT_TRUE(Kk != nullptr);
ASSERT_TRUE(Ai != nullptr);
+ ASSERT_FALSE(Ai->IsDirect());
ASSERT_TRUE(Aj1 != nullptr);
+ ASSERT_FALSE(Aj1->IsDirect());
ASSERT_TRUE(Aj2 != nullptr);
+ ASSERT_FALSE(Aj2->IsDirect());
EXPECT_NE(Ii, Ai);
EXPECT_NE(Jj1, Aj1);
EXPECT_NE(Jj2, Aj2);
@@ -1266,7 +1272,10 @@
hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", class_loader);
ArtMethod* clinit = klass->FindClassInitializer(kRuntimePointerSize);
- ArtMethod* getS0 = klass->FindDirectMethod("getS0", "()Ljava/lang/Object;", kRuntimePointerSize);
+ ArtMethod* getS0 =
+ klass->FindClassMethod("getS0", "()Ljava/lang/Object;", kRuntimePointerSize);
+ ASSERT_TRUE(getS0 != nullptr);
+ ASSERT_TRUE(getS0->IsStatic());
const DexFile::TypeId* type_id = dex_file->FindTypeId("LStaticsFromCode;");
ASSERT_TRUE(type_id != nullptr);
dex::TypeIndex type_idx = dex_file->GetIndexForTypeId(*type_id);
@@ -1489,9 +1498,12 @@
hs.NewHandle(class_linker_->FindClass(soa.Self(), "LMethodTypes;", class_loader)));
class_linker_->EnsureInitialized(soa.Self(), method_types, true, true);
- ArtMethod* method1 = method_types->FindVirtualMethod("method1",
- "(Ljava/lang/String;)Ljava/lang/String;",
- kRuntimePointerSize);
+ ArtMethod* method1 = method_types->FindClassMethod(
+ "method1",
+ "(Ljava/lang/String;)Ljava/lang/String;",
+ kRuntimePointerSize);
+ ASSERT_TRUE(method1 != nullptr);
+ ASSERT_FALSE(method1->IsDirect());
const DexFile& dex_file = *(method1->GetDexFile());
Handle<mirror::DexCache> dex_cache = hs.NewHandle(
@@ -1522,10 +1534,12 @@
// Resolve the MethodType associated with a different method signature
// and assert it's different.
- ArtMethod* method2 = method_types->FindVirtualMethod(
+ ArtMethod* method2 = method_types->FindClassMethod(
"method2",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
kRuntimePointerSize);
+ ASSERT_TRUE(method2 != nullptr);
+ ASSERT_FALSE(method2->IsDirect());
const DexFile::MethodId& method2_id = dex_file.GetMethodId(method2->GetDexMethodIndex());
Handle<mirror::MethodType> method2_type = hs.NewHandle(
class_linker_->ResolveMethodType(dex_file, method2_id.proto_idx_, dex_cache, class_loader));
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index 41db4d8..b163cdb 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -181,19 +181,18 @@
if (lhs_shorty.find('L', 1) != StringPiece::npos) {
const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_);
const DexFile::TypeList* rhs_params = rhs.dex_file_->GetProtoParameters(*rhs.proto_id_);
- // Both lists are empty or have contents, or else shorty is broken.
- DCHECK_EQ(params == nullptr, rhs_params == nullptr);
- if (params != nullptr) {
- uint32_t params_size = params->Size();
- DCHECK_EQ(params_size, rhs_params->Size()); // Parameter list size must match.
- for (uint32_t i = 0; i < params_size; ++i) {
- const DexFile::TypeId& param_id = dex_file_->GetTypeId(params->GetTypeItem(i).type_idx_);
- const DexFile::TypeId& rhs_param_id =
- rhs.dex_file_->GetTypeId(rhs_params->GetTypeItem(i).type_idx_);
- if (!DexFileStringEquals(dex_file_, param_id.descriptor_idx_,
- rhs.dex_file_, rhs_param_id.descriptor_idx_)) {
- return false; // Parameter type mismatch.
- }
+ // We found a reference parameter in the matching shorty, so both lists must be non-empty.
+ DCHECK(params != nullptr);
+ DCHECK(rhs_params != nullptr);
+ uint32_t params_size = params->Size();
+ DCHECK_EQ(params_size, rhs_params->Size()); // Parameter list size must match.
+ for (uint32_t i = 0; i < params_size; ++i) {
+ const DexFile::TypeId& param_id = dex_file_->GetTypeId(params->GetTypeItem(i).type_idx_);
+ const DexFile::TypeId& rhs_param_id =
+ rhs.dex_file_->GetTypeId(rhs_params->GetTypeItem(i).type_idx_);
+ if (!DexFileStringEquals(dex_file_, param_id.descriptor_idx_,
+ rhs.dex_file_, rhs_param_id.descriptor_idx_)) {
+ return false; // Parameter type mismatch.
}
}
}
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 6547299..828148a 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -50,6 +50,8 @@
const InlineInfoEncoding& encoding,
uint8_t inlining_depth)
REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(!outer_method->IsObsolete());
+
// This method is being used by artQuickResolutionTrampoline, before it sets up
// the passed parameters in a GC friendly way. Therefore we must never be
// suspended while executing it.
@@ -78,7 +80,8 @@
}
// Lookup the declaring class of the inlined method.
- const DexFile* dex_file = caller->GetDexFile();
+ ObjPtr<mirror::DexCache> dex_cache = caller->GetDexCache();
+ const DexFile* dex_file = dex_cache->GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(method_index);
ArtMethod* inlined_method = caller->GetDexCacheResolvedMethod(method_index, kRuntimePointerSize);
if (inlined_method != nullptr && !inlined_method->IsRuntimeMethod()) {
@@ -90,25 +93,17 @@
mirror::ClassLoader* class_loader = caller->GetDeclaringClass()->GetClassLoader();
mirror::Class* klass = class_linker->LookupClass(self, descriptor, class_loader);
if (klass == nullptr) {
- LOG(FATAL) << "Could not find an inlined method from an .oat file: "
- << "the class " << descriptor << " was not found in the class loader of "
- << caller->PrettyMethod() << ". "
- << "This must be due to playing wrongly with class loaders";
+ LOG(FATAL) << "Could not find an inlined method from an .oat file: the class " << descriptor
+ << " was not found in the class loader of " << caller->PrettyMethod() << ". "
+ << "This must be due to playing wrongly with class loaders";
}
- // Lookup the method.
- const char* method_name = dex_file->GetMethodName(method_id);
- const Signature signature = dex_file->GetMethodSignature(method_id);
-
- inlined_method = klass->FindDeclaredDirectMethod(method_name, signature, kRuntimePointerSize);
+ inlined_method = klass->FindClassMethod(dex_cache, method_index, kRuntimePointerSize);
if (inlined_method == nullptr) {
- inlined_method = klass->FindDeclaredVirtualMethod(method_name, signature, kRuntimePointerSize);
- if (inlined_method == nullptr) {
- LOG(FATAL) << "Could not find an inlined method from an .oat file: "
- << "the class " << descriptor << " does not have "
- << method_name << signature << " declared. "
- << "This must be due to duplicate classes or playing wrongly with class loaders";
- }
+ LOG(FATAL) << "Could not find an inlined method from an .oat file: the class " << descriptor
+ << " does not have " << dex_file->GetMethodName(method_id)
+ << dex_file->GetMethodSignature(method_id) << " declared. "
+ << "This must be due to duplicate classes or playing wrongly with class loaders";
}
caller->SetDexCacheResolvedMethod(method_index, inlined_method, kRuntimePointerSize);
@@ -444,39 +439,20 @@
ArtMethod* referrer,
Thread* self) {
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
- ArtMethod* resolved_method = class_linker->GetResolvedMethod(method_idx, referrer);
- if (resolved_method == nullptr) {
+ constexpr ClassLinker::ResolveMode resolve_mode =
+ access_check ? ClassLinker::ResolveMode::kCheckICCEAndIAE
+ : ClassLinker::ResolveMode::kNoChecks;
+ ArtMethod* resolved_method;
+ if (type == kStatic) {
+ resolved_method = class_linker->ResolveMethod<resolve_mode>(self, method_idx, referrer, type);
+ } else {
StackHandleScope<1> hs(self);
- ObjPtr<mirror::Object> null_this = nullptr;
- HandleWrapperObjPtr<mirror::Object> h_this(
- hs.NewHandleWrapper(type == kStatic ? &null_this : this_object));
- constexpr ClassLinker::ResolveMode resolve_mode =
- access_check ? ClassLinker::kForceICCECheck
- : ClassLinker::kNoICCECheckForCache;
+ HandleWrapperObjPtr<mirror::Object> h_this(hs.NewHandleWrapper(this_object));
resolved_method = class_linker->ResolveMethod<resolve_mode>(self, method_idx, referrer, type);
}
- // Resolution and access check.
if (UNLIKELY(resolved_method == nullptr)) {
DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
return nullptr; // Failure.
- } else if (access_check) {
- mirror::Class* methods_class = resolved_method->GetDeclaringClass();
- bool can_access_resolved_method =
- referrer->GetDeclaringClass()->CheckResolvedMethodAccess(methods_class,
- resolved_method,
- referrer->GetDexCache(),
- method_idx,
- type);
- if (UNLIKELY(!can_access_resolved_method)) {
- DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
- return nullptr; // Failure.
- }
- // Incompatible class change should have been handled in resolve method.
- if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
- ThrowIncompatibleClassChangeError(type, resolved_method->GetInvokeType(), resolved_method,
- referrer);
- return nullptr; // Failure.
- }
}
// Next, null pointer check.
if (UNLIKELY(*this_object == nullptr && type != kStatic)) {
@@ -690,24 +666,14 @@
}
ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
ObjPtr<mirror::DexCache> dex_cache = referrer->GetDexCache();
- ArtMethod* resolved_method = dex_cache->GetResolvedMethod(method_idx, kRuntimePointerSize);
+ constexpr ClassLinker::ResolveMode resolve_mode = access_check
+ ? ClassLinker::ResolveMode::kCheckICCEAndIAE
+ : ClassLinker::ResolveMode::kNoChecks;
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ ArtMethod* resolved_method = linker->GetResolvedMethod<type, resolve_mode>(method_idx, referrer);
if (UNLIKELY(resolved_method == nullptr)) {
return nullptr;
}
- if (access_check) {
- // Check for incompatible class change errors and access.
- bool icce = resolved_method->CheckIncompatibleClassChange(type);
- if (UNLIKELY(icce)) {
- return nullptr;
- }
- ObjPtr<mirror::Class> methods_class = resolved_method->GetDeclaringClass();
- if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
- !referring_class->CanAccessMember(methods_class,
- resolved_method->GetAccessFlags()))) {
- // Potential illegal access, may need to refine the method's class.
- return nullptr;
- }
- }
if (type == kInterface) { // Most common form of slow path dispatch.
return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method,
kRuntimePointerSize);
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 36885d8..6abf7c5 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1182,7 +1182,7 @@
HandleWrapper<mirror::Object> h_receiver(
hs.NewHandleWrapper(virtual_or_interface ? &receiver : &dummy));
DCHECK_EQ(caller->GetDexFile(), called_method.dex_file);
- called = linker->ResolveMethod<ClassLinker::kForceICCECheck>(
+ called = linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
self, called_method.dex_method_index, caller, invoke_type);
// Update .bss entry in oat file if any.
@@ -1235,8 +1235,11 @@
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(caller->GetDeclaringClass()->GetClassLoader()));
// TODO Maybe put this into a mirror::Class function.
- mirror::Class* ref_class = linker->ResolveReferencedClassOfMethod(
- called_method.dex_method_index, dex_cache, class_loader);
+ ObjPtr<mirror::Class> ref_class = linker->LookupResolvedType(
+ *dex_cache->GetDexFile(),
+ dex_cache->GetDexFile()->GetMethodId(called_method.dex_method_index).class_idx_,
+ dex_cache.Get(),
+ class_loader.Get());
if (ref_class->IsInterface()) {
called = ref_class->FindVirtualMethodForInterfaceSuper(called, kRuntimePointerSize);
} else {
@@ -2622,10 +2625,8 @@
// Resolve method - it's either MethodHandle.invoke() or MethodHandle.invokeExact().
ClassLinker* linker = Runtime::Current()->GetClassLinker();
- ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::kForceICCECheck>(self,
- inst->VRegB(),
- caller_method,
- kVirtual);
+ ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
+ self, inst->VRegB(), caller_method, kVirtual);
DCHECK((resolved_method ==
jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact)) ||
(resolved_method ==
diff --git a/runtime/instrumentation_test.cc b/runtime/instrumentation_test.cc
index 2a601c9..9e9fa71 100644
--- a/runtime/instrumentation_test.cc
+++ b/runtime/instrumentation_test.cc
@@ -16,6 +16,7 @@
#include "instrumentation.h"
+#include "art_method-inl.h"
#include "base/enums.h"
#include "common_runtime_test.h"
#include "common_throws.h"
@@ -484,10 +485,11 @@
Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
ASSERT_TRUE(klass != nullptr);
- ArtMethod* method = klass->FindDeclaredDirectMethod("returnReference",
- "()Ljava/lang/Object;",
- kRuntimePointerSize);
+ ArtMethod* method =
+ klass->FindClassMethod("returnReference", "()Ljava/lang/Object;", kRuntimePointerSize);
ASSERT_TRUE(method != nullptr);
+ ASSERT_TRUE(method->IsDirect());
+ ASSERT_TRUE(method->GetDeclaringClass() == klass);
TestEvent(instrumentation::Instrumentation::kMethodExited,
/*event_method*/ method,
/*event_field*/ nullptr,
@@ -503,10 +505,10 @@
Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
ASSERT_TRUE(klass != nullptr);
- ArtMethod* method = klass->FindDeclaredDirectMethod("returnPrimitive",
- "()I",
- kRuntimePointerSize);
+ ArtMethod* method = klass->FindClassMethod("returnPrimitive", "()I", kRuntimePointerSize);
ASSERT_TRUE(method != nullptr);
+ ASSERT_TRUE(method->IsDirect());
+ ASSERT_TRUE(method->GetDeclaringClass() == klass);
TestEvent(instrumentation::Instrumentation::kMethodExited,
/*event_method*/ method,
/*event_field*/ nullptr,
@@ -583,9 +585,11 @@
Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
ASSERT_TRUE(klass != nullptr);
- ArtMethod* method_to_deoptimize = klass->FindDeclaredDirectMethod("instanceMethod", "()V",
- kRuntimePointerSize);
+ ArtMethod* method_to_deoptimize =
+ klass->FindClassMethod("instanceMethod", "()V", kRuntimePointerSize);
ASSERT_TRUE(method_to_deoptimize != nullptr);
+ ASSERT_TRUE(method_to_deoptimize->IsDirect());
+ ASSERT_TRUE(method_to_deoptimize->GetDeclaringClass() == klass);
EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
EXPECT_FALSE(instr->IsDeoptimized(method_to_deoptimize));
@@ -630,9 +634,11 @@
Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
ASSERT_TRUE(klass != nullptr);
- ArtMethod* method_to_deoptimize = klass->FindDeclaredDirectMethod("instanceMethod", "()V",
- kRuntimePointerSize);
+ ArtMethod* method_to_deoptimize =
+ klass->FindClassMethod("instanceMethod", "()V", kRuntimePointerSize);
ASSERT_TRUE(method_to_deoptimize != nullptr);
+ ASSERT_TRUE(method_to_deoptimize->IsDirect());
+ ASSERT_TRUE(method_to_deoptimize->GetDeclaringClass() == klass);
EXPECT_FALSE(instr->AreAllMethodsDeoptimized());
EXPECT_FALSE(instr->IsDeoptimized(method_to_deoptimize));
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 0687b75..be2d34d 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -593,10 +593,8 @@
}
ArtMethod* invoke_method =
- class_linker->ResolveMethod<ClassLinker::kForceICCECheck>(self,
- invoke_method_idx,
- shadow_frame.GetMethod(),
- kVirtual);
+ class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
+ self, invoke_method_idx, shadow_frame.GetMethod(), kVirtual);
// There is a common dispatch method for method handles that takes
// arguments either from a range or an array of arguments depending
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 152cce4..7f9363f 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -265,7 +265,7 @@
bool ok = false;
auto* cl = Runtime::Current()->GetClassLinker();
if (cl->EnsureInitialized(self, h_klass, true, true)) {
- auto* cons = h_klass->FindDeclaredDirectMethod("<init>", "()V", cl->GetImagePointerSize());
+ auto* cons = h_klass->FindConstructor("()V", cl->GetImagePointerSize());
if (cons != nullptr) {
Handle<mirror::Object> h_obj(hs.NewHandle(klass->AllocObject(self)));
CHECK(h_obj != nullptr); // We don't expect OOM at compile-time.
@@ -591,8 +591,7 @@
}
auto* cl = Runtime::Current()->GetClassLinker();
- ArtMethod* constructor = h_class->FindDeclaredDirectMethod(
- "<init>", "([B)V", cl->GetImagePointerSize());
+ ArtMethod* constructor = h_class->FindConstructor("([B)V", cl->GetImagePointerSize());
if (constructor == nullptr) {
AbortTransactionOrFail(self, "Could not find ByteArrayInputStream constructor");
return;
@@ -1010,8 +1009,7 @@
Handle<mirror::Class> h_class(hs.NewHandle(klass));
Handle<mirror::Object> h_obj(hs.NewHandle(h_class->AllocObject(self)));
if (h_obj != nullptr) {
- ArtMethod* init_method = h_class->FindDirectMethod(
- "<init>", "()V", class_linker->GetImagePointerSize());
+ ArtMethod* init_method = h_class->FindConstructor("()V", class_linker->GetImagePointerSize());
if (init_method == nullptr) {
AbortTransactionOrFail(self, "Could not find <init> for %s", class_descriptor);
return nullptr;
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index c2ef724..3461a65 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -387,8 +387,9 @@
ScopedObjectAccess soa(self);
mirror::Class* klass = mirror::String::GetJavaLangString();
ArtMethod* method =
- klass->FindDeclaredDirectMethod("<init>", "(Ljava/lang/String;)V",
- Runtime::Current()->GetClassLinker()->GetImagePointerSize());
+ klass->FindConstructor("(Ljava/lang/String;)V",
+ Runtime::Current()->GetClassLinker()->GetImagePointerSize());
+ ASSERT_TRUE(method != nullptr);
// create instruction data for invoke-direct {v0, v1} of method with fake index
uint16_t inst_data[3] = { 0x2070, 0x0000, 0x0010 };
@@ -966,12 +967,14 @@
ASSERT_TRUE(floating_decimal != nullptr);
ASSERT_TRUE(class_linker->EnsureInitialized(self, floating_decimal, true, true));
- ArtMethod* caller_method = floating_decimal->FindDeclaredDirectMethod(
+ ArtMethod* caller_method = floating_decimal->FindClassMethod(
"getBinaryToASCIIBuffer",
"()Lsun/misc/FloatingDecimal$BinaryToASCIIBuffer;",
class_linker->GetImagePointerSize());
// floating_decimal->DumpClass(LOG_STREAM(ERROR), mirror::Class::kDumpClassFullDetail);
ASSERT_TRUE(caller_method != nullptr);
+ ASSERT_TRUE(caller_method->IsDirect());
+ ASSERT_TRUE(caller_method->GetDeclaringClass() == floating_decimal.Get());
ShadowFrame* caller_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, caller_method, 0);
shadow_frame->SetLink(caller_frame);
@@ -1020,10 +1023,12 @@
ASSERT_TRUE(double_class != nullptr);
ASSERT_TRUE(class_linker->EnsureInitialized(self, double_class, true, true));
- ArtMethod* method = double_class->FindDeclaredDirectMethod("toString",
- "(D)Ljava/lang/String;",
- class_linker->GetImagePointerSize());
+ ArtMethod* method = double_class->FindClassMethod("toString",
+ "(D)Ljava/lang/String;",
+ class_linker->GetImagePointerSize());
ASSERT_TRUE(method != nullptr);
+ ASSERT_TRUE(method->IsDirect());
+ ASSERT_TRUE(method->GetDeclaringClass() == double_class.Get());
// create instruction data for invoke-direct {v0, v1} of method with fake index
uint16_t inst_data[3] = { 0x2070, 0x0000, 0x0010 };
@@ -1179,8 +1184,8 @@
boot_cp.Assign(boot_cp_class->AllocObject(self)->AsClassLoader());
CHECK(boot_cp != nullptr);
- ArtMethod* boot_cp_init = boot_cp_class->FindDeclaredDirectMethod(
- "<init>", "()V", class_linker->GetImagePointerSize());
+ ArtMethod* boot_cp_init = boot_cp_class->FindConstructor(
+ "()V", class_linker->GetImagePointerSize());
CHECK(boot_cp_init != nullptr);
JValue result;
@@ -1333,8 +1338,8 @@
Handle<mirror::String> input = hs.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "abd"));
// Find the constructor.
- ArtMethod* throw_cons = throw_class->FindDeclaredDirectMethod(
- "<init>", "(Ljava/lang/String;)V", class_linker->GetImagePointerSize());
+ ArtMethod* throw_cons = throw_class->FindConstructor(
+ "(Ljava/lang/String;)V", class_linker->GetImagePointerSize());
ASSERT_TRUE(throw_cons != nullptr);
Handle<mirror::Constructor> cons;
if (class_linker->GetImagePointerSize() == PointerSize::k64) {
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index dbad614..e6c140b 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -233,17 +233,10 @@
}
ArtMethod* method = nullptr;
auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
- if (is_static) {
- method = c->FindDirectMethod(name, sig, pointer_size);
- } else if (c->IsInterface()) {
+ if (c->IsInterface()) {
method = c->FindInterfaceMethod(name, sig, pointer_size);
} else {
- method = c->FindVirtualMethod(name, sig, pointer_size);
- if (method == nullptr) {
- // No virtual method matching the signature. Search declared
- // private methods and constructors.
- method = c->FindDeclaredDirectMethod(name, sig, pointer_size);
- }
+ method = c->FindClassMethod(name, sig, pointer_size);
}
if (method == nullptr || method->IsStatic() != is_static) {
ThrowNoSuchMethodError(soa, c, name, sig, is_static ? "static" : "non-static");
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index e1e4f9c..e0afbb6 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -626,9 +626,9 @@
hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
mirror::Class* c = class_linker_->FindClass(soa.Self(), "LMyClassNatives;", loader);
const auto pointer_size = class_linker_->GetImagePointerSize();
- ArtMethod* method = direct ? c->FindDirectMethod(method_name, method_sig, pointer_size) :
- c->FindVirtualMethod(method_name, method_sig, pointer_size);
+ ArtMethod* method = c->FindClassMethod(method_name, method_sig, pointer_size);
ASSERT_TRUE(method != nullptr) << method_name << " " << method_sig;
+ ASSERT_EQ(direct, method->IsDirect());
method->SetEntryPointFromQuickCompiledCode(class_linker_->GetRuntimeQuickGenericJniStub());
}
// Start runtime.
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 003cd4e..121c259 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -533,7 +533,11 @@
PointerSize pointer_size) {
ObjPtr<Class> declaring_class = method->GetDeclaringClass();
DCHECK(declaring_class != nullptr) << PrettyClass();
- DCHECK(declaring_class->IsInterface()) << method->PrettyMethod();
+ if (UNLIKELY(!declaring_class->IsInterface())) {
+ DCHECK(declaring_class->IsObjectClass()) << method->PrettyMethod();
+ DCHECK(method->IsPublic() && !method->IsStatic());
+ return FindVirtualMethodForVirtual(method, pointer_size);
+ }
DCHECK(!method->IsCopied());
// TODO cache to improve lookup speed
const int32_t iftable_count = GetIfTableCount();
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index b0e5b6a..6f70b19 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -396,95 +396,44 @@
}
}
-ArtMethod* Class::FindInterfaceMethod(const StringPiece& name,
- const StringPiece& signature,
- PointerSize pointer_size) {
- // Check the current class before checking the interfaces.
- ArtMethod* method = FindDeclaredVirtualMethod(name, signature, pointer_size);
- if (method != nullptr) {
- return method;
- }
-
- int32_t iftable_count = GetIfTableCount();
- ObjPtr<IfTable> iftable = GetIfTable();
- for (int32_t i = 0; i < iftable_count; ++i) {
- method = iftable->GetInterface(i)->FindDeclaredVirtualMethod(name, signature, pointer_size);
- if (method != nullptr) {
- return method;
+template <typename SignatureType>
+static inline ArtMethod* FindInterfaceMethodWithSignature(ObjPtr<Class> klass,
+ const StringPiece& name,
+ const SignatureType& signature,
+ PointerSize pointer_size)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ // If the current class is not an interface, skip the search of its declared methods;
+ // such lookup is used only to distinguish between IncompatibleClassChangeError and
+ // NoSuchMethodError and the caller has already tried to search methods in the class.
+ if (LIKELY(klass->IsInterface())) {
+ // Search declared methods, both direct and virtual.
+ // (This lookup is used also for invoke-static on interface classes.)
+ for (ArtMethod& method : klass->GetDeclaredMethodsSlice(pointer_size)) {
+ if (method.GetName() == name && method.GetSignature() == signature) {
+ return &method;
+ }
}
}
- return nullptr;
-}
-ArtMethod* Class::FindInterfaceMethod(const StringPiece& name,
- const Signature& signature,
- PointerSize pointer_size) {
- // Check the current class before checking the interfaces.
- ArtMethod* method = FindDeclaredVirtualMethod(name, signature, pointer_size);
- if (method != nullptr) {
- return method;
- }
-
- int32_t iftable_count = GetIfTableCount();
- ObjPtr<IfTable> iftable = GetIfTable();
- for (int32_t i = 0; i < iftable_count; ++i) {
- method = iftable->GetInterface(i)->FindDeclaredVirtualMethod(name, signature, pointer_size);
- if (method != nullptr) {
- return method;
+ // TODO: If there is a unique maximally-specific non-abstract superinterface method,
+ // we should return it, otherwise an arbitrary one can be returned.
+ ObjPtr<IfTable> iftable = klass->GetIfTable();
+ for (int32_t i = 0, iftable_count = iftable->Count(); i < iftable_count; ++i) {
+ ObjPtr<Class> iface = iftable->GetInterface(i);
+ for (ArtMethod& method : iface->GetVirtualMethodsSlice(pointer_size)) {
+ if (method.GetName() == name && method.GetSignature() == signature) {
+ return &method;
+ }
}
}
- return nullptr;
-}
-ArtMethod* Class::FindInterfaceMethod(ObjPtr<DexCache> dex_cache,
- uint32_t dex_method_idx,
- PointerSize pointer_size) {
- // Check the current class before checking the interfaces.
- ArtMethod* method = FindDeclaredVirtualMethod(dex_cache, dex_method_idx, pointer_size);
- if (method != nullptr) {
- return method;
- }
-
- int32_t iftable_count = GetIfTableCount();
- ObjPtr<IfTable> iftable = GetIfTable();
- for (int32_t i = 0; i < iftable_count; ++i) {
- method = iftable->GetInterface(i)->FindDeclaredVirtualMethod(
- dex_cache, dex_method_idx, pointer_size);
- if (method != nullptr) {
- return method;
- }
- }
- return nullptr;
-}
-
-ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name,
- const StringPiece& signature,
- PointerSize pointer_size) {
- for (auto& method : GetDirectMethods(pointer_size)) {
- if (name == method.GetName() && method.GetSignature() == signature) {
- return &method;
- }
- }
- return nullptr;
-}
-
-ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name,
- const Signature& signature,
- PointerSize pointer_size) {
- for (auto& method : GetDirectMethods(pointer_size)) {
- if (name == method.GetName() && signature == method.GetSignature()) {
- return &method;
- }
- }
- return nullptr;
-}
-
-ArtMethod* Class::FindDeclaredDirectMethod(ObjPtr<DexCache> dex_cache,
- uint32_t dex_method_idx,
- PointerSize pointer_size) {
- if (GetDexCache() == dex_cache) {
- for (auto& method : GetDirectMethods(pointer_size)) {
- if (method.GetDexMethodIndex() == dex_method_idx) {
+ // Then search for public non-static methods in the java.lang.Object.
+ if (LIKELY(klass->IsInterface())) {
+ ObjPtr<Class> object_class = klass->GetSuperClass();
+ DCHECK(object_class->IsObjectClass());
+ for (ArtMethod& method : object_class->GetDeclaredMethodsSlice(pointer_size)) {
+ if (method.IsPublic() && !method.IsStatic() &&
+ method.GetName() == name && method.GetSignature() == signature) {
return &method;
}
}
@@ -492,37 +441,220 @@
return nullptr;
}
-ArtMethod* Class::FindDirectMethod(const StringPiece& name,
- const StringPiece& signature,
- PointerSize pointer_size) {
- for (ObjPtr<Class> klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
- ArtMethod* method = klass->FindDeclaredDirectMethod(name, signature, pointer_size);
- if (method != nullptr) {
- return method;
- }
- }
- return nullptr;
+ArtMethod* Class::FindInterfaceMethod(const StringPiece& name,
+ const StringPiece& signature,
+ PointerSize pointer_size) {
+ return FindInterfaceMethodWithSignature(this, name, signature, pointer_size);
}
-ArtMethod* Class::FindDirectMethod(const StringPiece& name,
- const Signature& signature,
- PointerSize pointer_size) {
- for (ObjPtr<Class> klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
- ArtMethod* method = klass->FindDeclaredDirectMethod(name, signature, pointer_size);
- if (method != nullptr) {
- return method;
- }
- }
- return nullptr;
+ArtMethod* Class::FindInterfaceMethod(const StringPiece& name,
+ const Signature& signature,
+ PointerSize pointer_size) {
+ return FindInterfaceMethodWithSignature(this, name, signature, pointer_size);
}
-ArtMethod* Class::FindDirectMethod(ObjPtr<DexCache> dex_cache,
- uint32_t dex_method_idx,
- PointerSize pointer_size) {
- for (ObjPtr<Class> klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
- ArtMethod* method = klass->FindDeclaredDirectMethod(dex_cache, dex_method_idx, pointer_size);
- if (method != nullptr) {
- return method;
+ArtMethod* Class::FindInterfaceMethod(ObjPtr<DexCache> dex_cache,
+ uint32_t dex_method_idx,
+ PointerSize pointer_size) {
+ // We always search by name and signature, ignoring the type index in the MethodId.
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
+ StringPiece name = dex_file.StringDataByIdx(method_id.name_idx_);
+ const Signature signature = dex_file.GetMethodSignature(method_id);
+ return FindInterfaceMethod(name, signature, pointer_size);
+}
+
+static inline bool IsInheritedMethod(ObjPtr<mirror::Class> klass,
+ ObjPtr<mirror::Class> declaring_class,
+ ArtMethod& method)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK_EQ(declaring_class, method.GetDeclaringClass());
+ DCHECK_NE(klass, declaring_class);
+ DCHECK(klass->IsArrayClass() ? declaring_class->IsObjectClass()
+ : klass->IsSubClass(declaring_class));
+ uint32_t access_flags = method.GetAccessFlags();
+ if ((access_flags & (kAccPublic | kAccProtected)) != 0) {
+ return true;
+ }
+ if ((access_flags & kAccPrivate) != 0) {
+ return false;
+ }
+ for (; klass != declaring_class; klass = klass->GetSuperClass()) {
+ if (!klass->IsInSamePackage(declaring_class)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+template <typename SignatureType>
+static inline ArtMethod* FindClassMethodWithSignature(ObjPtr<Class> this_klass,
+ const StringPiece& name,
+ const SignatureType& signature,
+ PointerSize pointer_size)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Search declared methods first.
+ for (ArtMethod& method : this_klass->GetDeclaredMethodsSlice(pointer_size)) {
+ ArtMethod* np_method = method.GetInterfaceMethodIfProxy(pointer_size);
+ if (np_method->GetName() == name && np_method->GetSignature() == signature) {
+ return &method;
+ }
+ }
+
+ // Then search the superclass chain. If we find an inherited method, return it.
+ // If we find a method that's not inherited because of access restrictions,
+ // try to find a method inherited from an interface in copied methods.
+ ObjPtr<Class> klass = this_klass->GetSuperClass();
+ ArtMethod* uninherited_method = nullptr;
+ for (; klass != nullptr; klass = klass->GetSuperClass()) {
+ DCHECK(!klass->IsProxyClass());
+ for (ArtMethod& method : klass->GetDeclaredMethodsSlice(pointer_size)) {
+ if (method.GetName() == name && method.GetSignature() == signature) {
+ if (IsInheritedMethod(this_klass, klass, method)) {
+ return &method;
+ }
+ uninherited_method = &method;
+ break;
+ }
+ }
+ if (uninherited_method != nullptr) {
+ break;
+ }
+ }
+
+ // Then search copied methods.
+ // If we found a method that's not inherited, stop the search in its declaring class.
+ ObjPtr<Class> end_klass = klass;
+ DCHECK_EQ(uninherited_method != nullptr, end_klass != nullptr);
+ klass = this_klass;
+ if (UNLIKELY(klass->IsProxyClass())) {
+ DCHECK(klass->GetCopiedMethodsSlice(pointer_size).empty());
+ klass = klass->GetSuperClass();
+ }
+ for (; klass != end_klass; klass = klass->GetSuperClass()) {
+ DCHECK(!klass->IsProxyClass());
+ for (ArtMethod& method : klass->GetCopiedMethodsSlice(pointer_size)) {
+ if (method.GetName() == name && method.GetSignature() == signature) {
+ return &method; // No further check needed, copied methods are inherited by definition.
+ }
+ }
+ }
+ return uninherited_method; // Return the `uninherited_method` if any.
+}
+
+
+ArtMethod* Class::FindClassMethod(const StringPiece& name,
+ const StringPiece& signature,
+ PointerSize pointer_size) {
+ return FindClassMethodWithSignature(this, name, signature, pointer_size);
+}
+
+ArtMethod* Class::FindClassMethod(const StringPiece& name,
+ const Signature& signature,
+ PointerSize pointer_size) {
+ return FindClassMethodWithSignature(this, name, signature, pointer_size);
+}
+
+ArtMethod* Class::FindClassMethod(ObjPtr<DexCache> dex_cache,
+ uint32_t dex_method_idx,
+ PointerSize pointer_size) {
+ // FIXME: Hijacking a proxy class by a custom class loader can break this assumption.
+ DCHECK(!IsProxyClass());
+
+ // First try to find a declared method by dex_method_idx if we have a dex_cache match.
+ ObjPtr<DexCache> this_dex_cache = GetDexCache();
+ if (this_dex_cache == dex_cache) {
+ // Lookup is always performed in the class referenced by the MethodId.
+ DCHECK_EQ(dex_type_idx_, GetDexFile().GetMethodId(dex_method_idx).class_idx_.index_);
+ for (ArtMethod& method : GetDeclaredMethodsSlice(pointer_size)) {
+ if (method.GetDexMethodIndex() == dex_method_idx) {
+ return &method;
+ }
+ }
+ }
+ // If not found, we need to search by name and signature.
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
+ const Signature signature = dex_file.GetMethodSignature(method_id);
+ StringPiece name; // Delay strlen() until actually needed.
+ // If we do not have a dex_cache match, try to find the declared method in this class now.
+ if (this_dex_cache != dex_cache && !GetDeclaredMethodsSlice(pointer_size).empty()) {
+ DCHECK(name.empty());
+ name = dex_file.StringDataByIdx(method_id.name_idx_);
+ for (ArtMethod& method : GetDeclaredMethodsSlice(pointer_size)) {
+ if (method.GetName() == name && method.GetSignature() == signature) {
+ return &method;
+ }
+ }
+ }
+
+ // Then search the superclass chain. If we find an inherited method, return it.
+ // If we find a method that's not inherited because of access restrictions,
+ // try to find a method inherited from an interface in copied methods.
+ ArtMethod* uninherited_method = nullptr;
+ ObjPtr<Class> klass = GetSuperClass();
+ for (; klass != nullptr; klass = klass->GetSuperClass()) {
+ ArtMethod* candidate_method = nullptr;
+ ArraySlice<ArtMethod> declared_methods = klass->GetDeclaredMethodsSlice(pointer_size);
+ if (klass->GetDexCache() == dex_cache) {
+ // Matching dex_cache. We cannot compare the `dex_method_idx` anymore because
+ // the type index differs, so compare the name index and proto index.
+ for (ArtMethod& method : declared_methods) {
+ const DexFile::MethodId& cmp_method_id = dex_file.GetMethodId(method.GetDexMethodIndex());
+ if (cmp_method_id.name_idx_ == method_id.name_idx_ &&
+ cmp_method_id.proto_idx_ == method_id.proto_idx_) {
+ candidate_method = &method;
+ break;
+ }
+ }
+ } else {
+ if (!declared_methods.empty() && name.empty()) {
+ name = dex_file.StringDataByIdx(method_id.name_idx_);
+ }
+ for (ArtMethod& method : declared_methods) {
+ if (method.GetName() == name && method.GetSignature() == signature) {
+ candidate_method = &method;
+ break;
+ }
+ }
+ }
+ if (candidate_method != nullptr) {
+ if (IsInheritedMethod(this, klass, *candidate_method)) {
+ return candidate_method;
+ } else {
+ uninherited_method = candidate_method;
+ break;
+ }
+ }
+ }
+
+ // Then search copied methods.
+ // If we found a method that's not inherited, stop the search in its declaring class.
+ ObjPtr<Class> end_klass = klass;
+ DCHECK_EQ(uninherited_method != nullptr, end_klass != nullptr);
+ // After we have searched the declared methods of the super-class chain,
+ // search copied methods which can contain methods from interfaces.
+ for (klass = this; klass != end_klass; klass = klass->GetSuperClass()) {
+ ArraySlice<ArtMethod> copied_methods = klass->GetCopiedMethodsSlice(pointer_size);
+ if (!copied_methods.empty() && name.empty()) {
+ name = dex_file.StringDataByIdx(method_id.name_idx_);
+ }
+ for (ArtMethod& method : copied_methods) {
+ if (method.GetName() == name && method.GetSignature() == signature) {
+ return &method; // No further check needed, copied methods are inherited by definition.
+ }
+ }
+ }
+ return uninherited_method; // Return the `uninherited_method` if any.
+}
+
+ArtMethod* Class::FindConstructor(const StringPiece& signature, PointerSize pointer_size) {
+ // Internal helper, never called on proxy classes. We can skip GetInterfaceMethodIfProxy().
+ DCHECK(!IsProxyClass());
+ StringPiece name("<init>");
+ for (ArtMethod& method : GetDirectMethodsSliceUnchecked(pointer_size)) {
+ if (method.GetName() == name && method.GetSignature() == signature) {
+ return &method;
}
}
return nullptr;
@@ -539,47 +671,6 @@
return nullptr;
}
-// TODO These should maybe be changed to be named FindOwnedVirtualMethod or something similar
-// because they do not only find 'declared' methods and will return copied methods. This behavior is
-// desired and correct but the naming can lead to confusion because in the java language declared
-// excludes interface methods which might be found by this.
-ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name,
- const StringPiece& signature,
- PointerSize pointer_size) {
- for (auto& method : GetVirtualMethods(pointer_size)) {
- ArtMethod* const np_method = method.GetInterfaceMethodIfProxy(pointer_size);
- if (name == np_method->GetName() && np_method->GetSignature() == signature) {
- return &method;
- }
- }
- return nullptr;
-}
-
-ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name,
- const Signature& signature,
- PointerSize pointer_size) {
- for (auto& method : GetVirtualMethods(pointer_size)) {
- ArtMethod* const np_method = method.GetInterfaceMethodIfProxy(pointer_size);
- if (name == np_method->GetName() && signature == np_method->GetSignature()) {
- return &method;
- }
- }
- return nullptr;
-}
-
-ArtMethod* Class::FindDeclaredVirtualMethod(ObjPtr<DexCache> dex_cache,
- uint32_t dex_method_idx,
- PointerSize pointer_size) {
- if (GetDexCache() == dex_cache) {
- for (auto& method : GetDeclaredVirtualMethods(pointer_size)) {
- if (method.GetDexMethodIndex() == dex_method_idx) {
- return &method;
- }
- }
- }
- return nullptr;
-}
-
ArtMethod* Class::FindDeclaredVirtualMethodByName(const StringPiece& name,
PointerSize pointer_size) {
for (auto& method : GetVirtualMethods(pointer_size)) {
@@ -591,42 +682,6 @@
return nullptr;
}
-ArtMethod* Class::FindVirtualMethod(const StringPiece& name,
- const StringPiece& signature,
- PointerSize pointer_size) {
- for (ObjPtr<Class> klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
- ArtMethod* method = klass->FindDeclaredVirtualMethod(name, signature, pointer_size);
- if (method != nullptr) {
- return method;
- }
- }
- return nullptr;
-}
-
-ArtMethod* Class::FindVirtualMethod(const StringPiece& name,
- const Signature& signature,
- PointerSize pointer_size) {
- for (ObjPtr<Class> klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
- ArtMethod* method = klass->FindDeclaredVirtualMethod(name, signature, pointer_size);
- if (method != nullptr) {
- return method;
- }
- }
- return nullptr;
-}
-
-ArtMethod* Class::FindVirtualMethod(ObjPtr<DexCache> dex_cache,
- uint32_t dex_method_idx,
- PointerSize pointer_size) {
- for (ObjPtr<Class> klass = this; klass != nullptr; klass = klass->GetSuperClass()) {
- ArtMethod* method = klass->FindDeclaredVirtualMethod(dex_cache, dex_method_idx, pointer_size);
- if (method != nullptr) {
- return method;
- }
- }
- return nullptr;
-}
-
ArtMethod* Class::FindVirtualMethodForInterfaceSuper(ArtMethod* method, PointerSize pointer_size) {
DCHECK(method->GetDeclaringClass()->IsInterface());
DCHECK(IsInterface()) << "Should only be called on a interface class";
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index e516a06..c626897 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -915,6 +915,13 @@
ArtMethod* FindVirtualMethodForVirtualOrInterface(ArtMethod* method, PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Find a method with the given name and signature in an interface class.
+ //
+ // Search for the method declared in the class, then search for a method declared in any
+ // superinterface, then search the superclass java.lang.Object (implicitly declared methods
+ // in an interface without superinterfaces, see JLS 9.2, can be inherited, see JLS 9.4.1).
+ // TODO: Implement search for a unique maximally-specific non-abstract superinterface method.
+
ArtMethod* FindInterfaceMethod(const StringPiece& name,
const StringPiece& signature,
PointerSize pointer_size)
@@ -930,49 +937,46 @@
PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
- ArtMethod* FindDeclaredDirectMethod(const StringPiece& name,
- const StringPiece& signature,
- PointerSize pointer_size)
+ // Find a method with the given name and signature in a non-interface class.
+ //
+ // Search for the method in the class, following the JLS rules which conflict with the RI
+ // in some cases. The JLS says that inherited methods are searched (JLS 15.12.2.1) and
+ // these can come from a superclass or a superinterface (JLS 8.4.8). We perform the
+ // following search:
+ // 1. Search the methods declared directly in the class. If we find a method with the
+ // given name and signature, return that method.
+ // 2. Search the methods declared in superclasses until we find a method with the given
+ // signature or complete the search in java.lang.Object. If we find a method with the
+ // given name and signature, check if it's been inherited by the class where we're
+ // performing the lookup (qualifying type). If it's inherited, return it. Otherwise,
+ // just remember the method and its declaring class and proceed to step 3.
+ // 3. Search "copied" methods (containing methods inherited from interfaces) in the class
+ // and its superclass chain. If we found a method in step 2 (which was not inherited,
+ // otherwise we would not be performing step 3), end the search when we reach its
+ // declaring class, otherwise search the entire superclass chain. If we find a method
+ // with the given name and signature, return that method.
+ // 4. Return the method found in step 2 if any (not inherited), or null.
+ //
+ // It's the responsibility of the caller to throw exceptions if the returned method (or null)
+ // does not satisfy the request. Special consideration should be given to the case where this
+ // function returns a method that's not inherited (found in step 2, returned in step 4).
+
+ ArtMethod* FindClassMethod(const StringPiece& name,
+ const StringPiece& signature,
+ PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
- ArtMethod* FindDeclaredDirectMethod(const StringPiece& name,
- const Signature& signature,
- PointerSize pointer_size)
+ ArtMethod* FindClassMethod(const StringPiece& name,
+ const Signature& signature,
+ PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
- ArtMethod* FindDeclaredDirectMethod(ObjPtr<DexCache> dex_cache,
- uint32_t dex_method_idx,
- PointerSize pointer_size)
+ ArtMethod* FindClassMethod(ObjPtr<DexCache> dex_cache,
+ uint32_t dex_method_idx,
+ PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
- ArtMethod* FindDirectMethod(const StringPiece& name,
- const StringPiece& signature,
- PointerSize pointer_size)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- ArtMethod* FindDirectMethod(const StringPiece& name,
- const Signature& signature,
- PointerSize pointer_size)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- ArtMethod* FindDirectMethod(ObjPtr<DexCache> dex_cache,
- uint32_t dex_method_idx,
- PointerSize pointer_size)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name,
- const StringPiece& signature,
- PointerSize pointer_size)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name,
- const Signature& signature,
- PointerSize pointer_size)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- ArtMethod* FindDeclaredVirtualMethod(ObjPtr<DexCache> dex_cache,
- uint32_t dex_method_idx,
- PointerSize pointer_size)
+ ArtMethod* FindConstructor(const StringPiece& signature, PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
ArtMethod* FindDeclaredVirtualMethodByName(const StringPiece& name,
@@ -983,21 +987,6 @@
PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
- ArtMethod* FindVirtualMethod(const StringPiece& name,
- const StringPiece& signature,
- PointerSize pointer_size)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- ArtMethod* FindVirtualMethod(const StringPiece& name,
- const Signature& signature,
- PointerSize pointer_size)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- ArtMethod* FindVirtualMethod(ObjPtr<DexCache> dex_cache,
- uint32_t dex_method_idx,
- PointerSize pointer_size)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
ArtMethod* FindClassInitializer(PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_);
bool HasDefaultMethods() REQUIRES_SHARED(Locks::mutator_lock_) {
diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc
index 5b1ba8d..194d9bc 100644
--- a/runtime/mirror/dex_cache_test.cc
+++ b/runtime/mirror/dex_cache_test.cc
@@ -128,14 +128,18 @@
hs.NewHandle(class_linker_->FindClass(soa.Self(), "LMethodTypes;", class_loader)));
class_linker_->EnsureInitialized(soa.Self(), method_types, true, true);
- ArtMethod* method1 = method_types->FindVirtualMethod(
+ ArtMethod* method1 = method_types->FindClassMethod(
"method1",
"(Ljava/lang/String;)Ljava/lang/String;",
kRuntimePointerSize);
- ArtMethod* method2 = method_types->FindVirtualMethod(
+ ASSERT_TRUE(method1 != nullptr);
+ ASSERT_FALSE(method1->IsDirect());
+ ArtMethod* method2 = method_types->FindClassMethod(
"method2",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
kRuntimePointerSize);
+ ASSERT_TRUE(method2 != nullptr);
+ ASSERT_FALSE(method2->IsDirect());
const DexFile& dex_file = *(method1->GetDexFile());
Handle<mirror::DexCache> dex_cache = hs.NewHandle(
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index fed9c1c..4d66e2b 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -372,8 +372,7 @@
}
// Based on ClassLinker::ResolveMethod.
-static void PreloadDexCachesResolveMethod(Handle<mirror::DexCache> dex_cache, uint32_t method_idx,
- InvokeType invoke_type)
+static void PreloadDexCachesResolveMethod(Handle<mirror::DexCache> dex_cache, uint32_t method_idx)
REQUIRES_SHARED(Locks::mutator_lock_) {
ArtMethod* method = dex_cache->GetResolvedMethod(method_idx, kRuntimePointerSize);
if (method != nullptr) {
@@ -381,25 +380,15 @@
}
const DexFile* dex_file = dex_cache->GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(method_idx);
- ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(method_id.class_idx_);
+ ObjPtr<mirror::Class> klass =
+ ClassLinker::LookupResolvedType(method_id.class_idx_, dex_cache.Get(), nullptr);
if (klass == nullptr) {
return;
}
- switch (invoke_type) {
- case kDirect:
- case kStatic:
- method = klass->FindDirectMethod(dex_cache.Get(), method_idx, kRuntimePointerSize);
- break;
- case kInterface:
- method = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, kRuntimePointerSize);
- break;
- case kSuper:
- case kVirtual:
- method = klass->FindVirtualMethod(dex_cache.Get(), method_idx, kRuntimePointerSize);
- break;
- default:
- LOG(FATAL) << "Unreachable - invocation type: " << invoke_type;
- UNREACHABLE();
+ if (klass->IsInterface()) {
+ method = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, kRuntimePointerSize);
+ } else {
+ method = klass->FindClassMethod(dex_cache.Get(), method_idx, kRuntimePointerSize);
}
if (method == nullptr) {
return;
@@ -557,13 +546,11 @@
}
for (; it.HasNextDirectMethod(); it.Next()) {
uint32_t method_idx = it.GetMemberIndex();
- InvokeType invoke_type = it.GetMethodInvokeType(class_def);
- PreloadDexCachesResolveMethod(dex_cache, method_idx, invoke_type);
+ PreloadDexCachesResolveMethod(dex_cache, method_idx);
}
for (; it.HasNextVirtualMethod(); it.Next()) {
uint32_t method_idx = it.GetMemberIndex();
- InvokeType invoke_type = it.GetMethodInvokeType(class_def);
- PreloadDexCachesResolveMethod(dex_cache, method_idx, invoke_type);
+ PreloadDexCachesResolveMethod(dex_cache, method_idx);
}
}
}
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index debee91..31694c4 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -40,6 +40,7 @@
#include "art_jvmti.h"
#include "base/array_ref.h"
#include "base/logging.h"
+#include "base/stringpiece.h"
#include "class_linker-inl.h"
#include "debugger.h"
#include "dex_file.h"
@@ -572,13 +573,15 @@
// Try and get the declared method. First try to get a virtual method then a direct method if that's
// not found.
static art::ArtMethod* FindMethod(art::Handle<art::mirror::Class> klass,
- const char* name,
+ art::StringPiece name,
art::Signature sig) REQUIRES_SHARED(art::Locks::mutator_lock_) {
- art::ArtMethod* m = klass->FindDeclaredVirtualMethod(name, sig, art::kRuntimePointerSize);
- if (m == nullptr) {
- m = klass->FindDeclaredDirectMethod(name, sig, art::kRuntimePointerSize);
+ DCHECK(!klass->IsProxyClass());
+ for (art::ArtMethod& m : klass->GetDeclaredMethodsSlice(art::kRuntimePointerSize)) {
+ if (m.GetName() == name && m.GetSignature() == sig) {
+ return &m;
+ }
}
- return m;
+ return nullptr;
}
bool Redefiner::ClassRedefinition::CheckSameMethods() {
diff --git a/runtime/openjdkjvmti/ti_search.cc b/runtime/openjdkjvmti/ti_search.cc
index 6e0196e..fa58295 100644
--- a/runtime/openjdkjvmti/ti_search.cc
+++ b/runtime/openjdkjvmti/ti_search.cc
@@ -105,17 +105,21 @@
}
art::ArtMethod* get_property =
- properties_class->FindDeclaredVirtualMethod(
+ properties_class->FindClassMethod(
"getProperty",
"(Ljava/lang/String;)Ljava/lang/String;",
art::kRuntimePointerSize);
DCHECK(get_property != nullptr);
+ DCHECK(!get_property->IsDirect());
+ DCHECK(get_property->GetDeclaringClass() == properties_class);
art::ArtMethod* set_property =
- properties_class->FindDeclaredVirtualMethod(
+ properties_class->FindClassMethod(
"setProperty",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;",
art::kRuntimePointerSize);
DCHECK(set_property != nullptr);
+ DCHECK(!set_property->IsDirect());
+ DCHECK(set_property->GetDeclaringClass() == properties_class);
// This is an allocation. Do this late to avoid the need for handles.
ScopedLocalRef<jobject> cp_jobj(self->GetJniEnv(), nullptr);
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index 4e95b01..b055bf9 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -18,6 +18,7 @@
#include <vector>
#include "art_field-inl.h"
+#include "art_method-inl.h"
#include "base/enums.h"
#include "class_linker-inl.h"
#include "common_compiler_test.h"
@@ -63,21 +64,27 @@
jsize array_index = 0;
// Fill the method array
DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
- ArtMethod* method = javaLangObject->FindDeclaredVirtualMethod(
+ ArtMethod* method = javaLangObject->FindClassMethod(
"equals", "(Ljava/lang/Object;)Z", kRuntimePointerSize);
CHECK(method != nullptr);
+ CHECK(!method->IsDirect());
+ CHECK(method->GetDeclaringClass() == javaLangObject);
DCHECK(!Runtime::Current()->IsActiveTransaction());
soa.Env()->SetObjectArrayElement(
proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method)));
- method = javaLangObject->FindDeclaredVirtualMethod("hashCode", "()I", kRuntimePointerSize);
+ method = javaLangObject->FindClassMethod("hashCode", "()I", kRuntimePointerSize);
CHECK(method != nullptr);
+ CHECK(!method->IsDirect());
+ CHECK(method->GetDeclaringClass() == javaLangObject);
soa.Env()->SetObjectArrayElement(
proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method)));
- method = javaLangObject->FindDeclaredVirtualMethod(
+ method = javaLangObject->FindClassMethod(
"toString", "()Ljava/lang/String;", kRuntimePointerSize);
CHECK(method != nullptr);
+ CHECK(!method->IsDirect());
+ CHECK(method->GetDeclaringClass() == javaLangObject);
soa.Env()->SetObjectArrayElement(
proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method)));
diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc
index 260be8f..d830387 100644
--- a/runtime/reference_table_test.cc
+++ b/runtime/reference_table_test.cc
@@ -56,8 +56,8 @@
h_ref_class->AllocObject(self)));
CHECK(h_ref_instance != nullptr);
- ArtMethod* constructor = h_ref_class->FindDeclaredDirectMethod(
- "<init>", "(Ljava/lang/Object;)V", class_linker->GetImagePointerSize());
+ ArtMethod* constructor = h_ref_class->FindConstructor(
+ "(Ljava/lang/Object;)V", class_linker->GetImagePointerSize());
CHECK(constructor != nullptr);
uint32_t args[2];
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index 1ba4b7b..d00f08b 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -108,9 +108,9 @@
class_loader);
CHECK(c != nullptr);
- *method = is_static ? c->FindDirectMethod(method_name, method_signature, kRuntimePointerSize)
- : c->FindVirtualMethod(method_name, method_signature, kRuntimePointerSize);
- CHECK(method != nullptr);
+ *method = c->FindClassMethod(method_name, method_signature, kRuntimePointerSize);
+ CHECK(*method != nullptr);
+ CHECK_EQ(is_static, (*method)->IsStatic());
if (is_static) {
*receiver = nullptr;
@@ -520,10 +520,11 @@
mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LMain;", class_loader);
ASSERT_TRUE(klass != nullptr);
- ArtMethod* method = klass->FindDirectMethod("main",
- "([Ljava/lang/String;)V",
- kRuntimePointerSize);
+ ArtMethod* method = klass->FindClassMethod("main",
+ "([Ljava/lang/String;)V",
+ kRuntimePointerSize);
ASSERT_TRUE(method != nullptr);
+ ASSERT_TRUE(method->IsStatic());
// Start runtime.
bool started = runtime_->Start();
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index bf9e405..74b9810 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -633,9 +633,10 @@
hs.NewHandle(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_ClassLoader)));
CHECK(cl->EnsureInitialized(soa.Self(), class_loader_class, true, true));
- ArtMethod* getSystemClassLoader = class_loader_class->FindDirectMethod(
+ ArtMethod* getSystemClassLoader = class_loader_class->FindClassMethod(
"getSystemClassLoader", "()Ljava/lang/ClassLoader;", pointer_size);
CHECK(getSystemClassLoader != nullptr);
+ CHECK(getSystemClassLoader->IsStatic());
JValue result = InvokeWithJValues(soa,
nullptr,
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 004b68e..5ee4487 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -2780,7 +2780,7 @@
}
}
ArtMethod* exception_init_method =
- exception_class->FindDeclaredDirectMethod("<init>", signature, cl->GetImagePointerSize());
+ exception_class->FindConstructor(signature, cl->GetImagePointerSize());
CHECK(exception_init_method != nullptr) << "No <init>" << signature << " in "
<< PrettyDescriptor(exception_class_descriptor);
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index 634bd47..48b703a 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -192,18 +192,21 @@
ASSERT_TRUE(c != nullptr);
ArtMethod* m;
- m = c->FindVirtualMethod("charAt", "(I)C", kRuntimePointerSize);
+ m = c->FindClassMethod("charAt", "(I)C", kRuntimePointerSize);
ASSERT_TRUE(m != nullptr);
+ ASSERT_FALSE(m->IsDirect());
EXPECT_EQ("Java_java_lang_String_charAt", m->JniShortName());
EXPECT_EQ("Java_java_lang_String_charAt__I", m->JniLongName());
- m = c->FindVirtualMethod("indexOf", "(Ljava/lang/String;I)I", kRuntimePointerSize);
+ m = c->FindClassMethod("indexOf", "(Ljava/lang/String;I)I", kRuntimePointerSize);
ASSERT_TRUE(m != nullptr);
+ ASSERT_FALSE(m->IsDirect());
EXPECT_EQ("Java_java_lang_String_indexOf", m->JniShortName());
EXPECT_EQ("Java_java_lang_String_indexOf__Ljava_lang_String_2I", m->JniLongName());
- m = c->FindDirectMethod("copyValueOf", "([CII)Ljava/lang/String;", kRuntimePointerSize);
+ m = c->FindClassMethod("copyValueOf", "([CII)Ljava/lang/String;", kRuntimePointerSize);
ASSERT_TRUE(m != nullptr);
+ ASSERT_TRUE(m->IsStatic());
EXPECT_EQ("Java_java_lang_String_copyValueOf", m->JniShortName());
EXPECT_EQ("Java_java_lang_String_copyValueOf___3CII", m->JniLongName());
}
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index ea480f4..0351fd3 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -72,8 +72,8 @@
private:
static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
- // Last update: Change quickening info format.
- static constexpr uint8_t kVdexVersion[] = { '0', '0', '8', '\0' };
+ // Last update: Change method lookup.
+ static constexpr uint8_t kVdexVersion[] = { '0', '0', '9', '\0' };
uint8_t magic_[4];
uint8_t version_[4];
diff --git a/runtime/verifier/method_resolution_kind.h b/runtime/verifier/method_resolution_kind.h
deleted file mode 100644
index f72eb7a..0000000
--- a/runtime/verifier/method_resolution_kind.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_VERIFIER_METHOD_RESOLUTION_KIND_H_
-#define ART_RUNTIME_VERIFIER_METHOD_RESOLUTION_KIND_H_
-
-namespace art {
-namespace verifier {
-
-// Values corresponding to the method resolution algorithms defined in mirror::Class.
-enum MethodResolutionKind {
- kDirectMethodResolution,
- kVirtualMethodResolution,
- kInterfaceMethodResolution,
-};
-
-} // namespace verifier
-} // namespace art
-
-#endif // ART_RUNTIME_VERIFIER_METHOD_RESOLUTION_KIND_H_
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index efb02f6..6dc7953 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -39,7 +39,6 @@
#include "indenter.h"
#include "intern_table.h"
#include "leb128.h"
-#include "method_resolution_kind.h"
#include "mirror/class.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache-inl.h"
@@ -230,7 +229,7 @@
}
previous_method_idx = method_idx;
InvokeType type = it->GetMethodInvokeType(class_def);
- ArtMethod* method = linker->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
+ ArtMethod* method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
*dex_file, method_idx, dex_cache, class_loader, nullptr, type);
if (method == nullptr) {
DCHECK(self->IsExceptionPending());
@@ -3821,21 +3820,6 @@
return *common_super;
}
-inline static MethodResolutionKind GetMethodResolutionKind(
- MethodType method_type, bool is_interface) {
- if (method_type == METHOD_DIRECT || method_type == METHOD_STATIC) {
- return kDirectMethodResolution;
- } else if (method_type == METHOD_INTERFACE) {
- return kInterfaceMethodResolution;
- } else if (method_type == METHOD_SUPER && is_interface) {
- return kInterfaceMethodResolution;
- } else {
- DCHECK(method_type == METHOD_VIRTUAL || method_type == METHOD_SUPER
- || method_type == METHOD_POLYMORPHIC);
- return kVirtualMethodResolution;
- }
-}
-
ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(
uint32_t dex_method_idx, MethodType method_type) {
const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx);
@@ -3849,47 +3833,41 @@
if (klass_type.IsUnresolvedTypes()) {
return nullptr; // Can't resolve Class so no more to do here
}
- mirror::Class* klass = klass_type.GetClass();
+ ObjPtr<mirror::Class> klass = klass_type.GetClass();
const RegType& referrer = GetDeclaringClass();
auto* cl = Runtime::Current()->GetClassLinker();
auto pointer_size = cl->GetImagePointerSize();
- MethodResolutionKind res_kind = GetMethodResolutionKind(method_type, klass->IsInterface());
ArtMethod* res_method = dex_cache_->GetResolvedMethod(dex_method_idx, pointer_size);
- bool stash_method = false;
if (res_method == nullptr) {
- const char* name = dex_file_->GetMethodName(method_id);
- const Signature signature = dex_file_->GetMethodSignature(method_id);
-
- if (res_kind == kDirectMethodResolution) {
- res_method = klass->FindDirectMethod(name, signature, pointer_size);
- } else if (res_kind == kVirtualMethodResolution) {
- res_method = klass->FindVirtualMethod(name, signature, pointer_size);
+ // Try to find the method with the appropriate lookup for the klass type (interface or not).
+ // If this lookup does not match `method_type`, errors shall be reported below.
+ if (klass->IsInterface()) {
+ res_method = klass->FindInterfaceMethod(dex_cache_.Get(), dex_method_idx, pointer_size);
} else {
- DCHECK_EQ(res_kind, kInterfaceMethodResolution);
- res_method = klass->FindInterfaceMethod(name, signature, pointer_size);
+ res_method = klass->FindClassMethod(dex_cache_.Get(), dex_method_idx, pointer_size);
}
-
if (res_method != nullptr) {
- stash_method = true;
- } else {
- // If a virtual or interface method wasn't found with the expected type, look in
- // the direct methods. This can happen when the wrong invoke type is used or when
- // a class has changed, and will be flagged as an error in later checks.
- // Note that in this case, we do not put the resolved method in the Dex cache
- // because it was not discovered using the expected type of method resolution.
- if (res_kind != kDirectMethodResolution) {
- // Record result of the initial resolution attempt.
- VerifierDeps::MaybeRecordMethodResolution(*dex_file_, dex_method_idx, res_kind, nullptr);
- // Change resolution type to 'direct' and try to resolve again.
- res_kind = kDirectMethodResolution;
- res_method = klass->FindDirectMethod(name, signature, pointer_size);
- }
+ dex_cache_->SetResolvedMethod(dex_method_idx, res_method, pointer_size);
}
}
- // Record result of method resolution attempt.
- VerifierDeps::MaybeRecordMethodResolution(*dex_file_, dex_method_idx, res_kind, res_method);
+ // Record result of method resolution attempt. The klass resolution has recorded whether
+ // the class is an interface or not and therefore the type of the lookup performed above.
+ // TODO: Maybe we should not record dependency if the invoke type does not match the lookup type.
+ VerifierDeps::MaybeRecordMethodResolution(*dex_file_, dex_method_idx, res_method);
+
+ if (res_method == nullptr) {
+ // Try to find the method also with the other type for better error reporting below
+ // but do not store such bogus lookup result in the DexCache or VerifierDeps.
+ if (klass->IsInterface()) {
+ res_method = klass->FindClassMethod(dex_cache_.Get(), dex_method_idx, pointer_size);
+ } else {
+ // If there was an interface method with the same signature,
+ // we would have found it also in the "copied" methods.
+ DCHECK(klass->FindInterfaceMethod(dex_cache_.Get(), dex_method_idx, pointer_size) == nullptr);
+ }
+ }
if (res_method == nullptr) {
Fail(VERIFY_ERROR_NO_METHOD) << "couldn't find method "
@@ -3940,11 +3918,6 @@
}
}
- // Only stash after the above passed. Otherwise the method wasn't guaranteed to be correct.
- if (stash_method) {
- dex_cache_->SetResolvedMethod(dex_method_idx, res_method, pointer_size);
- }
-
// Check if access is allowed.
if (!referrer.CanAccessMember(res_method->GetDeclaringClass(), res_method->GetAccessFlags())) {
Fail(VERIFY_ERROR_ACCESS_METHOD) << "illegal method access (call "
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index 122e05f..112eec8 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -54,9 +54,7 @@
MergeSets(my_deps->unassignable_types_, other_deps.unassignable_types_);
MergeSets(my_deps->classes_, other_deps.classes_);
MergeSets(my_deps->fields_, other_deps.fields_);
- MergeSets(my_deps->direct_methods_, other_deps.direct_methods_);
- MergeSets(my_deps->virtual_methods_, other_deps.virtual_methods_);
- MergeSets(my_deps->interface_methods_, other_deps.interface_methods_);
+ MergeSets(my_deps->methods_, other_deps.methods_);
for (dex::TypeIndex entry : other_deps.unverified_classes_) {
my_deps->unverified_classes_.push_back(entry);
}
@@ -317,7 +315,6 @@
void VerifierDeps::AddMethodResolution(const DexFile& dex_file,
uint32_t method_idx,
- MethodResolutionKind resolution_kind,
ArtMethod* method) {
DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
if (dex_deps == nullptr) {
@@ -334,14 +331,7 @@
MethodResolution method_tuple(method_idx,
GetAccessFlags(method),
GetMethodDeclaringClassStringId(dex_file, method_idx, method));
- if (resolution_kind == kDirectMethodResolution) {
- dex_deps->direct_methods_.emplace(method_tuple);
- } else if (resolution_kind == kVirtualMethodResolution) {
- dex_deps->virtual_methods_.emplace(method_tuple);
- } else {
- DCHECK_EQ(resolution_kind, kInterfaceMethodResolution);
- dex_deps->interface_methods_.emplace(method_tuple);
- }
+ dex_deps->methods_.insert(method_tuple);
}
mirror::Class* VerifierDeps::FindOneClassPathBoundaryForInterface(mirror::Class* destination,
@@ -537,11 +527,10 @@
void VerifierDeps::MaybeRecordMethodResolution(const DexFile& dex_file,
uint32_t method_idx,
- MethodResolutionKind resolution_kind,
ArtMethod* method) {
VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
if (thread_deps != nullptr) {
- thread_deps->AddMethodResolution(dex_file, method_idx, resolution_kind, method);
+ thread_deps->AddMethodResolution(dex_file, method_idx, method);
}
}
@@ -698,9 +687,7 @@
EncodeSet(buffer, deps.unassignable_types_);
EncodeSet(buffer, deps.classes_);
EncodeSet(buffer, deps.fields_);
- EncodeSet(buffer, deps.direct_methods_);
- EncodeSet(buffer, deps.virtual_methods_);
- EncodeSet(buffer, deps.interface_methods_);
+ EncodeSet(buffer, deps.methods_);
EncodeUint16Vector(buffer, deps.unverified_classes_);
}
}
@@ -723,9 +710,7 @@
DecodeSet(&data_start, data_end, &deps->unassignable_types_);
DecodeSet(&data_start, data_end, &deps->classes_);
DecodeSet(&data_start, data_end, &deps->fields_);
- DecodeSet(&data_start, data_end, &deps->direct_methods_);
- DecodeSet(&data_start, data_end, &deps->virtual_methods_);
- DecodeSet(&data_start, data_end, &deps->interface_methods_);
+ DecodeSet(&data_start, data_end, &deps->methods_);
DecodeUint16Vector(&data_start, data_end, &deps->unverified_classes_);
}
CHECK_LE(data_start, data_end);
@@ -763,9 +748,7 @@
(unassignable_types_ == rhs.unassignable_types_) &&
(classes_ == rhs.classes_) &&
(fields_ == rhs.fields_) &&
- (direct_methods_ == rhs.direct_methods_) &&
- (virtual_methods_ == rhs.virtual_methods_) &&
- (interface_methods_ == rhs.interface_methods_) &&
+ (methods_ == rhs.methods_) &&
(unverified_classes_ == rhs.unverified_classes_);
}
@@ -825,27 +808,21 @@
}
}
- for (const auto& entry :
- { std::make_pair(kDirectMethodResolution, dep.second->direct_methods_),
- std::make_pair(kVirtualMethodResolution, dep.second->virtual_methods_),
- std::make_pair(kInterfaceMethodResolution, dep.second->interface_methods_) }) {
- for (const MethodResolution& method : entry.second) {
- const DexFile::MethodId& method_id = dex_file.GetMethodId(method.GetDexMethodIndex());
+ for (const MethodResolution& method : dep.second->methods_) {
+ const DexFile::MethodId& method_id = dex_file.GetMethodId(method.GetDexMethodIndex());
+ vios->Stream()
+ << dex_file.GetMethodDeclaringClassDescriptor(method_id) << "->"
+ << dex_file.GetMethodName(method_id)
+ << dex_file.GetMethodSignature(method_id).ToString()
+ << " is expected to be ";
+ if (!method.IsResolved()) {
+ vios->Stream() << "unresolved\n";
+ } else {
vios->Stream()
- << dex_file.GetMethodDeclaringClassDescriptor(method_id) << "->"
- << dex_file.GetMethodName(method_id)
- << dex_file.GetMethodSignature(method_id).ToString()
- << " is expected to be ";
- if (!method.IsResolved()) {
- vios->Stream() << "unresolved\n";
- } else {
- vios->Stream()
- << "in class "
- << GetStringFromId(dex_file, method.GetDeclaringClassIndex())
- << ", have the access flags " << std::hex << method.GetAccessFlags() << std::dec
- << ", and be of kind " << entry.first
- << "\n";
- }
+ << "in class "
+ << GetStringFromId(dex_file, method.GetDeclaringClassIndex())
+ << ", have the access flags " << std::hex << method.GetAccessFlags() << std::dec
+ << "\n";
}
}
@@ -1030,7 +1007,6 @@
bool VerifierDeps::VerifyMethods(Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
const std::set<MethodResolution>& methods,
- MethodResolutionKind kind,
Thread* self) const {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
PointerSize pointer_size = class_linker->GetImagePointerSize();
@@ -1054,27 +1030,20 @@
}
DCHECK(cls->IsResolved());
ArtMethod* method = nullptr;
- if (kind == kDirectMethodResolution) {
- method = cls->FindDirectMethod(name, signature, pointer_size);
- } else if (kind == kVirtualMethodResolution) {
- method = cls->FindVirtualMethod(name, signature, pointer_size);
- } else {
- DCHECK_EQ(kind, kInterfaceMethodResolution);
+ if (cls->IsInterface()) {
method = cls->FindInterfaceMethod(name, signature, pointer_size);
+ } else {
+ method = cls->FindClassMethod(name, signature, pointer_size);
}
if (entry.IsResolved()) {
std::string temp;
if (method == nullptr) {
- LOG(INFO) << "VerifierDeps: Could not resolve "
- << kind
- << " method "
+ LOG(INFO) << "VerifierDeps: Could not resolve method "
<< GetMethodDescription(dex_file, entry.GetDexMethodIndex());
return false;
} else if (expected_decl_klass != method->GetDeclaringClass()->GetDescriptor(&temp)) {
- LOG(INFO) << "VerifierDeps: Unexpected declaring class for "
- << kind
- << " method resolution "
+ LOG(INFO) << "VerifierDeps: Unexpected declaring class for method resolution "
<< GetMethodDescription(dex_file, entry.GetDexMethodIndex())
<< " (expected="
<< expected_decl_klass
@@ -1083,9 +1052,7 @@
<< ")";
return false;
} else if (entry.GetAccessFlags() != GetAccessFlags(method)) {
- LOG(INFO) << "VerifierDeps: Unexpected access flags for resolved "
- << kind
- << " method resolution "
+ LOG(INFO) << "VerifierDeps: Unexpected access flags for resolved method resolution "
<< GetMethodDescription(dex_file, entry.GetDexMethodIndex())
<< std::hex
<< " (expected="
@@ -1096,9 +1063,7 @@
return false;
}
} else if (method != nullptr) {
- LOG(INFO) << "VerifierDeps: Unexpected successful resolution of "
- << kind
- << " method "
+ LOG(INFO) << "VerifierDeps: Unexpected successful resolution of method "
<< GetMethodDescription(dex_file, entry.GetDexMethodIndex());
return false;
}
@@ -1118,12 +1083,7 @@
result = result && VerifyClasses(class_loader, dex_file, deps.classes_, self);
result = result && VerifyFields(class_loader, dex_file, deps.fields_, self);
- result = result && VerifyMethods(
- class_loader, dex_file, deps.direct_methods_, kDirectMethodResolution, self);
- result = result && VerifyMethods(
- class_loader, dex_file, deps.virtual_methods_, kVirtualMethodResolution, self);
- result = result && VerifyMethods(
- class_loader, dex_file, deps.interface_methods_, kInterfaceMethodResolution, self);
+ result = result && VerifyMethods(class_loader, dex_file, deps.methods_, self);
return result;
}
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index 43eb948..b883a9e 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -25,7 +25,6 @@
#include "base/mutex.h"
#include "dex_file_types.h"
#include "handle.h"
-#include "method_resolution_kind.h"
#include "obj_ptr.h"
#include "thread.h"
#include "verifier_enums.h" // For MethodVerifier::FailureKind.
@@ -88,12 +87,10 @@
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::verifier_deps_lock_);
- // Record the outcome `method` of resolving method `method_idx` from `dex_file`
- // using `res_kind` kind of method resolution algorithm. If `method` is null,
- // the method is assumed unresolved.
+ // Record the outcome `method` of resolving method `method_idx` from `dex_file`.
+ // If `method` is null, the method is assumed unresolved.
static void MaybeRecordMethodResolution(const DexFile& dex_file,
uint32_t method_idx,
- MethodResolutionKind res_kind,
ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::verifier_deps_lock_);
@@ -193,9 +190,7 @@
// Sets of recorded class/field/method resolutions.
std::set<ClassResolution> classes_;
std::set<FieldResolution> fields_;
- std::set<MethodResolution> direct_methods_;
- std::set<MethodResolution> virtual_methods_;
- std::set<MethodResolution> interface_methods_;
+ std::set<MethodResolution> methods_;
// List of classes that were not fully verified in that dex file.
std::vector<dex::TypeIndex> unverified_classes_;
@@ -267,7 +262,6 @@
void AddMethodResolution(const DexFile& dex_file,
uint32_t method_idx,
- MethodResolutionKind res_kind,
ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::verifier_deps_lock_);
@@ -321,7 +315,6 @@
bool VerifyMethods(Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
const std::set<MethodResolution>& methods,
- MethodResolutionKind kind,
Thread* self) const
REQUIRES_SHARED(Locks::mutator_lock_);