Check same dex file for finding class descriptor string id

Use ClassDef for finding same dex file class descriptor string id
for vdex. Removes some calls to FindStringId, the remaining calls to
FindStringId are due to multidex or referring to types in the boot
class path.

Also check method index slot to see if we get lucky.

Host perf:
DexFile::FindStringId: 2.57% -> 0.94%

Not done for fields since these do not seem to reach the FindStringId
case accordingto perf. The remaining calls to FindStringId come from:
100.00% verifier::VerifierDeps::GetClassDescriptorStringId
-> 66.62% verifier::VerifierDeps::AddAssignability
-> 33.38% verifier::VerifierDeps::AddMethodResolution

FB install time: 35.54s -> 34.41s (avg of 40 samples at 960MHZ N6P).

Bug: 32641252

Test: test-art-host

Change-Id: If50408cf1be5c2d2127140780b8d5af66306939c
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index 8a0f4cf..a65e82b 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -16,6 +16,8 @@
 
 #include "verifier_deps.h"
 
+#include <cstring>
+
 #include "compiler_callbacks.h"
 #include "leb128.h"
 #include "mirror/class-inl.h"
@@ -56,17 +58,80 @@
   }
 }
 
-template <typename T>
-uint32_t VerifierDeps::GetDeclaringClassStringId(const DexFile& dex_file, T* element) {
+uint32_t VerifierDeps::GetClassDescriptorStringId(const DexFile& dex_file,
+                                                  ObjPtr<mirror::Class> klass) {
+  DCHECK(klass != nullptr);
+  ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
+  // Array classes do not have a dex cache.
+  if (!klass->IsArrayClass() && !klass->IsProxyClass()) {
+    DCHECK(dex_cache != nullptr) << klass->PrettyClass();
+    if (dex_cache->GetDexFile() == &dex_file) {
+      // FindStringId is slow, try to go through the class def if we have one.
+      const DexFile::ClassDef* class_def = klass->GetClassDef();
+      DCHECK(class_def != nullptr) << klass->PrettyClass();
+      std::string temp;
+      const DexFile::TypeId& type_id = dex_file.GetTypeId(class_def->class_idx_);
+      DCHECK_EQ(GetIdFromString(dex_file, klass->GetDescriptor(&temp)), type_id.descriptor_idx_);
+      return type_id.descriptor_idx_;
+    }
+  }
+  std::string temp;
+  return GetIdFromString(dex_file, klass->GetDescriptor(&temp));
+}
+
+// Try to find the string descriptor of the class. type_idx is a best guess of a matching string id.
+static uint32_t TryGetClassDescriptorStringId(const DexFile& dex_file,
+                                              dex::TypeIndex type_idx,
+                                              ObjPtr<mirror::Class> klass)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (!klass->IsArrayClass()) {
+    const DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx);
+    const DexFile& klass_dex = klass->GetDexFile();
+    const DexFile::TypeId& klass_type_id = klass_dex.GetTypeId(klass->GetClassDef()->class_idx_);
+    if (strcmp(dex_file.GetTypeDescriptor(type_id),
+               klass_dex.GetTypeDescriptor(klass_type_id)) == 0) {
+      return type_id.descriptor_idx_;
+    }
+  }
+  return DexFile::kDexNoIndex;
+}
+
+uint32_t VerifierDeps::GetMethodDeclaringClassStringId(const DexFile& dex_file,
+                                                       uint32_t dex_method_index,
+                                                       ArtMethod* method) {
   static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant");
-  if (element == nullptr) {
+  if (method == nullptr) {
     return VerifierDeps::kUnresolvedMarker;
-  } else {
-    std::string temp;
-    uint32_t string_id = GetIdFromString(
-        dex_file, element->GetDeclaringClass()->GetDescriptor(&temp));
+  }
+  const uint32_t string_id = TryGetClassDescriptorStringId(
+      dex_file,
+      dex_file.GetMethodId(dex_method_index).class_idx_,
+      method->GetDeclaringClass());
+  if (string_id != DexFile::kDexNoIndex) {
+    // Got lucky using the original dex file, return based on the input dex file.
+    DCHECK_EQ(GetClassDescriptorStringId(dex_file, method->GetDeclaringClass()), string_id);
     return string_id;
   }
+  return GetClassDescriptorStringId(dex_file, method->GetDeclaringClass());
+}
+
+uint32_t VerifierDeps::GetFieldDeclaringClassStringId(const DexFile& dex_file,
+                                                      uint32_t dex_field_idx,
+                                                      ArtField* field) {
+  static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant");
+  if (field == nullptr) {
+    return VerifierDeps::kUnresolvedMarker;
+  }
+  const uint32_t string_id = TryGetClassDescriptorStringId(
+      dex_file,
+      dex_file.GetFieldId(dex_field_idx).class_idx_,
+      field->GetDeclaringClass());
+  if (string_id != DexFile::kDexNoIndex) {
+    // Got lucky using the original dex file, return based on the input dex file.
+    DCHECK_EQ(GetClassDescriptorStringId(dex_file, field->GetDeclaringClass()), string_id);
+    return string_id;
+  }
+  return GetClassDescriptorStringId(dex_file, field->GetDeclaringClass());
 }
 
 uint32_t VerifierDeps::GetIdFromString(const DexFile& dex_file, const std::string& str) {
@@ -171,8 +236,11 @@
   }
 
   MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-  dex_deps->fields_.emplace(FieldResolution(
-      field_idx, GetAccessFlags(field), GetDeclaringClassStringId(dex_file, field)));
+  dex_deps->fields_.emplace(FieldResolution(field_idx,
+                                            GetAccessFlags(field),
+                                            GetFieldDeclaringClassStringId(dex_file,
+                                                                           field_idx,
+                                                                           field)));
 }
 
 void VerifierDeps::AddMethodResolution(const DexFile& dex_file,
@@ -194,7 +262,7 @@
   MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
   MethodResolution method_tuple(method_idx,
                                 GetAccessFlags(method),
-                                GetDeclaringClassStringId(dex_file, method));
+                                GetMethodDeclaringClassStringId(dex_file, method_idx, method));
   if (resolution_kind == kDirectMethodResolution) {
     dex_deps->direct_methods_.emplace(method_tuple);
   } else if (resolution_kind == kVirtualMethodResolution) {
@@ -263,12 +331,8 @@
   MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
 
   // Get string IDs for both descriptors and store in the appropriate set.
-
-  std::string temp1, temp2;
-  std::string destination_desc(destination->GetDescriptor(&temp1));
-  std::string source_desc(source->GetDescriptor(&temp2));
-  uint32_t destination_id = GetIdFromString(dex_file, destination_desc);
-  uint32_t source_id = GetIdFromString(dex_file, source_desc);
+  uint32_t destination_id = GetClassDescriptorStringId(dex_file, destination);
+  uint32_t source_id = GetClassDescriptorStringId(dex_file, source);
 
   if (is_assignable) {
     dex_deps->assignable_types_.emplace(TypeAssignability(destination_id, source_id));
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index 23e22d9..e35af41 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -232,8 +232,19 @@
 
   // Returns a string ID of the descriptor of the declaring class of `element`,
   // or `kUnresolvedMarker` if `element` is null.
-  template <typename T>
-  uint32_t GetDeclaringClassStringId(const DexFile& dex_file, T* element)
+  uint32_t GetMethodDeclaringClassStringId(const DexFile& dex_file,
+                                           uint32_t dex_method_idx,
+                                           ArtMethod* method)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(Locks::verifier_deps_lock_);
+  uint32_t GetFieldDeclaringClassStringId(const DexFile& dex_file,
+                                          uint32_t dex_field_idx,
+                                          ArtField* field)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(Locks::verifier_deps_lock_);
+
+  // Returns a string ID of the descriptor of the class.
+  uint32_t GetClassDescriptorStringId(const DexFile& dex_file, ObjPtr<mirror::Class> klass)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(Locks::verifier_deps_lock_);