Skip to content

Commit e6c2429

Browse files
committedMar 25, 2019
Use a class instead of lambda-based callbacks to organize garbage collector.
lld's mark-sweep garbage collector was written in the visitor pattern. There are functions that traverses a given graph, and the functions calls callback functions to dispatch according to node type. The code was originaly pretty simple, and lambdas worked pretty well. However, as we add more features to the garbage collector, that became more like a callback hell. We now have a callback function that wraps another callback function, for example. It is not easy to follow the flow of the control. This patch rewrites it as a regular class. What was once a lambda is now a regular class member function. I think this change fixes the readability issue. No functionality change intended. Differential Revision: https://reviews.llvm.org/D59800 llvm-svn: 356966
1 parent ea40d5b commit e6c2429

File tree

1 file changed

+120
-117
lines changed

1 file changed

+120
-117
lines changed
 

‎lld/ELF/MarkLive.cpp

+120-117
Original file line numberDiff line numberDiff line change
@@ -41,66 +41,72 @@ using namespace llvm::support::endian;
4141
using namespace lld;
4242
using namespace lld::elf;
4343

44+
namespace {
45+
template <class ELFT> class MarkLive {
46+
public:
47+
void run();
48+
49+
private:
50+
void enqueue(InputSectionBase *Sec, uint64_t Offset);
51+
void markSymbol(Symbol *Sym);
52+
53+
template <class RelTy>
54+
void resolveReloc(InputSectionBase &Sec, RelTy &Rel, bool IsLSDA);
55+
56+
template <class RelTy>
57+
void scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels);
58+
59+
// A list of sections to visit.
60+
SmallVector<InputSection *, 256> Queue;
61+
62+
// There are normally few input sections whose names are valid C
63+
// identifiers, so we just store a std::vector instead of a multimap.
64+
DenseMap<StringRef, std::vector<InputSectionBase *>> CNamedSections;
65+
};
66+
} // namespace
67+
4468
template <class ELFT>
45-
static typename ELFT::uint getAddend(InputSectionBase &Sec,
46-
const typename ELFT::Rel &Rel) {
69+
static uint64_t getAddend(InputSectionBase &Sec,
70+
const typename ELFT::Rel &Rel) {
4771
return Target->getImplicitAddend(Sec.data().begin() + Rel.r_offset,
4872
Rel.getType(Config->IsMips64EL));
4973
}
5074

5175
template <class ELFT>
52-
static typename ELFT::uint getAddend(InputSectionBase &Sec,
53-
const typename ELFT::Rela &Rel) {
76+
static uint64_t getAddend(InputSectionBase &Sec,
77+
const typename ELFT::Rela &Rel) {
5478
return Rel.r_addend;
5579
}
5680

57-
// There are normally few input sections whose names are valid C
58-
// identifiers, so we just store a std::vector instead of a multimap.
59-
static DenseMap<StringRef, std::vector<InputSectionBase *>> CNamedSections;
60-
61-
template <class ELFT, class RelT>
62-
static void
63-
resolveReloc(InputSectionBase &Sec, RelT &Rel,
64-
llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
65-
Symbol &B = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
81+
template <class ELFT>
82+
template <class RelTy>
83+
void MarkLive<ELFT>::resolveReloc(InputSectionBase &Sec, RelTy &Rel,
84+
bool IsLSDA) {
85+
Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
6686

6787
// If a symbol is referenced in a live section, it is used.
68-
B.Used = true;
69-
if (auto *SS = dyn_cast<SharedSymbol>(&B))
70-
if (!SS->isWeak())
71-
SS->getFile<ELFT>().IsNeeded = true;
88+
Sym.Used = true;
7289

73-
if (auto *D = dyn_cast<Defined>(&B)) {
90+
if (auto *D = dyn_cast<Defined>(&Sym)) {
7491
auto *RelSec = dyn_cast_or_null<InputSectionBase>(D->Section);
7592
if (!RelSec)
7693
return;
94+
7795
uint64_t Offset = D->Value;
7896
if (D->isSection())
7997
Offset += getAddend<ELFT>(Sec, Rel);
80-
Fn(RelSec, Offset);
98+
99+
if (!IsLSDA || !(RelSec->Flags & SHF_EXECINSTR))
100+
enqueue(RelSec, Offset);
81101
return;
82102
}
83103

84-
if (!B.isDefined())
85-
for (InputSectionBase *Sec : CNamedSections.lookup(B.getName()))
86-
Fn(Sec, 0);
87-
}
88-
89-
// Calls Fn for each section that Sec refers to via relocations.
90-
template <class ELFT>
91-
static void
92-
forEachSuccessor(InputSection &Sec,
93-
llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
94-
if (Sec.AreRelocsRela) {
95-
for (const typename ELFT::Rela &Rel : Sec.template relas<ELFT>())
96-
resolveReloc<ELFT>(Sec, Rel, Fn);
97-
} else {
98-
for (const typename ELFT::Rel &Rel : Sec.template rels<ELFT>())
99-
resolveReloc<ELFT>(Sec, Rel, Fn);
100-
}
104+
if (auto *SS = dyn_cast<SharedSymbol>(&Sym))
105+
if (!SS->isWeak())
106+
SS->getFile<ELFT>().IsNeeded = true;
101107

102-
for (InputSectionBase *IS : Sec.DependentSections)
103-
Fn(IS, 0);
108+
for (InputSectionBase *Sec : CNamedSections.lookup(Sym.getName()))
109+
enqueue(Sec, 0);
104110
}
105111

106112
// The .eh_frame section is an unfortunate special case.
@@ -117,54 +123,33 @@ forEachSuccessor(InputSection &Sec,
117123
// A possible improvement would be to fully process .eh_frame in the middle of
118124
// the gc pass. With that we would be able to also gc some sections holding
119125
// LSDAs and personality functions if we found that they were unused.
120-
template <class ELFT, class RelTy>
121-
static void
122-
scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels,
123-
llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
124-
const endianness E = ELFT::TargetEndianness;
125-
126-
for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) {
126+
template <class ELFT>
127+
template <class RelTy>
128+
void MarkLive<ELFT>::scanEhFrameSection(EhInputSection &EH,
129+
ArrayRef<RelTy> Rels) {
130+
for (size_t I = 0, End = EH.Pieces.size(); I < End; ++I) {
127131
EhSectionPiece &Piece = EH.Pieces[I];
128-
unsigned FirstRelI = Piece.FirstRelocation;
132+
size_t FirstRelI = Piece.FirstRelocation;
129133
if (FirstRelI == (unsigned)-1)
130134
continue;
131-
if (read32<E>(Piece.data().data() + 4) == 0) {
135+
136+
if (read32<ELFT::TargetEndianness>(Piece.data().data() + 4) == 0) {
132137
// This is a CIE, we only need to worry about the first relocation. It is
133138
// known to point to the personality function.
134-
resolveReloc<ELFT>(EH, Rels[FirstRelI], Fn);
139+
resolveReloc(EH, Rels[FirstRelI], false);
135140
continue;
136141
}
142+
137143
// This is a FDE. The relocations point to the described function or to
138144
// a LSDA. We only need to keep the LSDA alive, so ignore anything that
139145
// points to executable sections.
140-
typename ELFT::uint PieceEnd = Piece.InputOff + Piece.Size;
141-
for (unsigned I2 = FirstRelI, N2 = Rels.size(); I2 < N2; ++I2) {
142-
const RelTy &Rel = Rels[I2];
143-
if (Rel.r_offset >= PieceEnd)
144-
break;
145-
resolveReloc<ELFT>(EH, Rels[I2],
146-
[&](InputSectionBase *Sec, uint64_t Offset) {
147-
if (Sec && Sec != &InputSection::Discarded &&
148-
!(Sec->Flags & SHF_EXECINSTR))
149-
Fn(Sec, 0);
150-
});
151-
}
146+
uint64_t PieceEnd = Piece.InputOff + Piece.Size;
147+
for (size_t J = FirstRelI, End2 = Rels.size(); J < End2; ++J)
148+
if (Rels[J].r_offset < PieceEnd)
149+
resolveReloc(EH, Rels[J], true);
152150
}
153151
}
154152

155-
template <class ELFT>
156-
static void
157-
scanEhFrameSection(EhInputSection &EH,
158-
llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) {
159-
if (!EH.NumRelocations)
160-
return;
161-
162-
if (EH.AreRelocsRela)
163-
scanEhFrameSection<ELFT>(EH, EH.template relas<ELFT>(), Fn);
164-
else
165-
scanEhFrameSection<ELFT>(EH, EH.template rels<ELFT>(), Fn);
166-
}
167-
168153
// Some sections are used directly by the loader, so they should never be
169154
// garbage-collected. This function returns true if a given section is such
170155
// section.
@@ -183,57 +168,54 @@ static bool isReserved(InputSectionBase *Sec) {
183168
}
184169
}
185170

186-
// This is the main function of the garbage collector.
187-
// Starting from GC-root sections, this function visits all reachable
188-
// sections to set their "Live" bits.
189-
template <class ELFT> static void doGcSections() {
190-
SmallVector<InputSection *, 256> Q;
191-
CNamedSections.clear();
192-
193-
auto Enqueue = [&](InputSectionBase *Sec, uint64_t Offset) {
194-
// Skip over discarded sections. This in theory shouldn't happen, because
195-
// the ELF spec doesn't allow a relocation to point to a deduplicated
196-
// COMDAT section directly. Unfortunately this happens in practice (e.g.
197-
// .eh_frame) so we need to add a check.
198-
if (Sec == &InputSection::Discarded)
199-
return;
200-
171+
template <class ELFT>
172+
void MarkLive<ELFT>::enqueue(InputSectionBase *Sec, uint64_t Offset) {
173+
// Skip over discarded sections. This in theory shouldn't happen, because
174+
// the ELF spec doesn't allow a relocation to point to a deduplicated
175+
// COMDAT section directly. Unfortunately this happens in practice (e.g.
176+
// .eh_frame) so we need to add a check.
177+
if (Sec == &InputSection::Discarded)
178+
return;
201179

202-
// Usually, a whole section is marked as live or dead, but in mergeable
203-
// (splittable) sections, each piece of data has independent liveness bit.
204-
// So we explicitly tell it which offset is in use.
205-
if (auto *MS = dyn_cast<MergeInputSection>(Sec))
206-
MS->getSectionPiece(Offset)->Live = true;
180+
// Usually, a whole section is marked as live or dead, but in mergeable
181+
// (splittable) sections, each piece of data has independent liveness bit.
182+
// So we explicitly tell it which offset is in use.
183+
if (auto *MS = dyn_cast<MergeInputSection>(Sec))
184+
MS->getSectionPiece(Offset)->Live = true;
207185

208-
if (Sec->Live)
209-
return;
210-
Sec->Live = true;
186+
if (Sec->Live)
187+
return;
188+
Sec->Live = true;
211189

212-
// Add input section to the queue.
213-
if (InputSection *S = dyn_cast<InputSection>(Sec))
214-
Q.push_back(S);
215-
};
190+
// Add input section to the queue.
191+
if (InputSection *S = dyn_cast<InputSection>(Sec))
192+
Queue.push_back(S);
193+
}
216194

217-
auto MarkSymbol = [&](Symbol *Sym) {
218-
if (auto *D = dyn_cast_or_null<Defined>(Sym))
219-
if (auto *IS = dyn_cast_or_null<InputSectionBase>(D->Section))
220-
Enqueue(IS, D->Value);
221-
};
195+
template <class ELFT> void MarkLive<ELFT>::markSymbol(Symbol *Sym) {
196+
if (auto *D = dyn_cast_or_null<Defined>(Sym))
197+
if (auto *IS = dyn_cast_or_null<InputSectionBase>(D->Section))
198+
enqueue(IS, D->Value);
199+
}
222200

201+
// This is the main function of the garbage collector.
202+
// Starting from GC-root sections, this function visits all reachable
203+
// sections to set their "Live" bits.
204+
template <class ELFT> void MarkLive<ELFT>::run() {
223205
// Add GC root symbols.
224-
MarkSymbol(Symtab->find(Config->Entry));
225-
MarkSymbol(Symtab->find(Config->Init));
226-
MarkSymbol(Symtab->find(Config->Fini));
206+
markSymbol(Symtab->find(Config->Entry));
207+
markSymbol(Symtab->find(Config->Init));
208+
markSymbol(Symtab->find(Config->Fini));
227209
for (StringRef S : Config->Undefined)
228-
MarkSymbol(Symtab->find(S));
210+
markSymbol(Symtab->find(S));
229211
for (StringRef S : Script->ReferencedSymbols)
230-
MarkSymbol(Symtab->find(S));
212+
markSymbol(Symtab->find(S));
231213

232214
// Preserve externally-visible symbols if the symbols defined by this
233215
// file can interrupt other ELF file's symbols at runtime.
234216
for (Symbol *S : Symtab->getSymbols())
235217
if (S->includeInDynsym())
236-
MarkSymbol(S);
218+
markSymbol(S);
237219

238220
// Preserve special sections and those which are specified in linker
239221
// script KEEP command.
@@ -244,31 +226,49 @@ template <class ELFT> static void doGcSections() {
244226
// referenced by .eh_frame sections, so we scan them for that here.
245227
if (auto *EH = dyn_cast<EhInputSection>(Sec)) {
246228
EH->Live = true;
247-
scanEhFrameSection<ELFT>(*EH, Enqueue);
229+
if (!EH->NumRelocations)
230+
continue;
231+
232+
if (EH->AreRelocsRela)
233+
scanEhFrameSection(*EH, EH->template relas<ELFT>());
234+
else
235+
scanEhFrameSection(*EH, EH->template rels<ELFT>());
248236
}
249237

250238
if (Sec->Flags & SHF_LINK_ORDER)
251239
continue;
252240

253241
if (isReserved(Sec) || Script->shouldKeep(Sec)) {
254-
Enqueue(Sec, 0);
242+
enqueue(Sec, 0);
255243
} else if (isValidCIdentifier(Sec->Name)) {
256244
CNamedSections[Saver.save("__start_" + Sec->Name)].push_back(Sec);
257245
CNamedSections[Saver.save("__stop_" + Sec->Name)].push_back(Sec);
258246
}
259247
}
260248

261249
// Mark all reachable sections.
262-
while (!Q.empty())
263-
forEachSuccessor<ELFT>(*Q.pop_back_val(), Enqueue);
250+
while (!Queue.empty()) {
251+
InputSectionBase &Sec = *Queue.pop_back_val();
252+
253+
if (Sec.AreRelocsRela) {
254+
for (const typename ELFT::Rela &Rel : Sec.template relas<ELFT>())
255+
resolveReloc(Sec, Rel, false);
256+
} else {
257+
for (const typename ELFT::Rel &Rel : Sec.template rels<ELFT>())
258+
resolveReloc(Sec, Rel, false);
259+
}
260+
261+
for (InputSectionBase *IS : Sec.DependentSections)
262+
enqueue(IS, 0);
263+
}
264264
}
265265

266266
// Before calling this function, Live bits are off for all
267267
// input sections. This function make some or all of them on
268268
// so that they are emitted to the output file.
269269
template <class ELFT> void elf::markLive() {
270+
// If -gc-sections is not given, no sections are removed.
270271
if (!Config->GcSections) {
271-
// If -gc-sections is missing, no sections are removed.
272272
for (InputSectionBase *Sec : InputSections)
273273
Sec->Live = true;
274274

@@ -280,6 +280,8 @@ template <class ELFT> void elf::markLive() {
280280
return;
281281
}
282282

283+
// Otheriwse, do mark-sweep GC.
284+
//
283285
// The -gc-sections option works only for SHF_ALLOC sections
284286
// (sections that are memory-mapped at runtime). So we can
285287
// unconditionally make non-SHF_ALLOC sections alive except
@@ -303,12 +305,13 @@ template <class ELFT> void elf::markLive() {
303305
bool IsAlloc = (Sec->Flags & SHF_ALLOC);
304306
bool IsLinkOrder = (Sec->Flags & SHF_LINK_ORDER);
305307
bool IsRel = (Sec->Type == SHT_REL || Sec->Type == SHT_RELA);
308+
306309
if (!IsAlloc && !IsLinkOrder && !IsRel)
307310
Sec->Live = true;
308311
}
309312

310313
// Follow the graph to mark all live sections.
311-
doGcSections<ELFT>();
314+
MarkLive<ELFT>().run();
312315

313316
// Report garbage-collected sections.
314317
if (Config->PrintGcSections)

0 commit comments

Comments
 (0)
Please sign in to comment.