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