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:
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 
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 
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 
57 MapperJITLinkMemoryManager::MapperJITLinkMemoryManager(
58     std::unique_ptr<MemoryMapper> Mapper)
59     : Mapper(std::move(Mapper)) {}
60 
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 
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