Use ObjPtr for ResolvedFieldAccessTest and ResolvedMethodAccessTest

Also added LookupResolvedType that is guaranteed to not do thread
suspension but deals with multidex since GetResolvedType will
return null if the type was resolved in another dex file.

Added test.

Bug: 31113334

Test: test-art-host CC baker

Change-Id: I50493bca7d8ce9760546c3116b717484c62c47a4
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 06a8243..0d3c012 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -7638,6 +7638,32 @@
   return string;
 }
 
+ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(const DexFile& dex_file,
+                                                      uint16_t type_idx,
+                                                      ObjPtr<mirror::DexCache> dex_cache,
+                                                      ObjPtr<mirror::ClassLoader> class_loader) {
+  ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
+  if (type == nullptr) {
+    const char* descriptor = dex_file.StringByTypeIdx(type_idx);
+    DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
+    if (descriptor[1] == '\0') {
+      // only the descriptors of primitive types should be 1 character long, also avoid class lookup
+      // for primitive classes that aren't backed by dex files.
+      type = FindPrimitiveClass(descriptor[0]);
+    } else {
+      Thread* const self = Thread::Current();
+      DCHECK(self != nullptr);
+      const size_t hash = ComputeModifiedUtf8Hash(descriptor);
+      // Find the class in the loaded classes table.
+      type = LookupClass(self, descriptor, hash, class_loader.Decode());
+    }
+  }
+  if (type != nullptr || type->IsResolved()) {
+    return type;
+  }
+  return nullptr;
+}
+
 mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file,
                                         uint16_t type_idx,
                                         mirror::Class* referrer) {