xref: /openbsd-src/gnu/llvm/llvm/lib/ExecutionEngine/JITLink/JITLinkMemoryManager.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
109467b48Spatrick //===--- JITLinkMemoryManager.cpp - JITLinkMemoryManager implementation ---===//
209467b48Spatrick //
3*d415bd75Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*d415bd75Srobert // See https://llvm.org/LICENSE.txt for license information.
5*d415bd75Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick 
909467b48Spatrick #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
10*d415bd75Srobert #include "llvm/ExecutionEngine/JITLink/JITLink.h"
11*d415bd75Srobert #include "llvm/Support/FormatVariadic.h"
1209467b48Spatrick #include "llvm/Support/Process.h"
1309467b48Spatrick 
14*d415bd75Srobert #define DEBUG_TYPE "jitlink"
15*d415bd75Srobert 
16*d415bd75Srobert using namespace llvm;
17*d415bd75Srobert 
1809467b48Spatrick namespace llvm {
1909467b48Spatrick namespace jitlink {
2009467b48Spatrick 
2109467b48Spatrick JITLinkMemoryManager::~JITLinkMemoryManager() = default;
22*d415bd75Srobert JITLinkMemoryManager::InFlightAlloc::~InFlightAlloc() = default;
2309467b48Spatrick 
BasicLayout(LinkGraph & G)24*d415bd75Srobert BasicLayout::BasicLayout(LinkGraph &G) : G(G) {
2509467b48Spatrick 
26*d415bd75Srobert   for (auto &Sec : G.sections()) {
27*d415bd75Srobert     // Skip empty sections.
28*d415bd75Srobert     if (Sec.blocks().empty())
29*d415bd75Srobert       continue;
3009467b48Spatrick 
31*d415bd75Srobert     auto &Seg = Segments[{Sec.getMemProt(), Sec.getMemDeallocPolicy()}];
32*d415bd75Srobert     for (auto *B : Sec.blocks())
33*d415bd75Srobert       if (LLVM_LIKELY(!B->isZeroFill()))
34*d415bd75Srobert         Seg.ContentBlocks.push_back(B);
35*d415bd75Srobert       else
36*d415bd75Srobert         Seg.ZeroFillBlocks.push_back(B);
37*d415bd75Srobert   }
38*d415bd75Srobert 
39*d415bd75Srobert   // Build Segments map.
40*d415bd75Srobert   auto CompareBlocks = [](const Block *LHS, const Block *RHS) {
41*d415bd75Srobert     // Sort by section, address and size
42*d415bd75Srobert     if (LHS->getSection().getOrdinal() != RHS->getSection().getOrdinal())
43*d415bd75Srobert       return LHS->getSection().getOrdinal() < RHS->getSection().getOrdinal();
44*d415bd75Srobert     if (LHS->getAddress() != RHS->getAddress())
45*d415bd75Srobert       return LHS->getAddress() < RHS->getAddress();
46*d415bd75Srobert     return LHS->getSize() < RHS->getSize();
47*d415bd75Srobert   };
48*d415bd75Srobert 
49*d415bd75Srobert   LLVM_DEBUG(dbgs() << "Generated BasicLayout for " << G.getName() << ":\n");
50*d415bd75Srobert   for (auto &KV : Segments) {
51*d415bd75Srobert     auto &Seg = KV.second;
52*d415bd75Srobert 
53*d415bd75Srobert     llvm::sort(Seg.ContentBlocks, CompareBlocks);
54*d415bd75Srobert     llvm::sort(Seg.ZeroFillBlocks, CompareBlocks);
55*d415bd75Srobert 
56*d415bd75Srobert     for (auto *B : Seg.ContentBlocks) {
57*d415bd75Srobert       Seg.ContentSize = alignToBlock(Seg.ContentSize, *B);
58*d415bd75Srobert       Seg.ContentSize += B->getSize();
59*d415bd75Srobert       Seg.Alignment = std::max(Seg.Alignment, Align(B->getAlignment()));
60*d415bd75Srobert     }
61*d415bd75Srobert 
62*d415bd75Srobert     uint64_t SegEndOffset = Seg.ContentSize;
63*d415bd75Srobert     for (auto *B : Seg.ZeroFillBlocks) {
64*d415bd75Srobert       SegEndOffset = alignToBlock(SegEndOffset, *B);
65*d415bd75Srobert       SegEndOffset += B->getSize();
66*d415bd75Srobert       Seg.Alignment = std::max(Seg.Alignment, Align(B->getAlignment()));
67*d415bd75Srobert     }
68*d415bd75Srobert     Seg.ZeroFillSize = SegEndOffset - Seg.ContentSize;
69*d415bd75Srobert 
70*d415bd75Srobert     LLVM_DEBUG({
71*d415bd75Srobert       dbgs() << "  Seg " << KV.first
72*d415bd75Srobert              << ": content-size=" << formatv("{0:x}", Seg.ContentSize)
73*d415bd75Srobert              << ", zero-fill-size=" << formatv("{0:x}", Seg.ZeroFillSize)
74*d415bd75Srobert              << ", align=" << formatv("{0:x}", Seg.Alignment.value()) << "\n";
75*d415bd75Srobert     });
76*d415bd75Srobert   }
77*d415bd75Srobert }
78*d415bd75Srobert 
79*d415bd75Srobert Expected<BasicLayout::ContiguousPageBasedLayoutSizes>
getContiguousPageBasedLayoutSizes(uint64_t PageSize)80*d415bd75Srobert BasicLayout::getContiguousPageBasedLayoutSizes(uint64_t PageSize) {
81*d415bd75Srobert   ContiguousPageBasedLayoutSizes SegsSizes;
82*d415bd75Srobert 
83*d415bd75Srobert   for (auto &KV : segments()) {
84*d415bd75Srobert     auto &AG = KV.first;
85*d415bd75Srobert     auto &Seg = KV.second;
86*d415bd75Srobert 
87*d415bd75Srobert     if (Seg.Alignment > PageSize)
88*d415bd75Srobert       return make_error<StringError>("Segment alignment greater than page size",
89*d415bd75Srobert                                      inconvertibleErrorCode());
90*d415bd75Srobert 
91*d415bd75Srobert     uint64_t SegSize = alignTo(Seg.ContentSize + Seg.ZeroFillSize, PageSize);
92*d415bd75Srobert     if (AG.getMemDeallocPolicy() == orc::MemDeallocPolicy::Standard)
93*d415bd75Srobert       SegsSizes.StandardSegs += SegSize;
94*d415bd75Srobert     else
95*d415bd75Srobert       SegsSizes.FinalizeSegs += SegSize;
96*d415bd75Srobert   }
97*d415bd75Srobert 
98*d415bd75Srobert   return SegsSizes;
99*d415bd75Srobert }
100*d415bd75Srobert 
apply()101*d415bd75Srobert Error BasicLayout::apply() {
102*d415bd75Srobert   for (auto &KV : Segments) {
103*d415bd75Srobert     auto &Seg = KV.second;
104*d415bd75Srobert 
105*d415bd75Srobert     assert(!(Seg.ContentBlocks.empty() && Seg.ZeroFillBlocks.empty()) &&
106*d415bd75Srobert            "Empty section recorded?");
107*d415bd75Srobert 
108*d415bd75Srobert     for (auto *B : Seg.ContentBlocks) {
109*d415bd75Srobert       // Align addr and working-mem-offset.
110*d415bd75Srobert       Seg.Addr = alignToBlock(Seg.Addr, *B);
111*d415bd75Srobert       Seg.NextWorkingMemOffset = alignToBlock(Seg.NextWorkingMemOffset, *B);
112*d415bd75Srobert 
113*d415bd75Srobert       // Update block addr.
114*d415bd75Srobert       B->setAddress(Seg.Addr);
115*d415bd75Srobert       Seg.Addr += B->getSize();
116*d415bd75Srobert 
117*d415bd75Srobert       // Copy content to working memory, then update content to point at working
118*d415bd75Srobert       // memory.
119*d415bd75Srobert       memcpy(Seg.WorkingMem + Seg.NextWorkingMemOffset, B->getContent().data(),
120*d415bd75Srobert              B->getSize());
121*d415bd75Srobert       B->setMutableContent(
122*d415bd75Srobert           {Seg.WorkingMem + Seg.NextWorkingMemOffset, B->getSize()});
123*d415bd75Srobert       Seg.NextWorkingMemOffset += B->getSize();
124*d415bd75Srobert     }
125*d415bd75Srobert 
126*d415bd75Srobert     for (auto *B : Seg.ZeroFillBlocks) {
127*d415bd75Srobert       // Align addr.
128*d415bd75Srobert       Seg.Addr = alignToBlock(Seg.Addr, *B);
129*d415bd75Srobert       // Update block addr.
130*d415bd75Srobert       B->setAddress(Seg.Addr);
131*d415bd75Srobert       Seg.Addr += B->getSize();
132*d415bd75Srobert     }
133*d415bd75Srobert 
134*d415bd75Srobert     Seg.ContentBlocks.clear();
135*d415bd75Srobert     Seg.ZeroFillBlocks.clear();
136*d415bd75Srobert   }
137*d415bd75Srobert 
138*d415bd75Srobert   return Error::success();
139*d415bd75Srobert }
140*d415bd75Srobert 
graphAllocActions()141*d415bd75Srobert orc::shared::AllocActions &BasicLayout::graphAllocActions() {
142*d415bd75Srobert   return G.allocActions();
143*d415bd75Srobert }
144*d415bd75Srobert 
Create(JITLinkMemoryManager & MemMgr,const JITLinkDylib * JD,SegmentMap Segments,OnCreatedFunction OnCreated)145*d415bd75Srobert void SimpleSegmentAlloc::Create(JITLinkMemoryManager &MemMgr,
146*d415bd75Srobert                                 const JITLinkDylib *JD, SegmentMap Segments,
147*d415bd75Srobert                                 OnCreatedFunction OnCreated) {
148*d415bd75Srobert 
149*d415bd75Srobert   static_assert(orc::AllocGroup::NumGroups == 16,
150*d415bd75Srobert                 "AllocGroup has changed. Section names below must be updated");
151*d415bd75Srobert   StringRef AGSectionNames[] = {
152*d415bd75Srobert       "__---.standard", "__R--.standard", "__-W-.standard", "__RW-.standard",
153*d415bd75Srobert       "__--X.standard", "__R-X.standard", "__-WX.standard", "__RWX.standard",
154*d415bd75Srobert       "__---.finalize", "__R--.finalize", "__-W-.finalize", "__RW-.finalize",
155*d415bd75Srobert       "__--X.finalize", "__R-X.finalize", "__-WX.finalize", "__RWX.finalize"};
156*d415bd75Srobert 
157*d415bd75Srobert   auto G =
158*d415bd75Srobert       std::make_unique<LinkGraph>("", Triple(), 0, support::native, nullptr);
159*d415bd75Srobert   orc::AllocGroupSmallMap<Block *> ContentBlocks;
160*d415bd75Srobert 
161*d415bd75Srobert   orc::ExecutorAddr NextAddr(0x100000);
162*d415bd75Srobert   for (auto &KV : Segments) {
163*d415bd75Srobert     auto &AG = KV.first;
164*d415bd75Srobert     auto &Seg = KV.second;
165*d415bd75Srobert 
166*d415bd75Srobert     auto AGSectionName =
167*d415bd75Srobert         AGSectionNames[static_cast<unsigned>(AG.getMemProt()) |
168*d415bd75Srobert                        static_cast<bool>(AG.getMemDeallocPolicy()) << 3];
169*d415bd75Srobert 
170*d415bd75Srobert     auto &Sec = G->createSection(AGSectionName, AG.getMemProt());
171*d415bd75Srobert     Sec.setMemDeallocPolicy(AG.getMemDeallocPolicy());
172*d415bd75Srobert 
173*d415bd75Srobert     if (Seg.ContentSize != 0) {
174*d415bd75Srobert       NextAddr =
175*d415bd75Srobert           orc::ExecutorAddr(alignTo(NextAddr.getValue(), Seg.ContentAlign));
176*d415bd75Srobert       auto &B =
177*d415bd75Srobert           G->createMutableContentBlock(Sec, G->allocateBuffer(Seg.ContentSize),
178*d415bd75Srobert                                        NextAddr, Seg.ContentAlign.value(), 0);
179*d415bd75Srobert       ContentBlocks[AG] = &B;
180*d415bd75Srobert       NextAddr += Seg.ContentSize;
181*d415bd75Srobert     }
182*d415bd75Srobert   }
183*d415bd75Srobert 
184*d415bd75Srobert   // GRef declared separately since order-of-argument-eval isn't specified.
185*d415bd75Srobert   auto &GRef = *G;
186*d415bd75Srobert   MemMgr.allocate(JD, GRef,
187*d415bd75Srobert                   [G = std::move(G), ContentBlocks = std::move(ContentBlocks),
188*d415bd75Srobert                    OnCreated = std::move(OnCreated)](
189*d415bd75Srobert                       JITLinkMemoryManager::AllocResult Alloc) mutable {
190*d415bd75Srobert                     if (!Alloc)
191*d415bd75Srobert                       OnCreated(Alloc.takeError());
192*d415bd75Srobert                     else
193*d415bd75Srobert                       OnCreated(SimpleSegmentAlloc(std::move(G),
194*d415bd75Srobert                                                    std::move(ContentBlocks),
195*d415bd75Srobert                                                    std::move(*Alloc)));
196*d415bd75Srobert                   });
197*d415bd75Srobert }
198*d415bd75Srobert 
199*d415bd75Srobert Expected<SimpleSegmentAlloc>
Create(JITLinkMemoryManager & MemMgr,const JITLinkDylib * JD,SegmentMap Segments)200*d415bd75Srobert SimpleSegmentAlloc::Create(JITLinkMemoryManager &MemMgr, const JITLinkDylib *JD,
201*d415bd75Srobert                            SegmentMap Segments) {
202*d415bd75Srobert   std::promise<MSVCPExpected<SimpleSegmentAlloc>> AllocP;
203*d415bd75Srobert   auto AllocF = AllocP.get_future();
204*d415bd75Srobert   Create(MemMgr, JD, std::move(Segments),
205*d415bd75Srobert          [&](Expected<SimpleSegmentAlloc> Result) {
206*d415bd75Srobert            AllocP.set_value(std::move(Result));
207*d415bd75Srobert          });
208*d415bd75Srobert   return AllocF.get();
209*d415bd75Srobert }
210*d415bd75Srobert 
211*d415bd75Srobert SimpleSegmentAlloc::SimpleSegmentAlloc(SimpleSegmentAlloc &&) = default;
212*d415bd75Srobert SimpleSegmentAlloc &
213*d415bd75Srobert SimpleSegmentAlloc::operator=(SimpleSegmentAlloc &&) = default;
214*d415bd75Srobert SimpleSegmentAlloc::~SimpleSegmentAlloc() = default;
215*d415bd75Srobert 
216*d415bd75Srobert SimpleSegmentAlloc::SegmentInfo
getSegInfo(orc::AllocGroup AG)217*d415bd75Srobert SimpleSegmentAlloc::getSegInfo(orc::AllocGroup AG) {
218*d415bd75Srobert   auto I = ContentBlocks.find(AG);
219*d415bd75Srobert   if (I != ContentBlocks.end()) {
220*d415bd75Srobert     auto &B = *I->second;
221*d415bd75Srobert     return {B.getAddress(), B.getAlreadyMutableContent()};
222*d415bd75Srobert   }
223*d415bd75Srobert   return {};
224*d415bd75Srobert }
225*d415bd75Srobert 
SimpleSegmentAlloc(std::unique_ptr<LinkGraph> G,orc::AllocGroupSmallMap<Block * > ContentBlocks,std::unique_ptr<JITLinkMemoryManager::InFlightAlloc> Alloc)226*d415bd75Srobert SimpleSegmentAlloc::SimpleSegmentAlloc(
227*d415bd75Srobert     std::unique_ptr<LinkGraph> G,
228*d415bd75Srobert     orc::AllocGroupSmallMap<Block *> ContentBlocks,
229*d415bd75Srobert     std::unique_ptr<JITLinkMemoryManager::InFlightAlloc> Alloc)
230*d415bd75Srobert     : G(std::move(G)), ContentBlocks(std::move(ContentBlocks)),
231*d415bd75Srobert       Alloc(std::move(Alloc)) {}
232*d415bd75Srobert 
233*d415bd75Srobert class InProcessMemoryManager::IPInFlightAlloc
234*d415bd75Srobert     : public JITLinkMemoryManager::InFlightAlloc {
23509467b48Spatrick public:
IPInFlightAlloc(InProcessMemoryManager & MemMgr,LinkGraph & G,BasicLayout BL,sys::MemoryBlock StandardSegments,sys::MemoryBlock FinalizationSegments)236*d415bd75Srobert   IPInFlightAlloc(InProcessMemoryManager &MemMgr, LinkGraph &G, BasicLayout BL,
237*d415bd75Srobert                   sys::MemoryBlock StandardSegments,
238*d415bd75Srobert                   sys::MemoryBlock FinalizationSegments)
239*d415bd75Srobert       : MemMgr(MemMgr), G(G), BL(std::move(BL)),
240*d415bd75Srobert         StandardSegments(std::move(StandardSegments)),
241*d415bd75Srobert         FinalizationSegments(std::move(FinalizationSegments)) {}
242*d415bd75Srobert 
finalize(OnFinalizedFunction OnFinalized)243*d415bd75Srobert   void finalize(OnFinalizedFunction OnFinalized) override {
244*d415bd75Srobert 
245*d415bd75Srobert     // Apply memory protections to all segments.
246*d415bd75Srobert     if (auto Err = applyProtections()) {
247*d415bd75Srobert       OnFinalized(std::move(Err));
248*d415bd75Srobert       return;
24909467b48Spatrick     }
250*d415bd75Srobert 
251*d415bd75Srobert     // Run finalization actions.
252*d415bd75Srobert     auto DeallocActions = runFinalizeActions(G.allocActions());
253*d415bd75Srobert     if (!DeallocActions) {
254*d415bd75Srobert       OnFinalized(DeallocActions.takeError());
255*d415bd75Srobert       return;
25609467b48Spatrick     }
257*d415bd75Srobert 
258*d415bd75Srobert     // Release the finalize segments slab.
259*d415bd75Srobert     if (auto EC = sys::Memory::releaseMappedMemory(FinalizationSegments)) {
260*d415bd75Srobert       OnFinalized(errorCodeToError(EC));
261*d415bd75Srobert       return;
26209467b48Spatrick     }
263*d415bd75Srobert 
264*d415bd75Srobert     // Continue with finalized allocation.
265*d415bd75Srobert     OnFinalized(MemMgr.createFinalizedAlloc(std::move(StandardSegments),
266*d415bd75Srobert                                             std::move(*DeallocActions)));
26709467b48Spatrick   }
268*d415bd75Srobert 
abandon(OnAbandonedFunction OnAbandoned)269*d415bd75Srobert   void abandon(OnAbandonedFunction OnAbandoned) override {
270*d415bd75Srobert     Error Err = Error::success();
271*d415bd75Srobert     if (auto EC = sys::Memory::releaseMappedMemory(FinalizationSegments))
272*d415bd75Srobert       Err = joinErrors(std::move(Err), errorCodeToError(EC));
273*d415bd75Srobert     if (auto EC = sys::Memory::releaseMappedMemory(StandardSegments))
274*d415bd75Srobert       Err = joinErrors(std::move(Err), errorCodeToError(EC));
275*d415bd75Srobert     OnAbandoned(std::move(Err));
27609467b48Spatrick   }
27709467b48Spatrick 
27809467b48Spatrick private:
applyProtections()27909467b48Spatrick   Error applyProtections() {
280*d415bd75Srobert     for (auto &KV : BL.segments()) {
281*d415bd75Srobert       const auto &AG = KV.first;
282*d415bd75Srobert       auto &Seg = KV.second;
283*d415bd75Srobert 
284*d415bd75Srobert       auto Prot = toSysMemoryProtectionFlags(AG.getMemProt());
285*d415bd75Srobert 
286*d415bd75Srobert       uint64_t SegSize =
287*d415bd75Srobert           alignTo(Seg.ContentSize + Seg.ZeroFillSize, MemMgr.PageSize);
288*d415bd75Srobert       sys::MemoryBlock MB(Seg.WorkingMem, SegSize);
289*d415bd75Srobert       if (auto EC = sys::Memory::protectMappedMemory(MB, Prot))
29009467b48Spatrick         return errorCodeToError(EC);
29109467b48Spatrick       if (Prot & sys::Memory::MF_EXEC)
292*d415bd75Srobert         sys::Memory::InvalidateInstructionCache(MB.base(), MB.allocatedSize());
29309467b48Spatrick     }
29409467b48Spatrick     return Error::success();
29509467b48Spatrick   }
29609467b48Spatrick 
297*d415bd75Srobert   InProcessMemoryManager &MemMgr;
298*d415bd75Srobert   LinkGraph &G;
299*d415bd75Srobert   BasicLayout BL;
300*d415bd75Srobert   sys::MemoryBlock StandardSegments;
301*d415bd75Srobert   sys::MemoryBlock FinalizationSegments;
30209467b48Spatrick };
30309467b48Spatrick 
304*d415bd75Srobert Expected<std::unique_ptr<InProcessMemoryManager>>
Create()305*d415bd75Srobert InProcessMemoryManager::Create() {
306*d415bd75Srobert   if (auto PageSize = sys::Process::getPageSize())
307*d415bd75Srobert     return std::make_unique<InProcessMemoryManager>(*PageSize);
308*d415bd75Srobert   else
309*d415bd75Srobert     return PageSize.takeError();
310*d415bd75Srobert }
31109467b48Spatrick 
allocate(const JITLinkDylib * JD,LinkGraph & G,OnAllocatedFunction OnAllocated)312*d415bd75Srobert void InProcessMemoryManager::allocate(const JITLinkDylib *JD, LinkGraph &G,
313*d415bd75Srobert                                       OnAllocatedFunction OnAllocated) {
314*d415bd75Srobert 
315*d415bd75Srobert   // FIXME: Just check this once on startup.
316*d415bd75Srobert   if (!isPowerOf2_64((uint64_t)PageSize)) {
317*d415bd75Srobert     OnAllocated(make_error<StringError>("Page size is not a power of 2",
318*d415bd75Srobert                                         inconvertibleErrorCode()));
319*d415bd75Srobert     return;
320*d415bd75Srobert   }
321*d415bd75Srobert 
322*d415bd75Srobert   BasicLayout BL(G);
323*d415bd75Srobert 
324*d415bd75Srobert   /// Scan the request and calculate the group and total sizes.
325*d415bd75Srobert   /// Check that segment size is no larger than a page.
326*d415bd75Srobert   auto SegsSizes = BL.getContiguousPageBasedLayoutSizes(PageSize);
327*d415bd75Srobert   if (!SegsSizes) {
328*d415bd75Srobert     OnAllocated(SegsSizes.takeError());
329*d415bd75Srobert     return;
330*d415bd75Srobert   }
331*d415bd75Srobert 
332*d415bd75Srobert   /// Check that the total size requested (including zero fill) is not larger
333*d415bd75Srobert   /// than a size_t.
334*d415bd75Srobert   if (SegsSizes->total() > std::numeric_limits<size_t>::max()) {
335*d415bd75Srobert     OnAllocated(make_error<JITLinkError>(
336*d415bd75Srobert         "Total requested size " + formatv("{0:x}", SegsSizes->total()) +
337*d415bd75Srobert         " for graph " + G.getName() + " exceeds address space"));
338*d415bd75Srobert     return;
339*d415bd75Srobert   }
340*d415bd75Srobert 
341*d415bd75Srobert   // Allocate one slab for the whole thing (to make sure everything is
342*d415bd75Srobert   // in-range), then partition into standard and finalization blocks.
343*d415bd75Srobert   //
344*d415bd75Srobert   // FIXME: Make two separate allocations in the future to reduce
345*d415bd75Srobert   // fragmentation: finalization segments will usually be a single page, and
346*d415bd75Srobert   // standard segments are likely to be more than one page. Where multiple
347*d415bd75Srobert   // allocations are in-flight at once (likely) the current approach will leave
348*d415bd75Srobert   // a lot of single-page holes.
349*d415bd75Srobert   sys::MemoryBlock Slab;
350*d415bd75Srobert   sys::MemoryBlock StandardSegsMem;
351*d415bd75Srobert   sys::MemoryBlock FinalizeSegsMem;
352*d415bd75Srobert   {
35309467b48Spatrick     const sys::Memory::ProtectionFlags ReadWrite =
35409467b48Spatrick         static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
35509467b48Spatrick                                                   sys::Memory::MF_WRITE);
35609467b48Spatrick 
35709467b48Spatrick     std::error_code EC;
358*d415bd75Srobert     Slab = sys::Memory::allocateMappedMemory(SegsSizes->total(), nullptr,
359*d415bd75Srobert                                              ReadWrite, EC);
36009467b48Spatrick 
361*d415bd75Srobert     if (EC) {
362*d415bd75Srobert       OnAllocated(errorCodeToError(EC));
363*d415bd75Srobert       return;
36409467b48Spatrick     }
36573471bf0Spatrick 
366*d415bd75Srobert     // Zero-fill the whole slab up-front.
367*d415bd75Srobert     memset(Slab.base(), 0, Slab.allocatedSize());
368*d415bd75Srobert 
369*d415bd75Srobert     StandardSegsMem = {Slab.base(),
370*d415bd75Srobert                        static_cast<size_t>(SegsSizes->StandardSegs)};
371*d415bd75Srobert     FinalizeSegsMem = {(void *)((char *)Slab.base() + SegsSizes->StandardSegs),
372*d415bd75Srobert                        static_cast<size_t>(SegsSizes->FinalizeSegs)};
373*d415bd75Srobert   }
374*d415bd75Srobert 
375*d415bd75Srobert   auto NextStandardSegAddr = orc::ExecutorAddr::fromPtr(StandardSegsMem.base());
376*d415bd75Srobert   auto NextFinalizeSegAddr = orc::ExecutorAddr::fromPtr(FinalizeSegsMem.base());
377*d415bd75Srobert 
378*d415bd75Srobert   LLVM_DEBUG({
379*d415bd75Srobert     dbgs() << "InProcessMemoryManager allocated:\n";
380*d415bd75Srobert     if (SegsSizes->StandardSegs)
381*d415bd75Srobert       dbgs() << formatv("  [ {0:x16} -- {1:x16} ]", NextStandardSegAddr,
382*d415bd75Srobert                         NextStandardSegAddr + StandardSegsMem.allocatedSize())
383*d415bd75Srobert              << " to stardard segs\n";
384*d415bd75Srobert     else
385*d415bd75Srobert       dbgs() << "  no standard segs\n";
386*d415bd75Srobert     if (SegsSizes->FinalizeSegs)
387*d415bd75Srobert       dbgs() << formatv("  [ {0:x16} -- {1:x16} ]", NextFinalizeSegAddr,
388*d415bd75Srobert                         NextFinalizeSegAddr + FinalizeSegsMem.allocatedSize())
389*d415bd75Srobert              << " to finalize segs\n";
390*d415bd75Srobert     else
391*d415bd75Srobert       dbgs() << "  no finalize segs\n";
392*d415bd75Srobert   });
393*d415bd75Srobert 
394*d415bd75Srobert   // Build ProtMap, assign addresses.
395*d415bd75Srobert   for (auto &KV : BL.segments()) {
396*d415bd75Srobert     auto &AG = KV.first;
397*d415bd75Srobert     auto &Seg = KV.second;
398*d415bd75Srobert 
399*d415bd75Srobert     auto &SegAddr =
400*d415bd75Srobert         (AG.getMemDeallocPolicy() == orc::MemDeallocPolicy::Standard)
401*d415bd75Srobert             ? NextStandardSegAddr
402*d415bd75Srobert             : NextFinalizeSegAddr;
403*d415bd75Srobert 
404*d415bd75Srobert     Seg.WorkingMem = SegAddr.toPtr<char *>();
405*d415bd75Srobert     Seg.Addr = SegAddr;
406*d415bd75Srobert 
407*d415bd75Srobert     SegAddr += alignTo(Seg.ContentSize + Seg.ZeroFillSize, PageSize);
408*d415bd75Srobert   }
409*d415bd75Srobert 
410*d415bd75Srobert   if (auto Err = BL.apply()) {
411*d415bd75Srobert     OnAllocated(std::move(Err));
412*d415bd75Srobert     return;
413*d415bd75Srobert   }
414*d415bd75Srobert 
415*d415bd75Srobert   OnAllocated(std::make_unique<IPInFlightAlloc>(*this, G, std::move(BL),
416*d415bd75Srobert                                                 std::move(StandardSegsMem),
417*d415bd75Srobert                                                 std::move(FinalizeSegsMem)));
418*d415bd75Srobert }
419*d415bd75Srobert 
deallocate(std::vector<FinalizedAlloc> Allocs,OnDeallocatedFunction OnDeallocated)420*d415bd75Srobert void InProcessMemoryManager::deallocate(std::vector<FinalizedAlloc> Allocs,
421*d415bd75Srobert                                         OnDeallocatedFunction OnDeallocated) {
422*d415bd75Srobert   std::vector<sys::MemoryBlock> StandardSegmentsList;
423*d415bd75Srobert   std::vector<std::vector<orc::shared::WrapperFunctionCall>> DeallocActionsList;
424*d415bd75Srobert 
425*d415bd75Srobert   {
426*d415bd75Srobert     std::lock_guard<std::mutex> Lock(FinalizedAllocsMutex);
427*d415bd75Srobert     for (auto &Alloc : Allocs) {
428*d415bd75Srobert       auto *FA = Alloc.release().toPtr<FinalizedAllocInfo *>();
429*d415bd75Srobert       StandardSegmentsList.push_back(std::move(FA->StandardSegments));
430*d415bd75Srobert       if (!FA->DeallocActions.empty())
431*d415bd75Srobert         DeallocActionsList.push_back(std::move(FA->DeallocActions));
432*d415bd75Srobert       FA->~FinalizedAllocInfo();
433*d415bd75Srobert       FinalizedAllocInfos.Deallocate(FA);
434*d415bd75Srobert     }
435*d415bd75Srobert   }
436*d415bd75Srobert 
437*d415bd75Srobert   Error DeallocErr = Error::success();
438*d415bd75Srobert 
439*d415bd75Srobert   while (!DeallocActionsList.empty()) {
440*d415bd75Srobert     auto &DeallocActions = DeallocActionsList.back();
441*d415bd75Srobert     auto &StandardSegments = StandardSegmentsList.back();
442*d415bd75Srobert 
443*d415bd75Srobert     /// Run any deallocate calls.
444*d415bd75Srobert     while (!DeallocActions.empty()) {
445*d415bd75Srobert       if (auto Err = DeallocActions.back().runWithSPSRetErrorMerged())
446*d415bd75Srobert         DeallocErr = joinErrors(std::move(DeallocErr), std::move(Err));
447*d415bd75Srobert       DeallocActions.pop_back();
448*d415bd75Srobert     }
449*d415bd75Srobert 
450*d415bd75Srobert     /// Release the standard segments slab.
451*d415bd75Srobert     if (auto EC = sys::Memory::releaseMappedMemory(StandardSegments))
452*d415bd75Srobert       DeallocErr = joinErrors(std::move(DeallocErr), errorCodeToError(EC));
453*d415bd75Srobert 
454*d415bd75Srobert     DeallocActionsList.pop_back();
455*d415bd75Srobert     StandardSegmentsList.pop_back();
456*d415bd75Srobert   }
457*d415bd75Srobert 
458*d415bd75Srobert   OnDeallocated(std::move(DeallocErr));
459*d415bd75Srobert }
460*d415bd75Srobert 
461*d415bd75Srobert JITLinkMemoryManager::FinalizedAlloc
createFinalizedAlloc(sys::MemoryBlock StandardSegments,std::vector<orc::shared::WrapperFunctionCall> DeallocActions)462*d415bd75Srobert InProcessMemoryManager::createFinalizedAlloc(
463*d415bd75Srobert     sys::MemoryBlock StandardSegments,
464*d415bd75Srobert     std::vector<orc::shared::WrapperFunctionCall> DeallocActions) {
465*d415bd75Srobert   std::lock_guard<std::mutex> Lock(FinalizedAllocsMutex);
466*d415bd75Srobert   auto *FA = FinalizedAllocInfos.Allocate<FinalizedAllocInfo>();
467*d415bd75Srobert   new (FA) FinalizedAllocInfo(
468*d415bd75Srobert       {std::move(StandardSegments), std::move(DeallocActions)});
469*d415bd75Srobert   return FinalizedAlloc(orc::ExecutorAddr::fromPtr(FA));
47009467b48Spatrick }
47109467b48Spatrick 
47209467b48Spatrick } // end namespace jitlink
47309467b48Spatrick } // end namespace llvm
474