1 //===---- EPCGenericJITLinkMemoryManager.cpp -- Mem management via EPC ----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"
10
11 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
12 #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
13 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
14
15 #include <limits>
16
17 using namespace llvm::jitlink;
18
19 namespace llvm {
20 namespace orc {
21
22 class EPCGenericJITLinkMemoryManager::InFlightAlloc
23 : public jitlink::JITLinkMemoryManager::InFlightAlloc {
24 public:
25
26 // FIXME: The C++98 initializer is an attempt to work around compile failures
27 // due to http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1397.
28 // We should be able to switch this back to member initialization once that
29 // issue is fixed.
30 struct SegInfo {
SegInfollvm::orc::EPCGenericJITLinkMemoryManager::InFlightAlloc::SegInfo31 SegInfo() : WorkingMem(nullptr), ContentSize(0), ZeroFillSize(0) {}
32
33 char *WorkingMem;
34 ExecutorAddr Addr;
35 uint64_t ContentSize;
36 uint64_t ZeroFillSize;
37 };
38
39 using SegInfoMap = AllocGroupSmallMap<SegInfo>;
40
InFlightAlloc(EPCGenericJITLinkMemoryManager & Parent,LinkGraph & G,ExecutorAddr AllocAddr,SegInfoMap Segs)41 InFlightAlloc(EPCGenericJITLinkMemoryManager &Parent, LinkGraph &G,
42 ExecutorAddr AllocAddr, SegInfoMap Segs)
43 : Parent(Parent), G(G), AllocAddr(AllocAddr), Segs(std::move(Segs)) {}
44
finalize(OnFinalizedFunction OnFinalize)45 void finalize(OnFinalizedFunction OnFinalize) override {
46 tpctypes::FinalizeRequest FR;
47 for (auto &KV : Segs) {
48 assert(KV.second.ContentSize <= std::numeric_limits<size_t>::max());
49 FR.Segments.push_back(tpctypes::SegFinalizeRequest{
50 tpctypes::toWireProtectionFlags(
51 toSysMemoryProtectionFlags(KV.first.getMemProt())),
52 KV.second.Addr,
53 alignTo(KV.second.ContentSize + KV.second.ZeroFillSize,
54 Parent.EPC.getPageSize()),
55 {KV.second.WorkingMem, static_cast<size_t>(KV.second.ContentSize)}});
56 }
57
58 // Transfer allocation actions.
59 std::swap(FR.Actions, G.allocActions());
60
61 Parent.EPC.callSPSWrapperAsync<
62 rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>(
63 Parent.SAs.Finalize,
64 [OnFinalize = std::move(OnFinalize), AllocAddr = this->AllocAddr](
65 Error SerializationErr, Error FinalizeErr) mutable {
66 // FIXME: Release abandoned alloc.
67 if (SerializationErr) {
68 cantFail(std::move(FinalizeErr));
69 OnFinalize(std::move(SerializationErr));
70 } else if (FinalizeErr)
71 OnFinalize(std::move(FinalizeErr));
72 else
73 OnFinalize(FinalizedAlloc(AllocAddr));
74 },
75 Parent.SAs.Allocator, std::move(FR));
76 }
77
abandon(OnAbandonedFunction OnAbandoned)78 void abandon(OnAbandonedFunction OnAbandoned) override {
79 // FIXME: Return memory to pool instead.
80 Parent.EPC.callSPSWrapperAsync<
81 rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>(
82 Parent.SAs.Deallocate,
83 [OnAbandoned = std::move(OnAbandoned)](Error SerializationErr,
84 Error DeallocateErr) mutable {
85 if (SerializationErr) {
86 cantFail(std::move(DeallocateErr));
87 OnAbandoned(std::move(SerializationErr));
88 } else
89 OnAbandoned(std::move(DeallocateErr));
90 },
91 Parent.SAs.Allocator, ArrayRef<ExecutorAddr>(AllocAddr));
92 }
93
94 private:
95 EPCGenericJITLinkMemoryManager &Parent;
96 LinkGraph &G;
97 ExecutorAddr AllocAddr;
98 SegInfoMap Segs;
99 };
100
allocate(const JITLinkDylib * JD,LinkGraph & G,OnAllocatedFunction OnAllocated)101 void EPCGenericJITLinkMemoryManager::allocate(const JITLinkDylib *JD,
102 LinkGraph &G,
103 OnAllocatedFunction OnAllocated) {
104 BasicLayout BL(G);
105
106 auto Pages = BL.getContiguousPageBasedLayoutSizes(EPC.getPageSize());
107 if (!Pages)
108 return OnAllocated(Pages.takeError());
109
110 EPC.callSPSWrapperAsync<rt::SPSSimpleExecutorMemoryManagerReserveSignature>(
111 SAs.Reserve,
112 [this, BL = std::move(BL), OnAllocated = std::move(OnAllocated)](
113 Error SerializationErr, Expected<ExecutorAddr> AllocAddr) mutable {
114 if (SerializationErr) {
115 cantFail(AllocAddr.takeError());
116 return OnAllocated(std::move(SerializationErr));
117 }
118 if (!AllocAddr)
119 return OnAllocated(AllocAddr.takeError());
120
121 completeAllocation(*AllocAddr, std::move(BL), std::move(OnAllocated));
122 },
123 SAs.Allocator, Pages->total());
124 }
125
deallocate(std::vector<FinalizedAlloc> Allocs,OnDeallocatedFunction OnDeallocated)126 void EPCGenericJITLinkMemoryManager::deallocate(
127 std::vector<FinalizedAlloc> Allocs, OnDeallocatedFunction OnDeallocated) {
128 EPC.callSPSWrapperAsync<
129 rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>(
130 SAs.Deallocate,
131 [OnDeallocated = std::move(OnDeallocated)](Error SerErr,
132 Error DeallocErr) mutable {
133 if (SerErr) {
134 cantFail(std::move(DeallocErr));
135 OnDeallocated(std::move(SerErr));
136 } else
137 OnDeallocated(std::move(DeallocErr));
138 },
139 SAs.Allocator, Allocs);
140 for (auto &A : Allocs)
141 A.release();
142 }
143
completeAllocation(ExecutorAddr AllocAddr,BasicLayout BL,OnAllocatedFunction OnAllocated)144 void EPCGenericJITLinkMemoryManager::completeAllocation(
145 ExecutorAddr AllocAddr, BasicLayout BL, OnAllocatedFunction OnAllocated) {
146
147 InFlightAlloc::SegInfoMap SegInfos;
148
149 ExecutorAddr NextSegAddr = AllocAddr;
150 for (auto &KV : BL.segments()) {
151 const auto &AG = KV.first;
152 auto &Seg = KV.second;
153
154 Seg.Addr = NextSegAddr;
155 KV.second.WorkingMem = BL.getGraph().allocateBuffer(Seg.ContentSize).data();
156 NextSegAddr += ExecutorAddrDiff(
157 alignTo(Seg.ContentSize + Seg.ZeroFillSize, EPC.getPageSize()));
158
159 auto &SegInfo = SegInfos[AG];
160 SegInfo.ContentSize = Seg.ContentSize;
161 SegInfo.ZeroFillSize = Seg.ZeroFillSize;
162 SegInfo.Addr = ExecutorAddr(Seg.Addr);
163 SegInfo.WorkingMem = Seg.WorkingMem;
164 }
165
166 if (auto Err = BL.apply())
167 return OnAllocated(std::move(Err));
168
169 OnAllocated(std::make_unique<InFlightAlloc>(*this, BL.getGraph(), AllocAddr,
170 std::move(SegInfos)));
171 }
172
173 } // end namespace orc
174 } // end namespace llvm
175