14fcf8434SAnubhab Ghosh //=== MapperJITLinkMemoryManager.cpp - Memory management with MemoryMapper ===// 24fcf8434SAnubhab Ghosh // 34fcf8434SAnubhab Ghosh // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 44fcf8434SAnubhab Ghosh // See https://llvm.org/LICENSE.txt for license information. 54fcf8434SAnubhab Ghosh // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64fcf8434SAnubhab Ghosh // 74fcf8434SAnubhab Ghosh //===----------------------------------------------------------------------===// 84fcf8434SAnubhab Ghosh 94fcf8434SAnubhab Ghosh #include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h" 104fcf8434SAnubhab Ghosh 114fcf8434SAnubhab Ghosh #include "llvm/ExecutionEngine/JITLink/JITLink.h" 124fcf8434SAnubhab Ghosh #include "llvm/Support/Process.h" 134fcf8434SAnubhab Ghosh 144fcf8434SAnubhab Ghosh using namespace llvm::jitlink; 154fcf8434SAnubhab Ghosh 164fcf8434SAnubhab Ghosh namespace llvm { 174fcf8434SAnubhab Ghosh namespace orc { 184fcf8434SAnubhab Ghosh 194fcf8434SAnubhab Ghosh class MapperJITLinkMemoryManager::InFlightAlloc 204fcf8434SAnubhab Ghosh : public JITLinkMemoryManager::InFlightAlloc { 214fcf8434SAnubhab Ghosh public: 224fcf8434SAnubhab Ghosh InFlightAlloc(MapperJITLinkMemoryManager &Parent, LinkGraph &G, 234fcf8434SAnubhab Ghosh ExecutorAddr AllocAddr, 244fcf8434SAnubhab Ghosh std::vector<MemoryMapper::AllocInfo::SegInfo> Segs) 254fcf8434SAnubhab Ghosh : Parent(Parent), G(G), AllocAddr(AllocAddr), Segs(std::move(Segs)) {} 264fcf8434SAnubhab Ghosh 274fcf8434SAnubhab Ghosh void finalize(OnFinalizedFunction OnFinalize) override { 284fcf8434SAnubhab Ghosh MemoryMapper::AllocInfo AI; 294fcf8434SAnubhab Ghosh AI.MappingBase = AllocAddr; 304fcf8434SAnubhab Ghosh 314fcf8434SAnubhab Ghosh std::swap(AI.Segments, Segs); 324fcf8434SAnubhab Ghosh std::swap(AI.Actions, G.allocActions()); 334fcf8434SAnubhab Ghosh 345df428eaSAnubhab Ghosh Parent.Mapper->initialize(AI, [OnFinalize = std::move(OnFinalize)]( 355df428eaSAnubhab Ghosh Expected<ExecutorAddr> Result) mutable { 364fcf8434SAnubhab Ghosh if (!Result) { 374fcf8434SAnubhab Ghosh OnFinalize(Result.takeError()); 384fcf8434SAnubhab Ghosh return; 394fcf8434SAnubhab Ghosh } 404fcf8434SAnubhab Ghosh 414fcf8434SAnubhab Ghosh OnFinalize(FinalizedAlloc(*Result)); 424fcf8434SAnubhab Ghosh }); 434fcf8434SAnubhab Ghosh } 444fcf8434SAnubhab Ghosh 454fcf8434SAnubhab Ghosh void abandon(OnAbandonedFunction OnFinalize) override { 464fcf8434SAnubhab Ghosh Parent.Mapper->release({AllocAddr}, std::move(OnFinalize)); 474fcf8434SAnubhab Ghosh } 484fcf8434SAnubhab Ghosh 494fcf8434SAnubhab Ghosh private: 504fcf8434SAnubhab Ghosh MapperJITLinkMemoryManager &Parent; 514fcf8434SAnubhab Ghosh LinkGraph &G; 524fcf8434SAnubhab Ghosh ExecutorAddr AllocAddr; 534fcf8434SAnubhab Ghosh std::vector<MemoryMapper::AllocInfo::SegInfo> Segs; 544fcf8434SAnubhab Ghosh }; 554fcf8434SAnubhab Ghosh 564fcf8434SAnubhab Ghosh MapperJITLinkMemoryManager::MapperJITLinkMemoryManager( 571eee6de8SAnubhab Ghosh size_t ReservationGranularity, std::unique_ptr<MemoryMapper> Mapper) 5823d0e71fSAnubhab Ghosh : ReservationUnits(ReservationGranularity), AvailableMemory(AMAllocator), 5923d0e71fSAnubhab Ghosh Mapper(std::move(Mapper)) {} 604fcf8434SAnubhab Ghosh 614fcf8434SAnubhab Ghosh void MapperJITLinkMemoryManager::allocate(const JITLinkDylib *JD, LinkGraph &G, 624fcf8434SAnubhab Ghosh OnAllocatedFunction OnAllocated) { 634fcf8434SAnubhab Ghosh BasicLayout BL(G); 644fcf8434SAnubhab Ghosh 654fcf8434SAnubhab Ghosh // find required address space 664fcf8434SAnubhab Ghosh auto SegsSizes = BL.getContiguousPageBasedLayoutSizes(Mapper->getPageSize()); 674fcf8434SAnubhab Ghosh if (!SegsSizes) { 684fcf8434SAnubhab Ghosh OnAllocated(SegsSizes.takeError()); 694fcf8434SAnubhab Ghosh return; 704fcf8434SAnubhab Ghosh } 714fcf8434SAnubhab Ghosh 721eee6de8SAnubhab Ghosh auto TotalSize = SegsSizes->total(); 731eee6de8SAnubhab Ghosh 741eee6de8SAnubhab Ghosh auto CompleteAllocation = [this, &G, BL = std::move(BL), 751eee6de8SAnubhab Ghosh OnAllocated = std::move(OnAllocated)]( 764fcf8434SAnubhab Ghosh Expected<ExecutorAddrRange> Result) mutable { 774fcf8434SAnubhab Ghosh if (!Result) { 781eee6de8SAnubhab Ghosh Mutex.unlock(); 794fcf8434SAnubhab Ghosh return OnAllocated(Result.takeError()); 804fcf8434SAnubhab Ghosh } 814fcf8434SAnubhab Ghosh 824fcf8434SAnubhab Ghosh auto NextSegAddr = Result->Start; 834fcf8434SAnubhab Ghosh 844fcf8434SAnubhab Ghosh std::vector<MemoryMapper::AllocInfo::SegInfo> SegInfos; 854fcf8434SAnubhab Ghosh 864fcf8434SAnubhab Ghosh for (auto &KV : BL.segments()) { 874fcf8434SAnubhab Ghosh auto &AG = KV.first; 884fcf8434SAnubhab Ghosh auto &Seg = KV.second; 894fcf8434SAnubhab Ghosh 904fcf8434SAnubhab Ghosh auto TotalSize = Seg.ContentSize + Seg.ZeroFillSize; 914fcf8434SAnubhab Ghosh 924fcf8434SAnubhab Ghosh Seg.Addr = NextSegAddr; 934fcf8434SAnubhab Ghosh Seg.WorkingMem = Mapper->prepare(NextSegAddr, TotalSize); 944fcf8434SAnubhab Ghosh 954fcf8434SAnubhab Ghosh NextSegAddr += alignTo(TotalSize, Mapper->getPageSize()); 964fcf8434SAnubhab Ghosh 974fcf8434SAnubhab Ghosh MemoryMapper::AllocInfo::SegInfo SI; 984fcf8434SAnubhab Ghosh SI.Offset = Seg.Addr - Result->Start; 994fcf8434SAnubhab Ghosh SI.ContentSize = Seg.ContentSize; 1004fcf8434SAnubhab Ghosh SI.ZeroFillSize = Seg.ZeroFillSize; 101*d3d9f7caSLang Hames SI.AG = AG; 1024fcf8434SAnubhab Ghosh SI.WorkingMem = Seg.WorkingMem; 1034fcf8434SAnubhab Ghosh 1044fcf8434SAnubhab Ghosh SegInfos.push_back(SI); 1054fcf8434SAnubhab Ghosh } 1064fcf8434SAnubhab Ghosh 1071eee6de8SAnubhab Ghosh UsedMemory.insert({Result->Start, NextSegAddr - Result->Start}); 1081eee6de8SAnubhab Ghosh 1091eee6de8SAnubhab Ghosh if (NextSegAddr < Result->End) { 1101eee6de8SAnubhab Ghosh // Save the remaining memory for reuse in next allocation(s) 11123d0e71fSAnubhab Ghosh AvailableMemory.insert(NextSegAddr, Result->End - 1, true); 1121eee6de8SAnubhab Ghosh } 1131eee6de8SAnubhab Ghosh Mutex.unlock(); 1141eee6de8SAnubhab Ghosh 1154fcf8434SAnubhab Ghosh if (auto Err = BL.apply()) { 1164fcf8434SAnubhab Ghosh OnAllocated(std::move(Err)); 1174fcf8434SAnubhab Ghosh return; 1184fcf8434SAnubhab Ghosh } 1194fcf8434SAnubhab Ghosh 1204fcf8434SAnubhab Ghosh OnAllocated(std::make_unique<InFlightAlloc>(*this, G, Result->Start, 1214fcf8434SAnubhab Ghosh std::move(SegInfos))); 1221eee6de8SAnubhab Ghosh }; 1231eee6de8SAnubhab Ghosh 12423d0e71fSAnubhab Ghosh Mutex.lock(); 12523d0e71fSAnubhab Ghosh 12623d0e71fSAnubhab Ghosh // find an already reserved range that is large enough 12723d0e71fSAnubhab Ghosh ExecutorAddrRange SelectedRange{}; 12823d0e71fSAnubhab Ghosh 12923d0e71fSAnubhab Ghosh for (AvailableMemoryMap::iterator It = AvailableMemory.begin(); 13023d0e71fSAnubhab Ghosh It != AvailableMemory.end(); It++) { 13123d0e71fSAnubhab Ghosh if (It.stop() - It.start() + 1 >= TotalSize) { 13223d0e71fSAnubhab Ghosh SelectedRange = ExecutorAddrRange(It.start(), It.stop() + 1); 13323d0e71fSAnubhab Ghosh It.erase(); 13423d0e71fSAnubhab Ghosh break; 13523d0e71fSAnubhab Ghosh } 13623d0e71fSAnubhab Ghosh } 13723d0e71fSAnubhab Ghosh 1381eee6de8SAnubhab Ghosh if (SelectedRange.empty()) { // no already reserved range was found 1391eee6de8SAnubhab Ghosh auto TotalAllocation = alignTo(TotalSize, ReservationUnits); 1401eee6de8SAnubhab Ghosh Mapper->reserve(TotalAllocation, std::move(CompleteAllocation)); 1411eee6de8SAnubhab Ghosh } else { 1421eee6de8SAnubhab Ghosh CompleteAllocation(SelectedRange); 1431eee6de8SAnubhab Ghosh } 1444fcf8434SAnubhab Ghosh } 1454fcf8434SAnubhab Ghosh 1464fcf8434SAnubhab Ghosh void MapperJITLinkMemoryManager::deallocate( 1474fcf8434SAnubhab Ghosh std::vector<FinalizedAlloc> Allocs, OnDeallocatedFunction OnDeallocated) { 148a31af321SAnubhab Ghosh std::vector<ExecutorAddr> Bases; 149a31af321SAnubhab Ghosh Bases.reserve(Allocs.size()); 150a31af321SAnubhab Ghosh for (auto &FA : Allocs) { 151a31af321SAnubhab Ghosh ExecutorAddr Addr = FA.getAddress(); 152a31af321SAnubhab Ghosh Bases.push_back(Addr); 153a31af321SAnubhab Ghosh } 154a31af321SAnubhab Ghosh 155a31af321SAnubhab Ghosh Mapper->deinitialize(Bases, [this, Allocs = std::move(Allocs), 156a31af321SAnubhab Ghosh OnDeallocated = std::move(OnDeallocated)]( 157a31af321SAnubhab Ghosh llvm::Error Err) mutable { 15847e9e588SLang Hames // TODO: How should we treat memory that we fail to deinitialize? 15947e9e588SLang Hames // We're currently bailing out and treating it as "burned" -- should we 16047e9e588SLang Hames // require that a failure to deinitialize still reset the memory so that 16147e9e588SLang Hames // we can reclaim it? 16247e9e588SLang Hames if (Err) { 16347e9e588SLang Hames for (auto &FA : Allocs) 16447e9e588SLang Hames FA.release(); 165a31af321SAnubhab Ghosh OnDeallocated(std::move(Err)); 16647e9e588SLang Hames return; 16747e9e588SLang Hames } 168a31af321SAnubhab Ghosh 169a31af321SAnubhab Ghosh { 1701eee6de8SAnubhab Ghosh std::lock_guard<std::mutex> Lock(Mutex); 1711eee6de8SAnubhab Ghosh 1724fcf8434SAnubhab Ghosh for (auto &FA : Allocs) { 1731eee6de8SAnubhab Ghosh ExecutorAddr Addr = FA.getAddress(); 1741eee6de8SAnubhab Ghosh ExecutorAddrDiff Size = UsedMemory[Addr]; 175143555b2SAnubhab Ghosh 176a31af321SAnubhab Ghosh UsedMemory.erase(Addr); 17723d0e71fSAnubhab Ghosh AvailableMemory.insert(Addr, Addr + Size - 1, true); 178a31af321SAnubhab Ghosh 17981801051SAnubhab Ghosh FA.release(); 18081801051SAnubhab Ghosh } 181a31af321SAnubhab Ghosh } 182a31af321SAnubhab Ghosh 1831eee6de8SAnubhab Ghosh OnDeallocated(Error::success()); 184a31af321SAnubhab Ghosh }); 1854fcf8434SAnubhab Ghosh } 1864fcf8434SAnubhab Ghosh 1874fcf8434SAnubhab Ghosh } // end namespace orc 1884fcf8434SAnubhab Ghosh } // end namespace llvm 189