[llvm] Orc two towers draft PR (PR #152485)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 7 05:17:07 PDT 2025
https://github.com/sonar3d created https://github.com/llvm/llvm-project/pull/152485
None
>From 94f8fb63eb6c27886625531da4aa0b2bd8f45db5 Mon Sep 17 00:00:00 2001
From: Sona Reddy <sonareddy at hotmail.com>
Date: Thu, 7 Aug 2025 21:56:31 +1000
Subject: [PATCH 1/7] updated debug obj manager plugin cpp file
---
.../Orc/DebugObjectManagerPlugin.cpp | 459 +++---------------
1 file changed, 65 insertions(+), 394 deletions(-)
diff --git a/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp b/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp
index 15e583ca7685d..5203453041911 100644
--- a/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp
@@ -36,68 +36,6 @@ using namespace llvm::object;
namespace llvm {
namespace orc {
-class DebugObjectSection {
-public:
- virtual void setTargetMemoryRange(SectionRange Range) = 0;
- virtual void dump(raw_ostream &OS, StringRef Name) {}
- virtual ~DebugObjectSection() = default;
-};
-
-template <typename ELFT>
-class ELFDebugObjectSection : public DebugObjectSection {
-public:
- // BinaryFormat ELF is not meant as a mutable format. We can only make changes
- // that don't invalidate the file structure.
- ELFDebugObjectSection(const typename ELFT::Shdr *Header)
- : Header(const_cast<typename ELFT::Shdr *>(Header)) {}
-
- void setTargetMemoryRange(SectionRange Range) override;
- void dump(raw_ostream &OS, StringRef Name) override;
-
- Error validateInBounds(StringRef Buffer, const char *Name) const;
-
-private:
- typename ELFT::Shdr *Header;
-};
-
-template <typename ELFT>
-void ELFDebugObjectSection<ELFT>::setTargetMemoryRange(SectionRange Range) {
- // All recorded sections are candidates for load-address patching.
- Header->sh_addr =
- static_cast<typename ELFT::uint>(Range.getStart().getValue());
-}
-
-template <typename ELFT>
-Error ELFDebugObjectSection<ELFT>::validateInBounds(StringRef Buffer,
- const char *Name) const {
- const uint8_t *Start = Buffer.bytes_begin();
- const uint8_t *End = Buffer.bytes_end();
- const uint8_t *HeaderPtr = reinterpret_cast<uint8_t *>(Header);
- if (HeaderPtr < Start || HeaderPtr + sizeof(typename ELFT::Shdr) > End)
- return make_error<StringError>(
- formatv("{0} section header at {1:x16} not within bounds of the "
- "given debug object buffer [{2:x16} - {3:x16}]",
- Name, &Header->sh_addr, Start, End),
- inconvertibleErrorCode());
- if (Header->sh_offset + Header->sh_size > Buffer.size())
- return make_error<StringError>(
- formatv("{0} section data [{1:x16} - {2:x16}] not within bounds of "
- "the given debug object buffer [{3:x16} - {4:x16}]",
- Name, Start + Header->sh_offset,
- Start + Header->sh_offset + Header->sh_size, Start, End),
- inconvertibleErrorCode());
- return Error::success();
-}
-
-template <typename ELFT>
-void ELFDebugObjectSection<ELFT>::dump(raw_ostream &OS, StringRef Name) {
- if (uint64_t Addr = Header->sh_addr) {
- OS << formatv(" {0:x16} {1}\n", Addr, Name);
- } else {
- OS << formatv(" {0}\n", Name);
- }
-}
-
enum DebugObjectFlags : int {
// Request final target memory load-addresses for all sections.
ReportFinalSectionLoadAddresses = 1 << 0,
@@ -106,121 +44,6 @@ enum DebugObjectFlags : int {
HasDebugSections = 1 << 1,
};
-/// The plugin creates a debug object from when JITLink starts processing the
-/// corresponding LinkGraph. It provides access to the pass configuration of
-/// the LinkGraph and calls the finalization function, once the resulting link
-/// artifact was emitted.
-///
-class DebugObject {
-public:
- DebugObject(JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD,
- ExecutionSession &ES)
- : MemMgr(MemMgr), JD(JD), ES(ES), Flags(DebugObjectFlags{}) {}
-
- bool hasFlags(DebugObjectFlags F) const { return Flags & F; }
- void setFlags(DebugObjectFlags F) {
- Flags = static_cast<DebugObjectFlags>(Flags | F);
- }
- void clearFlags(DebugObjectFlags F) {
- Flags = static_cast<DebugObjectFlags>(Flags & ~F);
- }
-
- using FinalizeContinuation = std::function<void(Expected<ExecutorAddrRange>)>;
-
- void finalizeAsync(FinalizeContinuation OnFinalize);
-
- virtual ~DebugObject() {
- if (Alloc) {
- std::vector<FinalizedAlloc> Allocs;
- Allocs.push_back(std::move(Alloc));
- if (Error Err = MemMgr.deallocate(std::move(Allocs)))
- ES.reportError(std::move(Err));
- }
- }
-
- virtual void reportSectionTargetMemoryRange(StringRef Name,
- SectionRange TargetMem) {}
-
-protected:
- using InFlightAlloc = JITLinkMemoryManager::InFlightAlloc;
- using FinalizedAlloc = JITLinkMemoryManager::FinalizedAlloc;
-
- virtual Expected<SimpleSegmentAlloc> finalizeWorkingMemory() = 0;
-
- JITLinkMemoryManager &MemMgr;
- const JITLinkDylib *JD = nullptr;
- ExecutionSession &ES;
-
-private:
- DebugObjectFlags Flags;
- FinalizedAlloc Alloc;
-};
-
-// Finalize working memory and take ownership of the resulting allocation. Start
-// copying memory over to the target and pass on the result once we're done.
-// Ownership of the allocation remains with us for the rest of our lifetime.
-void DebugObject::finalizeAsync(FinalizeContinuation OnFinalize) {
- assert(!Alloc && "Cannot finalize more than once");
-
- if (auto SimpleSegAlloc = finalizeWorkingMemory()) {
- auto ROSeg = SimpleSegAlloc->getSegInfo(MemProt::Read);
- ExecutorAddrRange DebugObjRange(ROSeg.Addr, ROSeg.WorkingMem.size());
- SimpleSegAlloc->finalize(
- [this, DebugObjRange,
- OnFinalize = std::move(OnFinalize)](Expected<FinalizedAlloc> FA) {
- if (FA) {
- Alloc = std::move(*FA);
- OnFinalize(DebugObjRange);
- } else
- OnFinalize(FA.takeError());
- });
- } else
- OnFinalize(SimpleSegAlloc.takeError());
-}
-
-/// The current implementation of ELFDebugObject replicates the approach used in
-/// RuntimeDyld: It patches executable and data section headers in the given
-/// object buffer with load-addresses of their corresponding sections in target
-/// memory.
-///
-class ELFDebugObject : public DebugObject {
-public:
- static Expected<std::unique_ptr<DebugObject>>
- Create(MemoryBufferRef Buffer, JITLinkContext &Ctx, ExecutionSession &ES);
-
- void reportSectionTargetMemoryRange(StringRef Name,
- SectionRange TargetMem) override;
-
- StringRef getBuffer() const { return Buffer->getMemBufferRef().getBuffer(); }
-
-protected:
- Expected<SimpleSegmentAlloc> finalizeWorkingMemory() override;
-
- template <typename ELFT>
- Error recordSection(StringRef Name,
- std::unique_ptr<ELFDebugObjectSection<ELFT>> Section);
- DebugObjectSection *getSection(StringRef Name);
-
-private:
- template <typename ELFT>
- static Expected<std::unique_ptr<ELFDebugObject>>
- CreateArchType(MemoryBufferRef Buffer, JITLinkMemoryManager &MemMgr,
- const JITLinkDylib *JD, ExecutionSession &ES);
-
- static std::unique_ptr<WritableMemoryBuffer>
- CopyBuffer(MemoryBufferRef Buffer, Error &Err);
-
- ELFDebugObject(std::unique_ptr<WritableMemoryBuffer> Buffer,
- JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD,
- ExecutionSession &ES)
- : DebugObject(MemMgr, JD, ES), Buffer(std::move(Buffer)) {
- setFlags(ReportFinalSectionLoadAddresses);
- }
-
- std::unique_ptr<WritableMemoryBuffer> Buffer;
- StringMap<std::unique_ptr<DebugObjectSection>> Sections;
-};
-
static const std::set<StringRef> DwarfSectionNames = {
#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \
ELF_NAME,
@@ -232,43 +55,21 @@ static bool isDwarfSection(StringRef SectionName) {
return DwarfSectionNames.count(SectionName) == 1;
}
-std::unique_ptr<WritableMemoryBuffer>
-ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer, Error &Err) {
- ErrorAsOutParameter _(Err);
- size_t Size = Buffer.getBufferSize();
- StringRef Name = Buffer.getBufferIdentifier();
- if (auto Copy = WritableMemoryBuffer::getNewUninitMemBuffer(Size, Name)) {
- memcpy(Copy->getBufferStart(), Buffer.getBufferStart(), Size);
- return Copy;
- }
-
- Err = errorCodeToError(make_error_code(errc::not_enough_memory));
- return nullptr;
-}
-
-template <typename ELFT>
-Expected<std::unique_ptr<ELFDebugObject>>
-ELFDebugObject::CreateArchType(MemoryBufferRef Buffer,
- JITLinkMemoryManager &MemMgr,
- const JITLinkDylib *JD, ExecutionSession &ES) {
- using SectionHeader = typename ELFT::Shdr;
+template <typename ELFT> Error fixUp(StringRef Buffer, LinkGraph &LG) {
Error Err = Error::success();
- std::unique_ptr<ELFDebugObject> DebugObj(
- new ELFDebugObject(CopyBuffer(Buffer, Err), MemMgr, JD, ES));
- if (Err)
- return std::move(Err);
- Expected<ELFFile<ELFT>> ObjRef = ELFFile<ELFT>::create(DebugObj->getBuffer());
- if (!ObjRef)
- return ObjRef.takeError();
+ // TODO:replace debugObj
+ // Expected<ELFFile<ELFT>> Buffer = ELFFile<ELFT>::create(LG.g);
+ // if (!Buffer)
+ // return Buffer.takeError();
- Expected<ArrayRef<SectionHeader>> Sections = ObjRef->sections();
+ Expected<ArrayRef<SectionHeader>> Sections = Buffer->sections();
if (!Sections)
return Sections.takeError();
for (const SectionHeader &Header : *Sections) {
- Expected<StringRef> Name = ObjRef->getSectionName(Header);
+ Expected<StringRef> Name = Buffer->getSectionName(Header);
if (!Name)
return Name.takeError();
if (Name->empty())
@@ -283,108 +84,13 @@ ELFDebugObject::CreateArchType(MemoryBufferRef Buffer,
if (!(Header.sh_flags & ELF::SHF_ALLOC))
continue;
- auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header);
- if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped)))
- return std::move(Err);
- }
+ if (auto *GraphSec = LG.findSectionByName(*Name))
+ Header->sh_addr =
+ static_cast<typename ELFT::uint>(SectionRange(*GraphSec).getStart().getValue());
return std::move(DebugObj);
}
-Expected<std::unique_ptr<DebugObject>>
-ELFDebugObject::Create(MemoryBufferRef Buffer, JITLinkContext &Ctx,
- ExecutionSession &ES) {
- unsigned char Class, Endian;
- std::tie(Class, Endian) = getElfArchType(Buffer.getBuffer());
-
- if (Class == ELF::ELFCLASS32) {
- if (Endian == ELF::ELFDATA2LSB)
- return CreateArchType<ELF32LE>(Buffer, Ctx.getMemoryManager(),
- Ctx.getJITLinkDylib(), ES);
- if (Endian == ELF::ELFDATA2MSB)
- return CreateArchType<ELF32BE>(Buffer, Ctx.getMemoryManager(),
- Ctx.getJITLinkDylib(), ES);
- return nullptr;
- }
- if (Class == ELF::ELFCLASS64) {
- if (Endian == ELF::ELFDATA2LSB)
- return CreateArchType<ELF64LE>(Buffer, Ctx.getMemoryManager(),
- Ctx.getJITLinkDylib(), ES);
- if (Endian == ELF::ELFDATA2MSB)
- return CreateArchType<ELF64BE>(Buffer, Ctx.getMemoryManager(),
- Ctx.getJITLinkDylib(), ES);
- return nullptr;
- }
- return nullptr;
-}
-
-Expected<SimpleSegmentAlloc> ELFDebugObject::finalizeWorkingMemory() {
- LLVM_DEBUG({
- dbgs() << "Section load-addresses in debug object for \""
- << Buffer->getBufferIdentifier() << "\":\n";
- for (const auto &KV : Sections)
- KV.second->dump(dbgs(), KV.first());
- });
-
- // TODO: This works, but what actual alignment requirements do we have?
- unsigned PageSize = sys::Process::getPageSizeEstimate();
- size_t Size = Buffer->getBufferSize();
-
- // Allocate working memory for debug object in read-only segment.
- auto Alloc = SimpleSegmentAlloc::Create(
- MemMgr, ES.getSymbolStringPool(), ES.getTargetTriple(), JD,
- {{MemProt::Read, {Size, Align(PageSize)}}});
- if (!Alloc)
- return Alloc;
-
- // Initialize working memory with a copy of our object buffer.
- auto SegInfo = Alloc->getSegInfo(MemProt::Read);
- memcpy(SegInfo.WorkingMem.data(), Buffer->getBufferStart(), Size);
- Buffer.reset();
-
- return Alloc;
-}
-
-void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name,
- SectionRange TargetMem) {
- if (auto *DebugObjSection = getSection(Name))
- DebugObjSection->setTargetMemoryRange(TargetMem);
-}
-
-template <typename ELFT>
-Error ELFDebugObject::recordSection(
- StringRef Name, std::unique_ptr<ELFDebugObjectSection<ELFT>> Section) {
- if (Error Err = Section->validateInBounds(this->getBuffer(), Name.data()))
- return Err;
- bool Inserted = Sections.try_emplace(Name, std::move(Section)).second;
- if (!Inserted)
- LLVM_DEBUG(dbgs() << "Skipping debug registration for section '" << Name
- << "' in object " << Buffer->getBufferIdentifier()
- << " (duplicate name)\n");
- return Error::success();
-}
-
-DebugObjectSection *ELFDebugObject::getSection(StringRef Name) {
- auto It = Sections.find(Name);
- return It == Sections.end() ? nullptr : It->second.get();
-}
-
-/// Creates a debug object based on the input object file from
-/// ObjectLinkingLayerJITLinkContext.
-///
-static Expected<std::unique_ptr<DebugObject>>
-createDebugObjectFromBuffer(ExecutionSession &ES, LinkGraph &G,
- JITLinkContext &Ctx, MemoryBufferRef ObjBuffer) {
- switch (G.getTargetTriple().getObjectFormat()) {
- case Triple::ELF:
- return ELFDebugObject::Create(ObjBuffer, Ctx, ES);
-
- default:
- // TODO: Once we add support for other formats, we might want to split this
- // into multiple files.
- return nullptr;
- }
-}
DebugObjectManagerPlugin::DebugObjectManagerPlugin(
ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target,
@@ -399,119 +105,84 @@ DebugObjectManagerPlugin::DebugObjectManagerPlugin(
DebugObjectManagerPlugin::~DebugObjectManagerPlugin() = default;
-void DebugObjectManagerPlugin::notifyMaterializing(
- MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx,
- MemoryBufferRef ObjBuffer) {
- std::lock_guard<std::mutex> Lock(PendingObjsLock);
- assert(PendingObjs.count(&MR) == 0 &&
- "Cannot have more than one pending debug object per "
- "MaterializationResponsibility");
-
- if (auto DebugObj = createDebugObjectFromBuffer(ES, G, Ctx, ObjBuffer)) {
- // Not all link artifacts allow debugging.
- if (*DebugObj == nullptr)
- return;
- if (RequireDebugSections && !(**DebugObj).hasFlags(HasDebugSections)) {
- LLVM_DEBUG(dbgs() << "Skipping debug registration for LinkGraph '"
- << G.getName() << "': no debug info\n");
- return;
- }
- PendingObjs[&MR] = std::move(*DebugObj);
- } else {
- ES.reportError(DebugObj.takeError());
+void fixUpDebugObject(LinkGraph &LG) {
+ auto *DebugObjSec = LG.getOriginalObjectContentSection();
+ assert(DebugObjSec && "No ELF debug object section?");
+ assert(DebugObjSec.blocks_size() == 1 && "ELF debug object contains multiple blocks?");
+ auto DebugObjContent = (*DebugObjSec.blocks_begin())->getAlreadyMutableContent();
+
+ // StringRef DebugObj(DebugObjContent.data(), DebugObjContent.size());
+
+ unsigned char Class, Endian;
+ std::tie(Class, Endian) = getElfArchType(DebugObjContent);
+ if (Class == ELF::ELFCLASS32) {
+ if (Endian == ELF::ELFDATA2LSB)
+ return fixUp<ELF32LE>(DebugObjContent, LG);
+ else if (Endian == ELF::ELFDATA2MSB)
+ return fixUp<ELF32BE>(DebugObjContent, LG);
+ } else if (Class == ELF::ELFCLASS64) {
+ if (Endian == ELF::ELFDATA2LSB)
+ return fixUp<ELF64LE>(DebugObjContent, LG);
+ else if (Endian == ELF::ELFDATA2MSB)
+ return fixUp<ELF64BE>(DebugObjContent, LG);
}
-}
+ // Unsupported combo. Remove the debug object section.
+ LG.removeSection(*DebugObjSec);
+ LLVM_DEBUG({
+ dbgs() << "Can't emit debug object for " << LG.getName()
+ << ": Unsupported ELF class / endianness.\n";
+ });
+ return Error::success();
+}
-void DebugObjectManagerPlugin::modifyPassConfig(
- MaterializationResponsibility &MR, LinkGraph &G,
- PassConfiguration &PassConfig) {
+void DebugObjectManagerPlugin::modifyPassConfig(MaterializationResponsibility &MR,
+ jitlink::LinkGraph &LG,
+ jitlink::PassConfiguration &PassConfig) {
// Not all link artifacts have associated debug objects.
- std::lock_guard<std::mutex> Lock(PendingObjsLock);
+ // std::lock_guard<std::mutex> Lock(PendingObjsLock);
auto It = PendingObjs.find(&MR);
if (It == PendingObjs.end())
return;
- DebugObject &DebugObj = *It->second;
- if (DebugObj.hasFlags(ReportFinalSectionLoadAddresses)) {
+ PassConfig.PrePrunePasses.push_back([](LinkGraph &LG) -> Error {
+
+ // Copy existing object content into the new debug object section
+ auto DebugObjContent = LG.getOriginalObjectContentSection();
+ // Create new debug section in LinkGraph
+
+ // Memory protection for reading graph
+ orc::MemProt Prot = MemProt::Read;
+ // Create debug section
+ LG.createSection(DebugObjContent, Prot);
+
+ return Error::success();
+ });
+
+ if (DebugObjContent.hasFlags(ReportFinalSectionLoadAddresses)) {
+ // patch up the addresses in the debug object
PassConfig.PostAllocationPasses.push_back(
- [&DebugObj](LinkGraph &Graph) -> Error {
- for (const Section &GraphSection : Graph.sections())
- DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(),
+ [&DebugObjContent](LinkGraph &LG) -> Error {
+ for (const Section &GraphSection : LG.sections())
+ DebugObjContent.reportSectionTargetMemoryRange(GraphSection.getName(),
SectionRange(GraphSection));
+ fixUpDebugObject(LG)
return Error::success();
});
}
}
-Error DebugObjectManagerPlugin::notifyEmitted(
- MaterializationResponsibility &MR) {
- std::lock_guard<std::mutex> Lock(PendingObjsLock);
- auto It = PendingObjs.find(&MR);
- if (It == PendingObjs.end())
- return Error::success();
-
- // During finalization the debug object is registered with the target.
- // Materialization must wait for this process to finish. Otherwise we might
- // start running code before the debugger processed the corresponding debug
- // info.
- std::promise<MSVCPError> FinalizePromise;
- std::future<MSVCPError> FinalizeErr = FinalizePromise.get_future();
-
- It->second->finalizeAsync(
- [this, &FinalizePromise, &MR](Expected<ExecutorAddrRange> TargetMem) {
- // Any failure here will fail materialization.
- if (!TargetMem) {
- FinalizePromise.set_value(TargetMem.takeError());
- return;
- }
- if (Error Err =
- Target->registerDebugObject(*TargetMem, AutoRegisterCode)) {
- FinalizePromise.set_value(std::move(Err));
- return;
- }
-
- // Once our tracking info is updated, notifyEmitted() can return and
- // finish materialization.
- FinalizePromise.set_value(MR.withResourceKeyDo([&](ResourceKey K) {
- assert(PendingObjs.count(&MR) && "We still hold PendingObjsLock");
- std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
- auto It = PendingObjs.find(&MR);
- RegisteredObjs[K].push_back(std::move(It->second));
- PendingObjs.erase(It);
- }));
- });
-
- return FinalizeErr.get();
-}
-
Error DebugObjectManagerPlugin::notifyFailed(
MaterializationResponsibility &MR) {
- std::lock_guard<std::mutex> Lock(PendingObjsLock);
+ // std::lock_guard<std::mutex> Lock(PendingObjsLock);
PendingObjs.erase(&MR);
return Error::success();
}
-void DebugObjectManagerPlugin::notifyTransferringResources(JITDylib &JD,
- ResourceKey DstKey,
- ResourceKey SrcKey) {
- // Debug objects are stored by ResourceKey only after registration.
- // Thus, pending objects don't need to be updated here.
- std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
- auto SrcIt = RegisteredObjs.find(SrcKey);
- if (SrcIt != RegisteredObjs.end()) {
- // Resources from distinct MaterializationResponsibilitys can get merged
- // after emission, so we can have multiple debug objects per resource key.
- for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second)
- RegisteredObjs[DstKey].push_back(std::move(DebugObj));
- RegisteredObjs.erase(SrcIt);
- }
-}
-
Error DebugObjectManagerPlugin::notifyRemovingResources(JITDylib &JD,
ResourceKey Key) {
// Removing the resource for a pending object fails materialization, so they
// get cleaned up in the notifyFailed() handler.
- std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
+ // std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
RegisteredObjs.erase(Key);
// TODO: Implement unregister notifications.
@@ -519,4 +190,4 @@ Error DebugObjectManagerPlugin::notifyRemovingResources(JITDylib &JD,
}
} // namespace orc
-} // namespace llvm
+} // namespace llvm
\ No newline at end of file
>From 7be63051e1b4a187347803d148bbebcc77f95fb1 Mon Sep 17 00:00:00 2001
From: Sona Reddy <sonareddy at hotmail.com>
Date: Thu, 7 Aug 2025 22:00:34 +1000
Subject: [PATCH 2/7] link graph linking layer cpp
---
.../Orc/LinkGraphLinkingLayer.cpp | 29 ++++++++++---------
1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/ExecutionEngine/Orc/LinkGraphLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/LinkGraphLinkingLayer.cpp
index d1a6eaf914a78..32e57b2a61dce 100644
--- a/llvm/lib/ExecutionEngine/Orc/LinkGraphLinkingLayer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/LinkGraphLinkingLayer.cpp
@@ -64,13 +64,6 @@ class LinkGraphLinkingLayer::JITLinkCtx final : public JITLinkContext {
JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; }
- void notifyMaterializing(LinkGraph &G) {
- for (auto &P : Plugins)
- P->notifyMaterializing(*MR, G, *this,
- ObjBuffer ? ObjBuffer->getMemBufferRef()
- : MemoryBufferRef());
- }
-
void notifyFailed(Error Err) override {
for (auto &P : Plugins)
Err = joinErrors(std::move(Err), P->notifyFailed(*MR));
@@ -108,7 +101,8 @@ class LinkGraphLinkingLayer::JITLinkCtx final : public JITLinkContext {
LookupContinuation->run(Result.takeError());
else {
AsyncLookupResult LR;
- LR.insert_range(*Result);
+ for (auto &KV : *Result)
+ LR[KV.first] = KV.second;
LookupContinuation->run(std::move(LR));
}
};
@@ -207,6 +201,7 @@ class LinkGraphLinkingLayer::JITLinkCtx final : public JITLinkContext {
if (auto Err = MR->notifyResolved(InternedResult))
return Err;
+ notifyLoaded();
return Error::success();
}
@@ -243,6 +238,11 @@ class LinkGraphLinkingLayer::JITLinkCtx final : public JITLinkContext {
return Error::success();
}
+ void notifyLoaded() {
+ for (auto &P : Plugins)
+ P->notifyLoaded(*MR);
+ }
+
Error notifyEmitted(jitlink::JITLinkMemoryManager::FinalizedAlloc FA) {
Error Err = Error::success();
for (auto &P : Plugins)
@@ -389,13 +389,16 @@ class LinkGraphLinkingLayer::JITLinkCtx final : public JITLinkContext {
for (auto *FB : BI.AnonEdges) {
auto &FBI = BlockInfos[FB];
- FBI.AnonBackEdges.insert_range(BI.AnonBackEdges);
+ for (auto *BB : BI.AnonBackEdges)
+ FBI.AnonBackEdges.insert(BB);
}
for (auto *BB : BI.AnonBackEdges) {
auto &BBI = BlockInfos[BB];
- BBI.SymbolDeps.insert_range(BI.SymbolDeps);
- BBI.AnonEdges.insert_range(BI.AnonEdges);
+ for (auto *SD : BI.SymbolDeps)
+ BBI.SymbolDeps.insert(SD);
+ for (auto *FB : BI.AnonEdges)
+ BBI.AnonEdges.insert(FB);
}
}
@@ -502,7 +505,6 @@ void LinkGraphLinkingLayer::emit(
assert(R && "R must not be null");
assert(G && "G must not be null");
auto Ctx = std::make_unique<JITLinkCtx>(*this, std::move(R), nullptr);
- Ctx->notifyMaterializing(*G);
link(std::move(G), std::move(Ctx));
}
@@ -514,7 +516,6 @@ void LinkGraphLinkingLayer::emit(
assert(ObjBuf && "Object must not be null");
auto Ctx =
std::make_unique<JITLinkCtx>(*this, std::move(R), std::move(ObjBuf));
- Ctx->notifyMaterializing(*G);
link(std::move(G), std::move(Ctx));
}
@@ -575,4 +576,4 @@ void LinkGraphLinkingLayer::handleTransferResources(JITDylib &JD,
}
} // End namespace orc.
-} // End namespace llvm.
+} // End namespace llvm.
\ No newline at end of file
>From d315e38533f7623abe998fb8f9920f4fa3018d03 Mon Sep 17 00:00:00 2001
From: Sona Reddy <sonareddy at hotmail.com>
Date: Thu, 7 Aug 2025 22:02:40 +1000
Subject: [PATCH 3/7] object linking layer cpp
---
.../Orc/ObjectLinkingLayer.cpp | 745 +++++++++++++++++-
1 file changed, 738 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
index 9bc0aa89c3533..3da46d97d3568 100644
--- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
@@ -12,7 +12,592 @@
#define DEBUG_TYPE "orc"
-namespace llvm::orc {
+using namespace llvm;
+using namespace llvm::jitlink;
+using namespace llvm::orc;
+
+namespace {
+
+bool hasInitializerSection(jitlink::LinkGraph &LG) {
+ bool IsMachO = LG.getTargetTriple().isOSBinFormatMachO();
+ bool IsElf = LG.getTargetTriple().isOSBinFormatELF();
+ if (!IsMachO && !IsElf)
+ return false;
+
+ for (auto &Sec : LG.sections()) {
+ if (IsMachO && isMachOInitializerSection(Sec.getName()))
+ return true;
+ if (IsElf && isELFInitializerSection(Sec.getName()))
+ return true;
+ }
+
+ return false;
+}
+
+ExecutorAddr getJITSymbolPtrForSymbol(Symbol &Sym, const Triple &TT) {
+ switch (TT.getArch()) {
+ case Triple::arm:
+ case Triple::armeb:
+ case Triple::thumb:
+ case Triple::thumbeb:
+ if (hasTargetFlags(Sym, aarch32::ThumbSymbol)) {
+ // Set LSB to indicate thumb target
+ assert(Sym.isCallable() && "Only callable symbols can have thumb flag");
+ assert((Sym.getAddress().getValue() & 0x01) == 0 && "LSB is clear");
+ return Sym.getAddress() + 0x01;
+ }
+ return Sym.getAddress();
+ default:
+ return Sym.getAddress();
+ }
+}
+
+JITSymbolFlags getJITSymbolFlagsForSymbol(Symbol &Sym) {
+ JITSymbolFlags Flags;
+
+ if (Sym.getLinkage() == Linkage::Weak)
+ Flags |= JITSymbolFlags::Weak;
+
+ if (Sym.getScope() == Scope::Default)
+ Flags |= JITSymbolFlags::Exported;
+
+ if (Sym.isCallable())
+ Flags |= JITSymbolFlags::Callable;
+
+ return Flags;
+}
+
+class LinkGraphMaterializationUnit : public MaterializationUnit {
+public:
+ static std::unique_ptr<LinkGraphMaterializationUnit>
+ Create(ObjectLinkingLayer &ObjLinkingLayer, std::unique_ptr<LinkGraph> G) {
+ auto LGI = scanLinkGraph(ObjLinkingLayer.getExecutionSession(), *G);
+ return std::unique_ptr<LinkGraphMaterializationUnit>(
+ new LinkGraphMaterializationUnit(ObjLinkingLayer, std::move(G),
+ std::move(LGI)));
+ }
+
+ StringRef getName() const override { return G->getName(); }
+ void materialize(std::unique_ptr<MaterializationResponsibility> MR) override {
+ ObjLinkingLayer.emit(std::move(MR), std::move(G));
+ }
+
+private:
+ static Interface scanLinkGraph(ExecutionSession &ES, LinkGraph &LG) {
+
+ Interface LGI;
+
+ auto AddSymbol = [&](Symbol *Sym) {
+ // Skip local symbols.
+ if (Sym->getScope() == Scope::Local)
+ return;
+ assert(Sym->hasName() && "Anonymous non-local symbol?");
+
+ LGI.SymbolFlags[ES.intern(Sym->getName())] =
+ getJITSymbolFlagsForSymbol(*Sym);
+ };
+
+ for (auto *Sym : LG.defined_symbols())
+ AddSymbol(Sym);
+ for (auto *Sym : LG.absolute_symbols())
+ AddSymbol(Sym);
+
+ if (hasInitializerSection(LG))
+ LGI.InitSymbol = makeInitSymbol(ES, LG);
+
+ return LGI;
+ }
+
+ static SymbolStringPtr makeInitSymbol(ExecutionSession &ES, LinkGraph &LG) {
+ std::string InitSymString;
+ raw_string_ostream(InitSymString)
+ << "$." << LG.getName() << ".__inits" << Counter++;
+ return ES.intern(InitSymString);
+ }
+
+ LinkGraphMaterializationUnit(ObjectLinkingLayer &ObjLinkingLayer,
+ std::unique_ptr<LinkGraph> G, Interface LGI)
+ : MaterializationUnit(std::move(LGI)), ObjLinkingLayer(ObjLinkingLayer),
+ G(std::move(G)) {}
+
+ void discard(const JITDylib &JD, const SymbolStringPtr &Name) override {
+ for (auto *Sym : G->defined_symbols())
+ if (Sym->getName() == *Name) {
+ assert(Sym->getLinkage() == Linkage::Weak &&
+ "Discarding non-weak definition");
+ G->makeExternal(*Sym);
+ break;
+ }
+ }
+
+ ObjectLinkingLayer &ObjLinkingLayer;
+ std::unique_ptr<LinkGraph> G;
+ static std::atomic<uint64_t> Counter;
+};
+
+std::atomic<uint64_t> LinkGraphMaterializationUnit::Counter{0};
+
+} // end anonymous namespace
+
+namespace llvm {
+namespace orc {
+
+class ObjectLinkingLayerJITLinkContext final : public JITLinkContext {
+public:
+ ObjectLinkingLayerJITLinkContext(
+ ObjectLinkingLayer &Layer,
+ std::unique_ptr<MaterializationResponsibility> MR,
+ std::unique_ptr<MemoryBuffer> ObjBuffer)
+ : JITLinkContext(&MR->getTargetJITDylib()), Layer(Layer),
+ MR(std::move(MR)), ObjBuffer(std::move(ObjBuffer)) {
+ std::lock_guard<std::mutex> Lock(Layer.LayerMutex);
+ Plugins = Layer.Plugins;
+ }
+
+ ~ObjectLinkingLayerJITLinkContext() {
+ // If there is an object buffer return function then use it to
+ // return ownership of the buffer.
+ if (Layer.ReturnObjectBuffer && ObjBuffer)
+ Layer.ReturnObjectBuffer(std::move(ObjBuffer));
+ }
+
+ JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; }
+
+ // void notifyMaterializing(LinkGraph &G) {
+ // for (auto &P : Plugins)
+ // P->notifyMaterializing(*MR, G, *this,
+ // ObjBuffer ? ObjBuffer->getMemBufferRef()
+ // : MemoryBufferRef());
+ // }
+
+
+ void notifyFailed(Error Err) override {
+ for (auto &P : Plugins)
+ Err = joinErrors(std::move(Err), P->notifyFailed(*MR));
+ Layer.getExecutionSession().reportError(std::move(Err));
+ MR->failMaterialization();
+ }
+
+ void lookup(const LookupMap &Symbols,
+ std::unique_ptr<JITLinkAsyncLookupContinuation> LC) override {
+
+ JITDylibSearchOrder LinkOrder;
+ MR->getTargetJITDylib().withLinkOrderDo(
+ [&](const JITDylibSearchOrder &LO) { LinkOrder = LO; });
+
+ auto &ES = Layer.getExecutionSession();
+
+ SymbolLookupSet LookupSet;
+ for (auto &KV : Symbols) {
+ orc::SymbolLookupFlags LookupFlags;
+ switch (KV.second) {
+ case jitlink::SymbolLookupFlags::RequiredSymbol:
+ LookupFlags = orc::SymbolLookupFlags::RequiredSymbol;
+ break;
+ case jitlink::SymbolLookupFlags::WeaklyReferencedSymbol:
+ LookupFlags = orc::SymbolLookupFlags::WeaklyReferencedSymbol;
+ break;
+ }
+ LookupSet.add(ES.intern(KV.first), LookupFlags);
+ }
+
+ // OnResolve -- De-intern the symbols and pass the result to the linker.
+ auto OnResolve = [LookupContinuation =
+ std::move(LC)](Expected<SymbolMap> Result) mutable {
+ if (!Result)
+ LookupContinuation->run(Result.takeError());
+ else {
+ AsyncLookupResult LR;
+ for (auto &KV : *Result)
+ LR[*KV.first] = KV.second;
+ LookupContinuation->run(std::move(LR));
+ }
+ };
+
+ ES.lookup(LookupKind::Static, LinkOrder, std::move(LookupSet),
+ SymbolState::Resolved, std::move(OnResolve),
+ [this](const SymbolDependenceMap &Deps) {
+ // Translate LookupDeps map to SymbolSourceJD.
+ for (auto &[DepJD, Deps] : Deps)
+ for (auto &DepSym : Deps)
+ SymbolSourceJDs[NonOwningSymbolStringPtr(DepSym)] = DepJD;
+ });
+ }
+
+ Error notifyResolved(LinkGraph &G) override {
+ auto &ES = Layer.getExecutionSession();
+
+ SymbolFlagsMap ExtraSymbolsToClaim;
+ bool AutoClaim = Layer.AutoClaimObjectSymbols;
+
+ SymbolMap InternedResult;
+ for (auto *Sym : G.defined_symbols())
+ if (Sym->hasName() && Sym->getScope() != Scope::Local) {
+ auto InternedName = ES.intern(Sym->getName());
+ auto Ptr = getJITSymbolPtrForSymbol(*Sym, G.getTargetTriple());
+ auto Flags = getJITSymbolFlagsForSymbol(*Sym);
+ InternedResult[InternedName] = {Ptr, Flags};
+ if (AutoClaim && !MR->getSymbols().count(InternedName)) {
+ assert(!ExtraSymbolsToClaim.count(InternedName) &&
+ "Duplicate symbol to claim?");
+ ExtraSymbolsToClaim[InternedName] = Flags;
+ }
+ }
+
+ for (auto *Sym : G.absolute_symbols())
+ if (Sym->hasName() && Sym->getScope() != Scope::Local) {
+ auto InternedName = ES.intern(Sym->getName());
+ auto Ptr = getJITSymbolPtrForSymbol(*Sym, G.getTargetTriple());
+ auto Flags = getJITSymbolFlagsForSymbol(*Sym);
+ InternedResult[InternedName] = {Ptr, Flags};
+ if (AutoClaim && !MR->getSymbols().count(InternedName)) {
+ assert(!ExtraSymbolsToClaim.count(InternedName) &&
+ "Duplicate symbol to claim?");
+ ExtraSymbolsToClaim[InternedName] = Flags;
+ }
+ }
+
+ if (!ExtraSymbolsToClaim.empty())
+ if (auto Err = MR->defineMaterializing(ExtraSymbolsToClaim))
+ return Err;
+
+ {
+
+ // Check that InternedResult matches up with MR->getSymbols(), overriding
+ // flags if requested.
+ // This guards against faulty transformations / compilers / object caches.
+
+ // First check that there aren't any missing symbols.
+ size_t NumMaterializationSideEffectsOnlySymbols = 0;
+ SymbolNameVector MissingSymbols;
+ for (auto &[Sym, Flags] : MR->getSymbols()) {
+
+ auto I = InternedResult.find(Sym);
+
+ // If this is a materialization-side-effects only symbol then bump
+ // the counter and remove in from the result, otherwise make sure that
+ // it's defined.
+ if (Flags.hasMaterializationSideEffectsOnly()) {
+ ++NumMaterializationSideEffectsOnlySymbols;
+ InternedResult.erase(Sym);
+ continue;
+ } else if (I == InternedResult.end())
+ MissingSymbols.push_back(Sym);
+ else if (Layer.OverrideObjectFlags)
+ I->second.setFlags(Flags);
+ }
+
+ // If there were missing symbols then report the error.
+ if (!MissingSymbols.empty())
+ return make_error<MissingSymbolDefinitions>(
+ Layer.getExecutionSession().getSymbolStringPool(), G.getName(),
+ std::move(MissingSymbols));
+
+ // If there are more definitions than expected, add them to the
+ // ExtraSymbols vector.
+ SymbolNameVector ExtraSymbols;
+ if (InternedResult.size() >
+ MR->getSymbols().size() - NumMaterializationSideEffectsOnlySymbols) {
+ for (auto &KV : InternedResult)
+ if (!MR->getSymbols().count(KV.first))
+ ExtraSymbols.push_back(KV.first);
+ }
+
+ // If there were extra definitions then report the error.
+ if (!ExtraSymbols.empty())
+ return make_error<UnexpectedSymbolDefinitions>(
+ Layer.getExecutionSession().getSymbolStringPool(), G.getName(),
+ std::move(ExtraSymbols));
+ }
+
+ if (auto Err = MR->notifyResolved(InternedResult))
+ return Err;
+
+ notifyLoaded();
+ return Error::success();
+ }
+
+ void notifyFinalized(JITLinkMemoryManager::FinalizedAlloc A) override {
+ if (auto Err = notifyEmitted(std::move(A))) {
+ Layer.getExecutionSession().reportError(std::move(Err));
+ MR->failMaterialization();
+ return;
+ }
+
+ if (auto Err = MR->notifyEmitted(SymbolDepGroups)) {
+ Layer.getExecutionSession().reportError(std::move(Err));
+ MR->failMaterialization();
+ }
+ }
+
+ LinkGraphPassFunction getMarkLivePass(const Triple &TT) const override {
+ return [this](LinkGraph &LG) { return markResponsibilitySymbolsLive(LG); };
+ }
+
+ Error modifyPassConfig(LinkGraph &LG, PassConfiguration &Config) override {
+ // Add passes to mark duplicate defs as should-discard, and to walk the
+ // link graph to build the symbol dependence graph.
+ Config.PrePrunePasses.push_back([this](LinkGraph &G) {
+ return claimOrExternalizeWeakAndCommonSymbols(G);
+ });
+
+ for (auto &P : Plugins)
+ P->modifyPassConfig(*MR, LG, Config);
+
+ Config.PreFixupPasses.push_back(
+ [this](LinkGraph &G) { return registerDependencies(G); });
+
+ return Error::success();
+ }
+
+ void notifyLoaded() {
+ for (auto &P : Plugins)
+ P->notifyLoaded(*MR);
+ }
+
+ Error notifyEmitted(jitlink::JITLinkMemoryManager::FinalizedAlloc FA) {
+ Error Err = Error::success();
+ for (auto &P : Plugins)
+ Err = joinErrors(std::move(Err), P->notifyEmitted(*MR));
+
+ if (Err) {
+ if (FA)
+ Err =
+ joinErrors(std::move(Err), Layer.MemMgr.deallocate(std::move(FA)));
+ return Err;
+ }
+
+ if (FA)
+ return Layer.recordFinalizedAlloc(*MR, std::move(FA));
+
+ return Error::success();
+ }
+
+private:
+ Error claimOrExternalizeWeakAndCommonSymbols(LinkGraph &G) {
+ auto &ES = Layer.getExecutionSession();
+
+ SymbolFlagsMap NewSymbolsToClaim;
+ std::vector<std::pair<SymbolStringPtr, Symbol *>> NameToSym;
+
+ auto ProcessSymbol = [&](Symbol *Sym) {
+ if (Sym->hasName() && Sym->getLinkage() == Linkage::Weak &&
+ Sym->getScope() != Scope::Local) {
+ auto Name = ES.intern(Sym->getName());
+ if (!MR->getSymbols().count(ES.intern(Sym->getName()))) {
+ NewSymbolsToClaim[Name] =
+ getJITSymbolFlagsForSymbol(*Sym) | JITSymbolFlags::Weak;
+ NameToSym.push_back(std::make_pair(std::move(Name), Sym));
+ }
+ }
+ };
+
+ for (auto *Sym : G.defined_symbols())
+ ProcessSymbol(Sym);
+ for (auto *Sym : G.absolute_symbols())
+ ProcessSymbol(Sym);
+
+ // Attempt to claim all weak defs that we're not already responsible for.
+ // This may fail if the resource tracker has become defunct, but should
+ // always succeed otherwise.
+ if (auto Err = MR->defineMaterializing(std::move(NewSymbolsToClaim)))
+ return Err;
+
+ // Walk the list of symbols that we just tried to claim. Symbols that we're
+ // responsible for are marked live. Symbols that we're not responsible for
+ // are turned into external references.
+ for (auto &KV : NameToSym) {
+ if (MR->getSymbols().count(KV.first))
+ KV.second->setLive(true);
+ else
+ G.makeExternal(*KV.second);
+ }
+
+ return Error::success();
+ }
+
+ Error markResponsibilitySymbolsLive(LinkGraph &G) const {
+ auto &ES = Layer.getExecutionSession();
+ for (auto *Sym : G.defined_symbols())
+ if (Sym->hasName() && MR->getSymbols().count(ES.intern(Sym->getName())))
+ Sym->setLive(true);
+ return Error::success();
+ }
+
+ Error registerDependencies(LinkGraph &G) {
+
+ struct BlockInfo {
+ bool InWorklist = false;
+ DenseSet<Symbol *> Defs;
+ DenseSet<Symbol *> SymbolDeps;
+ DenseSet<Block *> AnonEdges, AnonBackEdges;
+ };
+
+ DenseMap<Block *, BlockInfo> BlockInfos;
+
+ // Reserve space so that BlockInfos doesn't need to resize. This is
+ // essential to avoid invalidating pointers to entries below.
+ {
+ size_t NumBlocks = 0;
+ for (auto &Sec : G.sections())
+ NumBlocks += Sec.blocks_size();
+ BlockInfos.reserve(NumBlocks);
+ }
+
+ // Identify non-locally-scoped symbols defined by each block.
+ for (auto *Sym : G.defined_symbols()) {
+ if (Sym->getScope() != Scope::Local)
+ BlockInfos[&Sym->getBlock()].Defs.insert(Sym);
+ }
+
+ // Identify the symbolic and anonymous-block dependencies for each block.
+ for (auto *B : G.blocks()) {
+ auto &BI = BlockInfos[B];
+
+ for (auto &E : B->edges()) {
+
+ // External symbols are trivially depended on.
+ if (E.getTarget().isExternal()) {
+ BI.SymbolDeps.insert(&E.getTarget());
+ continue;
+ }
+
+ // Anonymous symbols aren't depended on at all (they're assumed to be
+ // already available).
+ if (E.getTarget().isAbsolute())
+ continue;
+
+ // If we get here then we depend on a symbol defined by some other
+ // block.
+ auto &TgtBI = BlockInfos[&E.getTarget().getBlock()];
+
+ // If that block has any definitions then use the first one as the
+ // "effective" dependence here (all symbols in TgtBI will become
+ // ready at the same time, and chosing a single symbol to represent
+ // the block keeps the SymbolDepGroup size small).
+ if (!TgtBI.Defs.empty()) {
+ BI.SymbolDeps.insert(*TgtBI.Defs.begin());
+ continue;
+ }
+
+ // Otherwise we've got a dependence on an anonymous block. Record it
+ // here for back-propagating symbol dependencies below.
+ BI.AnonEdges.insert(&E.getTarget().getBlock());
+ TgtBI.AnonBackEdges.insert(B);
+ }
+ }
+
+ // Prune anonymous blocks.
+ {
+ std::vector<Block *> BlocksToRemove;
+ for (auto &[B, BI] : BlockInfos) {
+ // Skip blocks with defs. We only care about anonyous blocks.
+ if (!BI.Defs.empty())
+ continue;
+
+ BlocksToRemove.push_back(B);
+
+ for (auto *FB : BI.AnonEdges)
+ BlockInfos[FB].AnonBackEdges.erase(B);
+
+ for (auto *BB : BI.AnonBackEdges)
+ BlockInfos[BB].AnonEdges.erase(B);
+
+ for (auto *FB : BI.AnonEdges) {
+ auto &FBI = BlockInfos[FB];
+ for (auto *BB : BI.AnonBackEdges)
+ FBI.AnonBackEdges.insert(BB);
+ }
+
+ for (auto *BB : BI.AnonBackEdges) {
+ auto &BBI = BlockInfos[BB];
+ for (auto *SD : BI.SymbolDeps)
+ BBI.SymbolDeps.insert(SD);
+ for (auto *FB : BI.AnonEdges)
+ BBI.AnonEdges.insert(FB);
+ }
+ }
+
+ for (auto *B : BlocksToRemove)
+ BlockInfos.erase(B);
+ }
+
+ // Build the initial dependence propagation worklist.
+ std::deque<Block *> Worklist;
+ for (auto &[B, BI] : BlockInfos) {
+ if (!BI.SymbolDeps.empty() && !BI.AnonBackEdges.empty()) {
+ Worklist.push_back(B);
+ BI.InWorklist = true;
+ }
+ }
+
+ // Propagate symbol deps through the graph.
+ while (!Worklist.empty()) {
+ auto *B = Worklist.front();
+ Worklist.pop_front();
+
+ auto &BI = BlockInfos[B];
+ BI.InWorklist = false;
+
+ for (auto *DB : BI.AnonBackEdges) {
+ auto &DBI = BlockInfos[DB];
+ for (auto *Sym : BI.SymbolDeps) {
+ if (DBI.SymbolDeps.insert(Sym).second && !DBI.InWorklist) {
+ Worklist.push_back(DB);
+ DBI.InWorklist = true;
+ }
+ }
+ }
+ }
+
+ // Transform our local dependence information into a list of
+ // SymbolDependenceGroups (in the SymbolDepGroups member), ready for use in
+ // the upcoming notifyFinalized call.
+ auto &TargetJD = MR->getTargetJITDylib();
+ auto &ES = TargetJD.getExecutionSession();
+
+ DenseMap<Symbol *, SymbolStringPtr> InternedNames;
+ auto GetInternedName = [&](Symbol *S) {
+ auto &Name = InternedNames[S];
+ if (!Name)
+ Name = ES.intern(S->getName());
+ return Name;
+ };
+
+ for (auto &[B, BI] : BlockInfos) {
+ if (!BI.Defs.empty()) {
+ SymbolDepGroups.push_back(SymbolDependenceGroup());
+ auto &SDG = SymbolDepGroups.back();
+
+ for (auto *Def : BI.Defs)
+ SDG.Symbols.insert(GetInternedName(Def));
+
+ for (auto *Dep : BI.SymbolDeps) {
+ auto DepName = GetInternedName(Dep);
+ if (Dep->isDefined())
+ SDG.Dependencies[&TargetJD].insert(std::move(DepName));
+ else {
+ auto SourceJDItr =
+ SymbolSourceJDs.find(NonOwningSymbolStringPtr(DepName));
+ if (SourceJDItr != SymbolSourceJDs.end())
+ SDG.Dependencies[SourceJDItr->second].insert(std::move(DepName));
+ }
+ }
+ }
+ }
+
+ return Error::success();
+ }
+
+ ObjectLinkingLayer &Layer;
+ std::vector<std::shared_ptr<ObjectLinkingLayer::Plugin>> Plugins;
+ std::unique_ptr<MaterializationResponsibility> MR;
+ std::unique_ptr<MemoryBuffer> ObjBuffer;
+ DenseMap<NonOwningSymbolStringPtr, JITDylib *> SymbolSourceJDs;
+ std::vector<SymbolDependenceGroup> SymbolDepGroups;
+};
+
+ObjectLinkingLayer::Plugin::~Plugin() = default;
char ObjectLinkingLayer::ID;
@@ -21,14 +606,160 @@ void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
assert(O && "Object must not be null");
MemoryBufferRef ObjBuffer = O->getMemBufferRef();
- if (auto G = jitlink::createLinkGraphFromObject(
- ObjBuffer, getExecutionSession().getSymbolStringPool())) {
- emit(std::move(R), std::move(*G), std::move(O));
+ auto Ctx = std::make_unique<ObjectLinkingLayerJITLinkContext>(
+ *this, std::move(R), std::move(O));
+
+ if (auto G = createLinkGraphFromObject(ObjBuffer)) {
+ // Ctx->notifyMaterializing(**G);
+ link(std::move(*G), std::move(Ctx));
} else {
- R->getExecutionSession().reportError(G.takeError());
- R->failMaterialization();
+ Ctx->notifyFailed(G.takeError());
+ }
+}
+
+void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
+ std::unique_ptr<LinkGraph> G) {
+ auto Ctx = std::make_unique<ObjectLinkingLayerJITLinkContext>(
+ *this, std::move(R), nullptr);
+ // Ctx->notifyMaterializing(*G);
+ link(std::move(G), std::move(Ctx));
+}
+
+Error ObjectLinkingLayer::recordFinalizedAlloc(
+ MaterializationResponsibility &MR, FinalizedAlloc FA) {
+ auto Err = MR.withResourceKeyDo(
+ [&](ResourceKey K) { Allocs[K].push_back(std::move(FA)); });
+
+ if (Err)
+ Err = joinErrors(std::move(Err), MemMgr.deallocate(std::move(FA)));
+
+ return Err;
+}
+
+Error ObjectLinkingLayer::handleRemoveResources(JITDylib &JD, ResourceKey K) {
+
+ {
+ Error Err = Error::success();
+ for (auto &P : Plugins)
+ Err = joinErrors(std::move(Err), P->notifyRemovingResources(JD, K));
+ if (Err)
+ return Err;
+ }
+
+ std::vector<FinalizedAlloc> AllocsToRemove;
+ getExecutionSession().runSessionLocked([&] {
+ auto I = Allocs.find(K);
+ if (I != Allocs.end()) {
+ std::swap(AllocsToRemove, I->second);
+ Allocs.erase(I);
+ }
+ });
+
+ if (AllocsToRemove.empty())
+ return Error::success();
+
+ return MemMgr.deallocate(std::move(AllocsToRemove));
+}
+
+void ObjectLinkingLayer::handleTransferResources(JITDylib &JD,
+ ResourceKey DstKey,
+ ResourceKey SrcKey) {
+ auto I = Allocs.find(SrcKey);
+ if (I != Allocs.end()) {
+ auto &SrcAllocs = I->second;
+ auto &DstAllocs = Allocs[DstKey];
+ DstAllocs.reserve(DstAllocs.size() + SrcAllocs.size());
+ for (auto &Alloc : SrcAllocs)
+ DstAllocs.push_back(std::move(Alloc));
+
+ // Erase SrcKey entry using value rather than iterator I: I may have been
+ // invalidated when we looked up DstKey.
+ Allocs.erase(SrcKey);
+ }
+
+ for (auto &P : Plugins)
+ P->notifyTransferringResources(JD, DstKey, SrcKey);
+}
+
+EHFrameRegistrationPlugin::EHFrameRegistrationPlugin(
+ ExecutionSession &ES, std::unique_ptr<EHFrameRegistrar> Registrar)
+ : ES(ES), Registrar(std::move(Registrar)) {}
+
+void EHFrameRegistrationPlugin::modifyPassConfig(
+ MaterializationResponsibility &MR, LinkGraph &G,
+ PassConfiguration &PassConfig) {
+
+ PassConfig.PostFixupPasses.push_back(createEHFrameRecorderPass(
+ G.getTargetTriple(), [this, &MR](ExecutorAddr Addr, size_t Size) {
+ if (Addr) {
+ std::lock_guard<std::mutex> Lock(EHFramePluginMutex);
+ assert(!InProcessLinks.count(&MR) &&
+ "Link for MR already being tracked?");
+ InProcessLinks[&MR] = {Addr, Size};
+ }
+ }));
+}
+
+Error EHFrameRegistrationPlugin::notifyEmitted(
+ MaterializationResponsibility &MR) {
+
+ ExecutorAddrRange EmittedRange;
+ {
+ std::lock_guard<std::mutex> Lock(EHFramePluginMutex);
+
+ auto EHFrameRangeItr = InProcessLinks.find(&MR);
+ if (EHFrameRangeItr == InProcessLinks.end())
+ return Error::success();
+
+ EmittedRange = EHFrameRangeItr->second;
+ assert(EmittedRange.Start && "eh-frame addr to register can not be null");
+ InProcessLinks.erase(EHFrameRangeItr);
+ }
+
+ if (auto Err = MR.withResourceKeyDo(
+ [&](ResourceKey K) { EHFrameRanges[K].push_back(EmittedRange); }))
+ return Err;
+
+ return Registrar->registerEHFrames(EmittedRange);
+}
+
+Error EHFrameRegistrationPlugin::notifyFailed(
+ MaterializationResponsibility &MR) {
+ std::lock_guard<std::mutex> Lock(EHFramePluginMutex);
+ InProcessLinks.erase(&MR);
+ return Error::success();
+}
+
+Error EHFrameRegistrationPlugin::notifyRemovingResources(JITDylib &JD,
+ ResourceKey K) {
+ std::vector<ExecutorAddrRange> RangesToRemove;
+
+ ES.runSessionLocked([&] {
+ auto I = EHFrameRanges.find(K);
+ if (I != EHFrameRanges.end()) {
+ RangesToRemove = std::move(I->second);
+ EHFrameRanges.erase(I);
+ }
+ });
+
+ Error Err = Error::success();
+ while (!RangesToRemove.empty()) {
+ auto RangeToRemove = RangesToRemove.back();
+ RangesToRemove.pop_back();
+ assert(RangeToRemove.Start && "Untracked eh-frame range must not be null");
+ Err = joinErrors(std::move(Err),
+ Registrar->deregisterEHFrames(RangeToRemove));
+ }
+
+ return Err;
+}
+
+void EHFrameRegistrationPlugin::notifyTransferringResources(
+ JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) {
+ auto SI = EHFrameRanges.find(SrcKey);
+ if (SI == EHFrameRanges.end())
return;
}
}
-} // namespace llvm::orc
+} // namespace llvm::orc
\ No newline at end of file
>From 73dcbf20835718e81c46349fce6a9c70ec0f501c Mon Sep 17 00:00:00 2001
From: Sona Reddy <sonareddy at hotmail.com>
Date: Thu, 7 Aug 2025 22:08:46 +1000
Subject: [PATCH 4/7] elf linkgraph builder cpp
---
llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.cpp | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.cpp
index e081f47ca42fd..d5caac4aa3da5 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.cpp
@@ -9,25 +9,21 @@
// Generic ELF LinkGraph building code.
//
//===----------------------------------------------------------------------===//
-
#include "ELFLinkGraphBuilder.h"
-
#define DEBUG_TYPE "jitlink"
-
static const char *DWSecNames[] = {
#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \
ELF_NAME,
#include "llvm/BinaryFormat/Dwarf.def"
#undef HANDLE_DWARF_SECTION
};
-
namespace llvm {
namespace jitlink {
-
StringRef ELFLinkGraphBuilderBase::CommonSectionName(".common");
ArrayRef<const char *> ELFLinkGraphBuilderBase::DwarfSectionNames = DWSecNames;
ELFLinkGraphBuilderBase::~ELFLinkGraphBuilderBase() = default;
+
} // end namespace jitlink
-} // end namespace llvm
+} // end namespace llvm
\ No newline at end of file
>From 871d0ee6ad144c929fa3d5f88d2d2b5c13bced78 Mon Sep 17 00:00:00 2001
From: Sona Reddy <sonareddy at hotmail.com>
Date: Thu, 7 Aug 2025 22:09:18 +1000
Subject: [PATCH 5/7] elf linkgraph builder h
---
.../lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h
index 8dd176cd07f92..9d4411ff9b7ee 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h
+++ b/llvm/lib/ExecutionEngine/JITLink/ELFLinkGraphBuilder.h
@@ -42,13 +42,22 @@ class ELFLinkGraphBuilderBase {
return *CommonSection;
}
+ Section &getOriginalObjectContentSection() {
+ if (!OriginalObjectContentSection)
+ OriginalObjectContentSection = &G->createSection(
+ OriginalObjectContentSectionName, orc::MemProt::Read | orc::MemProt::Write);
+ return *OriginalObjectContentSection;
+ }
+
std::unique_ptr<LinkGraph> G;
private:
static StringRef CommonSectionName;
+ static StringRef OriginalObjectContentSectionName;
static ArrayRef<const char *> DwarfSectionNames;
Section *CommonSection = nullptr;
+ Section *OriginalObjectContentSection = nullptr;
};
/// LinkGraph building code that's specific to the given ELFT, but common
@@ -696,4 +705,4 @@ Error ELFLinkGraphBuilder<ELFT>::forEachRelRelocation(
#undef DEBUG_TYPE
-#endif // LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H
+#endif // LIB_EXECUTIONENGINE_JITLINK_ELFLINKGRAPHBUILDER_H
\ No newline at end of file
>From 58e4c7521bce953fc9dddca10692abed33ea4a89 Mon Sep 17 00:00:00 2001
From: Sona Reddy <sonareddy at hotmail.com>
Date: Thu, 7 Aug 2025 22:11:53 +1000
Subject: [PATCH 6/7] updated debug obj manager plugin h include file
---
.../Orc/DebugObjectManagerPlugin.h | 55 ++++++-------------
1 file changed, 17 insertions(+), 38 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h b/llvm/include/llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h
index 254b897bca614..20ae0ab96ff21 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h
@@ -15,24 +15,12 @@
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
#include "llvm/ExecutionEngine/Orc/Core.h"
-#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
-#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
-#include "llvm/Support/Compiler.h"
+#include "llvm/ExecutionEngine/Orc/LinkGraphLinkingLayer.h"
#include "llvm/Support/Error.h"
-#include "llvm/Support/Memory.h"
-#include "llvm/Support/MemoryBufferRef.h"
-#include "llvm/TargetParser/Triple.h"
-
-#include <functional>
-#include <map>
-#include <memory>
-#include <mutex>
namespace llvm {
namespace orc {
-class DebugObject;
-
/// Creates and manages DebugObjects for JITLink artifacts.
///
/// DebugObjects are created when linking for a MaterializationResponsibility
@@ -46,11 +34,10 @@ class DebugObject;
/// DebugObjectRegistrar is notified. Ownership of DebugObjects remains with the
/// plugin.
///
-class LLVM_ABI DebugObjectManagerPlugin : public ObjectLinkingLayer::Plugin {
+class DebugObjectManagerPlugin : public LinkGraphLinkingLayer::Plugin {
public:
// DEPRECATED - Please specify options explicitly
- DebugObjectManagerPlugin(ExecutionSession &ES,
- std::unique_ptr<DebugObjectRegistrar> Target);
+ DebugObjectManagerPlugin(ExecutionSession &ES);
/// Create the plugin to submit DebugObjects for JITLink artifacts. For all
/// options the recommended setting is true.
@@ -67,42 +54,34 @@ class LLVM_ABI DebugObjectManagerPlugin : public ObjectLinkingLayer::Plugin {
/// sequence. When turning this off, the user has to issue the call to
/// __jit_debug_register_code() on the executor side manually.
///
- DebugObjectManagerPlugin(ExecutionSession &ES,
- std::unique_ptr<DebugObjectRegistrar> Target,
+ DebugObjectManagerPlugin(ExecutorSymbolDef RegisterDebugObject,
+ ExecutorSymbolDef DeregisterDebugObject,
bool RequireDebugSections, bool AutoRegisterCode);
~DebugObjectManagerPlugin();
- void notifyMaterializing(MaterializationResponsibility &MR,
- jitlink::LinkGraph &G, jitlink::JITLinkContext &Ctx,
- MemoryBufferRef InputObject) override;
+ Error fixUpDebugObject(jitlink::LinkGraph &LG);
+
+ Error notifyFailed(MaterializationResponsibility &MR) override {
+ return Error::success();
+ }
- Error notifyEmitted(MaterializationResponsibility &MR) override;
- Error notifyFailed(MaterializationResponsibility &MR) override;
- Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override;
+ Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
+ return Error::success();
+ }
void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
- ResourceKey SrcKey) override;
+ ResourceKey SrcKey) override {}
void modifyPassConfig(MaterializationResponsibility &MR,
jitlink::LinkGraph &LG,
jitlink::PassConfiguration &PassConfig) override;
private:
- ExecutionSession &ES;
-
- using OwnedDebugObject = std::unique_ptr<DebugObject>;
- std::map<MaterializationResponsibility *, OwnedDebugObject> PendingObjs;
- std::map<ResourceKey, std::vector<OwnedDebugObject>> RegisteredObjs;
-
- std::mutex PendingObjsLock;
- std::mutex RegisteredObjsLock;
-
- std::unique_ptr<DebugObjectRegistrar> Target;
- bool RequireDebugSections;
- bool AutoRegisterCode;
+ ExecutorSymbolDef RegisterDebugObject;
+ ExecutorSymbolDef DeregisterDebugObject;
};
} // namespace orc
} // namespace llvm
-#endif // LLVM_EXECUTIONENGINE_ORC_DEBUGOBJECTMANAGERPLUGIN_H
+#endif // LLVM_EXECUTIONENGINE_ORC_DEBUGOBJECTMANAGERPLUGIN_H
\ No newline at end of file
>From 3f25854b1efacbc26d34fe82404e124b30f82a2c Mon Sep 17 00:00:00 2001
From: Sona Reddy <sonareddy at hotmail.com>
Date: Thu, 7 Aug 2025 22:12:38 +1000
Subject: [PATCH 7/7] updated link graph linking layer h include file
---
.../ExecutionEngine/Orc/LinkGraphLinkingLayer.h | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/LinkGraphLinkingLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/LinkGraphLinkingLayer.h
index d3643f9301134..1fe4ae6ff9102 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/LinkGraphLinkingLayer.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/LinkGraphLinkingLayer.h
@@ -19,7 +19,6 @@
#include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/Layer.h"
#include "llvm/ExecutionEngine/Orc/LinkGraphLayer.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
#include <algorithm>
#include <cassert>
@@ -41,28 +40,21 @@ namespace orc {
///
/// Clients can use this class to add LinkGraphs to an ExecutionSession, and it
/// serves as a base for the ObjectLinkingLayer that can link object files.
-class LLVM_ABI LinkGraphLinkingLayer : public LinkGraphLayer,
- private ResourceManager {
+class LinkGraphLinkingLayer : public LinkGraphLayer, private ResourceManager {
class JITLinkCtx;
public:
/// Plugin instances can be added to the ObjectLinkingLayer to receive
/// callbacks when code is loaded or emitted, and when JITLink is being
/// configured.
- class LLVM_ABI Plugin {
+ class Plugin {
public:
virtual ~Plugin();
virtual void modifyPassConfig(MaterializationResponsibility &MR,
jitlink::LinkGraph &G,
jitlink::PassConfiguration &Config) {}
- // Deprecated. Don't use this in new code. There will be a proper mechanism
- // for capturing object buffers.
- virtual void notifyMaterializing(MaterializationResponsibility &MR,
- jitlink::LinkGraph &G,
- jitlink::JITLinkContext &Ctx,
- MemoryBufferRef InputObject) {}
-
+ virtual void notifyLoaded(MaterializationResponsibility &MR) {}
virtual Error notifyEmitted(MaterializationResponsibility &MR) {
return Error::success();
}
@@ -177,4 +169,4 @@ class LLVM_ABI LinkGraphLinkingLayer : public LinkGraphLayer,
} // end namespace orc
} // end namespace llvm
-#endif // LLVM_EXECUTIONENGINE_ORC_LINKGRAPHLINKINGLAYER_H
+#endif // LLVM_EXECUTIONENGINE_ORC_LINKGRAPHLINKINGLAYER_H
\ No newline at end of file
More information about the llvm-commits
mailing list