Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/wasm/MarkLive.cpp
Line
Count
Source (jump to first uncovered line)
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
// This file implements --gc-sections, which is a feature to remove unused
10
// chunks from the output. Unused chunks are those that are not reachable from
11
// known root symbols or chunks. This feature is implemented as a mark-sweep
12
// garbage collector.
13
//
14
// Here's how it works. Each InputChunk has a "Live" bit. The bit is off by
15
// default. Starting with the GC-roots, visit all reachable chunks and set their
16
// Live bits. The Writer will then ignore chunks whose Live bits are off, so
17
// that such chunk are not appear in the output.
18
//
19
//===----------------------------------------------------------------------===//
20
21
#include "MarkLive.h"
22
#include "Config.h"
23
#include "InputChunks.h"
24
#include "InputEvent.h"
25
#include "InputGlobal.h"
26
#include "SymbolTable.h"
27
#include "Symbols.h"
28
29
#define DEBUG_TYPE "lld"
30
31
using namespace llvm;
32
using namespace llvm::wasm;
33
34
193
void lld::wasm::markLive() {
35
193
  if (!config->gcSections)
36
52
    return;
37
141
38
141
  LLVM_DEBUG(dbgs() << "markLive\n");
39
141
  SmallVector<InputChunk *, 256> q;
40
141
41
534
  std::function<void(Symbol*)> enqueue = [&](Symbol *sym) {
42
534
    if (!sym || sym->isLive())
43
206
      return;
44
328
    LLVM_DEBUG(dbgs() << "markLive: " << sym->getName() << "\n");
45
328
    sym->markLive();
46
328
    if (InputChunk *chunk = sym->getChunk())
47
297
      q.push_back(chunk);
48
328
49
328
    // The ctor functions are all referenced by the synthetic callCtors
50
328
    // function.  However, this function does not contain relocations so we
51
328
    // have to manually mark the ctors as live if callCtors itself is live.
52
328
    if (sym == WasmSym::callCtors) {
53
9
      if (config->passiveSegments)
54
0
        enqueue(WasmSym::initMemory);
55
9
      if (config->isPic)
56
4
        enqueue(WasmSym::applyRelocs);
57
12
      for (const ObjFile *obj : symtab->objectFiles) {
58
12
        const WasmLinkingData &l = obj->getWasmObj()->linkingData();
59
17
        for (const WasmInitFunc &f : l.InitFunctions) {
60
17
          auto* initSym = obj->getFunctionSymbol(f.Symbol);
61
17
          if (!initSym->isDiscarded())
62
16
            enqueue(initSym);
63
17
        }
64
12
      }
65
9
    }
66
328
  };
67
141
68
141
  // Add GC root symbols.
69
141
  if (!config->entry.empty())
70
105
    enqueue(symtab->find(config->entry));
71
141
72
141
  // We need to preserve any exported symbol
73
141
  for (Symbol *sym : symtab->getSymbols())
74
809
    if (sym->isExported())
75
205
      enqueue(sym);
76
141
77
141
  // For relocatable output, we need to preserve all the ctor functions
78
141
  if (config->relocatable) {
79
0
    for (const ObjFile *obj : symtab->objectFiles) {
80
0
      const WasmLinkingData &l = obj->getWasmObj()->linkingData();
81
0
      for (const WasmInitFunc &f : l.InitFunctions)
82
0
        enqueue(obj->getFunctionSymbol(f.Symbol));
83
0
    }
84
0
  }
85
141
86
141
  if (config->isPic)
87
4
    enqueue(WasmSym::callCtors);
88
141
89
141
  // Follow relocations to mark all reachable chunks.
90
438
  while (!q.empty()) {
91
297
    InputChunk *c = q.pop_back_val();
92
297
93
297
    for (const WasmRelocation reloc : c->getRelocations()) {
94
218
      if (reloc.Type == R_WASM_TYPE_INDEX_LEB)
95
15
        continue;
96
203
      Symbol *sym = c->file->getSymbol(reloc.Index);
97
203
98
203
      // If the function has been assigned the special index zero in the table,
99
203
      // the relocation doesn't pull in the function body, since the function
100
203
      // won't actually go in the table (the runtime will trap attempts to call
101
203
      // that index, since we don't use it).  A function with a table index of
102
203
      // zero is only reachable via "call", not via "call_indirect".  The stub
103
203
      // functions used for weak-undefined symbols have this behaviour (compare
104
203
      // equal to null pointer, only reachable via direct call).
105
203
      if (reloc.Type == R_WASM_TABLE_INDEX_SLEB ||
106
203
          
reloc.Type == R_WASM_TABLE_INDEX_I32179
) {
107
44
        auto *funcSym = cast<FunctionSymbol>(sym);
108
44
        if (funcSym->hasTableIndex() && 
funcSym->getTableIndex() == 03
)
109
3
          continue;
110
200
      }
111
200
112
200
      enqueue(sym);
113
200
    }
114
297
  }
115
141
116
141
  // Report garbage-collected sections.
117
141
  if (config->printGcSections) {
118
3
    for (const ObjFile *obj : symtab->objectFiles) {
119
3
      for (InputChunk *c : obj->functions)
120
5
        if (!c->live)
121
1
          message("removing unused section " + toString(c));
122
3
      for (InputChunk *c : obj->segments)
123
2
        if (!c->live)
124
1
          message("removing unused section " + toString(c));
125
3
      for (InputGlobal *g : obj->globals)
126
2
        if (!g->live)
127
1
          message("removing unused section " + toString(g));
128
3
      for (InputEvent *e : obj->events)
129
0
        if (!e->live)
130
0
          message("removing unused section " + toString(e));
131
3
    }
132
2
    for (InputChunk *c : symtab->syntheticFunctions)
133
6
      if (!c->live)
134
3
        message("removing unused section " + toString(c));
135
2
    for (InputGlobal *g : symtab->syntheticGlobals)
136
2
      if (!g->live)
137
0
        message("removing unused section " + toString(g));
138
2
  }
139
141
}