Coverage Report

Created: 2019-05-19 14:56

/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
// 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 "SymbolTable.h"
10
#include "Config.h"
11
#include "InputChunks.h"
12
#include "InputEvent.h"
13
#include "InputGlobal.h"
14
#include "WriterUtils.h"
15
#include "lld/Common/ErrorHandler.h"
16
#include "lld/Common/Memory.h"
17
#include "llvm/ADT/SetVector.h"
18
19
#define DEBUG_TYPE "lld"
20
21
using namespace llvm;
22
using namespace llvm::wasm;
23
using namespace llvm::object;
24
using namespace lld;
25
using namespace lld::wasm;
26
27
SymbolTable *lld::wasm::Symtab;
28
29
294
void SymbolTable::addFile(InputFile *File) {
30
294
  log("Processing: " + toString(File));
31
294
  if (Config->Trace)
32
2
    message(toString(File));
33
294
  File->parse();
34
294
35
294
  // LLVM bitcode file
36
294
  if (auto *F = dyn_cast<BitcodeFile>(File))
37
43
    BitcodeFiles.push_back(F);
38
251
  else if (auto *F = dyn_cast<ObjFile>(File))
39
234
    ObjectFiles.push_back(F);
40
17
  else if (auto *F = dyn_cast<SharedFile>(File))
41
1
    SharedFiles.push_back(F);
42
294
}
43
44
// This function is where all the optimizations of link-time
45
// optimization happens. When LTO is in use, some input files are
46
// not in native object file format but in the LLVM bitcode format.
47
// This function compiles bitcode files into a few big native files
48
// using LLVM functions and replaces bitcode symbols with the results.
49
// Because all bitcode files that the program consists of are passed
50
// to the compiler at once, it can do whole-program optimization.
51
173
void SymbolTable::addCombinedLTOObject() {
52
173
  if (BitcodeFiles.empty())
53
143
    return;
54
30
55
30
  // Compile bitcode files and replace bitcode symbols.
56
30
  LTO.reset(new BitcodeCompiler);
57
30
  for (BitcodeFile *F : BitcodeFiles)
58
42
    LTO->add(*F);
59
30
60
47
  for (StringRef Filename : LTO->compile()) {
61
47
    auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"), "");
62
47
    Obj->parse(true);
63
47
    ObjectFiles.push_back(Obj);
64
47
  }
65
30
}
66
67
131
void SymbolTable::reportRemainingUndefines() {
68
949
  for (Symbol *Sym : SymVector) {
69
949
    if (!Sym->isUndefined() || 
Sym->isWeak()11
)
70
939
      continue;
71
10
    if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
72
2
      continue;
73
8
    if (!Sym->IsUsedInRegularObj)
74
3
      continue;
75
5
    error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym));
76
5
  }
77
131
}
78
79
237
Symbol *SymbolTable::find(StringRef Name) {
80
237
  auto It = SymMap.find(CachedHashStringRef(Name));
81
237
  if (It == SymMap.end() || 
It->second == -1226
)
82
11
    return nullptr;
83
226
  return SymVector[It->second];
84
226
}
85
86
8
void SymbolTable::replace(StringRef Name, Symbol* Sym) {
87
8
  auto It = SymMap.find(CachedHashStringRef(Name));
88
8
  SymVector[It->second] = Sym;
89
8
}
90
91
1.65k
std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) {
92
1.65k
  bool Trace = false;
93
1.65k
  auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()});
94
1.65k
  int &SymIndex = P.first->second;
95
1.65k
  bool IsNew = P.second;
96
1.65k
  if (SymIndex == -1) {
97
3
    SymIndex = SymVector.size();
98
3
    Trace = true;
99
3
    IsNew = true;
100
3
  }
101
1.65k
102
1.65k
  if (!IsNew)
103
174
    return {SymVector[SymIndex], false};
104
1.48k
105
1.48k
  Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
106
1.48k
  Sym->IsUsedInRegularObj = false;
107
1.48k
  Sym->Traced = Trace;
108
1.48k
  SymVector.emplace_back(Sym);
109
1.48k
  return {Sym, true};
110
1.48k
}
111
112
std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name,
113
774
                                              const InputFile *File) {
114
774
  Symbol *S;
115
774
  bool WasInserted;
116
774
  std::tie(S, WasInserted) = insertName(Name);
117
774
118
774
  if (!File || 
File->kind() == InputFile::ObjectKind760
)
119
711
    S->IsUsedInRegularObj = true;
120
774
121
774
  return {S, WasInserted};
122
774
}
123
124
static void reportTypeError(const Symbol *Existing, const InputFile *File,
125
1
                            llvm::wasm::WasmSymbolType Type) {
126
1
  error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
127
1
        toString(Existing->getWasmType()) + " in " +
128
1
        toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
129
1
        " in " + toString(File));
130
1
}
131
132
// Check the type of new symbol matches that of the symbol is replacing.
133
// Returns true if the function types match, false is there is a singature
134
// mismatch.
135
static bool signatureMatches(FunctionSymbol *Existing,
136
95
                             const WasmSignature *NewSig) {
137
95
  if (!NewSig)
138
1
    return true;
139
94
140
94
  const WasmSignature *OldSig = Existing->Signature;
141
94
  if (!OldSig) {
142
43
    Existing->Signature = NewSig;
143
43
    return true;
144
43
  }
145
51
146
51
  return *NewSig == *OldSig;
147
51
}
148
149
static void checkGlobalType(const Symbol *Existing, const InputFile *File,
150
4
                            const WasmGlobalType *NewType) {
151
4
  if (!isa<GlobalSymbol>(Existing)) {
152
0
    reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
153
0
    return;
154
0
  }
155
4
156
4
  const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
157
4
  if (*NewType != *OldType) {
158
0
    error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
159
0
          toString(*OldType) + " in " + toString(Existing->getFile()) +
160
0
          "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
161
0
  }
162
4
}
163
164
static void checkEventType(const Symbol *Existing, const InputFile *File,
165
                           const WasmEventType *NewType,
166
1
                           const WasmSignature *NewSig) {
167
1
  auto ExistingEvent = dyn_cast<EventSymbol>(Existing);
168
1
  if (!isa<EventSymbol>(Existing)) {
169
0
    reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT);
170
0
    return;
171
0
  }
172
1
173
1
  const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType();
174
1
  const WasmSignature *OldSig = ExistingEvent->Signature;
175
1
  if (NewType->Attribute != OldType->Attribute)
176
0
    error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " +
177
0
          toString(*OldType) + " in " + toString(Existing->getFile()) +
178
0
          "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
179
1
  if (*NewSig != *OldSig)
180
0
    warn("Event signature mismatch: " + Existing->getName() +
181
0
         "\n>>> defined as " + toString(*OldSig) + " in " +
182
0
         toString(Existing->getFile()) + "\n>>> defined as " +
183
0
         toString(*NewSig) + " in " + toString(File));
184
1
}
185
186
13
static void checkDataType(const Symbol *Existing, const InputFile *File) {
187
13
  if (!isa<DataSymbol>(Existing))
188
0
    reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
189
13
}
190
191
DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
192
                                                   uint32_t Flags,
193
172
                                                   InputFunction *Function) {
194
172
  LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
195
172
  assert(!find(Name));
196
172
  SyntheticFunctions.emplace_back(Function);
197
172
  return replaceSymbol<DefinedFunction>(insertName(Name).first, Name,
198
172
                                        Flags, nullptr, Function);
199
172
}
200
201
DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
202
493
                                                 uint32_t Flags) {
203
493
  LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
204
493
  assert(!find(Name));
205
493
  return replaceSymbol<DefinedData>(insertName(Name).first, Name, Flags);
206
493
}
207
208
DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
209
163
                                               InputGlobal *Global) {
210
163
  LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
211
163
                    << "\n");
212
163
  assert(!find(Name));
213
163
  SyntheticGlobals.emplace_back(Global);
214
163
  return replaceSymbol<DefinedGlobal>(insertName(Name).first, Name, Flags,
215
163
                                      nullptr, Global);
216
163
}
217
218
static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
219
90
                          uint32_t NewFlags) {
220
90
  // If existing symbol is undefined, replace it.
221
90
  if (!Existing->isDefined()) {
222
81
    LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
223
81
                      << Existing->getName() << "\n");
224
81
    return true;
225
81
  }
226
9
227
9
  // Now we have two defined symbols. If the new one is weak, we can ignore it.
228
9
  if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
229
6
    LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
230
6
    return false;
231
6
  }
232
3
233
3
  // If the existing symbol is weak, we should replace it.
234
3
  if (Existing->isWeak()) {
235
0
    LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
236
0
    return true;
237
0
  }
238
3
239
3
  // Neither symbol is week. They conflict.
240
3
  error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
241
3
        toString(Existing->getFile()) + "\n>>> defined in " +
242
3
        toString(NewFile));
243
3
  return true;
244
3
}
245
246
Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
247
                                        InputFile *File,
248
511
                                        InputFunction *Function) {
249
511
  LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " ["
250
511
                    << (Function ? toString(Function->Signature) : "none")
251
511
                    << "]\n");
252
511
  Symbol *S;
253
511
  bool WasInserted;
254
511
  std::tie(S, WasInserted) = insert(Name, File);
255
511
256
511
  auto Replace = [&](Symbol* Sym) {
257
506
    // If the new defined function doesn't have signture (i.e. bitcode
258
506
    // functions) but the old symbol does, then preserve the old signature
259
506
    const WasmSignature *OldSig = S->getSignature();
260
506
    auto* NewSym = replaceSymbol<DefinedFunction>(Sym, Name, Flags, File, Function);
261
506
    if (!NewSym->Signature)
262
45
      NewSym->Signature = OldSig;
263
506
  };
264
511
265
511
  if (WasInserted || 
S->isLazy()107
) {
266
421
    Replace(S);
267
421
    return S;
268
421
  }
269
90
270
90
  auto ExistingFunction = dyn_cast<FunctionSymbol>(S);
271
90
  if (!ExistingFunction) {
272
1
    reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION);
273
1
    return S;
274
1
  }
275
89
276
89
  if (Function && 
!signatureMatches(ExistingFunction, &Function->Signature)77
) {
277
8
    Symbol* Variant;
278
8
    if (getFunctionVariant(S, &Function->Signature, File, &Variant))
279
7
      // New variant, always replace
280
7
      Replace(Variant);
281
1
    else if (shouldReplace(S, File, Flags))
282
0
      // Variant already exists, replace it after checking shouldReplace
283
0
      Replace(Variant);
284
8
285
8
    // This variant we found take the place in the symbol table as the primary
286
8
    // variant.
287
8
    replace(Name, Variant);
288
8
    return Variant;
289
8
  }
290
81
291
81
  // Existing function with matching signature.
292
81
  if (shouldReplace(S, File, Flags))
293
78
    Replace(S);
294
81
295
81
  return S;
296
81
}
297
298
Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
299
                                    InputFile *File, InputSegment *Segment,
300
94
                                    uint32_t Address, uint32_t Size) {
301
94
  LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
302
94
                    << "\n");
303
94
  Symbol *S;
304
94
  bool WasInserted;
305
94
  std::tie(S, WasInserted) = insert(Name, File);
306
94
307
94
  auto Replace = [&]() {
308
93
    replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
309
93
  };
310
94
311
94
  if (WasInserted || 
S->isLazy()7
) {
312
87
    Replace();
313
87
    return S;
314
87
  }
315
7
316
7
  checkDataType(S, File);
317
7
318
7
  if (shouldReplace(S, File, Flags))
319
6
    Replace();
320
7
  return S;
321
7
}
322
323
Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
324
4
                                      InputFile *File, InputGlobal *Global) {
325
4
  LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
326
4
327
4
  Symbol *S;
328
4
  bool WasInserted;
329
4
  std::tie(S, WasInserted) = insert(Name, File);
330
4
331
4
  auto Replace = [&]() {
332
4
    replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
333
4
  };
334
4
335
4
  if (WasInserted || 
S->isLazy()0
) {
336
4
    Replace();
337
4
    return S;
338
4
  }
339
0
340
0
  checkGlobalType(S, File, &Global->getType());
341
0
342
0
  if (shouldReplace(S, File, Flags))
343
0
    Replace();
344
0
  return S;
345
0
}
346
347
Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags,
348
2
                                     InputFile *File, InputEvent *Event) {
349
2
  LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n");
350
2
351
2
  Symbol *S;
352
2
  bool WasInserted;
353
2
  std::tie(S, WasInserted) = insert(Name, File);
354
2
355
2
  auto Replace = [&]() {
356
1
    replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
357
1
  };
358
2
359
2
  if (WasInserted || 
S->isLazy()1
) {
360
1
    Replace();
361
1
    return S;
362
1
  }
363
1
364
1
  checkEventType(S, File, &Event->getType(), &Event->Signature);
365
1
366
1
  if (shouldReplace(S, File, Flags))
367
0
    Replace();
368
1
  return S;
369
1
}
370
371
Symbol *SymbolTable::addUndefinedFunction(StringRef Name, StringRef ImportName,
372
                                          StringRef ImportModule,
373
                                          uint32_t Flags, InputFile *File,
374
110
                                          const WasmSignature *Sig) {
375
110
  LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name <<
376
110
             " [" << (Sig ? toString(*Sig) : "none") << "]\n");
377
110
378
110
  Symbol *S;
379
110
  bool WasInserted;
380
110
  std::tie(S, WasInserted) = insert(Name, File);
381
110
382
110
  auto Replace = [&]() {
383
83
    replaceSymbol<UndefinedFunction>(S, Name, ImportName, ImportModule, Flags,
384
83
                                     File, Sig);
385
83
  };
386
110
387
110
  if (WasInserted)
388
83
    Replace();
389
27
  else if (auto *Lazy = dyn_cast<LazySymbol>(S))
390
9
    Lazy->fetch();
391
18
  else {
392
18
    auto ExistingFunction = dyn_cast<FunctionSymbol>(S);
393
18
    if (!ExistingFunction) {
394
0
      reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION);
395
0
      return S;
396
0
    }
397
18
    if (!signatureMatches(ExistingFunction, Sig))
398
0
      if (getFunctionVariant(S, Sig, File, &S))
399
0
        Replace();
400
18
  }
401
110
402
110
  return S;
403
110
}
404
405
Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
406
24
                                      InputFile *File) {
407
24
  LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
408
24
409
24
  Symbol *S;
410
24
  bool WasInserted;
411
24
  std::tie(S, WasInserted) = insert(Name, File);
412
24
413
24
  if (WasInserted)
414
16
    replaceSymbol<UndefinedData>(S, Name, Flags, File);
415
8
  else if (auto *Lazy = dyn_cast<LazySymbol>(S))
416
0
    Lazy->fetch();
417
8
  else if (S->isDefined())
418
6
    checkDataType(S, File);
419
24
  return S;
420
24
}
421
422
Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, StringRef ImportName,
423
                                        StringRef ImportModule, uint32_t Flags,
424
                                        InputFile *File,
425
29
                                        const WasmGlobalType *Type) {
426
29
  LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
427
29
428
29
  Symbol *S;
429
29
  bool WasInserted;
430
29
  std::tie(S, WasInserted) = insert(Name, File);
431
29
432
29
  if (WasInserted)
433
22
    replaceSymbol<UndefinedGlobal>(S, Name, ImportName, ImportModule, Flags,
434
22
                                   File, Type);
435
7
  else if (auto *Lazy = dyn_cast<LazySymbol>(S))
436
0
    Lazy->fetch();
437
7
  else if (S->isDefined())
438
4
    checkGlobalType(S, File, Type);
439
29
  return S;
440
29
}
441
442
52
void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
443
52
  LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
444
52
  StringRef Name = Sym->getName();
445
52
446
52
  Symbol *S;
447
52
  bool WasInserted;
448
52
  std::tie(S, WasInserted) = insertName(Name);
449
52
450
52
  if (WasInserted) {
451
35
    replaceSymbol<LazySymbol>(S, Name, 0, File, *Sym);
452
35
    return;
453
35
  }
454
17
455
17
  if (!S->isUndefined())
456
13
    return;
457
4
458
4
  // The existing symbol is undefined, load a new one from the archive,
459
4
  // unless the the existing symbol is weak in which case replace the undefined
460
4
  // symbols with a LazySymbol.
461
4
  if (S->isWeak()) {
462
1
    const WasmSignature *OldSig = nullptr;
463
1
    // In the case of an UndefinedFunction we need to preserve the expected
464
1
    // signature.
465
1
    if (auto *F = dyn_cast<UndefinedFunction>(S))
466
1
      OldSig = F->Signature;
467
1
    LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
468
1
    auto NewSym = replaceSymbol<LazySymbol>(S, Name, WASM_SYMBOL_BINDING_WEAK,
469
1
                                            File, *Sym);
470
1
    NewSym->Signature = OldSig;
471
1
    return;
472
1
  }
473
3
474
3
  LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
475
3
  File->addMember(Sym);
476
3
}
477
478
5
bool SymbolTable::addComdat(StringRef Name) {
479
5
  return ComdatGroups.insert(CachedHashStringRef(Name)).second;
480
5
}
481
482
// The new signature doesn't match.  Create a variant to the symbol with the
483
// signature encoded in the name and return that instead.  These symbols are
484
// then unified later in handleSymbolVariants.
485
bool SymbolTable::getFunctionVariant(Symbol* Sym, const WasmSignature *Sig,
486
8
                                     const InputFile *File, Symbol **Out) {
487
8
  LLVM_DEBUG(dbgs() << "getFunctionVariant: " << Sym->getName() << " -> "
488
8
                    << " " << toString(*Sig) << "\n");
489
8
  Symbol *Variant = nullptr;
490
8
491
8
  // Linear search through symbol variants.  Should never be more than two
492
8
  // or three entries here.
493
8
  auto &Variants = SymVariants[CachedHashStringRef(Sym->getName())];
494
8
  if (Variants.empty())
495
7
    Variants.push_back(Sym);
496
8
497
8
  for (Symbol* V : Variants) {
498
8
    if (*V->getSignature() == *Sig) {
499
1
      Variant = V;
500
1
      break;
501
1
    }
502
8
  }
503
8
504
8
  bool WasAdded = !Variant;
505
8
  if (WasAdded) {
506
7
    // Create a new variant;
507
7
    LLVM_DEBUG(dbgs() << "added new variant\n");
508
7
    Variant = reinterpret_cast<Symbol *>(make<SymbolUnion>());
509
7
    Variants.push_back(Variant);
510
7
  } else {
511
1
    LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*Variant) << "\n");
512
1
    assert(*Variant->getSignature() == *Sig);
513
1
  }
514
8
515
8
  *Out = Variant;
516
8
  return WasAdded;
517
8
}
518
519
// Set a flag for --trace-symbol so that we can print out a log message
520
// if a new symbol with the same name is inserted into the symbol table.
521
3
void SymbolTable::trace(StringRef Name) {
522
3
  SymMap.insert({CachedHashStringRef(Name), -1});
523
3
}
524
525
static const uint8_t UnreachableFn[] = {
526
    0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
527
    0x00 /* opcode unreachable */, 0x0b /* opcode end */
528
};
529
530
// Replace the given symbol body with an unreachable function.
531
// This is used by handleWeakUndefines in order to generate a callable
532
// equivalent of an undefined function and also handleSymbolVariants for
533
// undefined functions that don't match the signature of the definition.
534
InputFunction *SymbolTable::replaceWithUnreachable(Symbol *Sym,
535
                                                   const WasmSignature &Sig,
536
16
                                                   StringRef DebugName) {
537
16
  auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName);
538
16
  Func->setBody(UnreachableFn);
539
16
  SyntheticFunctions.emplace_back(Func);
540
16
  replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Sym->getFlags(), nullptr,
541
16
                                 Func);
542
16
  return Func;
543
16
}
544
545
// For weak undefined functions, there may be "call" instructions that reference
546
// the symbol. In this case, we need to synthesise a dummy/stub function that
547
// will abort at runtime, so that relocations can still provided an operand to
548
// the call instruction that passes Wasm validation.
549
149
void SymbolTable::handleWeakUndefines() {
550
1.13k
  for (Symbol *Sym : getSymbols()) {
551
1.13k
    if (!Sym->isUndefWeak())
552
1.12k
      continue;
553
10
554
10
    const WasmSignature *Sig = Sym->getSignature();
555
10
    if (!Sig) {
556
1
      // It is possible for undefined functions not to have a signature (eg. if
557
1
      // added via "--undefined"), but weak undefined ones do have a signature.
558
1
      // Lazy symbols may not be functions and therefore Sig can still be null
559
1
      // in some circumstantce.
560
1
      assert(!isa<FunctionSymbol>(Sym));
561
1
      continue;
562
1
    }
563
9
564
9
    // Add a synthetic dummy for weak undefined functions.  These dummies will
565
9
    // be GC'd if not used as the target of any "call" instructions.
566
9
    StringRef DebugName = Saver.save("undefined:" + toString(*Sym));
567
9
    InputFunction* Func = replaceWithUnreachable(Sym, *Sig, DebugName);
568
9
    // Ensure it compares equal to the null pointer, and so that table relocs
569
9
    // don't pull in the stub body (only call-operand relocs should do that).
570
9
    Func->setTableIndex(0);
571
9
    // Hide our dummy to prevent export.
572
9
    Sym->setHidden(true);
573
9
  }
574
149
}
575
576
static void reportFunctionSignatureMismatch(StringRef SymName,
577
                                            FunctionSymbol *A,
578
7
                                            FunctionSymbol *B, bool Error) {
579
7
  std::string msg = ("function signature mismatch: " + SymName +
580
7
                     "\n>>> defined as " + toString(*A->Signature) + " in " +
581
7
                     toString(A->getFile()) + "\n>>> defined as " +
582
7
                     toString(*B->Signature) + " in " + toString(B->getFile()))
583
7
                        .str();
584
7
  if (Error)
585
0
    error(msg);
586
7
  else
587
7
    warn(msg);
588
7
}
589
590
// Remove any variant symbols that were created due to function signature
591
// mismatches.
592
172
void SymbolTable::handleSymbolVariants() {
593
172
  for (auto Pair : SymVariants) {
594
7
    // Push the initial symbol onto the list of variants.
595
7
    StringRef SymName = Pair.first.val();
596
7
    std::vector<Symbol *> &Variants = Pair.second;
597
7
598
#ifndef NDEBUG
599
    LLVM_DEBUG(dbgs() << "symbol with (" << Variants.size()
600
                      << ") variants: " << SymName << "\n");
601
    for (auto *S: Variants) {
602
      auto *F = cast<FunctionSymbol>(S);
603
      LLVM_DEBUG(dbgs() << " variant: " + F->getName() << " "
604
                        << toString(*F->Signature) << "\n");
605
    }
606
#endif
607
608
7
    // Find the one definition.
609
7
    DefinedFunction *Defined = nullptr;
610
14
    for (auto *Symbol : Variants) {
611
14
      if (auto F = dyn_cast<DefinedFunction>(Symbol)) {
612
7
        Defined = F;
613
7
        break;
614
7
      }
615
14
    }
616
7
617
7
    // If there are no definitions, and the undefined symbols disagree on
618
7
    // the signature, there is not we can do since we don't know which one
619
7
    // to use as the signature on the import.
620
7
    if (!Defined) {
621
0
      reportFunctionSignatureMismatch(SymName,
622
0
                                      cast<FunctionSymbol>(Variants[0]),
623
0
                                      cast<FunctionSymbol>(Variants[1]), true);
624
0
      return;
625
0
    }
626
7
627
14
    
for (auto *Symbol : Variants)7
{
628
14
      if (Symbol != Defined) {
629
7
        auto *F = cast<FunctionSymbol>(Symbol);
630
7
        reportFunctionSignatureMismatch(SymName, F, Defined, false);
631
7
        StringRef DebugName = Saver.save("unreachable:" + toString(*F));
632
7
        replaceWithUnreachable(F, *F->Signature, DebugName);
633
7
      }
634
14
    }
635
7
  }
636
172
}