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
9 #include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"
10
11 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
12 #include "llvm/Support/Process.h"
13
14 #include <limits>
15
16 using namespace llvm::jitlink;
17
18 namespace llvm {
19 namespace orc {
20
21 class MapperJITLinkMemoryManager::InFlightAlloc
22 : public JITLinkMemoryManager::InFlightAlloc {
23 public:
InFlightAlloc(MapperJITLinkMemoryManager & Parent,LinkGraph & G,ExecutorAddr AllocAddr,std::vector<MemoryMapper::AllocInfo::SegInfo> Segs)24 InFlightAlloc(MapperJITLinkMemoryManager &Parent, LinkGraph &G,
25 ExecutorAddr AllocAddr,
26 std::vector<MemoryMapper::AllocInfo::SegInfo> Segs)
27 : Parent(Parent), G(G), AllocAddr(AllocAddr), Segs(std::move(Segs)) {}
28
finalize(OnFinalizedFunction OnFinalize)29 void finalize(OnFinalizedFunction OnFinalize) override {
30 MemoryMapper::AllocInfo AI;
31 AI.MappingBase = AllocAddr;
32
33 std::swap(AI.Segments, Segs);
34 std::swap(AI.Actions, G.allocActions());
35
36 Parent.Mapper->initialize(AI, [&](Expected<ExecutorAddr> Result) {
37 if (!Result) {
38 OnFinalize(Result.takeError());
39 return;
40 }
41
42 OnFinalize(FinalizedAlloc(*Result));
43 });
44 }
45
abandon(OnAbandonedFunction OnFinalize)46 void abandon(OnAbandonedFunction OnFinalize) override {
47 Parent.Mapper->release({AllocAddr}, std::move(OnFinalize));
48 }
49
50 private:
51 MapperJITLinkMemoryManager &Parent;
52 LinkGraph &G;
53 ExecutorAddr AllocAddr;
54 std::vector<MemoryMapper::AllocInfo::SegInfo> Segs;
55 };
56
MapperJITLinkMemoryManager(std::unique_ptr<MemoryMapper> Mapper)57 MapperJITLinkMemoryManager::MapperJITLinkMemoryManager(
58 std::unique_ptr<MemoryMapper> Mapper)
59 : Mapper(std::move(Mapper)) {}
60
allocate(const JITLinkDylib * JD,LinkGraph & G,OnAllocatedFunction OnAllocated)61 void MapperJITLinkMemoryManager::allocate(const JITLinkDylib *JD, LinkGraph &G,
62 OnAllocatedFunction OnAllocated) {
63 BasicLayout BL(G);
64
65 // find required address space
66 auto SegsSizes = BL.getContiguousPageBasedLayoutSizes(Mapper->getPageSize());
67 if (!SegsSizes) {
68 OnAllocated(SegsSizes.takeError());
69 return;
70 }
71
72 // Check if total size fits in address space
73 if (SegsSizes->total() > std::numeric_limits<size_t>::max()) {
74 OnAllocated(make_error<JITLinkError>(
75 formatv("Total requested size {:x} for graph {} exceeds address space",
76 SegsSizes->total(), G.getName())));
77 return;
78 }
79
80 Mapper->reserve(
81 SegsSizes->total(),
82 [this, &G, BL = std::move(BL), OnAllocated = std::move(OnAllocated)](
83 Expected<ExecutorAddrRange> Result) mutable {
84 if (!Result) {
85 return OnAllocated(Result.takeError());
86 }
87
88 auto NextSegAddr = Result->Start;
89
90 std::vector<MemoryMapper::AllocInfo::SegInfo> SegInfos;
91
92 for (auto &KV : BL.segments()) {
93 auto &AG = KV.first;
94 auto &Seg = KV.second;
95
96 auto TotalSize = Seg.ContentSize + Seg.ZeroFillSize;
97
98 Seg.Addr = NextSegAddr;
99 Seg.WorkingMem = Mapper->prepare(NextSegAddr, TotalSize);
100
101 NextSegAddr += alignTo(TotalSize, Mapper->getPageSize());
102
103 MemoryMapper::AllocInfo::SegInfo SI;
104 SI.Offset = Seg.Addr - Result->Start;
105 SI.ContentSize = Seg.ContentSize;
106 SI.ZeroFillSize = Seg.ZeroFillSize;
107 SI.Prot = (toSysMemoryProtectionFlags(AG.getMemProt()));
108 SI.WorkingMem = Seg.WorkingMem;
109
110 SegInfos.push_back(SI);
111 }
112
113 if (auto Err = BL.apply()) {
114 OnAllocated(std::move(Err));
115 return;
116 }
117
118 OnAllocated(std::make_unique<InFlightAlloc>(*this, G, Result->Start,
119 std::move(SegInfos)));
120 });
121 }
122
deallocate(std::vector<FinalizedAlloc> Allocs,OnDeallocatedFunction OnDeallocated)123 void MapperJITLinkMemoryManager::deallocate(
124 std::vector<FinalizedAlloc> Allocs, OnDeallocatedFunction OnDeallocated) {
125 std::vector<ExecutorAddr> Bases;
126 Bases.reserve(Allocs.size());
127 for (auto &FA : Allocs) {
128 Bases.push_back(FA.getAddress());
129 FA.release();
130 }
131 Mapper->release(Bases, std::move(OnDeallocated));
132 }
133
134 } // end namespace orc
135 } // end namespace llvm
136