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