llvm-project/llvm/lib/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.cpp
Lang Hames 4374ca3cab
[ORC] Align ExecutorSimpleMemoryManager w/ orc_rt::SimpleNativeMemoryMap (#163693)
Teach ExecutorSimpleMemoryManager to handle slab reserve/release
operations, plus separate initialize/deinitialize for regions within the
slab. The release operation automatically deinitializes any regions
within each slab that have not already been released.

EPCGenericJITLinkMemoryManager is updated to use the reserve (allocate),
initialize (finalize), and relesae (deallocate) operations.

This brings ExecutorSimpleMemoryManager into alignment with the
orc_rt::SimpleNativeMemoryMap class, allowing SimpleNativeMemoryMap to
be used as a backend for EPCGenericJITLinkMemoryManager.

A future commit will introduce a new MemoryMapper class that will make
SimpleNativeMemoryMap usable as a backend for
MapperJITLinkMemoryManager.

This work will make it easier to re-use in-tree APIs and tools with the
new ORC runtime.
2025-10-16 16:08:23 +11:00

173 lines
6.0 KiB
C++

//===---- EPCGenericJITLinkMemoryManager.cpp -- Mem management via EPC ----===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
#include <limits>
using namespace llvm::jitlink;
namespace llvm {
namespace orc {
class EPCGenericJITLinkMemoryManager::InFlightAlloc
: public jitlink::JITLinkMemoryManager::InFlightAlloc {
public:
// FIXME: The C++98 initializer is an attempt to work around compile failures
// due to http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1397.
// We should be able to switch this back to member initialization once that
// issue is fixed.
struct SegInfo {
SegInfo() : WorkingMem(nullptr), ContentSize(0), ZeroFillSize(0) {}
char *WorkingMem;
ExecutorAddr Addr;
uint64_t ContentSize;
uint64_t ZeroFillSize;
};
using SegInfoMap = AllocGroupSmallMap<SegInfo>;
InFlightAlloc(EPCGenericJITLinkMemoryManager &Parent, LinkGraph &G,
ExecutorAddr AllocAddr, SegInfoMap Segs)
: Parent(Parent), G(G), AllocAddr(AllocAddr), Segs(std::move(Segs)) {}
void finalize(OnFinalizedFunction OnFinalize) override {
tpctypes::FinalizeRequest FR;
for (auto &KV : Segs) {
assert(KV.second.ContentSize <= std::numeric_limits<size_t>::max());
FR.Segments.push_back(tpctypes::SegFinalizeRequest{
KV.first,
KV.second.Addr,
alignTo(KV.second.ContentSize + KV.second.ZeroFillSize,
Parent.EPC.getPageSize()),
{KV.second.WorkingMem, static_cast<size_t>(KV.second.ContentSize)}});
}
// Transfer allocation actions.
std::swap(FR.Actions, G.allocActions());
Parent.EPC.callSPSWrapperAsync<
rt::SPSSimpleExecutorMemoryManagerInitializeSignature>(
Parent.SAs.Initialize,
[OnFinalize = std::move(OnFinalize), AllocAddr = this->AllocAddr](
Error SerializationErr,
Expected<ExecutorAddr> InitializeKey) mutable {
// FIXME: Release abandoned alloc.
if (SerializationErr) {
cantFail(InitializeKey.takeError());
OnFinalize(std::move(SerializationErr));
} else if (!InitializeKey)
OnFinalize(InitializeKey.takeError());
else
OnFinalize(FinalizedAlloc(AllocAddr));
},
Parent.SAs.Allocator, std::move(FR));
}
void abandon(OnAbandonedFunction OnAbandoned) override {
// FIXME: Return memory to pool instead.
Parent.EPC.callSPSWrapperAsync<
rt::SPSSimpleExecutorMemoryManagerReleaseSignature>(
Parent.SAs.Release,
[OnAbandoned = std::move(OnAbandoned)](Error SerializationErr,
Error DeallocateErr) mutable {
if (SerializationErr) {
cantFail(std::move(DeallocateErr));
OnAbandoned(std::move(SerializationErr));
} else
OnAbandoned(std::move(DeallocateErr));
},
Parent.SAs.Allocator, ArrayRef<ExecutorAddr>(AllocAddr));
}
private:
EPCGenericJITLinkMemoryManager &Parent;
LinkGraph &G;
ExecutorAddr AllocAddr;
SegInfoMap Segs;
};
void EPCGenericJITLinkMemoryManager::allocate(const JITLinkDylib *JD,
LinkGraph &G,
OnAllocatedFunction OnAllocated) {
BasicLayout BL(G);
auto Pages = BL.getContiguousPageBasedLayoutSizes(EPC.getPageSize());
if (!Pages)
return OnAllocated(Pages.takeError());
EPC.callSPSWrapperAsync<rt::SPSSimpleExecutorMemoryManagerReserveSignature>(
SAs.Reserve,
[this, BL = std::move(BL), OnAllocated = std::move(OnAllocated)](
Error SerializationErr, Expected<ExecutorAddr> AllocAddr) mutable {
if (SerializationErr) {
cantFail(AllocAddr.takeError());
return OnAllocated(std::move(SerializationErr));
}
if (!AllocAddr)
return OnAllocated(AllocAddr.takeError());
completeAllocation(*AllocAddr, std::move(BL), std::move(OnAllocated));
},
SAs.Allocator, Pages->total());
}
void EPCGenericJITLinkMemoryManager::deallocate(
std::vector<FinalizedAlloc> Allocs, OnDeallocatedFunction OnDeallocated) {
EPC.callSPSWrapperAsync<rt::SPSSimpleExecutorMemoryManagerReleaseSignature>(
SAs.Release,
[OnDeallocated = std::move(OnDeallocated)](Error SerErr,
Error DeallocErr) mutable {
if (SerErr) {
cantFail(std::move(DeallocErr));
OnDeallocated(std::move(SerErr));
} else
OnDeallocated(std::move(DeallocErr));
},
SAs.Allocator, Allocs);
for (auto &A : Allocs)
A.release();
}
void EPCGenericJITLinkMemoryManager::completeAllocation(
ExecutorAddr AllocAddr, BasicLayout BL, OnAllocatedFunction OnAllocated) {
InFlightAlloc::SegInfoMap SegInfos;
ExecutorAddr NextSegAddr = AllocAddr;
for (auto &KV : BL.segments()) {
const auto &AG = KV.first;
auto &Seg = KV.second;
Seg.Addr = NextSegAddr;
KV.second.WorkingMem = BL.getGraph().allocateBuffer(Seg.ContentSize).data();
NextSegAddr += ExecutorAddrDiff(
alignTo(Seg.ContentSize + Seg.ZeroFillSize, EPC.getPageSize()));
auto &SegInfo = SegInfos[AG];
SegInfo.ContentSize = Seg.ContentSize;
SegInfo.ZeroFillSize = Seg.ZeroFillSize;
SegInfo.Addr = Seg.Addr;
SegInfo.WorkingMem = Seg.WorkingMem;
}
if (auto Err = BL.apply())
return OnAllocated(std::move(Err));
OnAllocated(std::make_unique<InFlightAlloc>(*this, BL.getGraph(), AllocAddr,
std::move(SegInfos)));
}
} // end namespace orc
} // end namespace llvm