Faster Class::FindClassMethod().

Avoid using `strlen()` on ASCII strings from DexFile.
This was a missed opportunity in
    https://android-review.googlesource.com/963405 .

Also optimize iteration over declared methods of a class.
Load the dex file before the loop and avoid the runtime
method check in `ArtMethod::GetMethodNameView()` by using
the `DexFile` interface directly.

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 181943478
Change-Id: I1ce3659b7f1fbcfc11d52626f9feb9be666d1161
diff --git a/libdexfile/dex/dex_file-inl.h b/libdexfile/dex/dex_file-inl.h
index 0e1fb68..c85751a 100644
--- a/libdexfile/dex/dex_file-inl.h
+++ b/libdexfile/dex/dex_file-inl.h
@@ -44,6 +44,7 @@
   return DecodeUnsignedLeb128(&ptr);
 }
 
+ALWAYS_INLINE
 inline const char* DexFile::GetStringDataAndUtf16Length(const dex::StringId& string_id,
                                                         uint32_t* utf16_length) const {
   DCHECK(utf16_length != nullptr) << GetLocation();
@@ -52,11 +53,13 @@
   return reinterpret_cast<const char*>(ptr);
 }
 
+ALWAYS_INLINE
 inline const char* DexFile::GetStringData(const dex::StringId& string_id) const {
   uint32_t ignored;
   return GetStringDataAndUtf16Length(string_id, &ignored);
 }
 
+ALWAYS_INLINE
 inline const char* DexFile::StringDataAndUtf16LengthByIdx(dex::StringIndex idx,
                                                           uint32_t* utf16_length) const {
   if (!idx.IsValid()) {
@@ -67,11 +70,13 @@
   return GetStringDataAndUtf16Length(string_id, utf16_length);
 }
 
+ALWAYS_INLINE
 inline const char* DexFile::StringDataByIdx(dex::StringIndex idx) const {
   uint32_t unicode_length;
   return StringDataAndUtf16LengthByIdx(idx, &unicode_length);
 }
 
+ALWAYS_INLINE
 inline std::string_view DexFile::StringViewByIdx(dex::StringIndex idx) const {
   uint32_t unicode_length;
   const char* data = StringDataAndUtf16LengthByIdx(idx, &unicode_length);
@@ -138,6 +143,16 @@
   return StringDataAndUtf16LengthByIdx(GetMethodId(idx).name_idx_, utf_length);
 }
 
+ALWAYS_INLINE
+inline std::string_view DexFile::GetMethodNameView(const dex::MethodId& method_id) const {
+  return StringViewByIdx(method_id.name_idx_);
+}
+
+ALWAYS_INLINE
+inline std::string_view DexFile::GetMethodNameView(uint32_t idx) const {
+  return GetMethodNameView(GetMethodId(idx));
+}
+
 inline const char* DexFile::GetMethodShorty(uint32_t idx) const {
   return StringDataByIdx(GetProtoId(GetMethodId(idx).proto_idx_).shorty_idx_);
 }
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index 5363b00..ca5e73b 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -404,6 +404,8 @@
   const char* GetMethodName(const dex::MethodId& method_id, uint32_t* utf_length) const;
   const char* GetMethodName(uint32_t idx) const;
   const char* GetMethodName(uint32_t idx, uint32_t* utf_length) const;
+  std::string_view GetMethodNameView(const dex::MethodId& method_id) const;
+  std::string_view GetMethodNameView(uint32_t idx) const;
 
   // Returns the shorty of a method by its index.
   const char* GetMethodShorty(uint32_t idx) const;
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 630a8a5..8dede3a 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -209,9 +209,7 @@
   if (LIKELY(dex_method_idx != dex::kDexNoIndex)) {
     DCHECK(!IsProxyMethod());
     const DexFile* dex_file = GetDexFile();
-    uint32_t length = 0;
-    const char* name = dex_file->GetMethodName(dex_file->GetMethodId(dex_method_idx), &length);
-    return StringViewFromUtf16Length(name, length);
+    return dex_file->GetMethodNameView(dex_method_idx);
   }
   return GetRuntimeMethodName();
 }
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 3f9d41c..8064bcc 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -634,7 +634,7 @@
   // 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) {
+    if (np_method->GetNameView() == name && np_method->GetSignature() == signature) {
       return &method;
     }
   }
@@ -647,7 +647,7 @@
   for (; klass != nullptr; klass = klass->GetSuperClass()) {
     DCHECK(!klass->IsProxyClass());
     for (ArtMethod& method : klass->GetDeclaredMethodsSlice(pointer_size)) {
-      if (method.GetName() == name && method.GetSignature() == signature) {
+      if (method.GetNameView() == name && method.GetSignature() == signature) {
         if (IsInheritedMethod(this_klass, klass, method)) {
           return &method;
         }
@@ -672,7 +672,7 @@
   for (; klass != end_klass; klass = klass->GetSuperClass()) {
     DCHECK(!klass->IsProxyClass());
     for (ArtMethod& method : klass->GetCopiedMethodsSlice(pointer_size)) {
-      if (method.GetName() == name && method.GetSignature() == signature) {
+      if (method.GetNameView() == name && method.GetSignature() == signature) {
         return &method;  // No further check needed, copied methods are inherited by definition.
       }
     }
@@ -693,6 +693,7 @@
   return FindClassMethodWithSignature(this, name, signature, pointer_size);
 }
 
+FLATTEN
 ArtMethod* Class::FindClassMethod(ObjPtr<DexCache> dex_cache,
                                   uint32_t dex_method_idx,
                                   PointerSize pointer_size) {
@@ -714,18 +715,19 @@
   const DexFile& dex_file = *dex_cache->GetDexFile();
   const dex::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
   const Signature signature = dex_file.GetMethodSignature(method_id);
-  std::string_view name;  // Delay strlen() until actually needed.
+  std::string_view name;  // Do not touch the dex file string data 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());
-    // Avoid string comparisons by comparing the respective unicode lengths first.
-    uint32_t length, other_length;  // UTF16 length.
-    name = dex_file.GetMethodName(method_id, &length);
+    name = dex_file.GetMethodNameView(method_id);
+    const DexFile& this_dex_file = *this_dex_cache->GetDexFile();
     for (ArtMethod& method : GetDeclaredMethodsSlice(pointer_size)) {
+      // Do not use ArtMethod::GetNameView() to avoid reloading dex file through the same
+      // declaring class from different methods and also avoid the runtime method check.
+      DCHECK(method.GetDexFile() == &this_dex_file);
       DCHECK_NE(method.GetDexMethodIndex(), dex::kDexNoIndex);
-      const char* other_name = method.GetDexFile()->GetMethodName(
-          method.GetDexMethodIndex(), &other_length);
-      if (length == other_length && name == other_name && signature == method.GetSignature()) {
+      std::string_view other_name = this_dex_file.GetMethodNameView(method.GetDexMethodIndex());
+      if (other_name == name && method.GetSignature() == signature) {
         return &method;
       }
     }
@@ -750,12 +752,18 @@
           break;
         }
       }
-    } else {
-      if (!declared_methods.empty() && name.empty()) {
-        name = dex_file.StringDataByIdx(method_id.name_idx_);
+    } else if (!declared_methods.empty()) {
+      if (name.empty()) {
+        name = dex_file.GetMethodNameView(method_id);
       }
+      const DexFile& other_dex_file = klass->GetDexFile();
       for (ArtMethod& method : declared_methods) {
-        if (method.GetName() == name && method.GetSignature() == signature) {
+        // Do not use ArtMethod::GetNameView() to avoid reloading dex file through the same
+        // declaring class from different methods and also avoid the runtime method check.
+        DCHECK(method.GetDexFile() == &other_dex_file);
+        DCHECK_NE(method.GetDexMethodIndex(), dex::kDexNoIndex);
+        std::string_view other_name = other_dex_file.GetMethodNameView(method.GetDexMethodIndex());
+        if (other_name == name && method.GetSignature() == signature) {
           candidate_method = &method;
           break;
         }
@@ -783,7 +791,7 @@
       name = dex_file.StringDataByIdx(method_id.name_idx_);
     }
     for (ArtMethod& method : copied_methods) {
-      if (method.GetName() == name && method.GetSignature() == signature) {
+      if (method.GetNameView() == name && method.GetSignature() == signature) {
         return &method;  // No further check needed, copied methods are inherited by definition.
       }
     }