LLVM  16.0.0git
MapperJITLinkMemoryManager.cpp
Go to the documentation of this file.
1 //=== MapperJITLinkMemoryManager.cpp - Memory management with MemoryMapper ===//
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 
10 
11 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/Support/Process.h"
14 
15 using namespace llvm::jitlink;
16 
17 namespace llvm {
18 namespace orc {
19 
22 public:
24  ExecutorAddr AllocAddr,
25  std::vector<MemoryMapper::AllocInfo::SegInfo> Segs)
26  : Parent(Parent), G(G), AllocAddr(AllocAddr), Segs(std::move(Segs)) {}
27 
28  void finalize(OnFinalizedFunction OnFinalize) override {
30  AI.MappingBase = AllocAddr;
31 
32  std::swap(AI.Segments, Segs);
33  std::swap(AI.Actions, G.allocActions());
34 
35  Parent.Mapper->initialize(AI, [OnFinalize = std::move(OnFinalize)](
36  Expected<ExecutorAddr> Result) mutable {
37  if (!Result) {
38  OnFinalize(Result.takeError());
39  return;
40  }
41 
42  OnFinalize(FinalizedAlloc(*Result));
43  });
44  }
45 
46  void abandon(OnAbandonedFunction OnFinalize) override {
47  Parent.Mapper->release({AllocAddr}, std::move(OnFinalize));
48  }
49 
50 private:
52  LinkGraph &G;
53  ExecutorAddr AllocAddr;
54  std::vector<MemoryMapper::AllocInfo::SegInfo> Segs;
55 };
56 
57 MapperJITLinkMemoryManager::MapperJITLinkMemoryManager(
58  size_t ReservationGranularity, std::unique_ptr<MemoryMapper> Mapper)
59  : ReservationUnits(ReservationGranularity), AvailableMemory(AMAllocator),
60  Mapper(std::move(Mapper)) {}
61 
63  OnAllocatedFunction OnAllocated) {
64  BasicLayout BL(G);
65 
66  // find required address space
67  auto SegsSizes = BL.getContiguousPageBasedLayoutSizes(Mapper->getPageSize());
68  if (!SegsSizes) {
69  OnAllocated(SegsSizes.takeError());
70  return;
71  }
72 
73  auto TotalSize = SegsSizes->total();
74 
75  auto CompleteAllocation = [this, &G, BL = std::move(BL),
76  OnAllocated = std::move(OnAllocated)](
77  Expected<ExecutorAddrRange> Result) mutable {
78  if (!Result) {
79  Mutex.unlock();
80  return OnAllocated(Result.takeError());
81  }
82 
83  auto NextSegAddr = Result->Start;
84 
85  std::vector<MemoryMapper::AllocInfo::SegInfo> SegInfos;
86 
87  for (auto &KV : BL.segments()) {
88  auto &AG = KV.first;
89  auto &Seg = KV.second;
90 
91  auto TotalSize = Seg.ContentSize + Seg.ZeroFillSize;
92 
93  Seg.Addr = NextSegAddr;
94  Seg.WorkingMem = Mapper->prepare(NextSegAddr, TotalSize);
95 
96  NextSegAddr += alignTo(TotalSize, Mapper->getPageSize());
97 
99  SI.Offset = Seg.Addr - Result->Start;
100  SI.ContentSize = Seg.ContentSize;
101  SI.ZeroFillSize = Seg.ZeroFillSize;
102  SI.AG = AG;
103  SI.WorkingMem = Seg.WorkingMem;
104 
105  SegInfos.push_back(SI);
106  }
107 
108  UsedMemory.insert({Result->Start, NextSegAddr - Result->Start});
109 
110  if (NextSegAddr < Result->End) {
111  // Save the remaining memory for reuse in next allocation(s)
112  AvailableMemory.insert(NextSegAddr, Result->End - 1, true);
113  }
114  Mutex.unlock();
115 
116  if (auto Err = BL.apply()) {
117  OnAllocated(std::move(Err));
118  return;
119  }
120 
121  OnAllocated(std::make_unique<InFlightAlloc>(*this, G, Result->Start,
122  std::move(SegInfos)));
123  };
124 
125  Mutex.lock();
126 
127  // find an already reserved range that is large enough
128  ExecutorAddrRange SelectedRange{};
129 
130  for (AvailableMemoryMap::iterator It = AvailableMemory.begin();
131  It != AvailableMemory.end(); It++) {
132  if (It.stop() - It.start() + 1 >= TotalSize) {
133  SelectedRange = ExecutorAddrRange(It.start(), It.stop() + 1);
134  It.erase();
135  break;
136  }
137  }
138 
139  if (SelectedRange.empty()) { // no already reserved range was found
140  auto TotalAllocation = alignTo(TotalSize, ReservationUnits);
141  Mapper->reserve(TotalAllocation, std::move(CompleteAllocation));
142  } else {
143  CompleteAllocation(SelectedRange);
144  }
145 }
146 
148  std::vector<FinalizedAlloc> Allocs, OnDeallocatedFunction OnDeallocated) {
149  std::vector<ExecutorAddr> Bases;
150  Bases.reserve(Allocs.size());
151  for (auto &FA : Allocs) {
152  ExecutorAddr Addr = FA.getAddress();
153  Bases.push_back(Addr);
154  }
155 
156  Mapper->deinitialize(Bases, [this, Allocs = std::move(Allocs),
157  OnDeallocated = std::move(OnDeallocated)](
158  llvm::Error Err) mutable {
159  // TODO: How should we treat memory that we fail to deinitialize?
160  // We're currently bailing out and treating it as "burned" -- should we
161  // require that a failure to deinitialize still reset the memory so that
162  // we can reclaim it?
163  if (Err) {
164  for (auto &FA : Allocs)
165  FA.release();
166  OnDeallocated(std::move(Err));
167  return;
168  }
169 
170  {
171  std::lock_guard<std::mutex> Lock(Mutex);
172 
173  for (auto &FA : Allocs) {
174  ExecutorAddr Addr = FA.getAddress();
175  ExecutorAddrDiff Size = UsedMemory[Addr];
176 
177  UsedMemory.erase(Addr);
178  AvailableMemory.insert(Addr, Addr + Size - 1, true);
179 
180  FA.release();
181  }
182  }
183 
184  OnDeallocated(Error::success());
185  });
186 }
187 
188 } // end namespace orc
189 } // end namespace llvm
llvm::orc::ExecutorAddr
Represents an address in the executor process.
Definition: ExecutorAddress.h:31
llvm::alignTo
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:156
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
llvm::unique_function
unique_function is a type-erasing functor similar to std::function.
Definition: FunctionExtras.h:56
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:329
llvm::IntervalMap::iterator
Definition: IntervalMap.h:1572
llvm::orc::MapperJITLinkMemoryManager::InFlightAlloc::finalize
void finalize(OnFinalizedFunction OnFinalize) override
Called to transfer working memory to the target and apply finalization.
Definition: MapperJITLinkMemoryManager.cpp:28
llvm::orc::MemoryMapper::AllocInfo::MappingBase
ExecutorAddr MappingBase
Definition: MemoryMapper.h:39
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:41
STLExtras.h
llvm::ARCISD::BL
@ BL
Definition: ARCISelLowering.h:34
llvm::orc::MemoryMapper::AllocInfo::SegInfo
Definition: MemoryMapper.h:31
Process.h
SI
@ SI
Definition: SIInstrInfo.cpp:7882
llvm::orc::ExecutorAddrRange
Represents an address range in the exceutor process.
Definition: ExecutorAddress.h:191
llvm::sys::SmartMutex< false >
G
const DataFlowGraph & G
Definition: RDFGraph.cpp:200
uint64_t
Addr
uint64_t Addr
Definition: ELFObjHandler.cpp:79
llvm::orc::MapperJITLinkMemoryManager::InFlightAlloc
Definition: MapperJITLinkMemoryManager.cpp:20
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::orc::MapperJITLinkMemoryManager::deallocate
void deallocate(std::vector< FinalizedAlloc > Allocs, OnDeallocatedFunction OnDeallocated) override
Deallocate a list of allocation objects.
Definition: MapperJITLinkMemoryManager.cpp:147
llvm::move
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1836
std::swap
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:853
llvm::sys::SmartMutex::unlock
bool unlock()
Definition: Mutex.h:45
llvm::orc::MapperJITLinkMemoryManager::InFlightAlloc::abandon
void abandon(OnAbandonedFunction OnFinalize) override
Called prior to finalization if the allocation should be abandoned.
Definition: MapperJITLinkMemoryManager.cpp:46
llvm::orc::MapperJITLinkMemoryManager
Definition: MapperJITLinkMemoryManager.h:23
MapperJITLinkMemoryManager.h
llvm::sys::SmartMutex::lock
bool lock()
Definition: Mutex.h:33
std
Definition: BitVector.h:851
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
llvm::orc::MemoryMapper::AllocInfo::Actions
shared::AllocActions Actions
Definition: MemoryMapper.h:41
llvm::orc::MapperJITLinkMemoryManager::InFlightAlloc::InFlightAlloc
InFlightAlloc(MapperJITLinkMemoryManager &Parent, LinkGraph &G, ExecutorAddr AllocAddr, std::vector< MemoryMapper::AllocInfo::SegInfo > Segs)
Definition: MapperJITLinkMemoryManager.cpp:23
llvm::orc::MemoryMapper::AllocInfo::Segments
std::vector< SegInfo > Segments
Definition: MemoryMapper.h:40
llvm::orc::MemoryMapper::AllocInfo
Represents a single allocation containing multiple segments and initialization and deinitialization a...
Definition: MemoryMapper.h:30
llvm::orc::MapperJITLinkMemoryManager::allocate
void allocate(const jitlink::JITLinkDylib *JD, jitlink::LinkGraph &G, OnAllocatedFunction OnAllocated) override
Start the allocation process.
Definition: MapperJITLinkMemoryManager.cpp:62