Index: test/wasm/weak-symbols.ll =================================================================== --- test/wasm/weak-symbols.ll +++ test/wasm/weak-symbols.ll @@ -25,7 +25,7 @@ ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1 ] +; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -59,7 +59,7 @@ ; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: exportWeak2 ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 4 +; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Type: ELEM ; CHECK-NEXT: Segments: ; CHECK-NEXT: - Offset: @@ -75,8 +75,6 @@ ; CHECK-NEXT: - Locals: ; CHECK-NEXT: Body: 4181808080000B ; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 41020B -; CHECK-NEXT: - Locals: ; CHECK-NEXT: Body: 4181808080000B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking @@ -88,6 +86,6 @@ ; CHECK-NEXT: Name: _start ; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Name: exportWeak1 -; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: - Index: 3 ; CHECK-NEXT: Name: exportWeak2 ; CHECK-NEXT: ... Index: wasm/CMakeLists.txt =================================================================== --- wasm/CMakeLists.txt +++ wasm/CMakeLists.txt @@ -5,6 +5,7 @@ add_lld_library(lldWasm Driver.cpp InputFiles.cpp + InputFunction.cpp InputSegment.cpp OutputSections.cpp SymbolTable.cpp Index: wasm/InputFiles.h =================================================================== --- wasm/InputFiles.h +++ wasm/InputFiles.h @@ -24,6 +24,7 @@ using llvm::object::Archive; using llvm::object::WasmObjectFile; using llvm::object::WasmSection; +using llvm::object::WasmSegment; using llvm::object::WasmSymbol; using llvm::wasm::WasmImport; using llvm::wasm::WasmSignature; @@ -115,6 +116,7 @@ // as opposed to the locally defined function. bool isImportedFunction(uint32_t Index) const; + InputSegment *createSegment(const WasmSegment &WasmSegment); Symbol *createDefined(const WasmSymbol &Sym, const InputSegment *Segment = nullptr, InputFunction *Function = nullptr); Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -15,6 +15,7 @@ #include "SymbolTable.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/Object/Binary.h" #include "llvm/Object/Wasm.h" #include "llvm/Support/raw_ostream.h" @@ -190,12 +191,8 @@ FunctionSymbols.resize(NumFunctionImports + WasmObj->functions().size()); GlobalSymbols.resize(NumGlobalImports + WasmObj->globals().size()); - for (const WasmSegment &S : WasmObj->dataSegments()) { - InputSegment *Seg = make(&S, this); - copyRelocationsRange(Seg->Relocations, DataSection->Relocations, - Seg->getInputSectionOffset(), Seg->getSize()); - Segments.emplace_back(Seg); - } + for (const WasmSegment &S : WasmObj->dataSegments()) + createSegment(S); ArrayRef Funcs = WasmObj->functions(); ArrayRef FuncTypes = WasmObj->functionTypes(); @@ -211,6 +208,7 @@ // Populate `FunctionSymbols` and `GlobalSymbols` based on the WasmSymbols // in the object + SmallBitVector ReachedFunctions(WasmObj->functions().size(), false); for (const SymbolRef &Sym : WasmObj->symbols()) { const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl()); Symbol *S; @@ -226,6 +224,8 @@ break; case WasmSymbol::SymbolType::FUNCTION_EXPORT: S = createDefined(WasmSym, nullptr, getFunction(WasmSym)); + if (S->getFile() == this) + ReachedFunctions[WasmSym.ElementIndex - NumFunctionImports] = true; break; case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME: // These are for debugging only, no need to create linker symbols for them @@ -244,6 +244,16 @@ } } + // This is a crude precursor to garbage collection, but it works really nicely + // for discarding multiple copies of inline (=Comdat/weak) symbols. If the + // function isn't reachable by any Symbol (because another file has defined + // the weak symbol), then it's discardable. We aren't considering here + // whether the Symbol is actually ever called. + for (uint32_t I = 0; I < ReachedFunctions.size(); ++I) { + if (!ReachedFunctions[I]) + Functions[I] = &InputFunction::Discarded; + } + // Populate `TableSymbols` with all symbols that are called indirectly uint32_t SegmentCount = WasmObj->elements().size(); if (SegmentCount) { @@ -266,6 +276,15 @@ DEBUG(dbgs() << "Globals : " << GlobalSymbols.size() << "\n"); } +InputSegment *ObjFile::createSegment(const WasmSegment& S) { + InputSegment *Seg = make(&S, this); + copyRelocationsRange(Seg->Relocations, DataSection->Relocations, + Seg->getInputSectionOffset(), + Seg->getInputSectionOffset() + Seg->getSize()); + Segments.emplace_back(Seg); + return Seg; +} + Symbol *ObjFile::createUndefined(const WasmSymbol &Sym, const WasmSignature *Signature) { return Symtab->addUndefined(this, &Sym, Signature); Index: wasm/InputFunction.h =================================================================== --- wasm/InputFunction.h +++ wasm/InputFunction.h @@ -18,8 +18,9 @@ #include "WriterUtils.h" #include "llvm/Object/Wasm.h" -using llvm::wasm::WasmRelocation; using llvm::wasm::WasmFunction; +using llvm::wasm::WasmRelocation; +using llvm::wasm::WasmSignature; namespace lld { namespace wasm { @@ -48,6 +49,8 @@ std::vector OutRelocations; const ObjFile *File; + static InputFunction Discarded; + protected: llvm::Optional OutputIndex; }; Index: wasm/InputFunction.cpp =================================================================== --- /dev/null +++ wasm/InputFunction.cpp @@ -0,0 +1,18 @@ +//===- InputFunction.cpp --------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "InputFunction.h" +#include "lld/Common/LLVM.h" + +#define DEBUG_TYPE "lld" + +using namespace llvm; +using namespace lld::wasm; + +InputFunction InputFunction::Discarded(nullptr, nullptr, nullptr); Index: wasm/InputSegment.h =================================================================== --- wasm/InputSegment.h +++ wasm/InputSegment.h @@ -63,6 +63,8 @@ const ObjFile *File; std::vector Relocations; + static InputSegment Discarded; + protected: const OutputSegment *OutputSeg = nullptr; uint32_t OutputSegmentOffset = 0; Index: wasm/InputSegment.cpp =================================================================== --- wasm/InputSegment.cpp +++ wasm/InputSegment.cpp @@ -16,8 +16,11 @@ using namespace llvm; using namespace lld::wasm; +InputSegment InputSegment::Discarded(nullptr, nullptr); + uint32_t InputSegment::translateVA(uint32_t Address) const { assert(Address >= startVA() && Address < endVA()); + assert(OutputSeg); int32_t Delta = OutputSeg->StartVA + OutputSegmentOffset - startVA(); DEBUG(dbgs() << "translateVA: " << getName() << " Delta=" << Delta << " Address=" << Address << "\n"); Index: wasm/SymbolTable.h =================================================================== --- wasm/SymbolTable.h +++ wasm/SymbolTable.h @@ -42,7 +42,6 @@ void addFile(InputFile *File); std::vector ObjectFiles; - std::vector SyntheticSymbols; void reportDuplicate(Symbol *Existing, InputFile *NewFile); void reportRemainingUndefines(); Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -593,6 +593,8 @@ DEBUG(dbgs() << "Functions: " << File->getName() << "\n"); for (InputFunction *Func : File->Functions) { + if (Func == &InputFunction::Discarded) + continue; DefinedFunctions.emplace_back(Func); Func->setOutputIndex(FunctionIndex++); } @@ -626,6 +628,8 @@ void Writer::createOutputSegments() { for (ObjFile *File : Symtab->ObjectFiles) { for (InputSegment *Segment : File->Segments) { + if (Segment == &InputSegment::Discarded) + continue; StringRef Name = getOutputDataSegmentName(Segment->getName()); OutputSegment *&S = SegmentMap[Name]; if (S == nullptr) {