//=== MapperJITLinkMemoryManager.cpp - Memory management with MemoryMapper ===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h" #include "llvm/ExecutionEngine/JITLink/JITLink.h" #include "llvm/Support/Process.h" #include using namespace llvm::jitlink; namespace llvm { namespace orc { class MapperJITLinkMemoryManager::InFlightAlloc : public JITLinkMemoryManager::InFlightAlloc { public: InFlightAlloc(MapperJITLinkMemoryManager &Parent, LinkGraph &G, ExecutorAddr AllocAddr, std::vector Segs) : Parent(Parent), G(G), AllocAddr(AllocAddr), Segs(std::move(Segs)) {} void finalize(OnFinalizedFunction OnFinalize) override { MemoryMapper::AllocInfo AI; AI.MappingBase = AllocAddr; std::swap(AI.Segments, Segs); std::swap(AI.Actions, G.allocActions()); Parent.Mapper->initialize(AI, [&](Expected Result) { if (!Result) { OnFinalize(Result.takeError()); return; } OnFinalize(FinalizedAlloc(*Result)); }); } void abandon(OnAbandonedFunction OnFinalize) override { Parent.Mapper->release({AllocAddr}, std::move(OnFinalize)); } private: MapperJITLinkMemoryManager &Parent; LinkGraph &G; ExecutorAddr AllocAddr; std::vector Segs; }; MapperJITLinkMemoryManager::MapperJITLinkMemoryManager( std::unique_ptr Mapper) : Mapper(std::move(Mapper)) {} void MapperJITLinkMemoryManager::allocate(const JITLinkDylib *JD, LinkGraph &G, OnAllocatedFunction OnAllocated) { BasicLayout BL(G); // find required address space auto SegsSizes = BL.getContiguousPageBasedLayoutSizes(Mapper->getPageSize()); if (!SegsSizes) { OnAllocated(SegsSizes.takeError()); return; } // Check if total size fits in address space if (SegsSizes->total() > std::numeric_limits::max()) { OnAllocated(make_error( formatv("Total requested size {:x} for graph {} exceeds address space", SegsSizes->total(), G.getName()))); return; } Mapper->reserve( SegsSizes->total(), [this, &G, BL = std::move(BL), OnAllocated = std::move(OnAllocated)]( Expected Result) mutable { if (!Result) { return OnAllocated(Result.takeError()); } auto NextSegAddr = Result->Start; std::vector SegInfos; for (auto &KV : BL.segments()) { auto &AG = KV.first; auto &Seg = KV.second; auto TotalSize = Seg.ContentSize + Seg.ZeroFillSize; Seg.Addr = NextSegAddr; Seg.WorkingMem = Mapper->prepare(NextSegAddr, TotalSize); NextSegAddr += alignTo(TotalSize, Mapper->getPageSize()); MemoryMapper::AllocInfo::SegInfo SI; SI.Offset = Seg.Addr - Result->Start; SI.ContentSize = Seg.ContentSize; SI.ZeroFillSize = Seg.ZeroFillSize; SI.Prot = (toSysMemoryProtectionFlags(AG.getMemProt())); SI.WorkingMem = Seg.WorkingMem; SegInfos.push_back(SI); } if (auto Err = BL.apply()) { OnAllocated(std::move(Err)); return; } OnAllocated(std::make_unique(*this, G, Result->Start, std::move(SegInfos))); }); } void MapperJITLinkMemoryManager::deallocate( std::vector Allocs, OnDeallocatedFunction OnDeallocated) { std::vector Bases; Bases.reserve(Allocs.size()); for (auto &FA : Allocs) { Bases.push_back(FA.getAddress()); FA.release(); } Mapper->release(Bases, std::move(OnDeallocated)); } } // end namespace orc } // end namespace llvm