[lld] r287314 - Simplify MergeOutputSection.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 17 21:05:43 PST 2016


Author: ruiu
Date: Thu Nov 17 23:05:43 2016
New Revision: 287314

URL: http://llvm.org/viewvc/llvm-project?rev=287314&view=rev
Log:
Simplify MergeOutputSection.

MergeOutputSection class was a bit hard to use because it provdes
a series of finalize functions that have to be called in a right way
at a right time. It also intereacted with MergeInputSection, and the
logic was somewhat entangled between the two classes.

This patch simplifies it by providing only one finalize function.
Now, all you have to do is to call MergeOutputSection::finalize
when you have added all sections to the output section. Then, it
internally merges strings and initliazes StringPiece objects.
I think this is much easier to understand.

This patch also adds comments.

Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/InputSection.h
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=287314&r1=287313&r2=287314&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Thu Nov 17 23:05:43 2016
@@ -677,12 +677,14 @@ MergeInputSection<ELFT>::splitStrings(Ar
   return V;
 }
 
+// Returns I'th piece's data.
 template <class ELFT>
-ArrayRef<uint8_t> MergeInputSection<ELFT>::getData(
-    std::vector<SectionPiece>::const_iterator I) const {
-  auto Next = I + 1;
-  size_t End = Next == Pieces.end() ? this->Data.size() : Next->InputOff;
-  return this->Data.slice(I->InputOff, End - I->InputOff);
+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
@@ -766,6 +768,14 @@ MergeInputSection<ELFT>::getSectionPiece
 // it is not just an addition to a base output offset.
 template <class ELFT>
 typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const {
+  // Initialize OffsetMap lazily.
+  std::call_once(InitOffsetMap, [&] {
+    OffsetMap.reserve(Pieces.size());
+    for (const SectionPiece &Piece : Pieces)
+      OffsetMap[Piece.InputOff] = Piece.OutputOff;
+  });
+
+  // Find a string starting at a given offset.
   auto It = OffsetMap.find(Offset);
   if (It != OffsetMap.end())
     return It->second;
@@ -783,29 +793,6 @@ typename ELFT::uint MergeInputSection<EL
   return Piece.OutputOff + Addend;
 }
 
-// Create a map from input offsets to output offsets for all section pieces.
-// It is called after finalize().
-template <class ELFT> void MergeInputSection<ELFT>::finalizePieces() {
-  OffsetMap.reserve(this->Pieces.size());
-  auto HashI = Hashes.begin();
-  for (auto I = Pieces.begin(), E = Pieces.end(); I != E; ++I) {
-    uint32_t Hash = *HashI;
-    ++HashI;
-    SectionPiece &Piece = *I;
-    if (!Piece.Live)
-      continue;
-    if (Piece.OutputOff == -1) {
-      // Offsets of tail-merged strings are computed lazily.
-      auto *OutSec = static_cast<MergeOutputSection<ELFT> *>(this->OutSec);
-      ArrayRef<uint8_t> D = this->getData(I);
-      StringRef S((const char *)D.data(), D.size());
-      CachedHashStringRef V(S, Hash);
-      Piece.OutputOff = OutSec->getOffset(V);
-    }
-    OffsetMap[Piece.InputOff] = Piece.OutputOff;
-  }
-}
-
 template class elf::InputSectionBase<ELF32LE>;
 template class elf::InputSectionBase<ELF32BE>;
 template class elf::InputSectionBase<ELF64LE>;

Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=287314&r1=287313&r2=287314&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Thu Nov 17 23:05:43 2016
@@ -17,6 +17,7 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/TinyPtrVector.h"
 #include "llvm/Object/ELF.h"
+#include <mutex>
 
 namespace lld {
 namespace elf {
@@ -187,13 +188,10 @@ public:
   // in the output section.
   uintX_t getOffset(uintX_t Offset) const;
 
-  void finalizePieces();
-
   // Splittable sections are handled as a sequence of data
   // rather than a single large blob of data.
   std::vector<SectionPiece> Pieces;
-  ArrayRef<uint8_t> getData(std::vector<SectionPiece>::const_iterator I) const;
-  std::vector<uint32_t> Hashes;
+  llvm::CachedHashStringRef getData(size_t Idx) const;
 
   // Returns the SectionPiece at a given input section offset.
   SectionPiece *getSectionPiece(uintX_t Offset);
@@ -203,7 +201,11 @@ private:
   std::vector<SectionPiece> splitStrings(ArrayRef<uint8_t> A, size_t Size);
   std::vector<SectionPiece> splitNonStrings(ArrayRef<uint8_t> A, size_t Size);
 
-  llvm::DenseMap<uintX_t, uintX_t> OffsetMap;
+  std::vector<uint32_t> Hashes;
+
+  mutable llvm::DenseMap<uintX_t, uintX_t> OffsetMap;
+  mutable std::once_flag InitOffsetMap;
+
   llvm::DenseSet<uintX_t> LiveOffsets;
 };
 

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=287314&r1=287313&r2=287314&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Thu Nov 17 23:05:43 2016
@@ -772,42 +772,49 @@ void MergeOutputSection<ELFT>::addSectio
   this->updateAlignment(Sec->Alignment);
   this->Entsize = Sec->Entsize;
   Sections.push_back(Sec);
-
-  auto HashI = Sec->Hashes.begin();
-  for (auto I = Sec->Pieces.begin(), E = Sec->Pieces.end(); I != E; ++I) {
-    SectionPiece &Piece = *I;
-    uint32_t Hash = *HashI;
-    ++HashI;
-    if (!Piece.Live)
-      continue;
-    StringRef Data = toStringRef(Sec->getData(I));
-    CachedHashStringRef V(Data, Hash);
-    uintX_t OutputOffset = Builder.add(V);
-    if (!shouldTailMerge())
-      Piece.OutputOff = OutputOffset;
-  }
-}
-
-template <class ELFT>
-unsigned MergeOutputSection<ELFT>::getOffset(CachedHashStringRef Val) {
-  return Builder.getOffset(Val);
 }
 
 template <class ELFT> bool MergeOutputSection<ELFT>::shouldTailMerge() const {
-  return Config->Optimize >= 2 && this->Flags & SHF_STRINGS;
+  return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
 }
 
 template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
+  // Add all string pieces to the string table builder to create section
+  // contents. If we are not tail-optimizing, offsets of strings are fixed
+  // when they are added to the builder (string table builder contains a
+  // hash table from strings to offsets), so we record them if available.
+  for (MergeInputSection<ELFT> *Sec : Sections) {
+    for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) {
+      if (!Sec->Pieces[I].Live)
+        continue;
+      uint32_t OutputOffset = Builder.add(Sec->getData(I));
+
+      // Save the offset in the generated string table.
+      if (!shouldTailMerge())
+        Sec->Pieces[I].OutputOff = OutputOffset;
+    }
+  }
+
+  // Fix the string table content. After this, the contents
+  // will never change.
   if (shouldTailMerge())
     Builder.finalize();
   else
     Builder.finalizeInOrder();
   this->Size = Builder.getSize();
-}
 
-template <class ELFT> void MergeOutputSection<ELFT>::finalizePieces() {
-  for (MergeInputSection<ELFT> *Sec : Sections)
-    Sec->finalizePieces();
+  // finalize() fixed tail-optimized strings, so we can now get
+  // offsets of strings. Get an offset for each string and save it
+  // to a corresponding StringPiece for easy access.
+  if (shouldTailMerge()) {
+    for (MergeInputSection<ELFT> *Sec : Sections) {
+      for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) {
+        if (!Sec->Pieces[I].Live)
+          continue;
+        Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
+      }
+    }
+  }
 }
 
 template <class ELFT>

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=287314&r1=287313&r2=287314&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Thu Nov 17 23:05:43 2016
@@ -88,7 +88,6 @@ public:
   OutputSectionBase *FirstInPtLoad = nullptr;
 
   virtual void finalize() {}
-  virtual void finalizePieces() {}
   virtual void assignOffsets() {}
   virtual void writeTo(uint8_t *Buf) {}
   virtual ~OutputSectionBase() = default;
@@ -265,9 +264,7 @@ public:
                      uintX_t Alignment);
   void addSection(InputSectionData *S) override;
   void writeTo(uint8_t *Buf) override;
-  unsigned getOffset(llvm::CachedHashStringRef Val);
   void finalize() override;
-  void finalizePieces() override;
   bool shouldTailMerge() const;
   Kind getKind() const override { return Merge; }
   static bool classof(const OutputSectionBase *B) {

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=287314&r1=287313&r2=287314&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Nov 17 23:05:43 2016
@@ -960,11 +960,6 @@ template <class ELFT> void Writer<ELFT>:
       {In<ELFT>::SymTab, In<ELFT>::ShStrTab, In<ELFT>::StrTab,
        In<ELFT>::DynStrTab, In<ELFT>::Got, In<ELFT>::MipsGot, In<ELFT>::GotPlt,
        In<ELFT>::RelaDyn, In<ELFT>::RelaPlt, In<ELFT>::Dynamic});
-
-  // Now that all output offsets are fixed. Finalize mergeable sections
-  // to fix their maps from input offsets to output offsets.
-  for (OutputSectionBase *Sec : OutputSections)
-    Sec->finalizePieces();
 }
 
 template <class ELFT> bool Writer<ELFT>::needsGot() {




More information about the llvm-commits mailing list