Coverage Report

Created: 2019-01-18 03:29

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/wasm/SymbolTable.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- SymbolTable.cpp ----------------------------------------------------===//
2
//
3
//                             The LLVM Linker
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
10
#include "SymbolTable.h"
11
#include "Config.h"
12
#include "InputChunks.h"
13
#include "InputEvent.h"
14
#include "InputGlobal.h"
15
#include "WriterUtils.h"
16
#include "lld/Common/ErrorHandler.h"
17
#include "lld/Common/Memory.h"
18
#include "llvm/ADT/SetVector.h"
19
20
#define DEBUG_TYPE "lld"
21
22
using namespace llvm;
23
using namespace llvm::wasm;
24
using namespace llvm::object;
25
using namespace lld;
26
using namespace lld::wasm;
27
28
SymbolTable *lld::wasm::Symtab;
29
30
211
void SymbolTable::addFile(InputFile *File) {
31
211
  log("Processing: " + toString(File));
32
211
  File->parse();
33
211
34
211
  // LLVM bitcode file
35
211
  if (auto *F = dyn_cast<BitcodeFile>(File))
36
38
    BitcodeFiles.push_back(F);
37
173
  else if (auto *F = dyn_cast<ObjFile>(File))
38
158
    ObjectFiles.push_back(F);
39
211
}
40
41
// This function is where all the optimizations of link-time
42
// optimization happens. When LTO is in use, some input files are
43
// not in native object file format but in the LLVM bitcode format.
44
// This function compiles bitcode files into a few big native files
45
// using LLVM functions and replaces bitcode symbols with the results.
46
// Because all bitcode files that the program consists of are passed
47
// to the compiler at once, it can do whole-program optimization.
48
108
void SymbolTable::addCombinedLTOObject() {
49
108
  if (BitcodeFiles.empty())
50
83
    return;
51
25
52
25
  // Compile bitcode files and replace bitcode symbols.
53
25
  LTO.reset(new BitcodeCompiler);
54
25
  for (BitcodeFile *F : BitcodeFiles)
55
36
    LTO->add(*F);
56
25
57
42
  for (StringRef Filename : LTO->compile()) {
58
42
    auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"));
59
42
    Obj->parse();
60
42
    ObjectFiles.push_back(Obj);
61
42
  }
62
25
}
63
64
89
void SymbolTable::reportRemainingUndefines() {
65
704
  for (Symbol *Sym : SymVector) {
66
704
    if (!Sym->isUndefined() || 
Sym->isWeak()8
)
67
697
      continue;
68
7
    if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
69
3
      continue;
70
4
    if (!Sym->IsUsedInRegularObj)
71
0
      continue;
72
4
    error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym));
73
4
  }
74
89
}
75
76
178
Symbol *SymbolTable::find(StringRef Name) {
77
178
  return SymMap.lookup(CachedHashStringRef(Name));
78
178
}
79
80
1.24k
std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) {
81
1.24k
  bool Inserted = false;
82
1.24k
  Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
83
1.24k
  if (!Sym) {
84
1.10k
    Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
85
1.10k
    Sym->IsUsedInRegularObj = false;
86
1.10k
    SymVector.emplace_back(Sym);
87
1.10k
    Inserted = true;
88
1.10k
  }
89
1.24k
  if (!File || 
File->kind() == InputFile::ObjectKind643
)
90
1.19k
    Sym->IsUsedInRegularObj = true;
91
1.24k
  return {Sym, Inserted};
92
1.24k
}
93
94
static void reportTypeError(const Symbol *Existing, const InputFile *File,
95
1
                            llvm::wasm::WasmSymbolType Type) {
96
1
  error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
97
1
        toString(Existing->getWasmType()) + " in " +
98
1
        toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
99
1
        " in " + toString(File));
100
1
}
101
102
// Check the type of new symbol matches that of the symbol is replacing.
103
// For functions this can also involve verifying that the signatures match.
104
static void checkFunctionType(Symbol *Existing, const InputFile *File,
105
78
                              const WasmSignature *NewSig) {
106
78
  auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing);
107
78
  if (!ExistingFunction) {
108
1
    reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION);
109
1
    return;
110
1
  }
111
77
112
77
  if (!NewSig)
113
0
    return;
114
77
115
77
  const WasmSignature *OldSig = ExistingFunction->Signature;
116
77
  if (!OldSig) {
117
36
    ExistingFunction->Signature = NewSig;
118
36
    return;
119
36
  }
120
41
121
41
  if (*NewSig != *OldSig)
122
7
    warn("function signature mismatch: " + Existing->getName() +
123
7
         "\n>>> defined as " + toString(*OldSig) + " in " +
124
7
         toString(Existing->getFile()) + "\n>>> defined as " +
125
7
         toString(*NewSig) + " in " + toString(File));
126
41
}
127
128
static void checkGlobalType(const Symbol *Existing, const InputFile *File,
129
3
                            const WasmGlobalType *NewType) {
130
3
  if (!isa<GlobalSymbol>(Existing)) {
131
0
    reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
132
0
    return;
133
0
  }
134
3
135
3
  const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
136
3
  if (*NewType != *OldType) {
137
0
    error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
138
0
          toString(*OldType) + " in " + toString(Existing->getFile()) +
139
0
          "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
140
0
  }
141
3
}
142
143
static void checkEventType(const Symbol *Existing, const InputFile *File,
144
                           const WasmEventType *NewType,
145
1
                           const WasmSignature *NewSig) {
146
1
  auto ExistingEvent = dyn_cast<EventSymbol>(Existing);
147
1
  if (!isa<EventSymbol>(Existing)) {
148
0
    reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT);
149
0
    return;
150
0
  }
151
1
152
1
  const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType();
153
1
  const WasmSignature *OldSig = ExistingEvent->Signature;
154
1
  if (NewType->Attribute != OldType->Attribute)
155
0
    error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " +
156
0
          toString(*OldType) + " in " + toString(Existing->getFile()) +
157
0
          "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
158
1
  if (*NewSig != *OldSig)
159
0
    warn("Event signature mismatch: " + Existing->getName() +
160
0
         "\n>>> defined as " + toString(*OldSig) + " in " +
161
0
         toString(Existing->getFile()) + "\n>>> defined as " +
162
0
         toString(*NewSig) + " in " + toString(File));
163
1
}
164
165
10
static void checkDataType(const Symbol *Existing, const InputFile *File) {
166
10
  if (!isa<DataSymbol>(Existing))
167
0
    reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
168
10
}
169
170
DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
171
                                                   uint32_t Flags,
172
111
                                                   InputFunction *Function) {
173
111
  LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
174
111
  assert(!find(Name));
175
111
  SyntheticFunctions.emplace_back(Function);
176
111
  return replaceSymbol<DefinedFunction>(insert(Name, nullptr).first, Name,
177
111
                                        Flags, nullptr, Function);
178
111
}
179
180
DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
181
331
                                                 uint32_t Flags) {
182
331
  LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
183
331
  assert(!find(Name));
184
331
  return replaceSymbol<DefinedData>(insert(Name, nullptr).first, Name, Flags);
185
331
}
186
187
DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
188
110
                                               InputGlobal *Global) {
189
110
  LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
190
110
                    << "\n");
191
110
  assert(!find(Name));
192
110
  SyntheticGlobals.emplace_back(Global);
193
110
  return replaceSymbol<DefinedGlobal>(insert(Name, nullptr).first, Name, Flags,
194
110
                                      nullptr, Global);
195
110
}
196
197
static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
198
87
                          uint32_t NewFlags) {
199
87
  // If existing symbol is undefined, replace it.
200
87
  if (!Existing->isDefined()) {
201
79
    LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
202
79
                      << Existing->getName() << "\n");
203
79
    return true;
204
79
  }
205
8
206
8
  // Now we have two defined symbols. If the new one is weak, we can ignore it.
207
8
  if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
208
6
    LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
209
6
    return false;
210
6
  }
211
2
212
2
  // If the existing symbol is weak, we should replace it.
213
2
  if (Existing->isWeak()) {
214
0
    LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
215
0
    return true;
216
0
  }
217
2
218
2
  // Neither symbol is week. They conflict.
219
2
  error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
220
2
        toString(Existing->getFile()) + "\n>>> defined in " +
221
2
        toString(NewFile));
222
2
  return true;
223
2
}
224
225
Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
226
                                        InputFile *File,
227
455
                                        InputFunction *Function) {
228
455
  LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " ["
229
455
                    << (Function ? toString(Function->Signature) : "none")
230
455
                    << "]\n");
231
455
  Symbol *S;
232
455
  bool WasInserted;
233
455
  std::tie(S, WasInserted) = insert(Name, File);
234
455
235
455
  if (WasInserted || 
S->isLazy()96
) {
236
376
    replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
237
376
    return S;
238
376
  }
239
79
240
79
  if (Function)
241
67
    checkFunctionType(S, File, &Function->Signature);
242
79
243
79
  if (shouldReplace(S, File, Flags)) {
244
75
    // If the new defined function doesn't have signture (i.e. bitcode
245
75
    // functions) but the old symbols does then preserve the old signature
246
75
    const WasmSignature *OldSig = nullptr;
247
75
    if (auto* F = dyn_cast<FunctionSymbol>(S))
248
74
      OldSig = F->Signature;
249
75
    auto NewSym = replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
250
75
    if (!NewSym->Signature)
251
11
      NewSym->Signature = OldSig;
252
75
  }
253
79
  return S;
254
79
}
255
256
Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
257
                                    InputFile *File, InputSegment *Segment,
258
68
                                    uint32_t Address, uint32_t Size) {
259
68
  LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
260
68
                    << "\n");
261
68
  Symbol *S;
262
68
  bool WasInserted;
263
68
  std::tie(S, WasInserted) = insert(Name, File);
264
68
265
68
  if (WasInserted || 
S->isLazy()7
) {
266
61
    replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
267
61
    return S;
268
61
  }
269
7
270
7
  checkDataType(S, File);
271
7
272
7
  if (shouldReplace(S, File, Flags))
273
6
    replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
274
7
  return S;
275
7
}
276
277
Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
278
4
                                      InputFile *File, InputGlobal *Global) {
279
4
  LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
280
4
281
4
  Symbol *S;
282
4
  bool WasInserted;
283
4
  std::tie(S, WasInserted) = insert(Name, File);
284
4
285
4
  if (WasInserted || 
S->isLazy()0
) {
286
4
    replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
287
4
    return S;
288
4
  }
289
0
290
0
  checkGlobalType(S, File, &Global->getType());
291
0
292
0
  if (shouldReplace(S, File, Flags))
293
0
    replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
294
0
  return S;
295
0
}
296
297
Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags,
298
2
                                     InputFile *File, InputEvent *Event) {
299
2
  LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n");
300
2
301
2
  Symbol *S;
302
2
  bool WasInserted;
303
2
  std::tie(S, WasInserted) = insert(Name, File);
304
2
305
2
  if (WasInserted || 
S->isLazy()1
) {
306
1
    replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
307
1
    return S;
308
1
  }
309
1
310
1
  checkEventType(S, File, &Event->getType(), &Event->Signature);
311
1
312
1
  if (shouldReplace(S, File, Flags))
313
0
    replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
314
1
  return S;
315
1
}
316
317
Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
318
                                          InputFile *File,
319
89
                                          const WasmSignature *Sig) {
320
89
  LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name <<
321
89
             " [" << (Sig ? toString(*Sig) : "none") << "]\n");
322
89
323
89
  Symbol *S;
324
89
  bool WasInserted;
325
89
  std::tie(S, WasInserted) = insert(Name, File);
326
89
327
89
  if (WasInserted)
328
69
    replaceSymbol<UndefinedFunction>(S, Name, Flags, File, Sig);
329
20
  else if (auto *Lazy = dyn_cast<LazySymbol>(S))
330
9
    Lazy->fetch();
331
11
  else
332
11
    checkFunctionType(S, File, Sig);
333
89
334
89
  return S;
335
89
}
336
337
Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
338
13
                                      InputFile *File) {
339
13
  LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
340
13
341
13
  Symbol *S;
342
13
  bool WasInserted;
343
13
  std::tie(S, WasInserted) = insert(Name, File);
344
13
345
13
  if (WasInserted)
346
9
    replaceSymbol<UndefinedData>(S, Name, Flags, File);
347
4
  else if (auto *Lazy = dyn_cast<LazySymbol>(S))
348
0
    Lazy->fetch();
349
4
  else if (S->isDefined())
350
3
    checkDataType(S, File);
351
13
  return S;
352
13
}
353
354
Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags,
355
                                        InputFile *File,
356
15
                                        const WasmGlobalType *Type) {
357
15
  LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
358
15
359
15
  Symbol *S;
360
15
  bool WasInserted;
361
15
  std::tie(S, WasInserted) = insert(Name, File);
362
15
363
15
  if (WasInserted)
364
11
    replaceSymbol<UndefinedGlobal>(S, Name, Flags, File, Type);
365
4
  else if (auto *Lazy = dyn_cast<LazySymbol>(S))
366
0
    Lazy->fetch();
367
4
  else if (S->isDefined())
368
3
    checkGlobalType(S, File, Type);
369
15
  return S;
370
15
}
371
372
51
void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
373
51
  LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
374
51
  StringRef Name = Sym->getName();
375
51
376
51
  Symbol *S;
377
51
  bool WasInserted;
378
51
  std::tie(S, WasInserted) = insert(Name, nullptr);
379
51
380
51
  if (WasInserted) {
381
35
    replaceSymbol<LazySymbol>(S, Name, File, *Sym);
382
35
    return;
383
35
  }
384
16
385
16
  // If there is an existing undefined symbol, load a new one from the archive.
386
16
  if (S->isUndefined()) {
387
3
    LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
388
3
    File->addMember(Sym);
389
3
  }
390
16
}
391
392
3
bool SymbolTable::addComdat(StringRef Name) {
393
3
  return Comdats.insert(CachedHashStringRef(Name)).second;
394
3
}