Use string length from DEX instead of recomputing

This gives around a 2% improvement in startup time overall. Here are results from a selection of
apps:

com.android.gallery3d/.app.GalleryActivity: 203.2ms → 197.7ms (change: -5.4ms, -2.7%)
com.android.messaging/.ui.conversationlist.ConversationListActivity:
  202.1ms → 199.1ms (change: -3.0ms, -1.5%)
com.android.contacts/.activities.PeopleActivity: 277.3ms → 270.7ms (change: -6.6ms, -2.4%)
com.android.camera2/com.android.camera.CameraLauncher:
  351.7ms → 344.1ms (change: -7.7ms, -2.2%)
com.android.dialer/.main.impl.MainActivity: 259.5ms → 254.2ms (change: -5.3ms, -2.0%)
com.android.settings/.Settings: 189.0ms → 186.5ms (change: -2.4ms, -1.3%)
com.android.email/.activity.Welcome: 222.8ms → 219.3ms (change: -3.6ms, -1.6%)
org.mozilla.firefox/.App: 370.2ms → 358.3ms (change: -11.9ms, -3.2%)

This is the average of 100 runs on a Pixel 2 XL.

Bug: 132691958
Test: device boots, start app many times
Change-Id: I93b6eb5105e32788cfc8159c6c21b400a161f86c
diff --git a/libdexfile/dex/dex_file-inl.h b/libdexfile/dex/dex_file-inl.h
index 15ba9cc..0c3f949 100644
--- a/libdexfile/dex/dex_file-inl.h
+++ b/libdexfile/dex/dex_file-inl.h
@@ -31,6 +31,13 @@
 
 namespace art {
 
+inline std::string_view StringViewFromUtf16Length(const char* utf8_data, size_t utf16_length) {
+  size_t utf8_length = LIKELY(utf8_data[utf16_length] == 0)  // Is ASCII?
+                           ? utf16_length
+                           : utf16_length + strlen(utf8_data + utf16_length);
+  return std::string_view(utf8_data, utf8_length);
+}
+
 inline int32_t DexFile::GetStringLength(const dex::StringId& string_id) const {
   const uint8_t* ptr = DataBegin() + string_id.string_data_off_;
   return DecodeUnsignedLeb128(&ptr);
@@ -64,6 +71,12 @@
   return StringDataAndUtf16LengthByIdx(idx, &unicode_length);
 }
 
+inline std::string_view DexFile::StringViewByIdx(dex::StringIndex idx) const {
+  uint32_t unicode_length;
+  const char* data = StringDataAndUtf16LengthByIdx(idx, &unicode_length);
+  return data != nullptr ? StringViewFromUtf16Length(data, unicode_length) : std::string_view("");
+}
+
 inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const {
   if (!idx.IsValid()) {
     return nullptr;
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index e119553..b892d82 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -262,6 +262,7 @@
   const char* StringDataAndUtf16LengthByIdx(dex::StringIndex idx, uint32_t* utf16_length) const;
 
   const char* StringDataByIdx(dex::StringIndex idx) const;
+  std::string_view StringViewByIdx(dex::StringIndex idx) const;
 
   // Looks up a string id for a given modified utf8 string.
   const dex::StringId* FindStringId(const char* string) const;
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 2670f91..d77c608 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -199,26 +199,19 @@
     const DexFile* dex_file = GetDexFile();
     return dex_file->GetMethodName(dex_file->GetMethodId(dex_method_idx));
   }
-  Runtime* const runtime = Runtime::Current();
-  if (this == runtime->GetResolutionMethod()) {
-    return "<runtime internal resolution method>";
-  } else if (this == runtime->GetImtConflictMethod()) {
-    return "<runtime internal imt conflict method>";
-  } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveAllCalleeSaves)) {
-    return "<runtime internal callee-save all registers method>";
-  } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsOnly)) {
-    return "<runtime internal callee-save reference registers method>";
-  } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsAndArgs)) {
-    return "<runtime internal callee-save reference and argument registers method>";
-  } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverything)) {
-    return "<runtime internal save-every-register method>";
-  } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForClinit)) {
-    return "<runtime internal save-every-register method for clinit>";
-  } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForSuspendCheck)) {
-    return "<runtime internal save-every-register method for suspend check>";
-  } else {
-    return "<unknown runtime internal method>";
+  return GetRuntimeMethodName();
+}
+
+inline std::string_view ArtMethod::GetNameView() {
+  uint32_t dex_method_idx = GetDexMethodIndex();
+  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 GetRuntimeMethodName();
 }
 
 inline ObjPtr<mirror::String> ArtMethod::ResolveNameString() {
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 3cdefe8..7f3aa80 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -838,6 +838,29 @@
   return long_name;
 }
 
+const char* ArtMethod::GetRuntimeMethodName() {
+  Runtime* const runtime = Runtime::Current();
+  if (this == runtime->GetResolutionMethod()) {
+    return "<runtime internal resolution method>";
+  } else if (this == runtime->GetImtConflictMethod()) {
+    return "<runtime internal imt conflict method>";
+  } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveAllCalleeSaves)) {
+    return "<runtime internal callee-save all registers method>";
+  } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsOnly)) {
+    return "<runtime internal callee-save reference registers method>";
+  } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsAndArgs)) {
+    return "<runtime internal callee-save reference and argument registers method>";
+  } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverything)) {
+    return "<runtime internal save-every-register method>";
+  } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForClinit)) {
+    return "<runtime internal save-every-register method for clinit>";
+  } else if (this == runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForSuspendCheck)) {
+    return "<runtime internal save-every-register method for suspend check>";
+  } else {
+    return "<unknown runtime internal method>";
+  }
+}
+
 // AssertSharedHeld doesn't work in GetAccessFlags, so use a NO_THREAD_SAFETY_ANALYSIS helper.
 // TODO: Figure out why ASSERT_SHARED_CAPABILITY doesn't work.
 template <ReadBarrierOption kReadBarrierOption>
diff --git a/runtime/art_method.h b/runtime/art_method.h
index d1647cc..83213d5 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -585,6 +585,8 @@
 
   ALWAYS_INLINE const char* GetName() REQUIRES_SHARED(Locks::mutator_lock_);
 
+  ALWAYS_INLINE std::string_view GetNameView() REQUIRES_SHARED(Locks::mutator_lock_);
+
   ObjPtr<mirror::String> ResolveNameString() REQUIRES_SHARED(Locks::mutator_lock_);
 
   const dex::CodeItem* GetCodeItem() REQUIRES_SHARED(Locks::mutator_lock_);
@@ -860,6 +862,9 @@
     } while (!access_flags_.compare_exchange_weak(old_access_flags, new_access_flags));
   }
 
+  // Used by GetName and GetNameView to share common code.
+  const char* GetRuntimeMethodName() REQUIRES_SHARED(Locks::mutator_lock_);
+
   DISALLOW_COPY_AND_ASSIGN(ArtMethod);  // Need to use CopyFrom to deal with 32 vs 64 bits.
 };
 
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 5025c02..ec07a50 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -446,7 +446,7 @@
     // 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) {
+      if (method.GetNameView() == name && method.GetSignature() == signature) {
         return &method;
       }
     }
@@ -458,7 +458,7 @@
   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) {
+      if (method.GetNameView() == name && method.GetSignature() == signature) {
         return &method;
       }
     }
@@ -470,7 +470,7 @@
     DCHECK(object_class->IsObjectClass());
     for (ArtMethod& method : object_class->GetDeclaredMethodsSlice(pointer_size)) {
       if (method.IsPublic() && !method.IsStatic() &&
-          method.GetName() == name && method.GetSignature() == signature) {
+          method.GetNameView() == name && method.GetSignature() == signature) {
         return &method;
       }
     }
@@ -496,7 +496,7 @@
   // We always search by name and signature, ignoring the type index in the MethodId.
   const DexFile& dex_file = *dex_cache->GetDexFile();
   const dex::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
-  std::string_view name = dex_file.StringDataByIdx(method_id.name_idx_);
+  std::string_view name = dex_file.StringViewByIdx(method_id.name_idx_);
   const Signature signature = dex_file.GetMethodSignature(method_id);
   return FindInterfaceMethod(name, signature, pointer_size);
 }