1c94d393aSSam Clegg //===- SymbolTable.cpp ----------------------------------------------------===//
2c94d393aSSam Clegg //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c94d393aSSam Clegg //
7c94d393aSSam Clegg //===----------------------------------------------------------------------===//
8c94d393aSSam Clegg 
9c94d393aSSam Clegg #include "SymbolTable.h"
10c94d393aSSam Clegg #include "Config.h"
115fa274beSSam Clegg #include "InputChunks.h"
12e915a71fSHeejin Ahn #include "InputEvent.h"
1393102974SSam Clegg #include "InputGlobal.h"
14b8621596SSam Clegg #include "WriterUtils.h"
15c94d393aSSam Clegg #include "lld/Common/ErrorHandler.h"
162017d52bSRui Ueyama #include "lld/Common/Memory.h"
177d67dd11SRui Ueyama #include "llvm/ADT/SetVector.h"
18c94d393aSSam Clegg 
19c94d393aSSam Clegg #define DEBUG_TYPE "lld"
20c94d393aSSam Clegg 
21c94d393aSSam Clegg using namespace llvm;
2220db381bSSam Clegg using namespace llvm::wasm;
2345218f4aSSam Clegg using namespace llvm::object;
24c94d393aSSam Clegg using namespace lld;
25c94d393aSSam Clegg using namespace lld::wasm;
26c94d393aSSam Clegg 
27c94d393aSSam Clegg SymbolTable *lld::wasm::Symtab;
28c94d393aSSam Clegg 
29*6540e570SSam Clegg static char encodeValType(ValType Type) {
30*6540e570SSam Clegg   switch (Type) {
31*6540e570SSam Clegg   case ValType::I32:
32*6540e570SSam Clegg     return 'i';
33*6540e570SSam Clegg   case ValType::I64:
34*6540e570SSam Clegg     return 'j';
35*6540e570SSam Clegg   case ValType::F32:
36*6540e570SSam Clegg     return 'f';
37*6540e570SSam Clegg   case ValType::F64:
38*6540e570SSam Clegg     return 'd';
39*6540e570SSam Clegg   case ValType::V128:
40*6540e570SSam Clegg     return 'V';
41*6540e570SSam Clegg   case ValType::EXCEPT_REF:
42*6540e570SSam Clegg     return 'e';
43*6540e570SSam Clegg   }
44*6540e570SSam Clegg   llvm_unreachable("invalid wasm type");
45*6540e570SSam Clegg }
46*6540e570SSam Clegg 
47*6540e570SSam Clegg static std::string encodeSignature(const WasmSignature &Sig) {
48*6540e570SSam Clegg   std::string S = ":";
49*6540e570SSam Clegg   for (ValType Type : Sig.Returns)
50*6540e570SSam Clegg     S += encodeValType(Type);
51*6540e570SSam Clegg   S += ':';
52*6540e570SSam Clegg   for (ValType Type : Sig.Params)
53*6540e570SSam Clegg     S += encodeValType(Type);
54*6540e570SSam Clegg   return S;
55*6540e570SSam Clegg }
56*6540e570SSam Clegg 
57*6540e570SSam Clegg static StringRef getVariantName(StringRef BaseName, const WasmSignature &Sig) {
58*6540e570SSam Clegg   return Saver.save(BaseName + encodeSignature(Sig));
59*6540e570SSam Clegg }
60*6540e570SSam Clegg 
61c94d393aSSam Clegg void SymbolTable::addFile(InputFile *File) {
62c94d393aSSam Clegg   log("Processing: " + toString(File));
631f3f774fSSam Clegg   if (Config->Trace)
641f3f774fSSam Clegg     message(toString(File));
65c94d393aSSam Clegg   File->parse();
66c94d393aSSam Clegg 
67c729c1b4SSam Clegg   // LLVM bitcode file
68c729c1b4SSam Clegg   if (auto *F = dyn_cast<BitcodeFile>(File))
69c729c1b4SSam Clegg     BitcodeFiles.push_back(F);
70c729c1b4SSam Clegg   else if (auto *F = dyn_cast<ObjFile>(File))
71c94d393aSSam Clegg     ObjectFiles.push_back(F);
72c94d393aSSam Clegg }
73c94d393aSSam Clegg 
74c729c1b4SSam Clegg // This function is where all the optimizations of link-time
75c729c1b4SSam Clegg // optimization happens. When LTO is in use, some input files are
76c729c1b4SSam Clegg // not in native object file format but in the LLVM bitcode format.
77c729c1b4SSam Clegg // This function compiles bitcode files into a few big native files
78c729c1b4SSam Clegg // using LLVM functions and replaces bitcode symbols with the results.
79c729c1b4SSam Clegg // Because all bitcode files that the program consists of are passed
80c729c1b4SSam Clegg // to the compiler at once, it can do whole-program optimization.
81c729c1b4SSam Clegg void SymbolTable::addCombinedLTOObject() {
82c729c1b4SSam Clegg   if (BitcodeFiles.empty())
83c729c1b4SSam Clegg     return;
84c729c1b4SSam Clegg 
85c729c1b4SSam Clegg   // Compile bitcode files and replace bitcode symbols.
86c729c1b4SSam Clegg   LTO.reset(new BitcodeCompiler);
87c729c1b4SSam Clegg   for (BitcodeFile *F : BitcodeFiles)
88c729c1b4SSam Clegg     LTO->add(*F);
89c729c1b4SSam Clegg 
90c729c1b4SSam Clegg   for (StringRef Filename : LTO->compile()) {
91c729c1b4SSam Clegg     auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp"));
92c729c1b4SSam Clegg     Obj->parse();
93c729c1b4SSam Clegg     ObjectFiles.push_back(Obj);
94c729c1b4SSam Clegg   }
95c729c1b4SSam Clegg }
96c729c1b4SSam Clegg 
97c94d393aSSam Clegg void SymbolTable::reportRemainingUndefines() {
9874fe0ba1SSam Clegg   for (Symbol *Sym : SymVector) {
99c729c1b4SSam Clegg     if (!Sym->isUndefined() || Sym->isWeak())
100c729c1b4SSam Clegg       continue;
101c729c1b4SSam Clegg     if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0)
102c729c1b4SSam Clegg       continue;
103c729c1b4SSam Clegg     if (!Sym->IsUsedInRegularObj)
104c729c1b4SSam Clegg       continue;
10547e2b6b2SSam Clegg     error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym));
106c94d393aSSam Clegg   }
107c94d393aSSam Clegg }
108c94d393aSSam Clegg 
109c94d393aSSam Clegg Symbol *SymbolTable::find(StringRef Name) {
1101f3f774fSSam Clegg   auto It = SymMap.find(CachedHashStringRef(Name));
1111f3f774fSSam Clegg   if (It == SymMap.end() || It->second == -1)
1121f3f774fSSam Clegg     return nullptr;
1131f3f774fSSam Clegg   return SymVector[It->second];
1141f3f774fSSam Clegg }
1151f3f774fSSam Clegg 
116*6540e570SSam Clegg void SymbolTable::replace(StringRef Name, Symbol* Sym) {
117*6540e570SSam Clegg   auto It = SymMap.find(CachedHashStringRef(Name));
118*6540e570SSam Clegg   SymVector[It->second] = Sym;
119*6540e570SSam Clegg }
120*6540e570SSam Clegg 
1211f3f774fSSam Clegg std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) {
1221f3f774fSSam Clegg   bool Trace = false;
1231f3f774fSSam Clegg   auto P = SymMap.insert({CachedHashStringRef(Name), (int)SymVector.size()});
1241f3f774fSSam Clegg   int &SymIndex = P.first->second;
1251f3f774fSSam Clegg   bool IsNew = P.second;
1261f3f774fSSam Clegg   if (SymIndex == -1) {
1271f3f774fSSam Clegg     SymIndex = SymVector.size();
1281f3f774fSSam Clegg     Trace = true;
1291f3f774fSSam Clegg     IsNew = true;
1301f3f774fSSam Clegg   }
1311f3f774fSSam Clegg 
1321f3f774fSSam Clegg   if (!IsNew)
1331f3f774fSSam Clegg     return {SymVector[SymIndex], false};
1341f3f774fSSam Clegg 
1351f3f774fSSam Clegg   Symbol *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
1361f3f774fSSam Clegg   Sym->IsUsedInRegularObj = false;
1371f3f774fSSam Clegg   Sym->Traced = Trace;
1381f3f774fSSam Clegg   SymVector.emplace_back(Sym);
1391f3f774fSSam Clegg   return {Sym, true};
140c94d393aSSam Clegg }
141c94d393aSSam Clegg 
142230dc11dSSam Clegg std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name,
143230dc11dSSam Clegg                                               const InputFile *File) {
1441f3f774fSSam Clegg   Symbol *S;
1451f3f774fSSam Clegg   bool WasInserted;
1461f3f774fSSam Clegg   std::tie(S, WasInserted) = insertName(Name);
1471f3f774fSSam Clegg 
1484c2cbfe6SSam Clegg   if (!File || File->kind() == InputFile::ObjectKind)
1491f3f774fSSam Clegg     S->IsUsedInRegularObj = true;
1501f3f774fSSam Clegg 
1511f3f774fSSam Clegg   return {S, WasInserted};
152c94d393aSSam Clegg }
153c94d393aSSam Clegg 
154e3498ec5SRui Ueyama static void reportTypeError(const Symbol *Existing, const InputFile *File,
1553876d89aSSam Clegg                             llvm::wasm::WasmSymbolType Type) {
156e3498ec5SRui Ueyama   error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " +
157e3498ec5SRui Ueyama         toString(Existing->getWasmType()) + " in " +
1583876d89aSSam Clegg         toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) +
1593876d89aSSam Clegg         " in " + toString(File));
160e3498ec5SRui Ueyama }
161e3498ec5SRui Ueyama 
1626f4286fbSHeejin Ahn // Check the type of new symbol matches that of the symbol is replacing.
163*6540e570SSam Clegg // Returns true if the function types match, false is there is a singature
164*6540e570SSam Clegg // mismatch.
165*6540e570SSam Clegg bool signatureMatches(FunctionSymbol *Existing, const WasmSignature *NewSig) {
166cefbf9acSSam Clegg   if (!NewSig)
167*6540e570SSam Clegg     return true;
168cefbf9acSSam Clegg 
169*6540e570SSam Clegg   const WasmSignature *OldSig = Existing->Signature;
170cefbf9acSSam Clegg   if (!OldSig) {
171*6540e570SSam Clegg     Existing->Signature = NewSig;
172*6540e570SSam Clegg     return true;
173cefbf9acSSam Clegg   }
174cefbf9acSSam Clegg 
175*6540e570SSam Clegg   return *NewSig == *OldSig;
176e3498ec5SRui Ueyama }
177e3498ec5SRui Ueyama 
178e3498ec5SRui Ueyama static void checkGlobalType(const Symbol *Existing, const InputFile *File,
179e3498ec5SRui Ueyama                             const WasmGlobalType *NewType) {
180e3498ec5SRui Ueyama   if (!isa<GlobalSymbol>(Existing)) {
1813876d89aSSam Clegg     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL);
182b8621596SSam Clegg     return;
183b8621596SSam Clegg   }
184b8621596SSam Clegg 
185e3498ec5SRui Ueyama   const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType();
186e3498ec5SRui Ueyama   if (*NewType != *OldType) {
187e3498ec5SRui Ueyama     error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " +
188e3498ec5SRui Ueyama           toString(*OldType) + " in " + toString(Existing->getFile()) +
189e3498ec5SRui Ueyama           "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
190c94d393aSSam Clegg   }
19124b3dcd4SSam Clegg }
19224b3dcd4SSam Clegg 
193e915a71fSHeejin Ahn static void checkEventType(const Symbol *Existing, const InputFile *File,
194e915a71fSHeejin Ahn                            const WasmEventType *NewType,
195e915a71fSHeejin Ahn                            const WasmSignature *NewSig) {
196e915a71fSHeejin Ahn   auto ExistingEvent = dyn_cast<EventSymbol>(Existing);
197e915a71fSHeejin Ahn   if (!isa<EventSymbol>(Existing)) {
198e915a71fSHeejin Ahn     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT);
199e915a71fSHeejin Ahn     return;
200e915a71fSHeejin Ahn   }
201e915a71fSHeejin Ahn 
202e915a71fSHeejin Ahn   const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType();
203e915a71fSHeejin Ahn   const WasmSignature *OldSig = ExistingEvent->Signature;
204e915a71fSHeejin Ahn   if (NewType->Attribute != OldType->Attribute)
205e915a71fSHeejin Ahn     error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " +
206e915a71fSHeejin Ahn           toString(*OldType) + " in " + toString(Existing->getFile()) +
207e915a71fSHeejin Ahn           "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
208e915a71fSHeejin Ahn   if (*NewSig != *OldSig)
209e915a71fSHeejin Ahn     warn("Event signature mismatch: " + Existing->getName() +
210e915a71fSHeejin Ahn          "\n>>> defined as " + toString(*OldSig) + " in " +
211e915a71fSHeejin Ahn          toString(Existing->getFile()) + "\n>>> defined as " +
212e915a71fSHeejin Ahn          toString(*NewSig) + " in " + toString(File));
213e915a71fSHeejin Ahn }
214e915a71fSHeejin Ahn 
215e3498ec5SRui Ueyama static void checkDataType(const Symbol *Existing, const InputFile *File) {
216e3498ec5SRui Ueyama   if (!isa<DataSymbol>(Existing))
2173876d89aSSam Clegg     reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
218e3498ec5SRui Ueyama }
219e3498ec5SRui Ueyama 
220dfb0b2c7SSam Clegg DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
221ebda41f8SNicholas Wilson                                                    uint32_t Flags,
222ebda41f8SNicholas Wilson                                                    InputFunction *Function) {
223e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
224b961abc8SRui Ueyama   assert(!find(Name));
225ebda41f8SNicholas Wilson   SyntheticFunctions.emplace_back(Function);
2264c2cbfe6SSam Clegg   return replaceSymbol<DefinedFunction>(insert(Name, nullptr).first, Name,
2274c2cbfe6SSam Clegg                                         Flags, nullptr, Function);
22850686856SSam Clegg }
22950686856SSam Clegg 
23000245539SSam Clegg DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name,
23100245539SSam Clegg                                                  uint32_t Flags) {
232e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n");
233b961abc8SRui Ueyama   assert(!find(Name));
2344c2cbfe6SSam Clegg   return replaceSymbol<DefinedData>(insert(Name, nullptr).first, Name, Flags);
235c94d393aSSam Clegg }
236c94d393aSSam Clegg 
23793102974SSam Clegg DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
23893102974SSam Clegg                                                InputGlobal *Global) {
239e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global
240e7245b42SNicola Zaghen                     << "\n");
241b961abc8SRui Ueyama   assert(!find(Name));
242ebda41f8SNicholas Wilson   SyntheticGlobals.emplace_back(Global);
2434c2cbfe6SSam Clegg   return replaceSymbol<DefinedGlobal>(insert(Name, nullptr).first, Name, Flags,
2444c2cbfe6SSam Clegg                                       nullptr, Global);
24593102974SSam Clegg }
24693102974SSam Clegg 
247e3498ec5SRui Ueyama static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
248e3498ec5SRui Ueyama                           uint32_t NewFlags) {
249c03c9040SRui Ueyama   // If existing symbol is undefined, replace it.
250e3498ec5SRui Ueyama   if (!Existing->isDefined()) {
251e7245b42SNicola Zaghen     LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: "
252e3498ec5SRui Ueyama                       << Existing->getName() << "\n");
253c03c9040SRui Ueyama     return true;
254c03c9040SRui Ueyama   }
255c03c9040SRui Ueyama 
256c03c9040SRui Ueyama   // Now we have two defined symbols. If the new one is weak, we can ignore it.
257c03c9040SRui Ueyama   if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
258e7245b42SNicola Zaghen     LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n");
259c03c9040SRui Ueyama     return false;
260c03c9040SRui Ueyama   }
261c03c9040SRui Ueyama 
262c03c9040SRui Ueyama   // If the existing symbol is weak, we should replace it.
263e3498ec5SRui Ueyama   if (Existing->isWeak()) {
264e7245b42SNicola Zaghen     LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n");
265c03c9040SRui Ueyama     return true;
266c03c9040SRui Ueyama   }
267c03c9040SRui Ueyama 
268c03c9040SRui Ueyama   // Neither symbol is week. They conflict.
269e3498ec5SRui Ueyama   error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
270e3498ec5SRui Ueyama         toString(Existing->getFile()) + "\n>>> defined in " +
271e3498ec5SRui Ueyama         toString(NewFile));
272c03c9040SRui Ueyama   return true;
273b8621596SSam Clegg }
27493e559b1SSam Clegg 
27593e559b1SSam Clegg Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
276e3498ec5SRui Ueyama                                         InputFile *File,
277e3498ec5SRui Ueyama                                         InputFunction *Function) {
2788b0b48f3SSam Clegg   LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " ["
2798b0b48f3SSam Clegg                     << (Function ? toString(Function->Signature) : "none")
2808b0b48f3SSam Clegg                     << "]\n");
28193e559b1SSam Clegg   Symbol *S;
28293e559b1SSam Clegg   bool WasInserted;
2834c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, File);
284c729c1b4SSam Clegg 
285*6540e570SSam Clegg   auto Replace = [&](Symbol* Sym) {
286*6540e570SSam Clegg     // If the new defined function doesn't have signture (i.e. bitcode
287*6540e570SSam Clegg     // functions) but the old symbol does, then preserve the old signature
288*6540e570SSam Clegg     const WasmSignature *OldSig = S->getSignature();
289*6540e570SSam Clegg     auto* NewSym = replaceSymbol<DefinedFunction>(Sym, Name, Flags, File, Function);
290*6540e570SSam Clegg     if (!NewSym->Signature)
291*6540e570SSam Clegg       NewSym->Signature = OldSig;
292*6540e570SSam Clegg   };
293*6540e570SSam Clegg 
294e3498ec5SRui Ueyama   if (WasInserted || S->isLazy()) {
295*6540e570SSam Clegg     Replace(S);
296e3498ec5SRui Ueyama     return S;
297e3498ec5SRui Ueyama   }
298e3498ec5SRui Ueyama 
299*6540e570SSam Clegg   auto ExistingFunction = dyn_cast<FunctionSymbol>(S);
300*6540e570SSam Clegg   if (!ExistingFunction) {
301*6540e570SSam Clegg     reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION);
302*6540e570SSam Clegg     return S;
3038b0b48f3SSam Clegg   }
304*6540e570SSam Clegg 
305*6540e570SSam Clegg   if (Function && !signatureMatches(ExistingFunction, &Function->Signature)) {
306*6540e570SSam Clegg     Symbol* Variant;
307*6540e570SSam Clegg     if (getFunctionVariant(S, &Function->Signature, File, &Variant))
308*6540e570SSam Clegg       // New variant, always replace
309*6540e570SSam Clegg       Replace(Variant);
310*6540e570SSam Clegg     else if (shouldReplace(S, File, Flags))
311*6540e570SSam Clegg       // Variant already exists, replace it after checking shouldReplace
312*6540e570SSam Clegg       Replace(Variant);
313*6540e570SSam Clegg 
314*6540e570SSam Clegg     // This variant we found take the place in the symbol table as the primary
315*6540e570SSam Clegg     // variant.
316*6540e570SSam Clegg     replace(Name, Variant);
317*6540e570SSam Clegg     return Variant;
318*6540e570SSam Clegg   }
319*6540e570SSam Clegg 
320*6540e570SSam Clegg   // Existing function with matching signature.
321*6540e570SSam Clegg   if (shouldReplace(S, File, Flags))
322*6540e570SSam Clegg     Replace(S);
323*6540e570SSam Clegg 
32493e559b1SSam Clegg   return S;
32593e559b1SSam Clegg }
32693e559b1SSam Clegg 
32700245539SSam Clegg Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
328e3498ec5SRui Ueyama                                     InputFile *File, InputSegment *Segment,
32993102974SSam Clegg                                     uint32_t Address, uint32_t Size) {
330e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address
331e7245b42SNicola Zaghen                     << "\n");
33293e559b1SSam Clegg   Symbol *S;
33393e559b1SSam Clegg   bool WasInserted;
3344c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, File);
335c729c1b4SSam Clegg 
336*6540e570SSam Clegg   auto Replace = [&]() {
337e3498ec5SRui Ueyama     replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
338*6540e570SSam Clegg   };
339*6540e570SSam Clegg 
340*6540e570SSam Clegg   if (WasInserted || S->isLazy()) {
341*6540e570SSam Clegg     Replace();
342e3498ec5SRui Ueyama     return S;
343e3498ec5SRui Ueyama   }
344e3498ec5SRui Ueyama 
345e3498ec5SRui Ueyama   checkDataType(S, File);
346e3498ec5SRui Ueyama 
347e3498ec5SRui Ueyama   if (shouldReplace(S, File, Flags))
348*6540e570SSam Clegg     Replace();
349c94d393aSSam Clegg   return S;
350c94d393aSSam Clegg }
351c94d393aSSam Clegg 
35293102974SSam Clegg Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
353e3498ec5SRui Ueyama                                       InputFile *File, InputGlobal *Global) {
354e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n");
3554c2cbfe6SSam Clegg 
35693102974SSam Clegg   Symbol *S;
35793102974SSam Clegg   bool WasInserted;
3584c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, File);
359c729c1b4SSam Clegg 
360*6540e570SSam Clegg   auto Replace = [&]() {
361e3498ec5SRui Ueyama     replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
362*6540e570SSam Clegg   };
363*6540e570SSam Clegg 
364*6540e570SSam Clegg   if (WasInserted || S->isLazy()) {
365*6540e570SSam Clegg     Replace();
36693102974SSam Clegg     return S;
36793102974SSam Clegg   }
36893102974SSam Clegg 
369e3498ec5SRui Ueyama   checkGlobalType(S, File, &Global->getType());
370e3498ec5SRui Ueyama 
371e3498ec5SRui Ueyama   if (shouldReplace(S, File, Flags))
372*6540e570SSam Clegg     Replace();
373e3498ec5SRui Ueyama   return S;
374e3498ec5SRui Ueyama }
375e3498ec5SRui Ueyama 
376e915a71fSHeejin Ahn Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags,
377e915a71fSHeejin Ahn                                      InputFile *File, InputEvent *Event) {
378e915a71fSHeejin Ahn   LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n");
379e915a71fSHeejin Ahn 
380e915a71fSHeejin Ahn   Symbol *S;
381e915a71fSHeejin Ahn   bool WasInserted;
382e915a71fSHeejin Ahn   std::tie(S, WasInserted) = insert(Name, File);
383e915a71fSHeejin Ahn 
384*6540e570SSam Clegg   auto Replace = [&]() {
385e915a71fSHeejin Ahn     replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
386*6540e570SSam Clegg   };
387*6540e570SSam Clegg 
388*6540e570SSam Clegg   if (WasInserted || S->isLazy()) {
389*6540e570SSam Clegg     Replace();
390e915a71fSHeejin Ahn     return S;
391e915a71fSHeejin Ahn   }
392e915a71fSHeejin Ahn 
393e915a71fSHeejin Ahn   checkEventType(S, File, &Event->getType(), &Event->Signature);
394e915a71fSHeejin Ahn 
395e915a71fSHeejin Ahn   if (shouldReplace(S, File, Flags))
396*6540e570SSam Clegg     Replace();
397e915a71fSHeejin Ahn   return S;
398e915a71fSHeejin Ahn }
399e915a71fSHeejin Ahn 
4009b84eeaaSDan Gohman Symbol *SymbolTable::addUndefinedFunction(StringRef Name, StringRef ImportName,
4019b84eeaaSDan Gohman                                           StringRef ImportModule,
4027cc07531SSam Clegg                                           uint32_t Flags, InputFile *File,
403e3498ec5SRui Ueyama                                           const WasmSignature *Sig) {
4048b0b48f3SSam Clegg   LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name <<
4058b0b48f3SSam Clegg              " [" << (Sig ? toString(*Sig) : "none") << "]\n");
406c03c9040SRui Ueyama 
407c94d393aSSam Clegg   Symbol *S;
408c94d393aSSam Clegg   bool WasInserted;
4094c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, File);
410c729c1b4SSam Clegg 
411*6540e570SSam Clegg   auto Replace = [&]() {
4129b84eeaaSDan Gohman     replaceSymbol<UndefinedFunction>(S, Name, ImportName, ImportModule, Flags,
4139b84eeaaSDan Gohman                                      File, Sig);
414*6540e570SSam Clegg   };
415*6540e570SSam Clegg 
416*6540e570SSam Clegg   if (WasInserted)
417*6540e570SSam Clegg     Replace();
418e3498ec5SRui Ueyama   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
419b961abc8SRui Ueyama     Lazy->fetch();
420*6540e570SSam Clegg   else {
421*6540e570SSam Clegg     auto ExistingFunction = dyn_cast<FunctionSymbol>(S);
422*6540e570SSam Clegg     if (!ExistingFunction) {
423*6540e570SSam Clegg       reportTypeError(S, File, WASM_SYMBOL_TYPE_FUNCTION);
424*6540e570SSam Clegg       return S;
425*6540e570SSam Clegg     }
426*6540e570SSam Clegg     if (!signatureMatches(ExistingFunction, Sig))
427*6540e570SSam Clegg       if (getFunctionVariant(S, Sig, File, &S))
428*6540e570SSam Clegg         Replace();
429*6540e570SSam Clegg   }
430cefbf9acSSam Clegg 
431c03c9040SRui Ueyama   return S;
432c03c9040SRui Ueyama }
433c03c9040SRui Ueyama 
434e3498ec5SRui Ueyama Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
435e3498ec5SRui Ueyama                                       InputFile *File) {
436e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n");
43793102974SSam Clegg 
438e3498ec5SRui Ueyama   Symbol *S;
439e3498ec5SRui Ueyama   bool WasInserted;
4404c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, File);
441f989a92dSSam Clegg 
442e3498ec5SRui Ueyama   if (WasInserted)
443e3498ec5SRui Ueyama     replaceSymbol<UndefinedData>(S, Name, Flags, File);
444e3498ec5SRui Ueyama   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
445b961abc8SRui Ueyama     Lazy->fetch();
446e3498ec5SRui Ueyama   else if (S->isDefined())
447e3498ec5SRui Ueyama     checkDataType(S, File);
448c94d393aSSam Clegg   return S;
449c94d393aSSam Clegg }
450c94d393aSSam Clegg 
4519b84eeaaSDan Gohman Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, StringRef ImportName,
4529b84eeaaSDan Gohman                                         StringRef ImportModule, uint32_t Flags,
453e3498ec5SRui Ueyama                                         InputFile *File,
454e3498ec5SRui Ueyama                                         const WasmGlobalType *Type) {
455e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n");
456e3498ec5SRui Ueyama 
457e3498ec5SRui Ueyama   Symbol *S;
458e3498ec5SRui Ueyama   bool WasInserted;
4594c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, File);
460c729c1b4SSam Clegg 
461e3498ec5SRui Ueyama   if (WasInserted)
4629b84eeaaSDan Gohman     replaceSymbol<UndefinedGlobal>(S, Name, ImportName, ImportModule, Flags,
4639b84eeaaSDan Gohman                                    File, Type);
464e3498ec5SRui Ueyama   else if (auto *Lazy = dyn_cast<LazySymbol>(S))
465b961abc8SRui Ueyama     Lazy->fetch();
466e3498ec5SRui Ueyama   else if (S->isDefined())
467e3498ec5SRui Ueyama     checkGlobalType(S, File, Type);
468e3498ec5SRui Ueyama   return S;
469e3498ec5SRui Ueyama }
470e3498ec5SRui Ueyama 
471e3498ec5SRui Ueyama void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
472e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n");
473c94d393aSSam Clegg   StringRef Name = Sym->getName();
474c03c9040SRui Ueyama 
475c94d393aSSam Clegg   Symbol *S;
476c94d393aSSam Clegg   bool WasInserted;
4774c2cbfe6SSam Clegg   std::tie(S, WasInserted) = insert(Name, nullptr);
478c03c9040SRui Ueyama 
479c94d393aSSam Clegg   if (WasInserted) {
48037b4ee52SSam Clegg     replaceSymbol<LazySymbol>(S, Name, 0, File, *Sym);
481c03c9040SRui Ueyama     return;
482c03c9040SRui Ueyama   }
483c03c9040SRui Ueyama 
48437b4ee52SSam Clegg   if (!S->isUndefined())
48537b4ee52SSam Clegg     return;
48637b4ee52SSam Clegg 
48737b4ee52SSam Clegg   // The existing symbol is undefined, load a new one from the archive,
48837b4ee52SSam Clegg   // unless the the existing symbol is weak in which case replace the undefined
48937b4ee52SSam Clegg   // symbols with a LazySymbol.
49037b4ee52SSam Clegg   if (S->isWeak()) {
49137b4ee52SSam Clegg     const WasmSignature *OldSig = nullptr;
49237b4ee52SSam Clegg     // In the case of an UndefinedFunction we need to preserve the expected
49337b4ee52SSam Clegg     // signature.
49437b4ee52SSam Clegg     if (auto *F = dyn_cast<UndefinedFunction>(S))
49537b4ee52SSam Clegg       OldSig = F->Signature;
49637b4ee52SSam Clegg     LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
49737b4ee52SSam Clegg     auto NewSym = replaceSymbol<LazySymbol>(S, Name, WASM_SYMBOL_BINDING_WEAK,
49837b4ee52SSam Clegg                                             File, *Sym);
49937b4ee52SSam Clegg     NewSym->Signature = OldSig;
50037b4ee52SSam Clegg     return;
50137b4ee52SSam Clegg   }
50237b4ee52SSam Clegg 
503e7245b42SNicola Zaghen   LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
504e3498ec5SRui Ueyama   File->addMember(Sym);
505c94d393aSSam Clegg }
506e0f6fcd0SSam Clegg 
507c4d9aa1bSNicholas Wilson bool SymbolTable::addComdat(StringRef Name) {
508c4d9aa1bSNicholas Wilson   return Comdats.insert(CachedHashStringRef(Name)).second;
509e0f6fcd0SSam Clegg }
5101f3f774fSSam Clegg 
511*6540e570SSam Clegg // The new signature doesn't match.  Create a variant to the symbol with the
512*6540e570SSam Clegg // signature encoded in the name and return that instead.  These symbols are
513*6540e570SSam Clegg // then unified later in handleSymbolVariants.
514*6540e570SSam Clegg bool SymbolTable::getFunctionVariant(Symbol* Sym, const WasmSignature *Sig,
515*6540e570SSam Clegg                                      const InputFile *File, Symbol **Out) {
516*6540e570SSam Clegg   StringRef NewName = getVariantName(Sym->getName(), *Sig);
517*6540e570SSam Clegg   LLVM_DEBUG(dbgs() << "getFunctionVariant: " << Sym->getName() << " -> " << NewName
518*6540e570SSam Clegg                     << " " << toString(*Sig) << "\n");
519*6540e570SSam Clegg   Symbol *Variant = nullptr;
520*6540e570SSam Clegg 
521*6540e570SSam Clegg   // Linear search through symbol variants.  Should never be more than two
522*6540e570SSam Clegg   // or three entries here.
523*6540e570SSam Clegg   auto &Variants = SymVariants[CachedHashStringRef(Sym->getName())];
524*6540e570SSam Clegg   if (Variants.size() == 0)
525*6540e570SSam Clegg     Variants.push_back(Sym);
526*6540e570SSam Clegg 
527*6540e570SSam Clegg   for (Symbol* V : Variants) {
528*6540e570SSam Clegg     if (*V->getSignature() == *Sig) {
529*6540e570SSam Clegg       Variant = V;
530*6540e570SSam Clegg       break;
531*6540e570SSam Clegg     }
532*6540e570SSam Clegg   }
533*6540e570SSam Clegg 
534*6540e570SSam Clegg   bool WasAdded = !Variant;
535*6540e570SSam Clegg   if (WasAdded) {
536*6540e570SSam Clegg     // Create a new variant;
537*6540e570SSam Clegg     LLVM_DEBUG(dbgs() << "added new variant\n");
538*6540e570SSam Clegg     Variant = reinterpret_cast<Symbol *>(make<SymbolUnion>());
539*6540e570SSam Clegg     Variants.push_back(Variant);
540*6540e570SSam Clegg   } else {
541*6540e570SSam Clegg     LLVM_DEBUG(dbgs() << "variant already exists: " << toString(*Variant) << "\n");
542*6540e570SSam Clegg     assert(*Variant->getSignature() == *Sig);
543*6540e570SSam Clegg   }
544*6540e570SSam Clegg 
545*6540e570SSam Clegg   *Out = Variant;
546*6540e570SSam Clegg   return WasAdded;
547*6540e570SSam Clegg }
548*6540e570SSam Clegg 
5491f3f774fSSam Clegg // Set a flag for --trace-symbol so that we can print out a log message
5501f3f774fSSam Clegg // if a new symbol with the same name is inserted into the symbol table.
5511f3f774fSSam Clegg void SymbolTable::trace(StringRef Name) {
5521f3f774fSSam Clegg   SymMap.insert({CachedHashStringRef(Name), -1});
5531f3f774fSSam Clegg }
554230dc11dSSam Clegg 
555230dc11dSSam Clegg static const uint8_t UnreachableFn[] = {
556230dc11dSSam Clegg     0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
557230dc11dSSam Clegg     0x00 /* opcode unreachable */, 0x0b /* opcode end */
558230dc11dSSam Clegg };
559230dc11dSSam Clegg 
560230dc11dSSam Clegg // Replace the given symbol body with an unreachable function.
561230dc11dSSam Clegg // This is used by handleWeakUndefines in order to generate a callable
562*6540e570SSam Clegg // equivalent of an undefined function and also handleSymbolVariants for
563*6540e570SSam Clegg // undefined functions that don't match the signature of the definition.
564230dc11dSSam Clegg InputFunction *SymbolTable::replaceWithUnreachable(Symbol *Sym,
565230dc11dSSam Clegg                                                    const WasmSignature &Sig,
566230dc11dSSam Clegg                                                    StringRef DebugName) {
567230dc11dSSam Clegg   auto *Func = make<SyntheticFunction>(Sig, Sym->getName(), DebugName);
568230dc11dSSam Clegg   Func->setBody(UnreachableFn);
569230dc11dSSam Clegg   SyntheticFunctions.emplace_back(Func);
570*6540e570SSam Clegg   replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Sym->getFlags(), nullptr,
571*6540e570SSam Clegg                                  Func);
572230dc11dSSam Clegg   return Func;
573230dc11dSSam Clegg }
574230dc11dSSam Clegg 
575230dc11dSSam Clegg // For weak undefined functions, there may be "call" instructions that reference
576230dc11dSSam Clegg // the symbol. In this case, we need to synthesise a dummy/stub function that
577230dc11dSSam Clegg // will abort at runtime, so that relocations can still provided an operand to
578230dc11dSSam Clegg // the call instruction that passes Wasm validation.
579230dc11dSSam Clegg void SymbolTable::handleWeakUndefines() {
580230dc11dSSam Clegg   for (Symbol *Sym : getSymbols()) {
581230dc11dSSam Clegg     if (!Sym->isUndefWeak())
582230dc11dSSam Clegg       continue;
583230dc11dSSam Clegg 
584*6540e570SSam Clegg     const WasmSignature *Sig = Sym->getSignature();
585*6540e570SSam Clegg     if (!Sig) {
586230dc11dSSam Clegg       // It is possible for undefined functions not to have a signature (eg. if
587230dc11dSSam Clegg       // added via "--undefined"), but weak undefined ones do have a signature.
588*6540e570SSam Clegg       // Lazy symbols may not be functions and therefore Sig can still be null
589*6540e570SSam Clegg       // in some circumstantce.
590*6540e570SSam Clegg       assert(!isa<FunctionSymbol>(Sym));
591230dc11dSSam Clegg       continue;
592*6540e570SSam Clegg     }
593230dc11dSSam Clegg 
594230dc11dSSam Clegg     // Add a synthetic dummy for weak undefined functions.  These dummies will
595230dc11dSSam Clegg     // be GC'd if not used as the target of any "call" instructions.
596230dc11dSSam Clegg     StringRef DebugName = Saver.save("undefined:" + toString(*Sym));
597230dc11dSSam Clegg     InputFunction* Func = replaceWithUnreachable(Sym, *Sig, DebugName);
598230dc11dSSam Clegg     // Ensure it compares equal to the null pointer, and so that table relocs
599230dc11dSSam Clegg     // don't pull in the stub body (only call-operand relocs should do that).
600230dc11dSSam Clegg     Func->setTableIndex(0);
601230dc11dSSam Clegg     // Hide our dummy to prevent export.
602230dc11dSSam Clegg     Sym->setHidden(true);
603230dc11dSSam Clegg   }
604230dc11dSSam Clegg }
605*6540e570SSam Clegg 
606*6540e570SSam Clegg static void reportFunctionSignatureMismatch(StringRef SymName,
607*6540e570SSam Clegg                                             FunctionSymbol *A,
608*6540e570SSam Clegg                                             FunctionSymbol *B, bool Error) {
609*6540e570SSam Clegg   std::string msg = ("function signature mismatch: " + SymName +
610*6540e570SSam Clegg                      "\n>>> defined as " + toString(*A->Signature) + " in " +
611*6540e570SSam Clegg                      toString(A->getFile()) + "\n>>> defined as " +
612*6540e570SSam Clegg                      toString(*B->Signature) + " in " + toString(B->getFile()))
613*6540e570SSam Clegg                         .str();
614*6540e570SSam Clegg   if (Error)
615*6540e570SSam Clegg     error(msg);
616*6540e570SSam Clegg   else
617*6540e570SSam Clegg     warn(msg);
618*6540e570SSam Clegg }
619*6540e570SSam Clegg 
620*6540e570SSam Clegg // Remove any variant symbols that were created due to function signature
621*6540e570SSam Clegg // mismatches.
622*6540e570SSam Clegg void SymbolTable::handleSymbolVariants() {
623*6540e570SSam Clegg   for (auto Pair : SymVariants) {
624*6540e570SSam Clegg     // Push the initial symbol onto the list of variants.
625*6540e570SSam Clegg     StringRef SymName = Pair.first.val();
626*6540e570SSam Clegg     std::vector<Symbol *> &Variants = Pair.second;
627*6540e570SSam Clegg 
628*6540e570SSam Clegg #ifndef NDEBUG
629*6540e570SSam Clegg     dbgs() << "symbol with (" << Variants.size()
630*6540e570SSam Clegg                       << ") variants: " << SymName << "\n";
631*6540e570SSam Clegg     for (auto *S: Variants) {
632*6540e570SSam Clegg       auto *F = cast<FunctionSymbol>(S);
633*6540e570SSam Clegg       dbgs() << " variant: " + F->getName() << " " << toString(*F->Signature) << "\n";
634*6540e570SSam Clegg     }
635*6540e570SSam Clegg #endif
636*6540e570SSam Clegg 
637*6540e570SSam Clegg     // Find the one definition.
638*6540e570SSam Clegg     DefinedFunction *Defined = nullptr;
639*6540e570SSam Clegg     for (auto *Symbol : Variants) {
640*6540e570SSam Clegg       if (auto F = dyn_cast<DefinedFunction>(Symbol)) {
641*6540e570SSam Clegg         Defined = F;
642*6540e570SSam Clegg         break;
643*6540e570SSam Clegg       }
644*6540e570SSam Clegg     }
645*6540e570SSam Clegg 
646*6540e570SSam Clegg     // If there are no definitions, and the undefined symbols disagree on
647*6540e570SSam Clegg     // the signature, there is not we can do since we don't know which one
648*6540e570SSam Clegg     // to use as the signature on the import.
649*6540e570SSam Clegg     if (!Defined) {
650*6540e570SSam Clegg       reportFunctionSignatureMismatch(SymName,
651*6540e570SSam Clegg                                       cast<FunctionSymbol>(Variants[0]),
652*6540e570SSam Clegg                                       cast<FunctionSymbol>(Variants[1]), true);
653*6540e570SSam Clegg       return;
654*6540e570SSam Clegg     }
655*6540e570SSam Clegg 
656*6540e570SSam Clegg     for (auto *Symbol : Variants) {
657*6540e570SSam Clegg       if (Symbol != Defined) {
658*6540e570SSam Clegg         auto *F = cast<FunctionSymbol>(Symbol);
659*6540e570SSam Clegg         reportFunctionSignatureMismatch(SymName, F, Defined, false);
660*6540e570SSam Clegg         StringRef DebugName = Saver.save("unreachable:" + toString(*F));
661*6540e570SSam Clegg         replaceWithUnreachable(F, *F->Signature, DebugName);
662*6540e570SSam Clegg       }
663*6540e570SSam Clegg     }
664*6540e570SSam Clegg   }
665*6540e570SSam Clegg }
666