xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MapperJITLinkMemoryManager.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1fcaf7f86SDimitry Andric //=== MapperJITLinkMemoryManager.cpp - Memory management with MemoryMapper ===//
2fcaf7f86SDimitry Andric //
3fcaf7f86SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fcaf7f86SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fcaf7f86SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fcaf7f86SDimitry Andric //
7fcaf7f86SDimitry Andric //===----------------------------------------------------------------------===//
8fcaf7f86SDimitry Andric 
9fcaf7f86SDimitry Andric #include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"
10fcaf7f86SDimitry Andric 
11*bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h"
12fcaf7f86SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h"
13fcaf7f86SDimitry Andric #include "llvm/Support/Process.h"
14fcaf7f86SDimitry Andric 
15fcaf7f86SDimitry Andric using namespace llvm::jitlink;
16fcaf7f86SDimitry Andric 
17fcaf7f86SDimitry Andric namespace llvm {
18fcaf7f86SDimitry Andric namespace orc {
19fcaf7f86SDimitry Andric 
20fcaf7f86SDimitry Andric class MapperJITLinkMemoryManager::InFlightAlloc
21fcaf7f86SDimitry Andric     : public JITLinkMemoryManager::InFlightAlloc {
22fcaf7f86SDimitry Andric public:
InFlightAlloc(MapperJITLinkMemoryManager & Parent,LinkGraph & G,ExecutorAddr AllocAddr,std::vector<MemoryMapper::AllocInfo::SegInfo> Segs)23fcaf7f86SDimitry Andric   InFlightAlloc(MapperJITLinkMemoryManager &Parent, LinkGraph &G,
24fcaf7f86SDimitry Andric                 ExecutorAddr AllocAddr,
25fcaf7f86SDimitry Andric                 std::vector<MemoryMapper::AllocInfo::SegInfo> Segs)
26fcaf7f86SDimitry Andric       : Parent(Parent), G(G), AllocAddr(AllocAddr), Segs(std::move(Segs)) {}
27fcaf7f86SDimitry Andric 
finalize(OnFinalizedFunction OnFinalize)28fcaf7f86SDimitry Andric   void finalize(OnFinalizedFunction OnFinalize) override {
29fcaf7f86SDimitry Andric     MemoryMapper::AllocInfo AI;
30fcaf7f86SDimitry Andric     AI.MappingBase = AllocAddr;
31fcaf7f86SDimitry Andric 
32fcaf7f86SDimitry Andric     std::swap(AI.Segments, Segs);
33fcaf7f86SDimitry Andric     std::swap(AI.Actions, G.allocActions());
34fcaf7f86SDimitry Andric 
35*bdd1243dSDimitry Andric     Parent.Mapper->initialize(AI, [OnFinalize = std::move(OnFinalize)](
36*bdd1243dSDimitry Andric                                       Expected<ExecutorAddr> Result) mutable {
37fcaf7f86SDimitry Andric       if (!Result) {
38fcaf7f86SDimitry Andric         OnFinalize(Result.takeError());
39fcaf7f86SDimitry Andric         return;
40fcaf7f86SDimitry Andric       }
41fcaf7f86SDimitry Andric 
42fcaf7f86SDimitry Andric       OnFinalize(FinalizedAlloc(*Result));
43fcaf7f86SDimitry Andric     });
44fcaf7f86SDimitry Andric   }
45fcaf7f86SDimitry Andric 
abandon(OnAbandonedFunction OnFinalize)46fcaf7f86SDimitry Andric   void abandon(OnAbandonedFunction OnFinalize) override {
47fcaf7f86SDimitry Andric     Parent.Mapper->release({AllocAddr}, std::move(OnFinalize));
48fcaf7f86SDimitry Andric   }
49fcaf7f86SDimitry Andric 
50fcaf7f86SDimitry Andric private:
51fcaf7f86SDimitry Andric   MapperJITLinkMemoryManager &Parent;
52fcaf7f86SDimitry Andric   LinkGraph &G;
53fcaf7f86SDimitry Andric   ExecutorAddr AllocAddr;
54fcaf7f86SDimitry Andric   std::vector<MemoryMapper::AllocInfo::SegInfo> Segs;
55fcaf7f86SDimitry Andric };
56fcaf7f86SDimitry Andric 
MapperJITLinkMemoryManager(size_t ReservationGranularity,std::unique_ptr<MemoryMapper> Mapper)57fcaf7f86SDimitry Andric MapperJITLinkMemoryManager::MapperJITLinkMemoryManager(
58*bdd1243dSDimitry Andric     size_t ReservationGranularity, std::unique_ptr<MemoryMapper> Mapper)
59*bdd1243dSDimitry Andric     : ReservationUnits(ReservationGranularity), AvailableMemory(AMAllocator),
60*bdd1243dSDimitry Andric       Mapper(std::move(Mapper)) {}
61fcaf7f86SDimitry Andric 
allocate(const JITLinkDylib * JD,LinkGraph & G,OnAllocatedFunction OnAllocated)62fcaf7f86SDimitry Andric void MapperJITLinkMemoryManager::allocate(const JITLinkDylib *JD, LinkGraph &G,
63fcaf7f86SDimitry Andric                                           OnAllocatedFunction OnAllocated) {
64fcaf7f86SDimitry Andric   BasicLayout BL(G);
65fcaf7f86SDimitry Andric 
66fcaf7f86SDimitry Andric   // find required address space
67fcaf7f86SDimitry Andric   auto SegsSizes = BL.getContiguousPageBasedLayoutSizes(Mapper->getPageSize());
68fcaf7f86SDimitry Andric   if (!SegsSizes) {
69fcaf7f86SDimitry Andric     OnAllocated(SegsSizes.takeError());
70fcaf7f86SDimitry Andric     return;
71fcaf7f86SDimitry Andric   }
72fcaf7f86SDimitry Andric 
73*bdd1243dSDimitry Andric   auto TotalSize = SegsSizes->total();
74fcaf7f86SDimitry Andric 
75*bdd1243dSDimitry Andric   auto CompleteAllocation = [this, &G, BL = std::move(BL),
76*bdd1243dSDimitry Andric                              OnAllocated = std::move(OnAllocated)](
77fcaf7f86SDimitry Andric                                 Expected<ExecutorAddrRange> Result) mutable {
78fcaf7f86SDimitry Andric     if (!Result) {
79*bdd1243dSDimitry Andric       Mutex.unlock();
80fcaf7f86SDimitry Andric       return OnAllocated(Result.takeError());
81fcaf7f86SDimitry Andric     }
82fcaf7f86SDimitry Andric 
83fcaf7f86SDimitry Andric     auto NextSegAddr = Result->Start;
84fcaf7f86SDimitry Andric 
85fcaf7f86SDimitry Andric     std::vector<MemoryMapper::AllocInfo::SegInfo> SegInfos;
86fcaf7f86SDimitry Andric 
87fcaf7f86SDimitry Andric     for (auto &KV : BL.segments()) {
88fcaf7f86SDimitry Andric       auto &AG = KV.first;
89fcaf7f86SDimitry Andric       auto &Seg = KV.second;
90fcaf7f86SDimitry Andric 
91fcaf7f86SDimitry Andric       auto TotalSize = Seg.ContentSize + Seg.ZeroFillSize;
92fcaf7f86SDimitry Andric 
93fcaf7f86SDimitry Andric       Seg.Addr = NextSegAddr;
94fcaf7f86SDimitry Andric       Seg.WorkingMem = Mapper->prepare(NextSegAddr, TotalSize);
95fcaf7f86SDimitry Andric 
96fcaf7f86SDimitry Andric       NextSegAddr += alignTo(TotalSize, Mapper->getPageSize());
97fcaf7f86SDimitry Andric 
98fcaf7f86SDimitry Andric       MemoryMapper::AllocInfo::SegInfo SI;
99fcaf7f86SDimitry Andric       SI.Offset = Seg.Addr - Result->Start;
100fcaf7f86SDimitry Andric       SI.ContentSize = Seg.ContentSize;
101fcaf7f86SDimitry Andric       SI.ZeroFillSize = Seg.ZeroFillSize;
102*bdd1243dSDimitry Andric       SI.AG = AG;
103fcaf7f86SDimitry Andric       SI.WorkingMem = Seg.WorkingMem;
104fcaf7f86SDimitry Andric 
105fcaf7f86SDimitry Andric       SegInfos.push_back(SI);
106fcaf7f86SDimitry Andric     }
107fcaf7f86SDimitry Andric 
108*bdd1243dSDimitry Andric     UsedMemory.insert({Result->Start, NextSegAddr - Result->Start});
109*bdd1243dSDimitry Andric 
110*bdd1243dSDimitry Andric     if (NextSegAddr < Result->End) {
111*bdd1243dSDimitry Andric       // Save the remaining memory for reuse in next allocation(s)
112*bdd1243dSDimitry Andric       AvailableMemory.insert(NextSegAddr, Result->End - 1, true);
113*bdd1243dSDimitry Andric     }
114*bdd1243dSDimitry Andric     Mutex.unlock();
115*bdd1243dSDimitry Andric 
116fcaf7f86SDimitry Andric     if (auto Err = BL.apply()) {
117fcaf7f86SDimitry Andric       OnAllocated(std::move(Err));
118fcaf7f86SDimitry Andric       return;
119fcaf7f86SDimitry Andric     }
120fcaf7f86SDimitry Andric 
121fcaf7f86SDimitry Andric     OnAllocated(std::make_unique<InFlightAlloc>(*this, G, Result->Start,
122fcaf7f86SDimitry Andric                                                 std::move(SegInfos)));
123*bdd1243dSDimitry Andric   };
124*bdd1243dSDimitry Andric 
125*bdd1243dSDimitry Andric   Mutex.lock();
126*bdd1243dSDimitry Andric 
127*bdd1243dSDimitry Andric   // find an already reserved range that is large enough
128*bdd1243dSDimitry Andric   ExecutorAddrRange SelectedRange{};
129*bdd1243dSDimitry Andric 
130*bdd1243dSDimitry Andric   for (AvailableMemoryMap::iterator It = AvailableMemory.begin();
131*bdd1243dSDimitry Andric        It != AvailableMemory.end(); It++) {
132*bdd1243dSDimitry Andric     if (It.stop() - It.start() + 1 >= TotalSize) {
133*bdd1243dSDimitry Andric       SelectedRange = ExecutorAddrRange(It.start(), It.stop() + 1);
134*bdd1243dSDimitry Andric       It.erase();
135*bdd1243dSDimitry Andric       break;
136*bdd1243dSDimitry Andric     }
137*bdd1243dSDimitry Andric   }
138*bdd1243dSDimitry Andric 
139*bdd1243dSDimitry Andric   if (SelectedRange.empty()) { // no already reserved range was found
140*bdd1243dSDimitry Andric     auto TotalAllocation = alignTo(TotalSize, ReservationUnits);
141*bdd1243dSDimitry Andric     Mapper->reserve(TotalAllocation, std::move(CompleteAllocation));
142*bdd1243dSDimitry Andric   } else {
143*bdd1243dSDimitry Andric     CompleteAllocation(SelectedRange);
144*bdd1243dSDimitry Andric   }
145fcaf7f86SDimitry Andric }
146fcaf7f86SDimitry Andric 
deallocate(std::vector<FinalizedAlloc> Allocs,OnDeallocatedFunction OnDeallocated)147fcaf7f86SDimitry Andric void MapperJITLinkMemoryManager::deallocate(
148fcaf7f86SDimitry Andric     std::vector<FinalizedAlloc> Allocs, OnDeallocatedFunction OnDeallocated) {
149fcaf7f86SDimitry Andric   std::vector<ExecutorAddr> Bases;
150fcaf7f86SDimitry Andric   Bases.reserve(Allocs.size());
151fcaf7f86SDimitry Andric   for (auto &FA : Allocs) {
152*bdd1243dSDimitry Andric     ExecutorAddr Addr = FA.getAddress();
153*bdd1243dSDimitry Andric     Bases.push_back(Addr);
154*bdd1243dSDimitry Andric   }
155*bdd1243dSDimitry Andric 
156*bdd1243dSDimitry Andric   Mapper->deinitialize(Bases, [this, Allocs = std::move(Allocs),
157*bdd1243dSDimitry Andric                                OnDeallocated = std::move(OnDeallocated)](
158*bdd1243dSDimitry Andric                                   llvm::Error Err) mutable {
159*bdd1243dSDimitry Andric     // TODO: How should we treat memory that we fail to deinitialize?
160*bdd1243dSDimitry Andric     // We're currently bailing out and treating it as "burned" -- should we
161*bdd1243dSDimitry Andric     // require that a failure to deinitialize still reset the memory so that
162*bdd1243dSDimitry Andric     // we can reclaim it?
163*bdd1243dSDimitry Andric     if (Err) {
164*bdd1243dSDimitry Andric       for (auto &FA : Allocs)
165*bdd1243dSDimitry Andric         FA.release();
166*bdd1243dSDimitry Andric       OnDeallocated(std::move(Err));
167*bdd1243dSDimitry Andric       return;
168*bdd1243dSDimitry Andric     }
169*bdd1243dSDimitry Andric 
170*bdd1243dSDimitry Andric     {
171*bdd1243dSDimitry Andric       std::lock_guard<std::mutex> Lock(Mutex);
172*bdd1243dSDimitry Andric 
173*bdd1243dSDimitry Andric       for (auto &FA : Allocs) {
174*bdd1243dSDimitry Andric         ExecutorAddr Addr = FA.getAddress();
175*bdd1243dSDimitry Andric         ExecutorAddrDiff Size = UsedMemory[Addr];
176*bdd1243dSDimitry Andric 
177*bdd1243dSDimitry Andric         UsedMemory.erase(Addr);
178*bdd1243dSDimitry Andric         AvailableMemory.insert(Addr, Addr + Size - 1, true);
179*bdd1243dSDimitry Andric 
180fcaf7f86SDimitry Andric         FA.release();
181fcaf7f86SDimitry Andric       }
182*bdd1243dSDimitry Andric     }
183*bdd1243dSDimitry Andric 
184*bdd1243dSDimitry Andric     OnDeallocated(Error::success());
185*bdd1243dSDimitry Andric   });
186fcaf7f86SDimitry Andric }
187fcaf7f86SDimitry Andric 
188fcaf7f86SDimitry Andric } // end namespace orc
189fcaf7f86SDimitry Andric } // end namespace llvm
190