LLVM 20.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"
14
15using namespace llvm::jitlink;
16
17namespace llvm {
18namespace orc {
19
22public:
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);
34
35 Parent.Mapper->initialize(AI, [OnFinalize = std::move(OnFinalize)](
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
50private:
52 LinkGraph &G;
53 ExecutorAddr AllocAddr;
54 std::vector<MemoryMapper::AllocInfo::SegInfo> Segs;
55};
56
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)](
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
uint64_t Addr
uint64_t Size
bool End
Definition: ELF_riscv.cpp:480
#define G(x, y, z)
Definition: MD5.cpp:56
Provides a library for accessing information about this process and other processes on the operating ...
This file contains some templates that are useful if you are working with the STL at all.
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
Represents an address in the executor process.
InFlightAlloc(MapperJITLinkMemoryManager &Parent, LinkGraph &G, ExecutorAddr AllocAddr, std::vector< MemoryMapper::AllocInfo::SegInfo > Segs)
void finalize(OnFinalizedFunction OnFinalize) override
Called to transfer working memory to the target and apply finalization.
void abandon(OnAbandonedFunction OnFinalize) override
Called prior to finalization if the allocation should be abandoned.
void deallocate(std::vector< FinalizedAlloc > Allocs, OnDeallocatedFunction OnDeallocated) override
Deallocate a list of allocation objects.
MapperJITLinkMemoryManager(size_t ReservationGranularity, std::unique_ptr< MemoryMapper > Mapper)
void allocate(const jitlink::JITLinkDylib *JD, jitlink::LinkGraph &G, OnAllocatedFunction OnAllocated) override
Start the allocation process.
unique_function is a type-erasing functor similar to std::function.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:155
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:1856
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:860
Represents an address range in the exceutor process.
Represents a single allocation containing multiple segments and initialization and deinitialization a...
Definition: MemoryMapper.h:30
std::vector< SegInfo > Segments
Definition: MemoryMapper.h:40
shared::AllocActions Actions
Definition: MemoryMapper.h:41