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.

llvm-svn: 287314
This commit is contained in:
Rui Ueyama 2016-11-18 05:05:43 +00:00
parent 37bf5c6a3f
commit 77f2a87575
5 changed files with 53 additions and 65 deletions

View File

@ -677,12 +677,14 @@ MergeInputSection<ELFT>::splitStrings(ArrayRef<uint8_t> Data, size_t EntSize) {
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(uintX_t Offset) const {
// 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<ELFT>::getOffset(uintX_t Offset) const {
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>;

View File

@ -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;
};

View File

@ -772,42 +772,49 @@ void MergeOutputSection<ELFT>::addSection(InputSectionData *C) {
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>

View File

@ -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) {

View File

@ -960,11 +960,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
{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() {