diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h --- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h @@ -21,6 +21,7 @@ #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" #include "llvm/ExecutionEngine/JITLink/MemoryFlags.h" #include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -402,10 +403,10 @@ friend class LinkGraph; private: - Symbol(Addressable &Base, orc::ExecutorAddrDiff Offset, StringRef Name, - orc::ExecutorAddrDiff Size, Linkage L, Scope S, bool IsLive, - bool IsCallable) - : Name(Name), Base(&Base), Offset(Offset), Size(Size) { + Symbol(Addressable &Base, orc::ExecutorAddrDiff Offset, + orc::SymbolStringPtr &&Name, orc::ExecutorAddrDiff Size, Linkage L, + Scope S, bool IsLive, bool IsCallable) + : Name(std::move(Name)), Base(&Base), Offset(Offset), Size(Size) { assert(Offset <= MaxOffset && "Offset out of range"); setLinkage(L); setScope(S); @@ -414,37 +415,42 @@ } static Symbol &constructCommon(BumpPtrAllocator &Allocator, Block &Base, - StringRef Name, orc::ExecutorAddrDiff Size, - Scope S, bool IsLive) { - assert(!Name.empty() && "Common symbol name cannot be empty"); + orc::SymbolStringPtr &&Name, + orc::ExecutorAddrDiff Size, Scope S, + bool IsLive) { + assert(Name && "Common symbol name cannot be empty"); assert(Base.isDefined() && "Cannot create common symbol from undefined block"); assert(static_cast(Base).getSize() == Size && "Common symbol size should match underlying block size"); auto *Sym = Allocator.Allocate(); - new (Sym) Symbol(Base, 0, Name, Size, Linkage::Weak, S, IsLive, false); + new (Sym) + Symbol(Base, 0, std::move(Name), Size, Linkage::Weak, S, IsLive, false); return *Sym; } static Symbol &constructExternal(BumpPtrAllocator &Allocator, - Addressable &Base, StringRef Name, + Addressable &Base, + orc::SymbolStringPtr &&Name, orc::ExecutorAddrDiff Size, Linkage L) { assert(!Base.isDefined() && "Cannot create external symbol from defined block"); - assert(!Name.empty() && "External symbol name cannot be empty"); + assert(Name && "External symbol name cannot be empty"); auto *Sym = Allocator.Allocate(); - new (Sym) Symbol(Base, 0, Name, Size, L, Scope::Default, false, false); + new (Sym) + Symbol(Base, 0, std::move(Name), Size, L, Scope::Default, false, false); return *Sym; } static Symbol &constructAbsolute(BumpPtrAllocator &Allocator, - Addressable &Base, StringRef Name, + Addressable &Base, + orc::SymbolStringPtr &&Name, orc::ExecutorAddrDiff Size, Linkage L, Scope S, bool IsLive) { assert(!Base.isDefined() && "Cannot create absolute symbol from a defined block"); auto *Sym = Allocator.Allocate(); - new (Sym) Symbol(Base, 0, Name, Size, L, S, IsLive, false); + new (Sym) Symbol(Base, 0, std::move(Name), Size, L, S, IsLive, false); return *Sym; } @@ -455,20 +461,22 @@ assert((Offset + Size) <= Base.getSize() && "Symbol extends past end of block"); auto *Sym = Allocator.Allocate(); - new (Sym) Symbol(Base, Offset, StringRef(), Size, Linkage::Strong, - Scope::Local, IsLive, IsCallable); + new (Sym) Symbol(Base, Offset, orc::SymbolStringPtr(nullptr), Size, + Linkage::Strong, Scope::Local, IsLive, IsCallable); return *Sym; } static Symbol &constructNamedDef(BumpPtrAllocator &Allocator, Block &Base, - orc::ExecutorAddrDiff Offset, StringRef Name, + orc::ExecutorAddrDiff Offset, + orc::SymbolStringPtr Name, orc::ExecutorAddrDiff Size, Linkage L, Scope S, bool IsLive, bool IsCallable) { assert((Offset + Size) <= Base.getSize() && "Symbol extends past end of block"); - assert(!Name.empty() && "Name cannot be empty"); + assert(Name && "Name cannot be empty"); auto *Sym = Allocator.Allocate(); - new (Sym) Symbol(Base, Offset, Name, Size, L, S, IsLive, IsCallable); + new (Sym) + Symbol(Base, Offset, std::move(Name), Size, L, S, IsLive, IsCallable); return *Sym; } @@ -485,18 +493,20 @@ Symbol &operator=(Symbol &&) = delete; /// Returns true if this symbol has a name. - bool hasName() const { return !Name.empty(); } + bool hasName() const { return Name != nullptr; } /// Returns the name of this symbol (empty if the symbol is anonymous). StringRef getName() const { - assert((!Name.empty() || getScope() == Scope::Local) && + assert((Name || getScope() == Scope::Local) && "Anonymous symbol has non-local scope"); - return Name; + if (!Name) + return StringRef(); + return *Name; } /// Rename this symbol. The client is responsible for updating scope and /// linkage if this name-change requires it. - void setName(StringRef Name) { this->Name = Name; } + void setName(orc::SymbolStringPtr &&Name) { this->Name = std::move(Name); } /// Returns true if this Symbol has content (potentially) defined within this /// object file (i.e. is anything but an external or absolute symbol). @@ -598,7 +608,7 @@ /// Set the linkage for this Symbol. void setLinkage(Linkage L) { - assert((L == Linkage::Strong || (!Base->isAbsolute() && !Name.empty())) && + assert((L == Linkage::Strong || (!Base->isAbsolute() && Name)) && "Linkage can only be applied to defined named symbols"); this->L = static_cast(L); } @@ -608,7 +618,7 @@ /// Set the visibility for this Symbol. void setScope(Scope S) { - assert((!Name.empty() || S == Scope::Local) && + assert((Name || S == Scope::Local) && "Can not set anonymous symbol to non-local scope"); assert((S == Scope::Default || Base->isDefined() || Base->isAbsolute()) && "Invalid visibility for symbol type"); @@ -642,8 +652,7 @@ static constexpr uint64_t MaxOffset = (1ULL << 59) - 1; - // FIXME: A char* or SymbolStringPtr may pack better. - StringRef Name; + orc::SymbolStringPtr Name; Addressable *Base = nullptr; uint64_t Offset : 59; uint64_t L : 1; @@ -946,12 +955,22 @@ support::endianness Endianness, GetEdgeKindNameFunction GetEdgeKindName) : Name(std::move(Name)), TT(TT), PointerSize(PointerSize), + Endianness(Endianness), GetEdgeKindName(std::move(GetEdgeKindName)) { + SSP = std::make_shared(); + } + + LinkGraph(std::string Name, std::shared_ptr SSP, + const Triple &TT, unsigned PointerSize, + support::endianness Endianness, + GetEdgeKindNameFunction GetEdgeKindName) + : Name(std::move(Name)), SSP(SSP), TT(TT), PointerSize(PointerSize), Endianness(Endianness), GetEdgeKindName(std::move(GetEdgeKindName)) {} LinkGraph(const LinkGraph &) = delete; LinkGraph &operator=(const LinkGraph &) = delete; LinkGraph(LinkGraph &&) = delete; LinkGraph &operator=(LinkGraph &&) = delete; + ~LinkGraph(); /// Returns the name of this graph (usually the name of the original /// underlying MemoryBuffer). @@ -968,6 +987,8 @@ const char *getEdgeKindName(Edge::Kind K) const { return GetEdgeKindName(K); } + std::shared_ptr getSymbolStringPool() { return SSP; } + /// Allocate a mutable buffer of the given size using the LinkGraph's /// allocator. MutableArrayRef allocateBuffer(size_t Size) { @@ -1087,9 +1108,10 @@ return Sym->getName() == Name; }) == 0 && "Duplicate external symbol"); + auto SSPName = SSP->intern(Name); auto &Sym = Symbol::constructExternal( - Allocator, createAddressable(orc::ExecutorAddr(), false), Name, Size, - L); + Allocator, createAddressable(orc::ExecutorAddr(), false), + std::move(SSPName), Size, L); ExternalSymbols.insert(&Sym); return Sym; } @@ -1103,8 +1125,10 @@ return Sym->getName() == Name; }) == 0) && "Duplicate absolute symbol"); - auto &Sym = Symbol::constructAbsolute(Allocator, createAddressable(Address), - Name, Size, L, S, IsLive); + auto SSPName = SSP->intern(Name); + auto &Sym = + Symbol::constructAbsolute(Allocator, createAddressable(Address), + std::move(SSPName), Size, L, S, IsLive); AbsoluteSymbols.insert(&Sym); return Sym; } @@ -1118,9 +1142,10 @@ return Sym->getName() == Name; }) == 0 && "Duplicate defined symbol"); + auto SSPName = SSP->intern(Name); auto &Sym = Symbol::constructCommon( - Allocator, createBlock(Section, Size, Address, Alignment, 0), Name, - Size, S, IsLive); + Allocator, createBlock(Section, Size, Address, Alignment, 0), + std::move(SSPName), Size, S, IsLive); Section.addSymbol(Sym); return Sym; } @@ -1139,13 +1164,16 @@ Symbol &addDefinedSymbol(Block &Content, orc::ExecutorAddrDiff Offset, StringRef Name, orc::ExecutorAddrDiff Size, Linkage L, Scope S, bool IsCallable, bool IsLive) { + auto SSPName = SSP->intern(Name); assert((S == Scope::Local || llvm::count_if(defined_symbols(), [&](const Symbol *Sym) { - return Sym->getName() == Name; + return Sym->getName() == + *SSPName; }) == 0) && "Duplicate defined symbol"); - auto &Sym = Symbol::constructNamedDef(Allocator, Content, Offset, Name, - Size, L, S, IsLive, IsCallable); + auto &Sym = Symbol::constructNamedDef(Allocator, Content, Offset, + std::move(SSPName), Size, L, S, + IsLive, IsCallable); Content.getSection().addSymbol(Sym); return Sym; } @@ -1413,6 +1441,7 @@ BumpPtrAllocator Allocator; std::string Name; + std::shared_ptr SSP; Triple TT; unsigned PointerSize; support::endianness Endianness; diff --git a/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h --- a/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h +++ b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.h @@ -46,7 +46,8 @@ const object::COFFObjectFile &getObject() const { return Obj; } virtual Error addRelocations() = 0; - virtual Symbol &createDLLImportEntry(StringRef StubName, Symbol &Target) = 0; + virtual Symbol &createDLLImportEntry(orc::SymbolStringPtr StubName, + Symbol &Target) = 0; Error graphifySections(); Error graphifySymbols(); diff --git a/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp --- a/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/COFFLinkGraphBuilder.cpp @@ -235,7 +235,8 @@ auto ExternalSym = createExternalSymbol( SymIndex, SymbolName.drop_front(getDLLImportStubPrefix().size()), *Sym, Sec); - GSym = &createDLLImportEntry(SymbolName, *ExternalSym); + auto SSPName = G->getSymbolStringPool()->intern(SymbolName); + GSym = &createDLLImportEntry(SSPName, *ExternalSym); } else GSym = createExternalSymbol(SymIndex, SymbolName, *Sym, Sec); } else if (Sym->isWeakExternal()) { diff --git a/llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp --- a/llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/COFF_x86_64.cpp @@ -62,9 +62,10 @@ return Error::success(); } - Symbol &createDLLImportEntry(StringRef StubName, Symbol &Target) override { + Symbol &createDLLImportEntry(orc::SymbolStringPtr StubName, + Symbol &Target) override { auto &Sym = DLLImportTable.getEntryForTarget(getGraph(), Target); - Sym.setName(StubName); + Sym.setName(std::move(StubName)); return Sym; } diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp --- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp @@ -147,6 +147,15 @@ B->~Block(); } +LinkGraph::~LinkGraph() { + for (auto *Sym : ExternalSymbols) { + Sym->~Symbol(); + } + for (auto *Sym : AbsoluteSymbols) { + Sym->~Symbol(); + } +} + Block &LinkGraph::splitBlock(Block &B, size_t SplitIndex, SplitBlockCache *Cache) { diff --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp --- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp @@ -59,8 +59,8 @@ // void *__dso_handle = &__dso_handle; auto G = std::make_unique( - "", TT, PointerSize, Endianness, - jitlink::getGenericEdgeKindName); + "", ENP.getExecutionSession().getSymbolStringPool(), TT, + PointerSize, Endianness, jitlink::getGenericEdgeKindName); auto &DSOHandleSection = G->createSection(".data.__dso_handle", jitlink::MemProt::Read); auto &DSOHandleBlock = G->createContentBlock( @@ -841,9 +841,13 @@ for (auto *Sym : G.external_symbols()) { if (Sym->getName() == "__tls_get_addr") { - Sym->setName("___orc_rt_elfnix_tls_get_addr"); + auto TLSGetAddr = + MP.getExecutionSession().intern("___orc_rt_elfnix_tls_get_addr"); + Sym->setName(std::move(TLSGetAddr)); } else if (Sym->getName() == "__tlsdesc_resolver") { - Sym->setName("___orc_rt_elfnix_tlsdesc_resolver"); + auto TLSGetAddr = + MP.getExecutionSession().intern("___orc_rt_elfnix_tlsdesc_resolver"); + Sym->setName(std::move(TLSGetAddr)); } } diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp --- a/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ExecutionUtils.cpp @@ -10,6 +10,7 @@ #include "llvm/ExecutionEngine/JITLink/x86_64.h" #include "llvm/ExecutionEngine/Orc/Layer.h" #include "llvm/ExecutionEngine/Orc/ObjectFileInterface.h" +#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" @@ -530,7 +531,8 @@ jitlink::x86_64::createAnonymousPointer(*G, Sec, &Target); auto NameCopy = G->allocateString(Twine(getImpPrefix()) + *KV.first); StringRef NameCopyRef = StringRef(NameCopy.data(), NameCopy.size()); - Ptr.setName(NameCopyRef); + auto SymbolName = G->getSymbolStringPool()->intern(NameCopyRef); + Ptr.setName(std::move(SymbolName)); Ptr.setLinkage(jitlink::Linkage::Strong); Ptr.setScope(jitlink::Scope::Default); diff --git a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp --- a/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp +++ b/llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp @@ -83,8 +83,8 @@ } auto G = std::make_unique( - "", TT, PointerSize, Endianness, - jitlink::getGenericEdgeKindName); + "", MOP.getExecutionSession().getSymbolStringPool(), TT, + PointerSize, Endianness, jitlink::getGenericEdgeKindName); auto &HeaderSection = G->createSection("__header", jitlink::MemProt::Read); auto &HeaderBlock = createHeaderBlock(*G, HeaderSection); @@ -812,7 +812,9 @@ // Rename external references to __tlv_bootstrap to ___orc_rt_tlv_get_addr. for (auto *Sym : G.external_symbols()) if (Sym->getName() == "__tlv_bootstrap") { - Sym->setName("___orc_rt_macho_tlv_get_addr"); + auto TLSGetADDR = + MP.getExecutionSession().intern("___orc_rt_macho_tlv_get_addr"); + Sym->setName(std::move(TLSGetADDR)); break; } diff --git a/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp --- a/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp +++ b/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp @@ -8,6 +8,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ExecutionEngine/JITLink/JITLink.h" +#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Memory.h" #include "gtest/gtest.h" @@ -68,6 +69,23 @@ EXPECT_TRUE(llvm::empty(G.absolute_symbols())); EXPECT_TRUE(llvm::empty(G.defined_symbols())); EXPECT_TRUE(llvm::empty(G.blocks())); + EXPECT_TRUE(G.getSymbolStringPool()); +} + +TEST(LinkGraphTest, ConstructionWithPool) { + auto SSP = std::make_shared(); + // Check that LinkGraph construction works as expected. + LinkGraph G("foo", SSP, Triple("x86_64-apple-darwin"), 8, support::little, + getGenericEdgeKindName); + EXPECT_EQ(G.getName(), "foo"); + EXPECT_EQ(G.getTargetTriple().str(), "x86_64-apple-darwin"); + EXPECT_EQ(G.getPointerSize(), 8U); + EXPECT_EQ(G.getEndianness(), support::little); + EXPECT_TRUE(llvm::empty(G.external_symbols())); + EXPECT_TRUE(llvm::empty(G.absolute_symbols())); + EXPECT_TRUE(llvm::empty(G.defined_symbols())); + EXPECT_TRUE(llvm::empty(G.blocks())); + EXPECT_EQ(&*G.getSymbolStringPool(), &*SSP); } TEST(LinkGraphTest, AddressAccess) { @@ -682,3 +700,17 @@ EXPECT_EQ(E2->getOffset(), 4U); } } + +TEST(LinkGraphTest, SymbolPoolSupport) { + // Check that we can get addresses for blocks, symbols, and edges. + LinkGraph G("foo", Triple("x86_64-apple-darwin"), 8, support::little, + getGenericEdgeKindName); + + auto &Sec1 = G.createSection("__data.1", MemProt::Read | MemProt::Write); + orc::ExecutorAddr B1Addr(0x1000); + auto &B1 = G.createContentBlock(Sec1, BlockContent, B1Addr, 8, 0); + auto &S1 = G.addDefinedSymbol(B1, 4, "S1", 4, Linkage::Strong, Scope::Default, + false, false); + auto SN1 = G.getSymbolStringPool()->intern("S1"); + ASSERT_EQ(S1.getName().bytes_begin(), (*SN1).bytes_begin()); +} \ No newline at end of file