Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -9,6 +9,7 @@ #include "lld/Common/Driver.h" #include "Config.h" +#include "InputGlobal.h" #include "MarkLive.h" #include "SymbolTable.h" #include "Writer.h" @@ -59,6 +60,8 @@ void addFile(StringRef Path); void addLibrary(StringRef Name); std::vector Files; + std::unique_ptr StackPointer; + llvm::wasm::WasmGlobal StackPointerGlobal; }; } // anonymous namespace @@ -296,18 +299,22 @@ Symbol *EntrySym = nullptr; if (!Config->Relocatable) { - static WasmSignature NullSignature = {{}, WASM_TYPE_NORESULT}; - static WasmGlobalType StackPointerType = {WASM_TYPE_I32, true}; - - // Add synthetic symbols before any others - WasmSym::CallCtors = Symtab->addSyntheticFunction( - "__wasm_call_ctors", &NullSignature, WASM_SYMBOL_VISIBILITY_HIDDEN); // Can't export the SP right now because it's mutable, and mutable // globals aren't yet supported in the official binary format. // TODO(sbc): Remove WASM_SYMBOL_VISIBILITY_HIDDEN if/when the // "mutable global" proposal is accepted. + StackPointerGlobal.Type = {WASM_TYPE_I32, true}; + StackPointerGlobal.InitExpr.Value.Int32 = 0; + StackPointerGlobal.InitExpr.Opcode = WASM_OPCODE_I32_CONST; + StackPointer = llvm::make_unique(StackPointerGlobal); + StackPointer->Live = true; + + static WasmSignature NullSignature = {{}, WASM_TYPE_NORESULT}; + // Add synthetic symbols before any others + WasmSym::CallCtors = Symtab->addSyntheticFunction( + "__wasm_call_ctors", &NullSignature, WASM_SYMBOL_VISIBILITY_HIDDEN); WasmSym::StackPointer = Symtab->addSyntheticGlobal( - "__stack_pointer", WASM_SYMBOL_VISIBILITY_HIDDEN, &StackPointerType); + "__stack_pointer", WASM_SYMBOL_VISIBILITY_HIDDEN, StackPointer.get()); WasmSym::HeapBase = Symtab->addSyntheticDataSymbol("__heap_base"); WasmSym::DsoHandle = Symtab->addSyntheticDataSymbol( "__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN); Index: wasm/InputChunks.h =================================================================== --- wasm/InputChunks.h +++ wasm/InputChunks.h @@ -7,8 +7,14 @@ // //===----------------------------------------------------------------------===// // -// An input chunk represents an indivisible blocks of code or data from an input -// file. i.e. a single wasm data segment or a single wasm function. +// An InputChunks represents an indivisible opaque region of a input wasm file. +// i.e. a single wasm data segment or a single wasm function. +// +// They are writen directly to the mmap'd output file afterwhich relcoations +// are applied. Because each Chunk is independed they can be written in +// parallel. +// +// Chunks are also unit on which garbage collection (--gc-sections) operates. // //===----------------------------------------------------------------------===// @@ -22,10 +28,8 @@ using llvm::object::WasmSegment; using llvm::wasm::WasmFunction; -using llvm::wasm::WasmGlobal; using llvm::wasm::WasmRelocation; using llvm::wasm::WasmSignature; -using llvm::wasm::WasmInitExpr; using llvm::object::WasmSection; namespace llvm { @@ -40,7 +44,7 @@ class InputChunk { public: - enum Kind { DataSegment, Function, Global }; + enum Kind { DataSegment, Function }; Kind kind() const { return SectionKind; } @@ -162,9 +166,7 @@ public: SyntheticFunction(const WasmSignature &S, ArrayRef Body, StringRef Name) - : InputFunction(S, nullptr, nullptr), Name(Name), Body(Body) { - Live = true; - } + : InputFunction(S, nullptr, nullptr), Name(Name), Body(Body) {} StringRef getName() const override { return Name; } @@ -175,51 +177,6 @@ ArrayRef Body; }; -// Represents a single Wasm Global within an input file. These are combined to -// form the final GLOBALS section. -class InputGlobal : public InputChunk { -public: - InputGlobal(const WasmGlobal *G, ObjFile *F) - : InputChunk(F, InputChunk::Global), 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; } - -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; } - - const WasmGlobal *Global; - llvm::Optional OutputIndex; -}; - -class SyntheticGlobal : public InputGlobal { -public: - SyntheticGlobal(const WasmGlobalType &Type, const WasmInitExpr &InitExpr) - : InputGlobal(nullptr, nullptr), InitExpr(InitExpr), Type(Type) { - Live = true; - } - - const WasmInitExpr &getInitExpr() const override { return InitExpr; } - const WasmGlobalType &getType() const override { return Type; } - -protected: - WasmInitExpr InitExpr; - const WasmGlobalType Type; -}; - } // namespace wasm std::string toString(const wasm::InputChunk *); Index: wasm/InputChunks.cpp =================================================================== --- wasm/InputChunks.cpp +++ wasm/InputChunks.cpp @@ -122,10 +122,3 @@ assert(!hasTableIndex()); TableIndex = Index; } - -void InputGlobal::setOutputIndex(uint32_t Index) { - DEBUG(dbgs() << "InputGlobal::setOutputIndex: " << getName() << " -> " - << Index << "\n"); - assert(!hasOutputIndex()); - OutputIndex = Index; -} Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -10,6 +10,7 @@ #include "InputFiles.h" #include "Config.h" #include "InputChunks.h" +#include "InputGlobal.h" #include "SymbolTable.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" @@ -210,7 +211,7 @@ } for (const WasmGlobal &G : WasmObj->globals()) { - InputGlobal *Global = make(&G, this); + InputGlobal *Global = make(G); Globals.emplace_back(Global); } Index: wasm/InputGlobal.h =================================================================== --- /dev/null +++ wasm/InputGlobal.h @@ -0,0 +1,52 @@ +//===- InputChunks.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_WASM_INPUT_GLOBAL_H +#define LLD_WASM_INPUT_GLOBAL_H + +#include "Config.h" +#include "InputFiles.h" +#include "WriterUtils.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/Object/Wasm.h" + +using llvm::wasm::WasmGlobal; +using llvm::wasm::WasmInitExpr; + +namespace lld { +namespace wasm { + +// Represents a single Wasm Global within an input file. These are combined to +// form the final GLOBALS section. +class InputGlobal { +public: + InputGlobal(const WasmGlobal &G) : Global(G) {} + + const WasmGlobalType &getType() const { return Global.Type; } + + uint32_t getOutputIndex() const { return OutputIndex.getValue(); } + bool hasOutputIndex() const { return OutputIndex.hasValue(); } + void setOutputIndex(uint32_t Index) { + assert(!hasOutputIndex()); + OutputIndex = Index; + } + + bool Live = false; + + WasmGlobal Global; + +protected: + llvm::Optional OutputIndex; +}; + +} // namespace wasm + +} // namespace lld + +#endif // LLD_WASM_INPUT_GLOBAL_H Index: wasm/SymbolTable.h =================================================================== --- wasm/SymbolTable.h +++ wasm/SymbolTable.h @@ -65,8 +65,8 @@ bool addComdat(StringRef Name, ObjFile *); DefinedData *addSyntheticDataSymbol(StringRef Name, uint32_t Flags = 0); - DefinedGlobal *addSyntheticGlobal(StringRef Name, uint32_t Flags = 0, - const WasmGlobalType *Type = nullptr); + DefinedGlobal *addSyntheticGlobal(StringRef Name, uint32_t Flags, + InputGlobal *Global); DefinedFunction *addSyntheticFunction(StringRef Name, const WasmSignature *Type, uint32_t Flags = 0); Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -10,6 +10,7 @@ #include "SymbolTable.h" #include "Config.h" #include "InputChunks.h" +#include "InputGlobal.h" #include "WriterUtils.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" @@ -148,12 +149,13 @@ } DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags, - const WasmGlobalType *Type) { - DEBUG(dbgs() << "addSyntheticGlobal: " << Name << "\n"); + InputGlobal *Global) { + DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global << "\n"); Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); - return replaceSymbol(S, Name, Flags, Type); + assert(WasInserted); + return replaceSymbol(S, Name, Flags, nullptr, Global); } static bool shouldReplace(const Symbol &Existing, InputFile *NewFile, Index: wasm/Symbols.h =================================================================== --- wasm/Symbols.h +++ wasm/Symbols.h @@ -219,13 +219,12 @@ class DefinedGlobal : public GlobalSymbol { public: - // Primary constructor for file-defined globals. DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, InputGlobal *Global); - // Second constructor used when creating synthetic globals. - DefinedGlobal(StringRef Name, uint32_t Flags, const WasmGlobalType *Type) - : GlobalSymbol(Name, DefinedGlobalKind, Flags, nullptr, Type) {} + static bool classof(const Symbol *S) { + return S->kind() == DefinedGlobalKind; + } InputGlobal *Global; }; Index: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -10,6 +10,7 @@ #include "Symbols.h" #include "Config.h" #include "InputChunks.h" +#include "InputGlobal.h" #include "InputFiles.h" #include "OutputSegment.h" #include "lld/Common/ErrorHandler.h" Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -10,6 +10,7 @@ #include "Writer.h" #include "Config.h" #include "InputChunks.h" +#include "InputGlobal.h" #include "OutputSections.h" #include "OutputSegment.h" #include "SymbolTable.h" @@ -82,8 +83,6 @@ uint32_t registerType(const WasmSignature &Sig); void createCtorFunction(); - void createStackPointer(uint32_t Address); - void calculateInitFunctions(); void assignIndexes(); void calculateImports(); @@ -142,7 +141,7 @@ std::unique_ptr Buffer; std::unique_ptr CtorFunction; std::string CtorFunctionBody; - std::unique_ptr StackPtrGlobal; + std::unique_ptr StackPointerInputGlobal; std::vector Segments; llvm::SmallDenseMap SegmentMap; @@ -240,12 +239,8 @@ raw_ostream &OS = Section->getStream(); writeUleb128(OS, NumGlobals, "global count"); - for (const InputGlobal *G : DefinedGlobals) { - WasmGlobal Global; - Global.Type = G->getType(); - Global.InitExpr = G->getInitExpr(); - writeGlobal(OS, Global); - } + for (const InputGlobal *G : DefinedGlobals) + writeGlobal(OS, G->Global); for (const DefinedData *Sym : DefinedFakeGlobals) { WasmGlobal Global; Global.Type = {WASM_TYPE_I32, false}; @@ -597,7 +592,7 @@ debugPrint("mem: stack size = %d\n", Config->ZStackSize); debugPrint("mem: stack base = %d\n", MemoryPtr); MemoryPtr += Config->ZStackSize; - createStackPointer(MemoryPtr); + WasmSym::StackPointer->Global->Global.InitExpr.Value.Int32 = MemoryPtr; debugPrint("mem: stack top = %d\n", MemoryPtr); // Set `__heap_base` to directly follow the end of the stack. We don't @@ -776,17 +771,6 @@ } void Writer::assignIndexes() { - uint32_t GlobalIndex = NumImportedGlobals + DefinedGlobals.size(); - for (ObjFile *File : Symtab->ObjectFiles) { - DEBUG(dbgs() << "Globals: " << File->getName() << "\n"); - for (InputGlobal *Global : File->Globals) { - if (!Global->Live) - continue; - Global->setOutputIndex(GlobalIndex++); - DefinedGlobals.push_back(Global); - } - } - uint32_t FunctionIndex = NumImportedFunctions + DefinedFunctions.size(); for (ObjFile *File : Symtab->ObjectFiles) { DEBUG(dbgs() << "Functions: " << File->getName() << "\n"); @@ -802,7 +786,7 @@ auto HandleRelocs = [&](InputChunk *Chunk) { if (!Chunk->Live) return; - ObjFile *File = Chunk->File; + ObjFile* File = Chunk->File; ArrayRef Types = File->getWasmObj()->types(); for (const WasmRelocation& Reloc : Chunk->getRelocations()) { if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32 || @@ -813,20 +797,45 @@ Sym->setTableIndex(TableIndex++); IndirectFunctions.emplace_back(Sym); } else if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) { + // Mark target type as live File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]); File->TypeIsUsed[Reloc.Index] = true; + } else if (Reloc.Type == R_WEBASSEMBLY_GLOBAL_INDEX_LEB) { + // Mark target global as live + GlobalSymbol *Sym = File->getGlobalSymbol(Reloc.Index); + if (auto *G = dyn_cast(Sym)) { + DEBUG(dbgs() << "marking global live: " << Sym->getName() << "\n"); + G->Global->Live = true; + } } } }; for (ObjFile *File : Symtab->ObjectFiles) { DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n"); - for (InputChunk* Chunk : File->Functions) HandleRelocs(Chunk); for (InputChunk* Chunk : File->Segments) HandleRelocs(Chunk); } + + uint32_t GlobalIndex = NumImportedGlobals + DefinedGlobals.size(); + auto AddDefinedGlobal = [&](InputGlobal* Global) { + if (Global->Live) { + DEBUG(dbgs() << "AddDefinedGlobal: " << GlobalIndex << "\n"); + Global->setOutputIndex(GlobalIndex++); + DefinedGlobals.push_back(Global); + } + }; + + if (WasmSym::StackPointer) + AddDefinedGlobal(WasmSym::StackPointer->Global); + + for (ObjFile *File : Symtab->ObjectFiles) { + DEBUG(dbgs() << "Globals: " << File->getName() << "\n"); + for (InputGlobal *Global : File->Globals) + AddDefinedGlobal(Global); + } } static StringRef getOutputDataSegmentName(StringRef Name) { @@ -896,6 +905,7 @@ CtorFunction = llvm::make_unique( *Signature, BodyArray, WasmSym::CallCtors->getName()); CtorFunction->setOutputIndex(FunctionIndex); + CtorFunction->Live = true; WasmSym::CallCtors->Function = CtorFunction.get(); DefinedFunctions.emplace_back(CtorFunction.get()); } @@ -919,17 +929,6 @@ }); } -void Writer::createStackPointer(uint32_t Address) { - WasmInitExpr InitExpr; - InitExpr.Opcode = WASM_OPCODE_I32_CONST; - InitExpr.Value.Int32 = Address; - StackPtrGlobal = make_unique( - WasmSym::StackPointer->getGlobalType(), InitExpr); - StackPtrGlobal->setOutputIndex(NumImportedGlobals + DefinedGlobals.size()); - DefinedGlobals.emplace_back(StackPtrGlobal.get()); - WasmSym::StackPointer->Global = StackPtrGlobal.get(); -} - void Writer::run() { log("-- calculateImports"); calculateImports();