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