summaryrefslogtreecommitdiff
path: root/runtime/class_linker-inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker-inl.h')
-rw-r--r--runtime/class_linker-inl.h127
1 files changed, 127 insertions, 0 deletions
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 4e8f8edf64..26c422b9eb 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -401,6 +401,104 @@ inline ArtMethod* ClassLinker::ResolveMethod(Thread* self,
return resolved_method;
}
+template <ClassLinker::ResolveMode kResolveMode>
+inline ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ ArtMethod* referrer,
+ InvokeType type) {
+ DCHECK(dex_cache->GetClassLoader() == class_loader.Get());
+ DCHECK(!Thread::Current()->IsExceptionPending()) << Thread::Current()->GetException()->Dump();
+ DCHECK(dex_cache != nullptr);
+ DCHECK(referrer == nullptr || !referrer->IsProxyMethod());
+ // Check for hit in the dex cache.
+ ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx);
+ Thread::PoisonObjectPointersIfDebug();
+ DCHECK(resolved == nullptr || !resolved->IsRuntimeMethod());
+ bool valid_dex_cache_method = resolved != nullptr;
+ if (kResolveMode == ResolveMode::kNoChecks && valid_dex_cache_method) {
+ // We have a valid method from the DexCache and no checks to perform.
+ DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
+ return resolved;
+ }
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ const dex::MethodId& method_id = dex_file.GetMethodId(method_idx);
+ ObjPtr<mirror::Class> klass = nullptr;
+ if (valid_dex_cache_method) {
+ // We have a valid method from the DexCache but we need to perform ICCE and IAE checks.
+ DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
+ klass = LookupResolvedType(method_id.class_idx_, dex_cache.Get(), class_loader.Get());
+ if (UNLIKELY(klass == nullptr)) {
+ // We normaly should not end up here. However the verifier currently doesn't guarantee
+ // the invariant of having the klass in the class table. b/73760543
+ klass = ResolveType(method_id.class_idx_, dex_cache, class_loader);
+ if (klass == nullptr) {
+ // This can only happen if the current thread is not allowed to load
+ // classes.
+ DCHECK(!Thread::Current()->CanLoadClasses());
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return nullptr;
+ }
+ }
+ } else {
+ // The method was not in the DexCache, resolve the declaring class.
+ klass = ResolveType(method_id.class_idx_, dex_cache, class_loader);
+ if (klass == nullptr) {
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return nullptr;
+ }
+ }
+
+ // Check if the invoke type matches the class type.
+ if (kResolveMode == ResolveMode::kCheckICCEAndIAE &&
+ CheckInvokeClassMismatch</* kThrow= */ true>(
+ dex_cache.Get(), type, [klass]() { return klass; })) {
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return nullptr;
+ }
+
+ if (!valid_dex_cache_method) {
+ resolved = FindResolvedMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx);
+ }
+
+ // Note: We can check for IllegalAccessError only if we have a referrer.
+ if (kResolveMode == ResolveMode::kCheckICCEAndIAE && resolved != nullptr && referrer != nullptr) {
+ ObjPtr<mirror::Class> methods_class = resolved->GetDeclaringClass();
+ ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
+ if (!referring_class->CheckResolvedMethodAccess(methods_class,
+ resolved,
+ dex_cache.Get(),
+ method_idx,
+ type)) {
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return nullptr;
+ }
+ }
+
+ // If we found a method, check for incompatible class changes.
+ if (LIKELY(resolved != nullptr) &&
+ LIKELY(kResolveMode == ResolveMode::kNoChecks ||
+ !resolved->CheckIncompatibleClassChange(type))) {
+ return resolved;
+ } else {
+ // If we had a method, or if we can find one with another lookup type,
+ // it's an incompatible-class-change error.
+ if (resolved == nullptr) {
+ resolved = FindIncompatibleMethod(klass, dex_cache.Get(), class_loader.Get(), method_idx);
+ }
+ if (resolved != nullptr) {
+ ThrowIncompatibleClassChangeError(type, resolved->GetInvokeType(), resolved, referrer);
+ } else {
+ // We failed to find the method (using all lookup types), so throw a NoSuchMethodError.
+ const char* name = dex_file.StringDataByIdx(method_id.name_idx_);
+ const Signature signature = dex_file.GetMethodSignature(method_id);
+ ThrowNoSuchMethodError(type, klass, name, signature);
+ }
+ Thread::Current()->AssertPendingException();
+ return nullptr;
+ }
+}
+
inline ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx,
ArtMethod* referrer,
bool is_static) {
@@ -431,6 +529,35 @@ inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,
return resolved_field;
}
+inline ArtField* ClassLinker::ResolveField(uint32_t field_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ bool is_static) {
+ DCHECK(dex_cache != nullptr);
+ DCHECK(dex_cache->GetClassLoader().Ptr() == class_loader.Get());
+ DCHECK(!Thread::Current()->IsExceptionPending()) << Thread::Current()->GetException()->Dump();
+ ArtField* resolved = dex_cache->GetResolvedField(field_idx);
+ Thread::PoisonObjectPointersIfDebug();
+ if (resolved != nullptr) {
+ return resolved;
+ }
+ const DexFile& dex_file = *dex_cache->GetDexFile();
+ const dex::FieldId& field_id = dex_file.GetFieldId(field_idx);
+ ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader);
+ if (klass == nullptr) {
+ DCHECK(Thread::Current()->IsExceptionPending());
+ return nullptr;
+ }
+
+ resolved = FindResolvedField(klass, dex_cache.Get(), class_loader.Get(), field_idx, is_static);
+ if (resolved == nullptr) {
+ const char* name = dex_file.GetFieldName(field_id);
+ const char* type = dex_file.GetFieldTypeDescriptor(field_id);
+ ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass, type, name);
+ }
+ return resolved;
+}
+
template <class Visitor>
inline void ClassLinker::VisitClassTables(const Visitor& visitor) {
Thread* const self = Thread::Current();