Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/MapperJITLinkMemoryManager.cpp
35266 views
//=== MapperJITLinkMemoryManager.cpp - Memory management with MemoryMapper ===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"910#include "llvm/ADT/STLExtras.h"11#include "llvm/ExecutionEngine/JITLink/JITLink.h"12#include "llvm/Support/Process.h"1314using namespace llvm::jitlink;1516namespace llvm {17namespace orc {1819class MapperJITLinkMemoryManager::InFlightAlloc20: public JITLinkMemoryManager::InFlightAlloc {21public:22InFlightAlloc(MapperJITLinkMemoryManager &Parent, LinkGraph &G,23ExecutorAddr AllocAddr,24std::vector<MemoryMapper::AllocInfo::SegInfo> Segs)25: Parent(Parent), G(G), AllocAddr(AllocAddr), Segs(std::move(Segs)) {}2627void finalize(OnFinalizedFunction OnFinalize) override {28MemoryMapper::AllocInfo AI;29AI.MappingBase = AllocAddr;3031std::swap(AI.Segments, Segs);32std::swap(AI.Actions, G.allocActions());3334Parent.Mapper->initialize(AI, [OnFinalize = std::move(OnFinalize)](35Expected<ExecutorAddr> Result) mutable {36if (!Result) {37OnFinalize(Result.takeError());38return;39}4041OnFinalize(FinalizedAlloc(*Result));42});43}4445void abandon(OnAbandonedFunction OnFinalize) override {46Parent.Mapper->release({AllocAddr}, std::move(OnFinalize));47}4849private:50MapperJITLinkMemoryManager &Parent;51LinkGraph &G;52ExecutorAddr AllocAddr;53std::vector<MemoryMapper::AllocInfo::SegInfo> Segs;54};5556MapperJITLinkMemoryManager::MapperJITLinkMemoryManager(57size_t ReservationGranularity, std::unique_ptr<MemoryMapper> Mapper)58: ReservationUnits(ReservationGranularity), AvailableMemory(AMAllocator),59Mapper(std::move(Mapper)) {}6061void MapperJITLinkMemoryManager::allocate(const JITLinkDylib *JD, LinkGraph &G,62OnAllocatedFunction OnAllocated) {63BasicLayout BL(G);6465// find required address space66auto SegsSizes = BL.getContiguousPageBasedLayoutSizes(Mapper->getPageSize());67if (!SegsSizes) {68OnAllocated(SegsSizes.takeError());69return;70}7172auto TotalSize = SegsSizes->total();7374auto CompleteAllocation = [this, &G, BL = std::move(BL),75OnAllocated = std::move(OnAllocated)](76Expected<ExecutorAddrRange> Result) mutable {77if (!Result) {78Mutex.unlock();79return OnAllocated(Result.takeError());80}8182auto NextSegAddr = Result->Start;8384std::vector<MemoryMapper::AllocInfo::SegInfo> SegInfos;8586for (auto &KV : BL.segments()) {87auto &AG = KV.first;88auto &Seg = KV.second;8990auto TotalSize = Seg.ContentSize + Seg.ZeroFillSize;9192Seg.Addr = NextSegAddr;93Seg.WorkingMem = Mapper->prepare(NextSegAddr, TotalSize);9495NextSegAddr += alignTo(TotalSize, Mapper->getPageSize());9697MemoryMapper::AllocInfo::SegInfo SI;98SI.Offset = Seg.Addr - Result->Start;99SI.ContentSize = Seg.ContentSize;100SI.ZeroFillSize = Seg.ZeroFillSize;101SI.AG = AG;102SI.WorkingMem = Seg.WorkingMem;103104SegInfos.push_back(SI);105}106107UsedMemory.insert({Result->Start, NextSegAddr - Result->Start});108109if (NextSegAddr < Result->End) {110// Save the remaining memory for reuse in next allocation(s)111AvailableMemory.insert(NextSegAddr, Result->End - 1, true);112}113Mutex.unlock();114115if (auto Err = BL.apply()) {116OnAllocated(std::move(Err));117return;118}119120OnAllocated(std::make_unique<InFlightAlloc>(*this, G, Result->Start,121std::move(SegInfos)));122};123124Mutex.lock();125126// find an already reserved range that is large enough127ExecutorAddrRange SelectedRange{};128129for (AvailableMemoryMap::iterator It = AvailableMemory.begin();130It != AvailableMemory.end(); It++) {131if (It.stop() - It.start() + 1 >= TotalSize) {132SelectedRange = ExecutorAddrRange(It.start(), It.stop() + 1);133It.erase();134break;135}136}137138if (SelectedRange.empty()) { // no already reserved range was found139auto TotalAllocation = alignTo(TotalSize, ReservationUnits);140Mapper->reserve(TotalAllocation, std::move(CompleteAllocation));141} else {142CompleteAllocation(SelectedRange);143}144}145146void MapperJITLinkMemoryManager::deallocate(147std::vector<FinalizedAlloc> Allocs, OnDeallocatedFunction OnDeallocated) {148std::vector<ExecutorAddr> Bases;149Bases.reserve(Allocs.size());150for (auto &FA : Allocs) {151ExecutorAddr Addr = FA.getAddress();152Bases.push_back(Addr);153}154155Mapper->deinitialize(Bases, [this, Allocs = std::move(Allocs),156OnDeallocated = std::move(OnDeallocated)](157llvm::Error Err) mutable {158// TODO: How should we treat memory that we fail to deinitialize?159// We're currently bailing out and treating it as "burned" -- should we160// require that a failure to deinitialize still reset the memory so that161// we can reclaim it?162if (Err) {163for (auto &FA : Allocs)164FA.release();165OnDeallocated(std::move(Err));166return;167}168169{170std::lock_guard<std::mutex> Lock(Mutex);171172for (auto &FA : Allocs) {173ExecutorAddr Addr = FA.getAddress();174ExecutorAddrDiff Size = UsedMemory[Addr];175176UsedMemory.erase(Addr);177AvailableMemory.insert(Addr, Addr + Size - 1, true);178179FA.release();180}181}182183OnDeallocated(Error::success());184});185}186187} // end namespace orc188} // end namespace llvm189190191