Index: test/wasm/gc-sections.ll =================================================================== --- test/wasm/gc-sections.ll +++ test/wasm/gc-sections.ll @@ -1,9 +1,9 @@ ; RUN: llc -filetype=obj %s -o %t.o ; RUN: lld -flavor wasm -print-gc-sections -o %t1.wasm %t.o | FileCheck %s -check-prefix=PRINT-GC -; PRINT-GC: removing unused section 'unused_function' in file '{{.*}}' -; PRINT-GC-NOT: removing unused section 'used_function' in file '{{.*}}' -; PRINT-GC: removing unused section '.data.unused_data' in file '{{.*}}' -; PRINT-GC-NOT: removing unused section '.data.used_data' in file '{{.*}}' +; PRINT-GC: removing unused function 'unused_function' in file '{{.*}}' +; PRINT-GC-NOT: removing unused function 'used_function' in file '{{.*}}' +; PRINT-GC: removing unused segment '.data.unused_data' in file '{{.*}}' +; PRINT-GC-NOT: removing unused segment '.data.used_data' in file '{{.*}}' target triple = "wasm32-unknown-unknown-wasm" Index: test/wasm/init-fini.ll =================================================================== --- test/wasm/init-fini.ll +++ test/wasm/init-fini.ll @@ -23,8 +23,8 @@ ret void } -define void @__cxa_atexit() { - ret void +define i32 @__cxa_atexit(i32 %func, i32 %arg, i32 %dso_handle) { + ret i32 0 } define hidden void @_start() { @@ -52,9 +52,9 @@ ; CHECK-NEXT: - Offset: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 1 -; CHECK-NEXT: Functions: [ 6, 9, 13, 15, 17 ] +; CHECK-NEXT: Functions: [ 6, 8, 12, 14, 16 ] -; CHECK: Body: 100010011007100B100E100B10101000100A100B10120B +; CHECK: Body: 100010011007100A100D100A100F10001009100A10110B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking ; CHECK-NEXT: DataSize: 0 @@ -78,28 +78,26 @@ ; CHECK-NEXT: - Index: 7 ; CHECK-NEXT: Name: .Lregister_call_dtors.101 ; CHECK-NEXT: - Index: 8 -; CHECK-NEXT: Name: .Lbitcast -; CHECK-NEXT: - Index: 9 ; CHECK-NEXT: Name: .Lcall_dtors.1001 -; CHECK-NEXT: - Index: 10 +; CHECK-NEXT: - Index: 9 ; CHECK-NEXT: Name: .Lregister_call_dtors.1001 -; CHECK-NEXT: - Index: 11 +; CHECK-NEXT: - Index: 10 ; CHECK-NEXT: Name: myctor -; CHECK-NEXT: - Index: 12 +; CHECK-NEXT: - Index: 11 ; CHECK-NEXT: Name: mydtor -; CHECK-NEXT: - Index: 13 +; CHECK-NEXT: - Index: 12 ; CHECK-NEXT: Name: .Lcall_dtors.101 -; CHECK-NEXT: - Index: 14 +; CHECK-NEXT: - Index: 13 ; CHECK-NEXT: Name: .Lregister_call_dtors.101 -; CHECK-NEXT: - Index: 15 +; CHECK-NEXT: - Index: 14 ; CHECK-NEXT: Name: .Lcall_dtors.202 -; CHECK-NEXT: - Index: 16 +; CHECK-NEXT: - Index: 15 ; CHECK-NEXT: Name: .Lregister_call_dtors.202 -; CHECK-NEXT: - Index: 17 +; CHECK-NEXT: - Index: 16 ; CHECK-NEXT: Name: .Lcall_dtors.2002 -; CHECK-NEXT: - Index: 18 +; CHECK-NEXT: - Index: 17 ; CHECK-NEXT: Name: .Lregister_call_dtors.2002 -; CHECK-NEXT: - Index: 19 +; CHECK-NEXT: - Index: 18 ; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: ... @@ -156,64 +154,59 @@ ; RELOC-NEXT: Function: 7 ; RELOC-NEXT: - Index: 9 ; RELOC-NEXT: Kind: FUNCTION -; RELOC-NEXT: Name: .Lbitcast +; RELOC-NEXT: Name: .Lcall_dtors.1001 ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] ; RELOC-NEXT: Function: 8 ; RELOC-NEXT: - Index: 10 ; RELOC-NEXT: Kind: FUNCTION -; RELOC-NEXT: Name: .Lcall_dtors.1001 +; RELOC-NEXT: Name: .Lregister_call_dtors.1001 ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] ; RELOC-NEXT: Function: 9 ; RELOC-NEXT: - Index: 11 -; RELOC-NEXT: Kind: FUNCTION -; RELOC-NEXT: Name: .Lregister_call_dtors.1001 -; RELOC-NEXT: Flags: [ BINDING_LOCAL ] -; RELOC-NEXT: Function: 10 -; RELOC-NEXT: - Index: 12 ; RELOC-NEXT: Kind: GLOBAL ; RELOC-NEXT: Name: __stack_pointer ; RELOC-NEXT: Flags: [ UNDEFINED ] ; RELOC-NEXT: Global: 0 -; RELOC-NEXT: - Index: 13 +; RELOC-NEXT: - Index: 12 ; RELOC-NEXT: Kind: FUNCTION ; RELOC-NEXT: Name: myctor ; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Function: 10 +; RELOC-NEXT: - Index: 13 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: mydtor +; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] ; RELOC-NEXT: Function: 11 ; RELOC-NEXT: - Index: 14 ; RELOC-NEXT: Kind: FUNCTION -; RELOC-NEXT: Name: mydtor -; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Name: .Lcall_dtors.101 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] ; RELOC-NEXT: Function: 12 ; RELOC-NEXT: - Index: 15 ; RELOC-NEXT: Kind: FUNCTION -; RELOC-NEXT: Name: .Lcall_dtors.101 +; RELOC-NEXT: Name: .Lregister_call_dtors.101 ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] ; RELOC-NEXT: Function: 13 ; RELOC-NEXT: - Index: 16 ; RELOC-NEXT: Kind: FUNCTION -; RELOC-NEXT: Name: .Lregister_call_dtors.101 +; RELOC-NEXT: Name: .Lcall_dtors.202 ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] ; RELOC-NEXT: Function: 14 ; RELOC-NEXT: - Index: 17 ; RELOC-NEXT: Kind: FUNCTION -; RELOC-NEXT: Name: .Lcall_dtors.202 +; RELOC-NEXT: Name: .Lregister_call_dtors.202 ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] ; RELOC-NEXT: Function: 15 ; RELOC-NEXT: - Index: 18 ; RELOC-NEXT: Kind: FUNCTION -; RELOC-NEXT: Name: .Lregister_call_dtors.202 +; RELOC-NEXT: Name: .Lcall_dtors.2002 ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] ; RELOC-NEXT: Function: 16 ; RELOC-NEXT: - Index: 19 ; RELOC-NEXT: Kind: FUNCTION -; RELOC-NEXT: Name: .Lcall_dtors.2002 -; RELOC-NEXT: Flags: [ BINDING_LOCAL ] -; RELOC-NEXT: Function: 17 -; RELOC-NEXT: - Index: 20 -; RELOC-NEXT: Kind: FUNCTION ; RELOC-NEXT: Name: .Lregister_call_dtors.2002 ; RELOC-NEXT: Flags: [ BINDING_LOCAL ] -; RELOC-NEXT: Function: 18 +; RELOC-NEXT: Function: 17 ; RELOC-NEXT: InitFunctions: ; RELOC-NEXT: - Priority: 101 ; RELOC-NEXT: Symbol: 1 @@ -222,21 +215,21 @@ ; RELOC-NEXT: - Priority: 101 ; RELOC-NEXT: Symbol: 8 ; RELOC-NEXT: - Priority: 101 -; RELOC-NEXT: Symbol: 13 +; RELOC-NEXT: Symbol: 12 ; RELOC-NEXT: - Priority: 101 -; RELOC-NEXT: Symbol: 16 +; RELOC-NEXT: Symbol: 15 ; RELOC-NEXT: - Priority: 202 -; RELOC-NEXT: Symbol: 13 +; RELOC-NEXT: Symbol: 12 ; RELOC-NEXT: - Priority: 202 -; RELOC-NEXT: Symbol: 18 +; RELOC-NEXT: Symbol: 17 ; RELOC-NEXT: - Priority: 1001 ; RELOC-NEXT: Symbol: 1 ; RELOC-NEXT: - Priority: 1001 -; RELOC-NEXT: Symbol: 11 +; RELOC-NEXT: Symbol: 10 ; RELOC-NEXT: - Priority: 2002 -; RELOC-NEXT: Symbol: 13 +; RELOC-NEXT: Symbol: 12 ; RELOC-NEXT: - Priority: 2002 -; RELOC-NEXT: Symbol: 20 +; RELOC-NEXT: Symbol: 19 ; RELOC-NEXT: - Type: CUSTOM ; RELOC-NEXT: Name: name ; RELOC-NEXT: FunctionNames: @@ -257,25 +250,23 @@ ; RELOC-NEXT: - Index: 7 ; RELOC-NEXT: Name: .Lregister_call_dtors.101 ; RELOC-NEXT: - Index: 8 -; RELOC-NEXT: Name: .Lbitcast -; RELOC-NEXT: - Index: 9 ; RELOC-NEXT: Name: .Lcall_dtors.1001 -; RELOC-NEXT: - Index: 10 +; RELOC-NEXT: - Index: 9 ; RELOC-NEXT: Name: .Lregister_call_dtors.1001 -; RELOC-NEXT: - Index: 11 +; RELOC-NEXT: - Index: 10 ; RELOC-NEXT: Name: myctor -; RELOC-NEXT: - Index: 12 +; RELOC-NEXT: - Index: 11 ; RELOC-NEXT: Name: mydtor -; RELOC-NEXT: - Index: 13 +; RELOC-NEXT: - Index: 12 ; RELOC-NEXT: Name: .Lcall_dtors.101 -; RELOC-NEXT: - Index: 14 +; RELOC-NEXT: - Index: 13 ; RELOC-NEXT: Name: .Lregister_call_dtors.101 -; RELOC-NEXT: - Index: 15 +; RELOC-NEXT: - Index: 14 ; RELOC-NEXT: Name: .Lcall_dtors.202 -; RELOC-NEXT: - Index: 16 +; RELOC-NEXT: - Index: 15 ; RELOC-NEXT: Name: .Lregister_call_dtors.202 -; RELOC-NEXT: - Index: 17 +; RELOC-NEXT: - Index: 16 ; RELOC-NEXT: Name: .Lcall_dtors.2002 -; RELOC-NEXT: - Index: 18 +; RELOC-NEXT: - Index: 17 ; RELOC-NEXT: Name: .Lregister_call_dtors.2002 ; RELOC-NEXT: ... Index: wasm/InputChunks.h =================================================================== --- wasm/InputChunks.h +++ wasm/InputChunks.h @@ -26,6 +26,7 @@ using llvm::wasm::WasmGlobal; using llvm::wasm::WasmRelocation; using llvm::wasm::WasmSignature; +using llvm::wasm::WasmGlobalType; using llvm::wasm::WasmInitExpr; using llvm::object::WasmSection; @@ -39,7 +40,32 @@ public: enum Kind { DataSegment, Function, Global }; - Kind kind() const { return SectionKind; } + Kind kind() const { return ChunkKind; } + StringRef getFileName() const { return File->getName(); } + + virtual StringRef getComdat() const = 0; + virtual StringRef getName() const = 0; + + ObjFile *File; + + // Signals that the section is part of the output. The garbage collector, + // and COMDAT handling can set a sections' Live bit. + // If GC is disabled, all sections start out as live by default. + unsigned Live : 1; + +protected: + InputChunk(ObjFile *F, Kind K) + : File(F), Live(!Config->GcSections), ChunkKind(K) {} + virtual ~InputChunk() = default; + Kind ChunkKind; +}; + +class InputSection : public InputChunk { +public: + static bool classof(const InputChunk *C) { + return C->kind() == DataSegment || + C->kind() == Function; + } uint32_t getSize() const { return data().size(); } @@ -54,30 +80,17 @@ uint32_t getOutputOffset() const { return OutputOffset; } ArrayRef getRelocations() const { return Relocations; } - StringRef getFileName() const { return File->getName(); } - - virtual StringRef getComdat() const = 0; - virtual StringRef getName() const = 0; std::vector OutRelocations; - ObjFile *File; - - // Signals that the section is part of the output. The garbage collector, - // and COMDAT handling can set a sections' Live bit. - // If GC is disabled, all sections start out as live by default. - unsigned Live : 1; protected: - InputChunk(ObjFile *F, Kind K) - : File(F), Live(!Config->GcSections), SectionKind(K) {} - virtual ~InputChunk() = default; + InputSection(ObjFile *F, Kind K) : InputChunk(F, K) {} void calcRelocations(); virtual ArrayRef data() const = 0; virtual uint32_t getInputSectionOffset() const = 0; std::vector Relocations; - int32_t OutputOffset = 0; - Kind SectionKind; + uint32_t OutputOffset = 0; }; // Represents a WebAssembly data segment which can be included as part of @@ -88,10 +101,10 @@ // // For example, by default, clang will produce a separate data section for // each global variable. -class InputSegment : public InputChunk { +class InputSegment : public InputSection { public: InputSegment(const WasmSegment &Seg, ObjFile *F) - : InputChunk(F, InputChunk::DataSegment), Segment(Seg) {} + : InputSection(F, InputChunk::DataSegment), Segment(Seg) {} static bool classof(const InputChunk *C) { return C->kind() == DataSegment; } @@ -126,11 +139,11 @@ // Represents a single wasm function within and input file. These are // combined to create the final output CODE section. -class InputFunction : public InputChunk { +class InputFunction : public InputSection { public: InputFunction(const WasmSignature &S, const WasmFunction *Func, ObjFile *F) - : InputChunk(F, InputChunk::Function), Signature(S), Function(Func) {} + : InputSection(F, InputChunk::Function), Signature(S), Function(Func) {} static bool classof(const InputChunk *C) { return C->kind() == InputChunk::Function; @@ -182,27 +195,24 @@ // form the final GLOBALS section. class InputGlobal : public InputChunk { public: - InputGlobal(const WasmGlobal *G, ObjFile *F) - : InputChunk(F, InputChunk::Global), Global(G) {} + InputGlobal(const WasmGlobalType &S, const WasmGlobal *G, ObjFile *F) + : InputChunk(F, InputChunk::Global), Signature(S), Global(G) {} static bool classof(const InputChunk *C) { return C->kind() == InputChunk::Global; } - StringRef getComdat() const override { return StringRef(); } uint32_t getOutputIndex() const { return OutputIndex.getValue(); } bool hasOutputIndex() const { return OutputIndex.hasValue(); } void setOutputIndex(uint32_t Index); virtual const WasmInitExpr &getInitExpr() const { return Global->InitExpr; } - virtual const WasmGlobalType &getType() const { return Global->Type; } + + const WasmGlobalType &Signature; protected: - // TODO(sbc): Globals don't really belong in this class heirarchy. - // Refactor so to avoid this ugliness. - StringRef getName() const override { return {}; } - ArrayRef data() const override { return {}; } - uint32_t getInputSectionOffset() const override { return 0; } + StringRef getComdat() const override { return StringRef(); } + StringRef getName() const override { return StringRef(); } const WasmGlobal *Global; llvm::Optional OutputIndex; @@ -211,19 +221,21 @@ class SyntheticGlobal : public InputGlobal { public: SyntheticGlobal(const WasmGlobalType &Type, const WasmInitExpr &InitExpr) - : InputGlobal(nullptr, nullptr), InitExpr(InitExpr), Type(Type) { + : InputGlobal(Type, nullptr, nullptr), InitExpr(InitExpr) { Live = true; } const WasmInitExpr &getInitExpr() const override { return InitExpr; } - const WasmGlobalType &getType() const override { return Type; } protected: WasmInitExpr InitExpr; - const WasmGlobalType Type; }; } // namespace wasm + +// Returns a chunk name for an error message. +std::string toString(const wasm::InputChunk::Kind Type); + } // namespace lld #endif // LLD_WASM_INPUT_CHUNKS_H Index: wasm/InputChunks.cpp =================================================================== --- wasm/InputChunks.cpp +++ wasm/InputChunks.cpp @@ -29,7 +29,7 @@ return Address + Delta; } -void InputChunk::copyRelocations(const WasmSection &Section) { +void InputSection::copyRelocations(const WasmSection &Section) { if (Section.Relocations.empty()) return; size_t Start = getInputSectionOffset(); @@ -82,7 +82,7 @@ applyRelocation(Buf, Reloc); } -void InputChunk::writeTo(uint8_t *SectionStart) const { +void InputSection::writeTo(uint8_t *SectionStart) const { memcpy(SectionStart + getOutputOffset(), data().data(), data().size()); applyRelocations(SectionStart, OutRelocations); } @@ -90,7 +90,7 @@ // Populate OutRelocations based on the input relocations and offset within the // output section. Calculates the updated index and offset for each relocation // as well as the value to write out in the final binary. -void InputChunk::calcRelocations() { +void InputSection::calcRelocations() { if (Relocations.empty()) return; int32_t Off = getOutputOffset() - getInputSectionOffset(); @@ -131,3 +131,15 @@ assert(!hasOutputIndex()); OutputIndex = Index; } + +std::string lld::toString(const wasm::InputChunk::Kind Type) { + switch (Type) { + case InputChunk::Function: + return "function"; + case InputChunk::DataSegment: + return "segment"; + case InputChunk::Global: + return "global"; + } + llvm_unreachable("invalid chunk type"); +} Index: wasm/InputFiles.h =================================================================== --- wasm/InputFiles.h +++ wasm/InputFiles.h @@ -121,10 +121,10 @@ uint32_t relocateTableIndex(uint32_t Original) const; uint32_t relocateSymbolIndex(uint32_t Original) const; - Symbol *createDefinedData(const WasmSymbol &Sym, InputChunk *Chunk, + Symbol *createDefinedData(const WasmSymbol &Sym, InputSegment *Segment, uint32_t Address, uint32_t DataSize); - Symbol *createDefinedFunction(const WasmSymbol &Sym, InputChunk *Chunk); - Symbol *createDefinedGlobal(const WasmSymbol &Sym, InputChunk *Chunk); + Symbol *createDefinedFunction(const WasmSymbol &Sym, InputFunction *Function); + Symbol *createDefinedGlobal(const WasmSymbol &Sym, InputGlobal *Global); Symbol *createUndefined(const WasmSymbol &Sym); void initializeSymbols(); Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -211,7 +211,7 @@ } for (const WasmGlobal &G : WasmObj->globals()) { - InputGlobal *Global = make(&G, this); + InputGlobal *Global = make(G.Type, &G, this); Globals.emplace_back(Global); } @@ -278,27 +278,28 @@ } Symbol *ObjFile::createDefinedFunction(const WasmSymbol &Sym, - InputChunk *Chunk) { + InputFunction *Function) { if (Sym.isBindingLocal()) - return make(Sym.Info.Name, Sym.Info.Flags, this, Chunk); + return make(Sym.Info.Name, Sym.Info.Flags, this, Function); return Symtab->addDefined(Sym.Info.Name, getType(Sym), Sym.Info.Flags, this, - Chunk); + Function); } -Symbol *ObjFile::createDefinedData(const WasmSymbol &Sym, InputChunk *Chunk, +Symbol *ObjFile::createDefinedData(const WasmSymbol &Sym, InputSegment *Segment, uint32_t Address, uint32_t Size) { if (Sym.isBindingLocal()) - return make(Sym.Info.Name, Sym.Info.Flags, this, Chunk, + return make(Sym.Info.Name, Sym.Info.Flags, this, Segment, Address, Size); return Symtab->addDefined(Sym.Info.Name, getType(Sym), Sym.Info.Flags, this, - Chunk, Address, Size); + Segment, Address, Size); } -Symbol *ObjFile::createDefinedGlobal(const WasmSymbol &Sym, InputChunk *Chunk) { +Symbol *ObjFile::createDefinedGlobal(const WasmSymbol &Sym, + InputGlobal *Global) { if (Sym.isBindingLocal()) - return make(Sym.Info.Name, Sym.Info.Flags, this, Chunk); + return make(Sym.Info.Name, Sym.Info.Flags, this, Global); return Symtab->addDefined(Sym.Info.Name, getType(Sym), Sym.Info.Flags, this, - Chunk); + Global); } void ArchiveFile::parse() { Index: wasm/MarkLive.cpp =================================================================== --- wasm/MarkLive.cpp +++ wasm/MarkLive.cpp @@ -37,7 +37,7 @@ return; DEBUG(dbgs() << "markLive\n"); - SmallVector Q; + SmallVector Q; auto Enqueue = [&](Symbol *Sym) { if (!Sym) @@ -46,7 +46,8 @@ if (!Chunk || Chunk->Live) return; Chunk->Live = true; - Q.push_back(Chunk); + if (InputSection *Section = dyn_cast(Chunk)) + Q.push_back(Section); }; // Add GC root symbols. @@ -59,16 +60,16 @@ if (!Sym->isHidden()) Enqueue(Sym); - // The ctor fuctions are all used the synthetic __wasm_call_ctors function, - // but since this function is created in-place it doesn't contain reloctations - // which mean we have to manually mark the ctors. + // The ctor functions are all used in the synthetic __wasm_call_ctors + // function, but since this function is created in-place it doesn't contain + // relocatations, which mean we have to manually mark the ctors. for (const ObjFile *Obj : Symtab->ObjectFiles) { const WasmLinkingData &L = Obj->getWasmObj()->linkingData(); for (const WasmInitFunc &F : L.InitFunctions) Enqueue(Obj->getFunctionSymbol(F.Symbol)); } - auto EnqueueSuccessors = [Enqueue](InputChunk &Chunk) { + auto EnqueueSuccessors = [Enqueue](InputSection &Chunk) { for (const WasmRelocation Reloc : Chunk.getRelocations()) if (Reloc.Type != R_WEBASSEMBLY_TYPE_INDEX_LEB) Enqueue(Chunk.File->getSymbol(Reloc.Index)); @@ -81,8 +82,8 @@ if (Config->PrintGcSections) { auto CheckChunk = [](const InputChunk *C) { if (!C->Live) - message("removing unused section '" + C->getName() + "' in file '" + - C->getFileName() + "'"); + message("removing unused " + toString(C->kind()) + " '" + C->getName() + + "' in file '" + C->getFileName() + "'"); }; for (const ObjFile *Obj : Symtab->ObjectFiles) { @@ -90,6 +91,8 @@ CheckChunk(C); for (InputChunk *C : Obj->Segments) CheckChunk(C); + for (InputGlobal *G : Obj->Globals) + CheckChunk(G); } } } Index: wasm/OutputSections.cpp =================================================================== --- wasm/OutputSections.cpp +++ wasm/OutputSections.cpp @@ -88,7 +88,7 @@ OS.flush(); BodySize = CodeSectionHeader.size(); - for (InputChunk *Func : Functions) { + for (InputSection *Func : Functions) { Func->setOutputOffset(BodySize); BodySize += Func->getSize(); } @@ -114,20 +114,20 @@ Buf += CodeSectionHeader.size(); // Write code section bodies - parallelForEach(Functions, [ContentsStart](const InputChunk *Chunk) { + parallelForEach(Functions, [ContentsStart](const InputSection *Chunk) { Chunk->writeTo(ContentsStart); }); } uint32_t CodeSection::numRelocations() const { uint32_t Count = 0; - for (const InputChunk *Func : Functions) + for (const InputSection *Func : Functions) Count += Func->OutRelocations.size(); return Count; } void CodeSection::writeRelocations(raw_ostream &OS) const { - for (const InputChunk *Func : Functions) + for (const InputSection *Func : Functions) for (const OutputRelocation &Reloc : Func->OutRelocations) writeReloc(OS, Reloc); } @@ -180,7 +180,7 @@ memcpy(SegStart, Segment->Header.data(), Segment->Header.size()); // Write segment data payload - for (const InputChunk *Chunk : Segment->InputSegments) + for (const InputSection *Chunk : Segment->InputSegments) Chunk->writeTo(ContentsStart); }); } @@ -188,14 +188,14 @@ uint32_t DataSection::numRelocations() const { uint32_t Count = 0; for (const OutputSegment *Seg : Segments) - for (const InputChunk *InputSeg : Seg->InputSegments) + for (const InputSection *InputSeg : Seg->InputSegments) Count += InputSeg->OutRelocations.size(); return Count; } void DataSection::writeRelocations(raw_ostream &OS) const { for (const OutputSegment *Seg : Segments) - for (const InputChunk *InputSeg : Seg->InputSegments) + for (const InputSection *InputSeg : Seg->InputSegments) for (const OutputRelocation &Reloc : InputSeg->OutRelocations) writeReloc(OS, Reloc); } Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -141,7 +141,7 @@ if (auto *Function = dyn_cast_or_null(Chunk)) FunctionSig = &Function->Signature; if (auto *Global = dyn_cast_or_null(Chunk)) - GlobalType = &Global->getType(); + GlobalType = &Global->Signature; return checkSymbolTypes(Existing, F, NewType, FunctionSig, GlobalType); } @@ -176,11 +176,7 @@ Symbol *SymbolTable::addDefined(StringRef Name, WasmSymbolType Type, uint32_t Flags, InputFile *F, InputChunk *Chunk, uint32_t Address, uint32_t DataSize) { - if (Type == WASM_SYMBOL_TYPE_FUNCTION) - DEBUG(dbgs() << "addDefined: func:" << Name << "\n"); - else - DEBUG(dbgs() << "addDefined: global:" << Name << " addr:" << Address - << "\n"); + DEBUG(dbgs() << "addDefined: " << toString(Type) << ":" << Name << "\n"); Symbol *S; bool WasInserted; bool Replace = false; @@ -217,13 +213,15 @@ checkSymbolTypes(*S, *F, Type, Chunk); switch (Type) { case WASM_SYMBOL_TYPE_FUNCTION: - replaceSymbol(S, Name, Flags, F, Chunk); + replaceSymbol(S, Name, Flags, F, + cast(Chunk)); break; case WASM_SYMBOL_TYPE_DATA: - replaceSymbol(S, Name, Flags, F, Chunk, Address, DataSize); + replaceSymbol(S, Name, Flags, F, cast(Chunk), + Address, DataSize); break; case WASM_SYMBOL_TYPE_GLOBAL: - replaceSymbol(S, Name, Flags, F, Chunk); + replaceSymbol(S, Name, Flags, F, cast(Chunk)); break; } } Index: wasm/Symbols.h =================================================================== --- wasm/Symbols.h +++ wasm/Symbols.h @@ -26,6 +26,9 @@ class InputFile; class InputChunk; +class InputFunction; +class InputGlobal; +class InputSegment; #define INVALID_INDEX UINT32_MAX @@ -126,16 +129,13 @@ void setTableIndex(uint32_t Index); protected: - void setFunctionType(const WasmSignature *Type); - - FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, - InputChunk *C) - : Symbol(Name, K, Flags, F, C) {} + FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F) + : Symbol(Name, K, Flags, F, nullptr) {} uint32_t TableIndex = INVALID_INDEX; - // Explicit function type, needed for undefined or synthetic functions only. - // For regular defined functions this information comes from the InputChunk. + // Explicit function type. For regular defined functions this information + // comes from the InputFunction. const WasmSignature *FunctionType = nullptr; }; @@ -143,31 +143,33 @@ public: // Primary constructor for file-defined functions. DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F = nullptr, - InputChunk *C = nullptr) - : FunctionSymbol(Name, DefinedFunctionKind, Flags, F, C) {} + InputFunction *Func = nullptr) + : FunctionSymbol(Name, DefinedFunctionKind, Flags, F) { + setFunction(Func); + } // Second constructor used when creating synthetic functions. DefinedFunction(StringRef Name, uint32_t Flags, const WasmSignature *Type) - : FunctionSymbol(Name, DefinedFunctionKind, Flags, nullptr, nullptr) { - setFunctionType(Type); + : FunctionSymbol(Name, DefinedFunctionKind, Flags, nullptr) { + FunctionType = Type; } static bool classof(const Symbol *S) { return S->kind() == DefinedFunctionKind; } - // This is used when constructing the __wasm_call_ctors function - // which happens after the DefinedSymbol has been created. + // This is used when constructing the __wasm_call_ctors function, which + // happens after the DefinedFunction has been created. // TODO(sbc): Refactor to avoid the need to handling this special case. - void setChunk(InputChunk *C) { Chunk = C; } + void setFunction(InputFunction *F); }; class UndefinedFunction : public FunctionSymbol { public: UndefinedFunction(StringRef Name, uint32_t Flags, InputFile *File = nullptr, const WasmSignature *Type = nullptr) - : FunctionSymbol(Name, UndefinedFunctionKind, Flags, File, nullptr) { - setFunctionType(Type); + : FunctionSymbol(Name, UndefinedFunctionKind, Flags, File) { + FunctionType = Type; } static bool classof(const Symbol *S) { @@ -215,6 +217,7 @@ public: UndefinedData(StringRef Name, uint32_t Flags, InputFile *File = nullptr) : DataSymbol(Name, UndefinedDataKind, Flags, File, nullptr) {} + static bool classof(const Symbol *S) { return S->kind() == UndefinedDataKind; } @@ -229,38 +232,45 @@ const WasmGlobalType &getGlobalType() const; protected: - void setGlobalType(const WasmGlobalType *Type); + GlobalSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F) + : Symbol(Name, K, Flags, F, nullptr) {} - GlobalSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, - InputChunk *C) - : Symbol(Name, K, Flags, F, C) {} - - // Explicit function type, needed for undefined or synthetic functions only. - // For regular defined globals this information comes from the InputChunk. + // Explicit global type. For regular defined globals this information comes + // from the InputGlobal. const WasmGlobalType *GlobalType = nullptr; }; class DefinedGlobal : public GlobalSymbol { public: // Primary constructor for file-defined globals. - DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, InputChunk *C) - : GlobalSymbol(Name, DefinedGlobalKind, Flags, File, C) {} + DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, + InputGlobal *G = nullptr) + : GlobalSymbol(Name, DefinedGlobalKind, Flags, File) { + setGlobal(G); + } // Second constructor used when creating synthetic globals. DefinedGlobal(StringRef Name, uint32_t Flags, const WasmGlobalType *Type) - : GlobalSymbol(Name, DefinedGlobalKind, Flags, nullptr, nullptr) { - setGlobalType(Type); + : GlobalSymbol(Name, DefinedGlobalKind, Flags, nullptr) { + GlobalType = Type; } - void setChunk(InputChunk *C) { Chunk = C; } + static bool classof(const Symbol *S) { + return S->kind() == DefinedGlobalKind; + } + + // This is used when constructing the __stack_pointer global, which happens + // after the DefinedGlobal has been created. + // TODO(sbc): Refactor to avoid the need to handling this special case. + void setGlobal(InputGlobal *G); }; class UndefinedGlobal : public GlobalSymbol { public: UndefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File = nullptr, const WasmGlobalType *Type = nullptr) - : GlobalSymbol(Name, UndefinedGlobalKind, Flags, File, nullptr) { - setGlobalType(Type); + : GlobalSymbol(Name, UndefinedGlobalKind, Flags, File) { + GlobalType = Type; } static bool classof(const Symbol *S) { Index: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -48,15 +48,20 @@ bool Symbol::hasOutputIndex() const { if (auto *F = dyn_cast_or_null(Chunk)) return F->hasOutputIndex(); + if (auto *G = dyn_cast_or_null(Chunk)) + return G->hasOutputIndex(); + assert(!isData()); + assert(!Chunk); return OutputIndex != INVALID_INDEX; } uint32_t Symbol::getOutputIndex() const { - assert(!isData()); if (auto *F = dyn_cast_or_null(Chunk)) return F->getOutputIndex(); if (auto *G = dyn_cast_or_null(Chunk)) return G->getOutputIndex(); + assert(!isData()); + assert(!Chunk); assert(OutputIndex != INVALID_INDEX); return OutputIndex; } @@ -102,19 +107,10 @@ } const WasmSignature &FunctionSymbol::getFunctionType() const { - if (auto *F = dyn_cast_or_null(Chunk)) - return F->Signature; - assert(FunctionType != nullptr); return *FunctionType; } -void FunctionSymbol::setFunctionType(const WasmSignature *Type) { - assert(FunctionType == nullptr); - assert(!Chunk); - FunctionType = Type; -} - uint32_t FunctionSymbol::getTableIndex() const { if (auto *F = dyn_cast_or_null(Chunk)) return F->getTableIndex(); @@ -141,9 +137,15 @@ TableIndex = Index; } +void DefinedFunction::setFunction(InputFunction *F) { + Chunk = F; + assert(FunctionType == nullptr || *FunctionType == F->Signature); + FunctionType = &F->Signature; +} + uint32_t DefinedData::getVirtualAddress() const { DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n"); - return Chunk ? dyn_cast(Chunk)->translateVA(VirtualAddress) + return Chunk ? cast(Chunk)->translateVA(VirtualAddress) : VirtualAddress; } @@ -166,18 +168,14 @@ } const WasmGlobalType &GlobalSymbol::getGlobalType() const { - if (auto *G = dyn_cast_or_null(Chunk)) - return G->getType(); - - DEBUG(dbgs() << "getGlobalType: " << getName() << "\n"); assert(GlobalType != nullptr); return *GlobalType; } -void GlobalSymbol::setGlobalType(const WasmGlobalType *Type) { - assert(GlobalType == nullptr); - assert(!Chunk); - GlobalType = Type; +void DefinedGlobal::setGlobal(InputGlobal *G) { + Chunk = G; + assert(GlobalType == nullptr || *GlobalType == G->Signature); + GlobalType = &G->Signature; } std::string lld::toString(const wasm::Symbol &Sym) { Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -243,7 +243,7 @@ writeUleb128(OS, NumGlobals, "global count"); for (const InputGlobal *G : DefinedGlobals) { WasmGlobal Global; - Global.Type = G->getType(); + Global.Type = G->Signature; Global.InitExpr = G->getInitExpr(); writeGlobal(OS, Global); } @@ -803,7 +803,7 @@ uint32_t TableIndex = kInitialTableOffset; for (ObjFile *File : Symtab->ObjectFiles) { DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n"); - auto HandleRelocs = [&](InputChunk *Chunk) { + auto HandleRelocs = [&](InputSection *Chunk) { if (!Chunk->Live) return; ArrayRef Types = File->getWasmObj()->types(); @@ -870,7 +870,6 @@ // in input object. void Writer::createCtorFunction() { uint32_t FunctionIndex = NumImportedFunctions + DefinedFunctions.size(); - WasmSym::CallCtors->setOutputIndex(FunctionIndex); // First write the body bytes to a string. std::string FunctionBody; @@ -895,8 +894,8 @@ CtorFunctionBody.size()); CtorFunction = llvm::make_unique( Signature, BodyArray, WasmSym::CallCtors->getName()); + WasmSym::CallCtors->setFunction(CtorFunction.get()); CtorFunction->setOutputIndex(FunctionIndex); - WasmSym::CallCtors->setChunk(CtorFunction.get()); DefinedFunctions.emplace_back(CtorFunction.get()); } @@ -927,7 +926,7 @@ WasmSym::StackPointer->getGlobalType(), InitExpr); StackPtrGlobal->setOutputIndex(NumImportedGlobals + DefinedGlobals.size()); DefinedGlobals.emplace_back(StackPtrGlobal.get()); - WasmSym::StackPointer->setChunk(StackPtrGlobal.get()); + WasmSym::StackPointer->setGlobal(StackPtrGlobal.get()); } void Writer::run() { Index: wasm/WriterUtils.cpp =================================================================== --- wasm/WriterUtils.cpp +++ wasm/WriterUtils.cpp @@ -218,8 +218,6 @@ } std::string lld::toString(const WasmGlobalType &Sig) { - std::string S = toString(static_cast(Sig.Type)); - if (Sig.Mutable) - return "mutable " + S; - return S; + return (Sig.Mutable ? "var " : "const ") + + toString(static_cast(Sig.Type)); }