diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index ae84d7ffe5e2..f11b7b79308b 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -719,16 +719,6 @@ void MergeInputSection<ELFT>::splitStrings(ArrayRef<uint8_t> Data,
   }
 }
 
-// Returns I'th piece's data.
-template <class ELFT>
-CachedHashStringRef MergeInputSection<ELFT>::getData(size_t I) const {
-  size_t End =
-      (Pieces.size() - 1 == I) ? this->Data.size() : Pieces[I + 1].InputOff;
-  const SectionPiece &P = Pieces[I];
-  StringRef S = toStringRef(this->Data.slice(P.InputOff, End - P.InputOff));
-  return {S, Hashes[I]};
-}
-
 // Split non-SHF_STRINGS section. Such section is a sequence of
 // fixed size records.
 template <class ELFT>
diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h
index 187a9853860a..617ad7b4ba40 100644
--- a/lld/ELF/InputSection.h
+++ b/lld/ELF/InputSection.h
@@ -194,7 +194,21 @@ public:
   // Splittable sections are handled as a sequence of data
   // rather than a single large blob of data.
   std::vector<SectionPiece> Pieces;
-  llvm::CachedHashStringRef getData(size_t Idx) const;
+
+  // Returns I'th piece's data. This function is very hot when
+  // string merging is enabled, so we want to inline.
+  LLVM_ATTRIBUTE_ALWAYS_INLINE
+  llvm::CachedHashStringRef getData(size_t I) const {
+    size_t Begin = Pieces[I].InputOff;
+    size_t End;
+    if (Pieces.size() - 1 == I)
+      End = this->Data.size();
+    else
+      End = Pieces[I + 1].InputOff;
+
+    StringRef S = {(const char *)(this->Data.data() + Begin), End - Begin};
+    return {S, Hashes[I]};
+  }
 
   // Returns the SectionPiece at a given input section offset.
   SectionPiece *getSectionPiece(uintX_t Offset);