1 //=== MapperJITLinkMemoryManager.cpp - Memory management with MemoryMapper ===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"
11 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
12 #include "llvm/Support/Process.h"
14 using namespace llvm::jitlink
;
19 class MapperJITLinkMemoryManager::InFlightAlloc
20 : public JITLinkMemoryManager::InFlightAlloc
{
22 InFlightAlloc(MapperJITLinkMemoryManager
&Parent
, LinkGraph
&G
,
23 ExecutorAddr AllocAddr
,
24 std::vector
<MemoryMapper::AllocInfo::SegInfo
> Segs
)
25 : Parent(Parent
), G(G
), AllocAddr(AllocAddr
), Segs(std::move(Segs
)) {}
27 void finalize(OnFinalizedFunction OnFinalize
) override
{
28 MemoryMapper::AllocInfo AI
;
29 AI
.MappingBase
= AllocAddr
;
31 std::swap(AI
.Segments
, Segs
);
32 std::swap(AI
.Actions
, G
.allocActions());
34 Parent
.Mapper
->initialize(AI
, [OnFinalize
= std::move(OnFinalize
)](
35 Expected
<ExecutorAddr
> Result
) mutable {
37 OnFinalize(Result
.takeError());
41 OnFinalize(FinalizedAlloc(*Result
));
45 void abandon(OnAbandonedFunction OnFinalize
) override
{
46 Parent
.Mapper
->release({AllocAddr
}, std::move(OnFinalize
));
50 MapperJITLinkMemoryManager
&Parent
;
52 ExecutorAddr AllocAddr
;
53 std::vector
<MemoryMapper::AllocInfo::SegInfo
> Segs
;
56 MapperJITLinkMemoryManager::MapperJITLinkMemoryManager(
57 size_t ReservationGranularity
, std::unique_ptr
<MemoryMapper
> Mapper
)
58 : ReservationUnits(ReservationGranularity
), AvailableMemory(AMAllocator
),
59 Mapper(std::move(Mapper
)) {}
61 void MapperJITLinkMemoryManager::allocate(const JITLinkDylib
*JD
, LinkGraph
&G
,
62 OnAllocatedFunction OnAllocated
) {
65 // find required address space
66 auto SegsSizes
= BL
.getContiguousPageBasedLayoutSizes(Mapper
->getPageSize());
68 OnAllocated(SegsSizes
.takeError());
72 auto TotalSize
= SegsSizes
->total();
74 auto CompleteAllocation
= [this, &G
, BL
= std::move(BL
),
75 OnAllocated
= std::move(OnAllocated
)](
76 Expected
<ExecutorAddrRange
> Result
) mutable {
79 return OnAllocated(Result
.takeError());
82 auto NextSegAddr
= Result
->Start
;
84 std::vector
<MemoryMapper::AllocInfo::SegInfo
> SegInfos
;
86 for (auto &KV
: BL
.segments()) {
88 auto &Seg
= KV
.second
;
90 auto TotalSize
= Seg
.ContentSize
+ Seg
.ZeroFillSize
;
92 Seg
.Addr
= NextSegAddr
;
93 Seg
.WorkingMem
= Mapper
->prepare(NextSegAddr
, TotalSize
);
95 NextSegAddr
+= alignTo(TotalSize
, Mapper
->getPageSize());
97 MemoryMapper::AllocInfo::SegInfo SI
;
98 SI
.Offset
= Seg
.Addr
- Result
->Start
;
99 SI
.ContentSize
= Seg
.ContentSize
;
100 SI
.ZeroFillSize
= Seg
.ZeroFillSize
;
102 SI
.WorkingMem
= Seg
.WorkingMem
;
104 SegInfos
.push_back(SI
);
107 UsedMemory
.insert({Result
->Start
, NextSegAddr
- Result
->Start
});
109 if (NextSegAddr
< Result
->End
) {
110 // Save the remaining memory for reuse in next allocation(s)
111 AvailableMemory
.insert(NextSegAddr
, Result
->End
- 1, true);
115 if (auto Err
= BL
.apply()) {
116 OnAllocated(std::move(Err
));
120 OnAllocated(std::make_unique
<InFlightAlloc
>(*this, G
, Result
->Start
,
121 std::move(SegInfos
)));
126 // find an already reserved range that is large enough
127 ExecutorAddrRange SelectedRange
{};
129 for (AvailableMemoryMap::iterator It
= AvailableMemory
.begin();
130 It
!= AvailableMemory
.end(); It
++) {
131 if (It
.stop() - It
.start() + 1 >= TotalSize
) {
132 SelectedRange
= ExecutorAddrRange(It
.start(), It
.stop() + 1);
138 if (SelectedRange
.empty()) { // no already reserved range was found
139 auto TotalAllocation
= alignTo(TotalSize
, ReservationUnits
);
140 Mapper
->reserve(TotalAllocation
, std::move(CompleteAllocation
));
142 CompleteAllocation(SelectedRange
);
146 void MapperJITLinkMemoryManager::deallocate(
147 std::vector
<FinalizedAlloc
> Allocs
, OnDeallocatedFunction OnDeallocated
) {
148 std::vector
<ExecutorAddr
> Bases
;
149 Bases
.reserve(Allocs
.size());
150 for (auto &FA
: Allocs
) {
151 ExecutorAddr Addr
= FA
.getAddress();
152 Bases
.push_back(Addr
);
155 Mapper
->deinitialize(Bases
, [this, Allocs
= std::move(Allocs
),
156 OnDeallocated
= std::move(OnDeallocated
)](
157 llvm::Error Err
) mutable {
158 // TODO: How should we treat memory that we fail to deinitialize?
159 // We're currently bailing out and treating it as "burned" -- should we
160 // require that a failure to deinitialize still reset the memory so that
161 // we can reclaim it?
163 for (auto &FA
: Allocs
)
165 OnDeallocated(std::move(Err
));
170 std::lock_guard
<std::mutex
> Lock(Mutex
);
172 for (auto &FA
: Allocs
) {
173 ExecutorAddr Addr
= FA
.getAddress();
174 ExecutorAddrDiff Size
= UsedMemory
[Addr
];
176 UsedMemory
.erase(Addr
);
177 AvailableMemory
.insert(Addr
, Addr
+ Size
- 1, true);
183 OnDeallocated(Error::success());
187 } // end namespace orc
188 } // end namespace llvm