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
15namespace 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.
20void 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 *s) {
53 Defined *b = s->getDefined();
54 if (!b)
55 return;
56 if (auto *sym = dyn_cast<DefinedRegular>(Val: b)) {
57 enqueue(sym->getChunk());
58 } else if (auto *sym = dyn_cast<DefinedImportData>(Val: b)) {
59 addImportFile(sym->file);
60 } else if (auto *sym = dyn_cast<DefinedImportThunk>(Val: b)) {
61 addImportFile(sym->wrappedSym->file);
62 sym->getChunk()->live = true;
63 }
64 };
65
66 // Add GC root chunks.
67 for (Symbol *b : ctx.config.gcroot)
68 addSym(b);
69
70 while (!worklist.empty()) {
71 SectionChunk *sc = worklist.pop_back_val();
72 assert(sc->live && "We mark as live when pushing onto the worklist!");
73
74 // Mark all symbols listed in the relocation table for this section.
75 for (Symbol *b : sc->symbols())
76 if (b)
77 addSym(b);
78
79 // Mark associative sections if any.
80 for (SectionChunk &c : sc->children())
81 enqueue(&c);
82
83 // Mark EC entry thunks.
84 if (Defined *entryThunk = sc->getEntryThunk())
85 addSym(entryThunk);
86 }
87}
88}
89