1 | //===- MarkLive.cpp -------------------------------------------------------===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "COFFLinkerContext.h" |
10 | #include "Chunks.h" |
11 | #include "Symbols.h" |
12 | #include "lld/Common/Timer.h" |
13 | #include "llvm/Support/TimeProfiler.h" |
14 | |
15 | namespace lld::coff { |
16 | |
17 | // Set live bit on for each reachable chunk. Unmarked (unreachable) |
18 | // COMDAT chunks will be ignored by Writer, so they will be excluded |
19 | // from the final output. |
20 | void markLive(COFFLinkerContext &ctx) { |
21 | llvm::TimeTraceScope timeScope("Mark live"); |
22 | ScopedTimer t(ctx.gcTimer); |
23 | |
24 | // We build up a worklist of sections which have been marked as live. We only |
25 | // push into the worklist when we discover an unmarked section, and we mark |
26 | // as we push, so sections never appear twice in the list. |
27 | SmallVector<SectionChunk *, 256> worklist; |
28 | |
29 | // COMDAT section chunks are dead by default. Add non-COMDAT chunks. Do not |
30 | // traverse DWARF sections. They are live, but they should not keep other |
31 | // sections alive. |
32 | for (Chunk *c : ctx.driver.getChunks()) |
33 | if (auto *sc = dyn_cast<SectionChunk>(Val: c)) |
34 | if (sc->live && !sc->isDWARF()) |
35 | worklist.push_back(Elt: sc); |
36 | |
37 | auto enqueue = [&](SectionChunk *c) { |
38 | if (c->live) |
39 | return; |
40 | c->live = true; |
41 | worklist.push_back(Elt: c); |
42 | }; |
43 | |
44 | std::function<void(Symbol *)> addSym; |
45 | |
46 | auto addImportFile = [&](ImportFile *file) { |
47 | file->live = true; |
48 | if (file->impchkThunk && file->impchkThunk->exitThunk) |
49 | addSym(file->impchkThunk->exitThunk); |
50 | }; |
51 | |
52 | addSym = [&](Symbol *b) { |
53 | if (auto *sym = dyn_cast<DefinedRegular>(Val: b)) { |
54 | enqueue(sym->getChunk()); |
55 | } else if (auto *sym = dyn_cast<DefinedImportData>(Val: b)) { |
56 | addImportFile(sym->file); |
57 | } else if (auto *sym = dyn_cast<DefinedImportThunk>(Val: b)) { |
58 | addImportFile(sym->wrappedSym->file); |
59 | sym->getChunk()->live = true; |
60 | } |
61 | }; |
62 | |
63 | // Add GC root chunks. |
64 | for (Symbol *b : ctx.config.gcroot) |
65 | addSym(b); |
66 | |
67 | while (!worklist.empty()) { |
68 | SectionChunk *sc = worklist.pop_back_val(); |
69 | assert(sc->live && "We mark as live when pushing onto the worklist!"); |
70 | |
71 | // Mark all symbols listed in the relocation table for this section. |
72 | for (Symbol *b : sc->symbols()) |
73 | if (b) |
74 | addSym(b); |
75 | |
76 | // Mark associative sections if any. |
77 | for (SectionChunk &c : sc->children()) |
78 | enqueue(&c); |
79 | |
80 | // Mark EC entry thunks. |
81 | if (Defined *entryThunk = sc->getEntryThunk()) |
82 | addSym(entryThunk); |
83 | } |
84 | } |
85 | } |
86 |