Index: wasm/InputFiles.h =================================================================== --- wasm/InputFiles.h +++ wasm/InputFiles.h @@ -107,11 +107,13 @@ ArrayRef getSymbols() const { return Symbols; } - Symbol *getFunctionSymbol(uint32_t Index) const { - return FunctionSymbols[Index]; + FunctionSymbol *getFunctionSymbol(uint32_t Index) const { + return cast(FunctionSymbols[Index]); } - Symbol *getGlobalSymbol(uint32_t Index) const { return GlobalSymbols[Index]; } + GlobalSymbol *getGlobalSymbol(uint32_t Index) const { + return cast(GlobalSymbols[Index]); + } private: uint32_t relocateVirtualAddress(uint32_t Index) const; @@ -119,9 +121,9 @@ uint32_t relocateGlobalIndex(uint32_t Original) const; uint32_t relocateTableIndex(uint32_t Original) const; - Symbol *createDefined(const WasmSymbol &Sym, Symbol::Kind Kind, - InputChunk *Chunk = nullptr, - uint32_t Address = UINT32_MAX); + Symbol *createDefinedGlobal(const WasmSymbol &Sym, InputChunk *Chunk, + uint32_t Address); + Symbol *createDefinedFunction(const WasmSymbol &Sym, InputChunk *Chunk); Symbol *createUndefined(const WasmSymbol &Sym, Symbol::Kind Kind, const WasmSignature *Signature = nullptr); void initializeSymbols(); Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -51,11 +51,14 @@ } uint32_t ObjFile::relocateVirtualAddress(uint32_t GlobalIndex) const { - return getGlobalSymbol(GlobalIndex)->getVirtualAddress(); + if (auto *DG = dyn_cast(getGlobalSymbol(GlobalIndex))) + return DG->getVirtualAddress(); + else + return 0; } uint32_t ObjFile::relocateFunctionIndex(uint32_t Original) const { - const Symbol *Sym = getFunctionSymbol(Original); + const FunctionSymbol *Sym = getFunctionSymbol(Original); uint32_t Index = Sym->getOutputIndex(); DEBUG(dbgs() << "relocateFunctionIndex: " << toString(*Sym) << ": " << Original << " -> " << Index << "\n"); @@ -68,7 +71,7 @@ } uint32_t ObjFile::relocateTableIndex(uint32_t Original) const { - const Symbol *Sym = getFunctionSymbol(Original); + const FunctionSymbol *Sym = getFunctionSymbol(Original); uint32_t Index = Sym->hasTableIndex() ? Sym->getTableIndex() : 0; DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original << " -> " << Index << "\n"); @@ -249,7 +252,7 @@ case WasmSymbol::SymbolType::FUNCTION_EXPORT: { InputFunction *Function = getFunction(WasmSym); if (!isExcludedByComdat(Function)) { - S = createDefined(WasmSym, Symbol::Kind::DefinedFunctionKind, Function); + S = createDefinedFunction(WasmSym, Function); break; } else { Function->Live = false; @@ -263,8 +266,7 @@ case WasmSymbol::SymbolType::GLOBAL_EXPORT: { InputSegment *Segment = getSegment(WasmSym); if (!isExcludedByComdat(Segment)) { - S = createDefined(WasmSym, Symbol::Kind::DefinedGlobalKind, Segment, - getGlobalValue(WasmSym)); + S = createDefinedGlobal(WasmSym, Segment, getGlobalValue(WasmSym)); break; } else { Segment->Live = false; @@ -302,15 +304,18 @@ return Symtab->addUndefined(Sym.Name, Kind, Sym.Flags, this, Signature); } -Symbol *ObjFile::createDefined(const WasmSymbol &Sym, Symbol::Kind Kind, - InputChunk *Chunk, uint32_t Address) { - Symbol *S; - if (Sym.isBindingLocal()) { - S = make(Sym.Name, true); - S->update(Kind, this, Sym.Flags, Chunk, Address); - return S; - } - return Symtab->addDefined(Sym.Name, Kind, Sym.Flags, this, Chunk, Address); +Symbol *ObjFile::createDefinedFunction(const WasmSymbol &Sym, + InputChunk *Chunk) { + if (Sym.isBindingLocal()) + return make(Sym.Name, Sym.Flags, this, Chunk); + return Symtab->addDefined(true, Sym.Name, Sym.Flags, this, Chunk); +} + +Symbol *ObjFile::createDefinedGlobal(const WasmSymbol &Sym, InputChunk *Chunk, + uint32_t Address) { + if (Sym.isBindingLocal()) + return make(Sym.Name, Sym.Flags, this, Chunk, Address); + return Symtab->addDefined(false, Sym.Name, Sym.Flags, this, Chunk, Address); } void ArchiveFile::parse() { Index: wasm/SymbolTable.h =================================================================== --- wasm/SymbolTable.h +++ wasm/SymbolTable.h @@ -49,7 +49,7 @@ Symbol *find(StringRef Name); ObjFile *findComdat(StringRef Name) const; - Symbol *addDefined(StringRef Name, Symbol::Kind Kind, uint32_t Flags, + Symbol *addDefined(bool IsFunction, StringRef Name, uint32_t Flags, InputFile *F, InputChunk *Chunk = nullptr, uint32_t Address = 0); Symbol *addUndefined(StringRef Name, Symbol::Kind Kind, uint32_t Flags, @@ -58,9 +58,10 @@ void addLazy(ArchiveFile *F, const Archive::Symbol *Sym); bool addComdat(StringRef Name, ObjFile *); - Symbol *addSyntheticGlobal(StringRef Name); - Symbol *addSyntheticFunction(StringRef Name, const WasmSignature *Type, - uint32_t Flags); + DefinedGlobal *addSyntheticGlobal(StringRef Name, uint32_t Flags = 0); + DefinedFunction *addSyntheticFunction(StringRef Name, + const WasmSignature *Type, + uint32_t Flags = 0); private: std::pair insert(StringRef Name); Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -66,7 +66,7 @@ Symbol *&Sym = SymMap[CachedHashStringRef(Name)]; if (Sym) return {Sym, false}; - Sym = make(Name, false); + Sym = reinterpret_cast(make()); SymVector.emplace_back(Sym); return {Sym, true}; } @@ -80,13 +80,10 @@ // Check the type of new symbol matches that of the symbol is replacing. // For functions this can also involve verifying that the signatures match. static void checkSymbolTypes(const Symbol &Existing, const InputFile &F, - Symbol::Kind Kind, const WasmSignature *NewSig) { + bool NewIsFunction, const WasmSignature *NewSig) { if (Existing.isLazy()) return; - bool NewIsFunction = Kind == Symbol::Kind::UndefinedFunctionKind || - Kind == Symbol::Kind::DefinedFunctionKind; - // First check the symbol types match (i.e. either both are function // symbols or both are data symbols). if (Existing.isFunction() != NewIsFunction) { @@ -98,105 +95,102 @@ } // For function symbols, optionally check the function signature matches too. - if (!NewIsFunction || !Config->CheckSignatures) + auto *ExistingFunc = dyn_cast(&Existing); + if (!ExistingFunc || !Config->CheckSignatures) return; + // Skip the signature check if the existing function has no signature (e.g. // if it is an undefined symbol generated by --undefined command line flag). - if (!Existing.hasFunctionType()) + if (!ExistingFunc->hasFunctionType()) return; - DEBUG(dbgs() << "checkSymbolTypes: " << Existing.getName() << "\n"); + DEBUG(dbgs() << "checkSymbolTypes: " << ExistingFunc->getName() << "\n"); assert(NewSig); - const WasmSignature &OldSig = Existing.getFunctionType(); + const WasmSignature &OldSig = ExistingFunc->getFunctionType(); if (*NewSig == OldSig) return; - error("function signature mismatch: " + Existing.getName() + + error("function signature mismatch: " + ExistingFunc->getName() + "\n>>> defined as " + toString(OldSig) + " in " + - toString(Existing.getFile()) + "\n>>> defined as " + toString(*NewSig) + - " in " + F.getName()); + toString(ExistingFunc->getFile()) + "\n>>> defined as " + + toString(*NewSig) + " in " + F.getName()); } static void checkSymbolTypes(const Symbol &Existing, const InputFile &F, - Symbol::Kind Kind, const InputChunk *Chunk) { + bool IsFunction, const InputChunk *Chunk) { const WasmSignature *Sig = nullptr; if (auto *F = dyn_cast_or_null(Chunk)) Sig = &F->Signature; - return checkSymbolTypes(Existing, F, Kind, Sig); + return checkSymbolTypes(Existing, F, IsFunction, Sig); } -Symbol *SymbolTable::addSyntheticFunction(StringRef Name, - const WasmSignature *Type, - uint32_t Flags) { +DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name, + const WasmSignature *Type, + uint32_t Flags) { DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n"); Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); assert(WasInserted); - S->update(Symbol::DefinedFunctionKind, nullptr, Flags); - S->setFunctionType(Type); - return S; + return replaceSymbol(S, Name, Flags, Type); } -Symbol *SymbolTable::addSyntheticGlobal(StringRef Name) { +DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags) { DEBUG(dbgs() << "addSyntheticGlobal: " << Name << "\n"); Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); assert(WasInserted); - S->update(Symbol::DefinedGlobalKind); - return S; + return replaceSymbol(S, Name, Flags); } -Symbol *SymbolTable::addDefined(StringRef Name, Symbol::Kind Kind, - uint32_t Flags, InputFile *F, InputChunk *Chunk, +Symbol *SymbolTable::addDefined(bool IsFunction, StringRef Name, uint32_t Flags, + InputFile *F, InputChunk *Chunk, uint32_t Address) { - DEBUG(dbgs() << "addDefined: " << Name << " addr:" << Address << "\n"); + if (IsFunction) + DEBUG(dbgs() << "addDefined: func:" << Name << "\n"); + else + DEBUG(dbgs() << "addDefined: global:" << Name << " addr:" << Address + << "\n"); Symbol *S; bool WasInserted; + bool Replace = false; + bool CheckTypes = false; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { - S->update(Kind, F, Flags, Chunk, Address); + Replace = true; } else if (S->isLazy()) { - // The existing symbol is lazy. Replace it without checking types since + // Existing symbol is lazy. Replace it without checking types since // lazy symbols don't have any type information. DEBUG(dbgs() << "replacing existing lazy symbol: " << Name << "\n"); - S->update(Kind, F, Flags, Chunk, Address); + Replace = true; } else if (!S->isDefined()) { - // The existing symbol table entry is undefined. The new symbol replaces - // it, after checking the type matches + // Existing symbol is undefined: replace it, while check types. DEBUG(dbgs() << "resolving existing undefined symbol: " << Name << "\n"); - checkSymbolTypes(*S, *F, Kind, Chunk); - S->update(Kind, F, Flags, Chunk, Address); + Replace = true; + CheckTypes = true; } else if ((Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { // the new symbol is weak we can ignore it DEBUG(dbgs() << "existing symbol takes precedence\n"); } else if (S->isWeak()) { - // the new symbol is not weak and the existing symbol is, so we replace - // it + // the existing symbol is, so we replace it DEBUG(dbgs() << "replacing existing weak symbol\n"); - checkSymbolTypes(*S, *F, Kind, Chunk); - S->update(Kind, F, Flags, Chunk, Address); + Replace = true; + CheckTypes = true; } else { // neither symbol is week. They conflict. reportDuplicate(S, F); } - return S; -} -Symbol *SymbolTable::addUndefinedFunction(StringRef Name, - const WasmSignature *Type) { - DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n"); - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(Name); - if (WasInserted) { - S->update(Symbol::UndefinedFunctionKind); - S->setFunctionType(Type); - } else if (!S->isFunction()) { - error("symbol type mismatch: " + Name); + if (Replace) { + if (CheckTypes) + checkSymbolTypes(*S, *F, IsFunction, Chunk); + if (IsFunction) + replaceSymbol(S, Name, Flags, F, Chunk); + else + replaceSymbol(S, Name, Flags, F, Chunk, Address); } return S; } @@ -208,17 +202,19 @@ Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); + bool IsFunction = Kind == Symbol::UndefinedFunctionKind; if (WasInserted) { - S->update(Kind, F, Flags); - if (Type) - S->setFunctionType(Type); - } else if (S->isLazy()) { + if (IsFunction) + replaceSymbol(S, Name, Flags, F, Type); + else + replaceSymbol(S, Name, Flags, F); + } else if (auto *LazySym = dyn_cast(S)) { DEBUG(dbgs() << "resolved by existing lazy\n"); - auto *AF = cast(S->getFile()); - AF->addMember(&S->getArchiveSymbol()); + auto *AF = cast(LazySym->getFile()); + AF->addMember(&LazySym->getArchiveSymbol()); } else if (S->isDefined()) { DEBUG(dbgs() << "resolved by existing\n"); - checkSymbolTypes(*S, *F, Kind, Type); + checkSymbolTypes(*S, *F, IsFunction, Type); } return S; } @@ -230,8 +226,7 @@ bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { - S->update(Symbol::LazyKind, F); - S->setArchiveSymbol(*Sym); + replaceSymbol(S, Name, F, *Sym); } else if (S->isUndefined()) { // There is an existing undefined symbol. The can load from the // archive. Index: wasm/Symbols.h =================================================================== --- wasm/Symbols.h +++ wasm/Symbols.h @@ -23,6 +23,7 @@ class InputFile; class InputChunk; +// The base class for real symbol classes. class Symbol { public: enum Kind { @@ -37,9 +38,7 @@ InvalidKind, }; - Symbol(StringRef Name, uint32_t Flags) : Flags(Flags), Name(Name) {} - - Kind getKind() const { return SymbolKind; } + Kind kind() const { return static_cast(SymbolKind); } bool isLazy() const { return SymbolKind == LazyKind; } bool isDefined() const { return SymbolKind <= LastDefinedKind; } @@ -63,9 +62,6 @@ InputFile *getFile() const { return File; } InputChunk *getChunk() const { return Chunk; } - bool hasFunctionType() const { return FunctionType != nullptr; } - const WasmSignature &getFunctionType() const; - void setFunctionType(const WasmSignature *Type); void setHidden(bool IsHidden); uint32_t getOutputIndex() const; @@ -77,6 +73,28 @@ // space of the output object. void setOutputIndex(uint32_t Index); +protected: + Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, InputChunk *C) + : Name(Name), SymbolKind(K), Flags(Flags), File(F), Chunk(C) {} + + StringRef Name; + Kind SymbolKind; + uint32_t Flags; + InputFile *File; + InputChunk *Chunk; + llvm::Optional OutputIndex; +}; + +class FunctionSymbol : public Symbol { +public: + static bool classof(const Symbol *S) { + return S->kind() == DefinedFunctionKind || + S->kind() == UndefinedFunctionKind; + } + + bool hasFunctionType() const { return FunctionType != nullptr; } + const WasmSignature &getFunctionType() const; + uint32_t getTableIndex() const; // Returns true if a table index has been set for this symbol @@ -85,30 +103,99 @@ // Set the table index of the symbol void setTableIndex(uint32_t Index); - // Returns the virtual address of a defined global. - // Only works for globals, not functions. +protected: + void setFunctionType(const WasmSignature *Type); + + FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, + InputChunk *C) + : Symbol(Name, K, Flags, F, C) {} + + llvm::Optional TableIndex; + + // Explict function type, needed for undefined or synthetic functions only. + const WasmSignature *FunctionType = nullptr; +}; + +class DefinedFunction : public FunctionSymbol { +public: + DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F = nullptr, + InputChunk *C = nullptr) + : FunctionSymbol(Name, DefinedFunctionKind, Flags, F, C) {} + + DefinedFunction(StringRef Name, uint32_t Flags, const WasmSignature *Type) + : FunctionSymbol(Name, DefinedFunctionKind, Flags, nullptr, nullptr) { + setFunctionType(Type); + } + + static bool classof(const Symbol *S) { + return S->kind() == DefinedFunctionKind; + } +}; + +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); + } + + static bool classof(const Symbol *S) { + return S->kind() == UndefinedFunctionKind; + } +}; + +class GlobalSymbol : public Symbol { +public: + static bool classof(const Symbol *S) { + return S->kind() == DefinedGlobalKind || S->kind() == UndefinedGlobalKind; + } + +protected: + GlobalSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, + InputChunk *C) + : Symbol(Name, K, Flags, F, C) {} +}; + +class DefinedGlobal : public GlobalSymbol { +public: + DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *F = nullptr, + InputChunk *C = nullptr, uint32_t Address = 0) + : GlobalSymbol(Name, DefinedGlobalKind, Flags, F, C), + VirtualAddress(Address) {} + + static bool classof(const Symbol *S) { + return S->kind() == DefinedGlobalKind; + } + uint32_t getVirtualAddress() const; void setVirtualAddress(uint32_t VA); - void update(Kind K, InputFile *F = nullptr, uint32_t Flags = 0, - InputChunk *chunk = nullptr, uint32_t Address = UINT32_MAX); +protected: + uint32_t VirtualAddress; +}; + +class UndefinedGlobal : public GlobalSymbol { +public: + UndefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File = nullptr) + : GlobalSymbol(Name, UndefinedGlobalKind, Flags, File, nullptr) {} + static bool classof(const Symbol *S) { + return S->kind() == UndefinedGlobalKind; + } +}; + +class LazySymbol : public Symbol { +public: + LazySymbol(StringRef Name, InputFile *File, const Archive::Symbol &Sym) + : Symbol(Name, LazyKind, 0, File, nullptr), ArchiveSymbol(Sym) {} + + static bool classof(const Symbol *S) { return S->kind() == LazyKind; } - void setArchiveSymbol(const Archive::Symbol &Sym) { ArchiveSymbol = Sym; } const Archive::Symbol &getArchiveSymbol() { return ArchiveSymbol; } protected: - uint32_t Flags; - uint32_t VirtualAddress = 0; - - StringRef Name; - Archive::Symbol ArchiveSymbol = {nullptr, 0, 0}; - Kind SymbolKind = InvalidKind; - InputFile *File = nullptr; - InputChunk *Chunk = nullptr; - llvm::Optional OutputIndex; - llvm::Optional TableIndex; - const WasmSignature *FunctionType = nullptr; + Archive::Symbol ArchiveSymbol; }; // linker-generated symbols @@ -116,27 +203,50 @@ // __stack_pointer // Global that holds the address of the top of the explicit value stack in // linear memory. - static Symbol *StackPointer; + static DefinedGlobal *StackPointer; // __data_end // Symbol marking the end of the data and bss. - static Symbol *DataEnd; + static DefinedGlobal *DataEnd; // __heap_base // Symbol marking the end of the data, bss and explicit stack. Any linear // memory following this address is not used by the linked code and can // therefore be used as a backing store for brk()/malloc() implementations. - static Symbol *HeapBase; + static DefinedGlobal *HeapBase; // __wasm_call_ctors // Function that directly calls all ctors in priority order. - static Symbol *CallCtors; + static DefinedFunction *CallCtors; // __dso_handle // Global used in calls to __cxa_atexit to determine current DLL - static Symbol *DsoHandle; + static DefinedGlobal *DsoHandle; +}; + +// A buffer class that is large enough to hold any Symbol-derived +// object. We allocate memory using this class and instantiate a symbol +// using the placement new. +union SymbolUnion { + alignas(DefinedFunction) char A[sizeof(DefinedFunction)]; + alignas(DefinedGlobal) char B[sizeof(DefinedGlobal)]; + alignas(LazySymbol) char C[sizeof(LazySymbol)]; + alignas(UndefinedFunction) char D[sizeof(UndefinedFunction)]; + alignas(UndefinedGlobal) char E[sizeof(UndefinedFunction)]; }; +template +T *replaceSymbol(Symbol *S, ArgT &&... Arg) { + static_assert(std::is_trivially_destructible(), + "Symbol types must be trivially destructible"); + static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small"); + static_assert(alignof(T) <= alignof(SymbolUnion), + "SymbolUnion not aligned enough"); + assert(static_cast(static_cast(nullptr)) == nullptr && + "Not a Symbol"); + return new (S) T(std::forward(Arg)...); +} + } // namespace wasm // Returns a symbol name for an error message. Index: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -22,32 +22,11 @@ using namespace lld; using namespace lld::wasm; -Symbol *WasmSym::CallCtors; -Symbol *WasmSym::DsoHandle; -Symbol *WasmSym::DataEnd; -Symbol *WasmSym::HeapBase; -Symbol *WasmSym::StackPointer; - -const WasmSignature &Symbol::getFunctionType() const { - if (Chunk != nullptr) - return dyn_cast(Chunk)->Signature; - - assert(FunctionType != nullptr); - return *FunctionType; -} - -void Symbol::setFunctionType(const WasmSignature *Type) { - assert(FunctionType == nullptr); - assert(!Chunk); - FunctionType = Type; -} - -uint32_t Symbol::getVirtualAddress() const { - assert(isGlobal()); - DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n"); - return Chunk ? dyn_cast(Chunk)->translateVA(VirtualAddress) - : VirtualAddress; -} +DefinedFunction *WasmSym::CallCtors; +DefinedGlobal *WasmSym::DsoHandle; +DefinedGlobal *WasmSym::DataEnd; +DefinedGlobal *WasmSym::HeapBase; +DefinedGlobal *WasmSym::StackPointer; bool Symbol::hasOutputIndex() const { if (auto *F = dyn_cast_or_null(Chunk)) @@ -61,12 +40,6 @@ return OutputIndex.getValue(); } -void Symbol::setVirtualAddress(uint32_t Value) { - DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n"); - assert(isGlobal()); - VirtualAddress = Value; -} - void Symbol::setOutputIndex(uint32_t Index) { DEBUG(dbgs() << "setOutputIndex " << Name << " -> " << Index << "\n"); assert(!dyn_cast_or_null(Chunk)); @@ -74,19 +47,54 @@ OutputIndex = Index; } -uint32_t Symbol::getTableIndex() const { +bool Symbol::isWeak() const { + return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK; +} + +bool Symbol::isLocal() const { + return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL; +} + +bool Symbol::isHidden() const { + return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN; +} + +void Symbol::setHidden(bool IsHidden) { + DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n"); + Flags &= ~WASM_SYMBOL_VISIBILITY_MASK; + if (IsHidden) + Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN; + else + Flags |= WASM_SYMBOL_VISIBILITY_DEFAULT; +} + +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(); return TableIndex.getValue(); } -bool Symbol::hasTableIndex() const { +bool FunctionSymbol::hasTableIndex() const { if (auto *F = dyn_cast_or_null(Chunk)) return F->hasTableIndex(); return TableIndex.hasValue(); } -void Symbol::setTableIndex(uint32_t Index) { +void FunctionSymbol::setTableIndex(uint32_t Index) { // For imports, we set the table index here on the Symbol; for defined // functions we set the index on the InputFunction so that we don't export // the same thing twice (keeps the table size down). @@ -99,35 +107,17 @@ TableIndex = Index; } -void Symbol::update(Kind K, InputFile *F, uint32_t Flags_, InputChunk *Chunk_, - uint32_t Address) { - SymbolKind = K; - File = F; - Flags = Flags_; - Chunk = Chunk_; - if (Address != UINT32_MAX) - setVirtualAddress(Address); -} - -bool Symbol::isWeak() const { - return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK; -} - -bool Symbol::isLocal() const { - return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL; -} - -bool Symbol::isHidden() const { - return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN; +uint32_t DefinedGlobal::getVirtualAddress() const { + assert(isGlobal()); + DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n"); + return Chunk ? dyn_cast(Chunk)->translateVA(VirtualAddress) + : VirtualAddress; } -void Symbol::setHidden(bool IsHidden) { - DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n"); - Flags &= ~WASM_SYMBOL_VISIBILITY_MASK; - if (IsHidden) - Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN; - else - Flags |= WASM_SYMBOL_VISIBILITY_DEFAULT; +void DefinedGlobal::setVirtualAddress(uint32_t Value) { + DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n"); + assert(isGlobal()); + VirtualAddress = Value; } std::string lld::toString(const wasm::Symbol &Sym) { Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -119,12 +119,12 @@ std::vector Types; DenseMap TypeIndices; - std::vector ImportedFunctions; - std::vector ImportedGlobals; + std::vector ImportedFunctions; + std::vector ImportedGlobals; std::vector ExportedSymbols; - std::vector DefinedGlobals; + std::vector DefinedGlobals; std::vector DefinedFunctions; - std::vector IndirectFunctions; + std::vector IndirectFunctions; std::vector InitFunctions; // Elements that are used to construct the final output @@ -164,7 +164,7 @@ writeUleb128(OS, NumImports, "import count"); - for (const Symbol *Sym : ImportedFunctions) { + for (const FunctionSymbol *Sym : ImportedFunctions) { WasmImport Import; Import.Module = "env"; Import.Field = Sym->getName(); @@ -234,7 +234,7 @@ raw_ostream &OS = Section->getStream(); writeUleb128(OS, DefinedGlobals.size(), "global count"); - for (const Symbol *Sym : DefinedGlobals) { + for (const DefinedGlobal *Sym : DefinedGlobals) { WasmGlobal Global; Global.Type.Type = WASM_TYPE_I32; Global.Type.Mutable = Sym == WasmSym::StackPointer; @@ -316,7 +316,7 @@ writeUleb128(OS, IndirectFunctions.size(), "elem count"); uint32_t TableIndex = kInitialTableOffset; - for (const Symbol *Sym : IndirectFunctions) { + for (const FunctionSymbol *Sym : IndirectFunctions) { assert(Sym->getTableIndex() == TableIndex); writeUleb128(OS, Sym->getOutputIndex(), "function index"); ++TableIndex; @@ -619,12 +619,12 @@ if (!Sym->isUndefined() || (Sym->isWeak() && !Config->Relocatable)) continue; - if (Sym->isFunction()) { - Sym->setOutputIndex(ImportedFunctions.size()); - ImportedFunctions.push_back(Sym); - } else { - Sym->setOutputIndex(ImportedGlobals.size()); - ImportedGlobals.push_back(Sym); + if (auto *F = dyn_cast(Sym)) { + F->setOutputIndex(ImportedFunctions.size()); + ImportedFunctions.push_back(F); + } else if (auto *G = dyn_cast(Sym)) { + G->setOutputIndex(ImportedGlobals.size()); + ImportedGlobals.push_back(G); } } } @@ -712,7 +712,7 @@ File->TypeMap[I] = registerType(Types[I]); } - for (const Symbol *Sym : ImportedFunctions) + for (const FunctionSymbol *Sym : ImportedFunctions) registerType(Sym->getFunctionType()); for (const InputFunction *F : DefinedFunctions) @@ -723,7 +723,7 @@ uint32_t GlobalIndex = ImportedGlobals.size() + DefinedGlobals.size(); uint32_t FunctionIndex = ImportedFunctions.size() + DefinedFunctions.size(); - auto AddDefinedGlobal = [&](Symbol* Sym) { + auto AddDefinedGlobal = [&](DefinedGlobal *Sym) { if (Sym) { DefinedGlobals.emplace_back(Sym); Sym->setOutputIndex(GlobalIndex++); @@ -743,12 +743,10 @@ DEBUG(dbgs() << "Globals: " << File->getName() << "\n"); for (Symbol *Sym : File->getSymbols()) { // Create wasm globals for data symbols defined in this file - if (!Sym->isDefined() || File != Sym->getFile()) + if (File != Sym->getFile()) continue; - if (Sym->isFunction()) - continue; - - AddDefinedGlobal(Sym); + if (auto *G = dyn_cast(Sym)) + AddDefinedGlobal(G); } } } @@ -772,7 +770,7 @@ for (const WasmRelocation& Reloc : Chunk->getRelocations()) { if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32 || Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_SLEB) { - Symbol *Sym = File->getFunctionSymbol(Reloc.Index); + FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.Index); if (Sym->hasTableIndex() || !Sym->hasOutputIndex()) continue; Sym->setTableIndex(TableIndex++);