Skip to content

Commit

Permalink
refactor DebugObject handling to prepare for compressing info
Browse files Browse the repository at this point in the history
Lazily create more objects in memory, since we rarely need these.
  • Loading branch information
vtjnash committed Jul 19, 2024
1 parent 500288c commit 492ae63
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 79 deletions.
21 changes: 14 additions & 7 deletions src/debug-registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,25 @@ class JITDebugInfoRegistry
};
private:

struct ObjectInfo {
const llvm::object::ObjectFile *object = nullptr;
size_t SectionSize = 0;
ptrdiff_t slide = 0;
llvm::object::SectionRef Section{};
llvm::DIContext *context = nullptr;
struct LazyObjectInfo {
std::unique_ptr<MemoryBuffer> data;
std::unique_ptr<const llvm::object::ObjectFile> object;
std::unique_ptr<llvm::DIContext> context;
LazyObjectInfo() = delete;
};

struct SectionInfo {
LazyObjectInfo *object;
size_t SectionSize;
ptrdiff_t slide;
uint64_t SectionIndex;
SectionInfo() = delete;
};

template<typename KeyT, typename ValT>
using rev_map = std::map<KeyT, ValT, std::greater<KeyT>>;

typedef rev_map<size_t, ObjectInfo> objectmap_t;
typedef rev_map<size_t, SectionInfo> objectmap_t;
typedef rev_map<uint64_t, objfileentry_t> objfilemap_t;

objectmap_t objectmap{};
Expand Down
28 changes: 14 additions & 14 deletions src/debuginfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,8 +335,8 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object,
#endif // defined(_OS_X86_64_)
#endif // defined(_OS_WINDOWS_)

auto ObjectCopy = new LazyObjectInfo{MemoryBuffer::getMemBufferCopy(Object.getData())}; // intentionally leaked so that we don't need to ref-count it
auto symbols = object::computeSymbolSizes(Object);
bool first = true;
for (const auto &sym_size : symbols) {
const object::SymbolRef &sym_iter = sym_size.first;
object::SymbolRef::Type SymbolType = cantFail(sym_iter.getType());
Expand Down Expand Up @@ -385,15 +385,12 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object,
jl_profile_atomic([&]() JL_NOTSAFEPOINT {
if (mi)
linfomap[Addr] = std::make_pair(Size, mi);
if (first) {
objectmap[SectionLoadAddr] = {&Object,
(size_t)SectionSize,
(ptrdiff_t)(SectionAddr - SectionLoadAddr),
*Section,
nullptr,
};
first = false;
}
objectmap.insert(std::pair{SectionLoadAddr, SectionInfo{
ObjectCopy,
(size_t)SectionSize,
(ptrdiff_t)(SectionAddr - SectionLoadAddr),
Section->getIndex()
}});
});
}
}
Expand Down Expand Up @@ -1213,11 +1210,14 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide,
auto fit = objmap.lower_bound(fptr);
if (fit != objmap.end() && fptr < fit->first + fit->second.SectionSize) {
*slide = fit->second.slide;
*Section = fit->second.Section;
auto lazyobject = fit->second.object;
if (!lazyobject->object)
lazyobject->object = cantFail(object::ObjectFile::createObjectFile(lazyobject->data->getMemBufferRef()));
*Section = *std::next(lazyobject->object->section_begin(), fit->second.SectionIndex);
if (context) {
if (fit->second.context == nullptr)
fit->second.context = DWARFContext::create(*fit->second.object).release();
*context = fit->second.context;
if (lazyobject->context == nullptr)
lazyobject->context = DWARFContext::create(*lazyobject->object);
*context = lazyobject->context.get();
}
found = 1;
}
Expand Down
65 changes: 7 additions & 58 deletions src/jitlayers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,22 +684,19 @@ struct JITObjectInfo {
class JLDebuginfoPlugin : public ObjectLinkingLayer::Plugin {
std::mutex PluginMutex;
std::map<MaterializationResponsibility *, std::unique_ptr<JITObjectInfo>> PendingObjs;
// Resources from distinct `MaterializationResponsibility`s can get merged
// after emission, so we can have multiple debug objects per resource key.
std::map<ResourceKey, SmallVector<std::unique_ptr<JITObjectInfo>, 0>> RegisteredObjs;

public:
void notifyMaterializing(MaterializationResponsibility &MR, jitlink::LinkGraph &G,
jitlink::JITLinkContext &Ctx,
MemoryBufferRef InputObject) override
{
// Keeping around a full copy of the input object file (and re-parsing it) is
// wasteful, but for now, this lets us reuse the existing debuginfo.cpp code.
// Should look into just directly pulling out all the information required in
// a JITLink pass and just keeping the required tables/DWARF sections around
// (perhaps using the LLVM DebuggerSupportPlugin as a reference).
auto NewBuffer =
MemoryBuffer::getMemBufferCopy(InputObject.getBuffer(), G.getName());
// Re-parsing the InputObject is wasteful, but for now, this lets us
// reuse the existing debuginfo.cpp code. Should look into just
// directly pulling out all the information required in a JITLink pass
// and just keeping the required tables/DWARF sections around (perhaps
// using the LLVM DebuggerSupportPlugin as a reference).
auto NewObj =
cantFail(object::ObjectFile::createObjectFile(NewBuffer->getMemBufferRef()));

Expand Down Expand Up @@ -733,13 +730,8 @@ class JLDebuginfoPlugin : public ObjectLinkingLayer::Plugin {
};

jl_register_jit_object(*NewInfo->Object, getLoadAddress, nullptr);
}

cantFail(MR.withResourceKeyDo([&](ResourceKey K) {
std::lock_guard<std::mutex> lock(PluginMutex);
RegisteredObjs[K].push_back(std::move(PendingObjs[&MR]));
PendingObjs.erase(&MR);
}));
}

return Error::success();
}
Expand All @@ -750,32 +742,6 @@ class JLDebuginfoPlugin : public ObjectLinkingLayer::Plugin {
PendingObjs.erase(&MR);
return Error::success();
}
#if JL_LLVM_VERSION >= 160000
Error notifyRemovingResources(JITDylib &JD, orc::ResourceKey K) override
#else
Error notifyRemovingResources(ResourceKey K) override
#endif
{
std::lock_guard<std::mutex> lock(PluginMutex);
RegisteredObjs.erase(K);
// TODO: If we ever unload code, need to notify debuginfo registry.
return Error::success();
}

#if JL_LLVM_VERSION >= 160000
void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) override
#else
void notifyTransferringResources(ResourceKey DstKey, ResourceKey SrcKey) override
#endif
{
std::lock_guard<std::mutex> lock(PluginMutex);
auto SrcIt = RegisteredObjs.find(SrcKey);
if (SrcIt != RegisteredObjs.end()) {
for (std::unique_ptr<JITObjectInfo> &Info : SrcIt->second)
RegisteredObjs[DstKey].push_back(std::move(Info));
RegisteredObjs.erase(SrcIt);
}
}

void modifyPassConfig(MaterializationResponsibility &MR, jitlink::LinkGraph &,
jitlink::PassConfiguration &PassConfig) override
Expand Down Expand Up @@ -985,24 +951,7 @@ void registerRTDyldJITObject(const object::ObjectFile &Object,
const RuntimeDyld::LoadedObjectInfo &L,
const std::shared_ptr<RTDyldMemoryManager> &MemMgr)
{
auto SavedObject = L.getObjectForDebug(Object).takeBinary();
// If the debug object is unavailable, save (a copy of) the original object
// for our backtraces.
// This copy seems unfortunate, but there doesn't seem to be a way to take
// ownership of the original buffer.
if (!SavedObject.first) {
auto NewBuffer =
MemoryBuffer::getMemBufferCopy(Object.getData(), Object.getFileName());
auto NewObj =
cantFail(object::ObjectFile::createObjectFile(NewBuffer->getMemBufferRef()));
SavedObject = std::make_pair(std::move(NewObj), std::move(NewBuffer));
}
const object::ObjectFile *DebugObj = SavedObject.first.release();
SavedObject.second.release();

StringMap<object::SectionRef> loadedSections;
// Use the original Object, not the DebugObject, as this is used for the
// RuntimeDyld::LoadedObjectInfo lookup.
for (const object::SectionRef &lSection : Object.sections()) {
auto sName = lSection.getName();
if (sName) {
Expand All @@ -1019,7 +968,7 @@ void registerRTDyldJITObject(const object::ObjectFile &Object,
return L.getSectionLoadAddress(search->second);
};

jl_register_jit_object(*DebugObj, getLoadAddress,
jl_register_jit_object(Object, getLoadAddress,
#if defined(_OS_WINDOWS_) && defined(_CPU_X86_64_)
[MemMgr](void *p) { return lookupWriteAddressFor(MemMgr.get(), p); }
#else
Expand Down

0 comments on commit 492ae63

Please sign in to comment.