1dad60f80SLang Hames //===---- EPCGenericJITLinkMemoryManager.cpp -- Mem management via EPC ----===//
2dad60f80SLang Hames //
3dad60f80SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4dad60f80SLang Hames // See https://llvm.org/LICENSE.txt for license information.
5dad60f80SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6dad60f80SLang Hames //
7dad60f80SLang Hames //===----------------------------------------------------------------------===//
8dad60f80SLang Hames
9dad60f80SLang Hames #include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"
10962a2479SLang Hames
11962a2479SLang Hames #include "llvm/ExecutionEngine/JITLink/JITLink.h"
12dad60f80SLang Hames #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
132c8e7849SLang Hames #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
14dad60f80SLang Hames
1502b46203SDavid Spickett #include <limits>
1602b46203SDavid Spickett
17962a2479SLang Hames using namespace llvm::jitlink;
18962a2479SLang Hames
19dad60f80SLang Hames namespace llvm {
20dad60f80SLang Hames namespace orc {
21dad60f80SLang Hames
22962a2479SLang Hames class EPCGenericJITLinkMemoryManager::InFlightAlloc
23962a2479SLang Hames : public jitlink::JITLinkMemoryManager::InFlightAlloc {
24dad60f80SLang Hames public:
255829ba7aSLang Hames
265829ba7aSLang Hames // FIXME: The C++98 initializer is an attempt to work around compile failures
275829ba7aSLang Hames // due to http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1397.
285829ba7aSLang Hames // We should be able to switch this back to member initialization once that
295829ba7aSLang Hames // issue is fixed.
30dad60f80SLang Hames struct SegInfo {
SegInfollvm::orc::EPCGenericJITLinkMemoryManager::InFlightAlloc::SegInfo31*5bbe452eSKazu Hirata SegInfo() : WorkingMem(nullptr), ContentSize(0), ZeroFillSize(0) {}
325829ba7aSLang Hames
33*5bbe452eSKazu Hirata char *WorkingMem;
34962a2479SLang Hames ExecutorAddr Addr;
35*5bbe452eSKazu Hirata uint64_t ContentSize;
36*5bbe452eSKazu Hirata uint64_t ZeroFillSize;
37dad60f80SLang Hames };
385829ba7aSLang Hames
39962a2479SLang Hames using SegInfoMap = AllocGroupSmallMap<SegInfo>;
40dad60f80SLang Hames
InFlightAlloc(EPCGenericJITLinkMemoryManager & Parent,LinkGraph & G,ExecutorAddr AllocAddr,SegInfoMap Segs)41962a2479SLang Hames InFlightAlloc(EPCGenericJITLinkMemoryManager &Parent, LinkGraph &G,
42962a2479SLang Hames ExecutorAddr AllocAddr, SegInfoMap Segs)
43962a2479SLang Hames : Parent(Parent), G(G), AllocAddr(AllocAddr), Segs(std::move(Segs)) {}
44dad60f80SLang Hames
finalize(OnFinalizedFunction OnFinalize)45962a2479SLang Hames void finalize(OnFinalizedFunction OnFinalize) override {
46dad60f80SLang Hames tpctypes::FinalizeRequest FR;
47dad60f80SLang Hames for (auto &KV : Segs) {
4802b46203SDavid Spickett assert(KV.second.ContentSize <= std::numeric_limits<size_t>::max());
4978b083dbSLang Hames FR.Segments.push_back(tpctypes::SegFinalizeRequest{
50dad60f80SLang Hames tpctypes::toWireProtectionFlags(
51962a2479SLang Hames toSysMemoryProtectionFlags(KV.first.getMemProt())),
52962a2479SLang Hames KV.second.Addr,
53dad60f80SLang Hames alignTo(KV.second.ContentSize + KV.second.ZeroFillSize,
54dad60f80SLang Hames Parent.EPC.getPageSize()),
55962a2479SLang Hames {KV.second.WorkingMem, static_cast<size_t>(KV.second.ContentSize)}});
56dad60f80SLang Hames }
57962a2479SLang Hames
58962a2479SLang Hames // Transfer allocation actions.
59089acf25SLang Hames std::swap(FR.Actions, G.allocActions());
60962a2479SLang Hames
6178b083dbSLang Hames Parent.EPC.callSPSWrapperAsync<
6278b083dbSLang Hames rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>(
63da7f993aSLang Hames Parent.SAs.Finalize,
64962a2479SLang Hames [OnFinalize = std::move(OnFinalize), AllocAddr = this->AllocAddr](
65962a2479SLang Hames Error SerializationErr, Error FinalizeErr) mutable {
66962a2479SLang Hames // FIXME: Release abandoned alloc.
674fc2a4ccSLang Hames if (SerializationErr) {
684fc2a4ccSLang Hames cantFail(std::move(FinalizeErr));
69dad60f80SLang Hames OnFinalize(std::move(SerializationErr));
70962a2479SLang Hames } else if (FinalizeErr)
71dad60f80SLang Hames OnFinalize(std::move(FinalizeErr));
72962a2479SLang Hames else
73118e953bSLang Hames OnFinalize(FinalizedAlloc(AllocAddr));
74dad60f80SLang Hames },
75da7f993aSLang Hames Parent.SAs.Allocator, std::move(FR));
76dad60f80SLang Hames }
77dad60f80SLang Hames
abandon(OnAbandonedFunction OnAbandoned)78962a2479SLang Hames void abandon(OnAbandonedFunction OnAbandoned) override {
79962a2479SLang Hames // FIXME: Return memory to pool instead.
80962a2479SLang Hames Parent.EPC.callSPSWrapperAsync<
8178b083dbSLang Hames rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>(
82962a2479SLang Hames Parent.SAs.Deallocate,
83962a2479SLang Hames [OnAbandoned = std::move(OnAbandoned)](Error SerializationErr,
84962a2479SLang Hames Error DeallocateErr) mutable {
85962a2479SLang Hames if (SerializationErr) {
86962a2479SLang Hames cantFail(std::move(DeallocateErr));
87962a2479SLang Hames OnAbandoned(std::move(SerializationErr));
88962a2479SLang Hames } else
89962a2479SLang Hames OnAbandoned(std::move(DeallocateErr));
90962a2479SLang Hames },
91962a2479SLang Hames Parent.SAs.Allocator, ArrayRef<ExecutorAddr>(AllocAddr));
92dad60f80SLang Hames }
93dad60f80SLang Hames
94dad60f80SLang Hames private:
95dad60f80SLang Hames EPCGenericJITLinkMemoryManager &Parent;
96962a2479SLang Hames LinkGraph &G;
97962a2479SLang Hames ExecutorAddr AllocAddr;
98dad60f80SLang Hames SegInfoMap Segs;
99dad60f80SLang Hames };
100dad60f80SLang Hames
allocate(const JITLinkDylib * JD,LinkGraph & G,OnAllocatedFunction OnAllocated)101962a2479SLang Hames void EPCGenericJITLinkMemoryManager::allocate(const JITLinkDylib *JD,
102962a2479SLang Hames LinkGraph &G,
103962a2479SLang Hames OnAllocatedFunction OnAllocated) {
104962a2479SLang Hames BasicLayout BL(G);
105dad60f80SLang Hames
106962a2479SLang Hames auto Pages = BL.getContiguousPageBasedLayoutSizes(EPC.getPageSize());
107962a2479SLang Hames if (!Pages)
108962a2479SLang Hames return OnAllocated(Pages.takeError());
109962a2479SLang Hames
110962a2479SLang Hames EPC.callSPSWrapperAsync<rt::SPSSimpleExecutorMemoryManagerReserveSignature>(
111962a2479SLang Hames SAs.Reserve,
112962a2479SLang Hames [this, BL = std::move(BL), OnAllocated = std::move(OnAllocated)](
113962a2479SLang Hames Error SerializationErr, Expected<ExecutorAddr> AllocAddr) mutable {
114962a2479SLang Hames if (SerializationErr) {
115962a2479SLang Hames cantFail(AllocAddr.takeError());
116962a2479SLang Hames return OnAllocated(std::move(SerializationErr));
117962a2479SLang Hames }
118962a2479SLang Hames if (!AllocAddr)
119962a2479SLang Hames return OnAllocated(AllocAddr.takeError());
120962a2479SLang Hames
121962a2479SLang Hames completeAllocation(*AllocAddr, std::move(BL), std::move(OnAllocated));
122962a2479SLang Hames },
123962a2479SLang Hames SAs.Allocator, Pages->total());
124dad60f80SLang Hames }
125dad60f80SLang Hames
deallocate(std::vector<FinalizedAlloc> Allocs,OnDeallocatedFunction OnDeallocated)126962a2479SLang Hames void EPCGenericJITLinkMemoryManager::deallocate(
127962a2479SLang Hames std::vector<FinalizedAlloc> Allocs, OnDeallocatedFunction OnDeallocated) {
128962a2479SLang Hames EPC.callSPSWrapperAsync<
129962a2479SLang Hames rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>(
130962a2479SLang Hames SAs.Deallocate,
131962a2479SLang Hames [OnDeallocated = std::move(OnDeallocated)](Error SerErr,
132962a2479SLang Hames Error DeallocErr) mutable {
133962a2479SLang Hames if (SerErr) {
134962a2479SLang Hames cantFail(std::move(DeallocErr));
135962a2479SLang Hames OnDeallocated(std::move(SerErr));
136962a2479SLang Hames } else
137962a2479SLang Hames OnDeallocated(std::move(DeallocErr));
138962a2479SLang Hames },
139962a2479SLang Hames SAs.Allocator, Allocs);
140962a2479SLang Hames for (auto &A : Allocs)
141962a2479SLang Hames A.release();
142962a2479SLang Hames }
143dad60f80SLang Hames
completeAllocation(ExecutorAddr AllocAddr,BasicLayout BL,OnAllocatedFunction OnAllocated)144962a2479SLang Hames void EPCGenericJITLinkMemoryManager::completeAllocation(
145962a2479SLang Hames ExecutorAddr AllocAddr, BasicLayout BL, OnAllocatedFunction OnAllocated) {
146962a2479SLang Hames
147962a2479SLang Hames InFlightAlloc::SegInfoMap SegInfos;
148962a2479SLang Hames
149962a2479SLang Hames ExecutorAddr NextSegAddr = AllocAddr;
150962a2479SLang Hames for (auto &KV : BL.segments()) {
151962a2479SLang Hames const auto &AG = KV.first;
152dad60f80SLang Hames auto &Seg = KV.second;
153962a2479SLang Hames
154118e953bSLang Hames Seg.Addr = NextSegAddr;
155962a2479SLang Hames KV.second.WorkingMem = BL.getGraph().allocateBuffer(Seg.ContentSize).data();
156962a2479SLang Hames NextSegAddr += ExecutorAddrDiff(
157962a2479SLang Hames alignTo(Seg.ContentSize + Seg.ZeroFillSize, EPC.getPageSize()));
158962a2479SLang Hames
159962a2479SLang Hames auto &SegInfo = SegInfos[AG];
160962a2479SLang Hames SegInfo.ContentSize = Seg.ContentSize;
161962a2479SLang Hames SegInfo.ZeroFillSize = Seg.ZeroFillSize;
162962a2479SLang Hames SegInfo.Addr = ExecutorAddr(Seg.Addr);
163962a2479SLang Hames SegInfo.WorkingMem = Seg.WorkingMem;
164dad60f80SLang Hames }
165dad60f80SLang Hames
166962a2479SLang Hames if (auto Err = BL.apply())
167962a2479SLang Hames return OnAllocated(std::move(Err));
168962a2479SLang Hames
169962a2479SLang Hames OnAllocated(std::make_unique<InFlightAlloc>(*this, BL.getGraph(), AllocAddr,
170962a2479SLang Hames std::move(SegInfos)));
171dad60f80SLang Hames }
172dad60f80SLang Hames
173dad60f80SLang Hames } // end namespace orc
174dad60f80SLang Hames } // end namespace llvm
175