1349cc55cSDimitry Andric //===---- EPCGenericJITLinkMemoryManager.cpp -- Mem management via EPC ----===// 2349cc55cSDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6349cc55cSDimitry Andric // 7349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8349cc55cSDimitry Andric 9349cc55cSDimitry Andric #include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h" 10349cc55cSDimitry Andric 11349cc55cSDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h" 12349cc55cSDimitry Andric #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h" 13349cc55cSDimitry Andric #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" 14349cc55cSDimitry Andric 15349cc55cSDimitry Andric #include <limits> 16349cc55cSDimitry Andric 17349cc55cSDimitry Andric using namespace llvm::jitlink; 18349cc55cSDimitry Andric 19349cc55cSDimitry Andric namespace llvm { 20349cc55cSDimitry Andric namespace orc { 21349cc55cSDimitry Andric 22349cc55cSDimitry Andric class EPCGenericJITLinkMemoryManager::InFlightAlloc 23349cc55cSDimitry Andric : public jitlink::JITLinkMemoryManager::InFlightAlloc { 24349cc55cSDimitry Andric public: 25349cc55cSDimitry Andric 26349cc55cSDimitry Andric // FIXME: The C++98 initializer is an attempt to work around compile failures 27349cc55cSDimitry Andric // due to http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1397. 28349cc55cSDimitry Andric // We should be able to switch this back to member initialization once that 29349cc55cSDimitry Andric // issue is fixed. 30349cc55cSDimitry Andric struct SegInfo { 31349cc55cSDimitry Andric SegInfo() : WorkingMem(nullptr), ContentSize(0), ZeroFillSize(0) {} 32349cc55cSDimitry Andric 33349cc55cSDimitry Andric char *WorkingMem; 34349cc55cSDimitry Andric ExecutorAddr Addr; 35349cc55cSDimitry Andric uint64_t ContentSize; 36349cc55cSDimitry Andric uint64_t ZeroFillSize; 37349cc55cSDimitry Andric }; 38349cc55cSDimitry Andric 39349cc55cSDimitry Andric using SegInfoMap = AllocGroupSmallMap<SegInfo>; 40349cc55cSDimitry Andric 41349cc55cSDimitry Andric InFlightAlloc(EPCGenericJITLinkMemoryManager &Parent, LinkGraph &G, 42349cc55cSDimitry Andric ExecutorAddr AllocAddr, SegInfoMap Segs) 43349cc55cSDimitry Andric : Parent(Parent), G(G), AllocAddr(AllocAddr), Segs(std::move(Segs)) {} 44349cc55cSDimitry Andric 45349cc55cSDimitry Andric void finalize(OnFinalizedFunction OnFinalize) override { 46349cc55cSDimitry Andric tpctypes::FinalizeRequest FR; 47349cc55cSDimitry Andric for (auto &KV : Segs) { 48349cc55cSDimitry Andric assert(KV.second.ContentSize <= std::numeric_limits<size_t>::max()); 49349cc55cSDimitry Andric FR.Segments.push_back(tpctypes::SegFinalizeRequest{ 50*bdd1243dSDimitry Andric KV.first, 51349cc55cSDimitry Andric KV.second.Addr, 52349cc55cSDimitry Andric alignTo(KV.second.ContentSize + KV.second.ZeroFillSize, 53349cc55cSDimitry Andric Parent.EPC.getPageSize()), 54349cc55cSDimitry Andric {KV.second.WorkingMem, static_cast<size_t>(KV.second.ContentSize)}}); 55349cc55cSDimitry Andric } 56349cc55cSDimitry Andric 57349cc55cSDimitry Andric // Transfer allocation actions. 5804eeddc0SDimitry Andric std::swap(FR.Actions, G.allocActions()); 59349cc55cSDimitry Andric 60349cc55cSDimitry Andric Parent.EPC.callSPSWrapperAsync< 61349cc55cSDimitry Andric rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>( 62349cc55cSDimitry Andric Parent.SAs.Finalize, 63349cc55cSDimitry Andric [OnFinalize = std::move(OnFinalize), AllocAddr = this->AllocAddr]( 64349cc55cSDimitry Andric Error SerializationErr, Error FinalizeErr) mutable { 65349cc55cSDimitry Andric // FIXME: Release abandoned alloc. 66349cc55cSDimitry Andric if (SerializationErr) { 67349cc55cSDimitry Andric cantFail(std::move(FinalizeErr)); 68349cc55cSDimitry Andric OnFinalize(std::move(SerializationErr)); 69349cc55cSDimitry Andric } else if (FinalizeErr) 70349cc55cSDimitry Andric OnFinalize(std::move(FinalizeErr)); 71349cc55cSDimitry Andric else 7204eeddc0SDimitry Andric OnFinalize(FinalizedAlloc(AllocAddr)); 73349cc55cSDimitry Andric }, 74349cc55cSDimitry Andric Parent.SAs.Allocator, std::move(FR)); 75349cc55cSDimitry Andric } 76349cc55cSDimitry Andric 77349cc55cSDimitry Andric void abandon(OnAbandonedFunction OnAbandoned) override { 78349cc55cSDimitry Andric // FIXME: Return memory to pool instead. 79349cc55cSDimitry Andric Parent.EPC.callSPSWrapperAsync< 80349cc55cSDimitry Andric rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>( 81349cc55cSDimitry Andric Parent.SAs.Deallocate, 82349cc55cSDimitry Andric [OnAbandoned = std::move(OnAbandoned)](Error SerializationErr, 83349cc55cSDimitry Andric Error DeallocateErr) mutable { 84349cc55cSDimitry Andric if (SerializationErr) { 85349cc55cSDimitry Andric cantFail(std::move(DeallocateErr)); 86349cc55cSDimitry Andric OnAbandoned(std::move(SerializationErr)); 87349cc55cSDimitry Andric } else 88349cc55cSDimitry Andric OnAbandoned(std::move(DeallocateErr)); 89349cc55cSDimitry Andric }, 90349cc55cSDimitry Andric Parent.SAs.Allocator, ArrayRef<ExecutorAddr>(AllocAddr)); 91349cc55cSDimitry Andric } 92349cc55cSDimitry Andric 93349cc55cSDimitry Andric private: 94349cc55cSDimitry Andric EPCGenericJITLinkMemoryManager &Parent; 95349cc55cSDimitry Andric LinkGraph &G; 96349cc55cSDimitry Andric ExecutorAddr AllocAddr; 97349cc55cSDimitry Andric SegInfoMap Segs; 98349cc55cSDimitry Andric }; 99349cc55cSDimitry Andric 100349cc55cSDimitry Andric void EPCGenericJITLinkMemoryManager::allocate(const JITLinkDylib *JD, 101349cc55cSDimitry Andric LinkGraph &G, 102349cc55cSDimitry Andric OnAllocatedFunction OnAllocated) { 103349cc55cSDimitry Andric BasicLayout BL(G); 104349cc55cSDimitry Andric 105349cc55cSDimitry Andric auto Pages = BL.getContiguousPageBasedLayoutSizes(EPC.getPageSize()); 106349cc55cSDimitry Andric if (!Pages) 107349cc55cSDimitry Andric return OnAllocated(Pages.takeError()); 108349cc55cSDimitry Andric 109349cc55cSDimitry Andric EPC.callSPSWrapperAsync<rt::SPSSimpleExecutorMemoryManagerReserveSignature>( 110349cc55cSDimitry Andric SAs.Reserve, 111349cc55cSDimitry Andric [this, BL = std::move(BL), OnAllocated = std::move(OnAllocated)]( 112349cc55cSDimitry Andric Error SerializationErr, Expected<ExecutorAddr> AllocAddr) mutable { 113349cc55cSDimitry Andric if (SerializationErr) { 114349cc55cSDimitry Andric cantFail(AllocAddr.takeError()); 115349cc55cSDimitry Andric return OnAllocated(std::move(SerializationErr)); 116349cc55cSDimitry Andric } 117349cc55cSDimitry Andric if (!AllocAddr) 118349cc55cSDimitry Andric return OnAllocated(AllocAddr.takeError()); 119349cc55cSDimitry Andric 120349cc55cSDimitry Andric completeAllocation(*AllocAddr, std::move(BL), std::move(OnAllocated)); 121349cc55cSDimitry Andric }, 122349cc55cSDimitry Andric SAs.Allocator, Pages->total()); 123349cc55cSDimitry Andric } 124349cc55cSDimitry Andric 125349cc55cSDimitry Andric void EPCGenericJITLinkMemoryManager::deallocate( 126349cc55cSDimitry Andric std::vector<FinalizedAlloc> Allocs, OnDeallocatedFunction OnDeallocated) { 127349cc55cSDimitry Andric EPC.callSPSWrapperAsync< 128349cc55cSDimitry Andric rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>( 129349cc55cSDimitry Andric SAs.Deallocate, 130349cc55cSDimitry Andric [OnDeallocated = std::move(OnDeallocated)](Error SerErr, 131349cc55cSDimitry Andric Error DeallocErr) mutable { 132349cc55cSDimitry Andric if (SerErr) { 133349cc55cSDimitry Andric cantFail(std::move(DeallocErr)); 134349cc55cSDimitry Andric OnDeallocated(std::move(SerErr)); 135349cc55cSDimitry Andric } else 136349cc55cSDimitry Andric OnDeallocated(std::move(DeallocErr)); 137349cc55cSDimitry Andric }, 138349cc55cSDimitry Andric SAs.Allocator, Allocs); 139349cc55cSDimitry Andric for (auto &A : Allocs) 140349cc55cSDimitry Andric A.release(); 141349cc55cSDimitry Andric } 142349cc55cSDimitry Andric 143349cc55cSDimitry Andric void EPCGenericJITLinkMemoryManager::completeAllocation( 144349cc55cSDimitry Andric ExecutorAddr AllocAddr, BasicLayout BL, OnAllocatedFunction OnAllocated) { 145349cc55cSDimitry Andric 146349cc55cSDimitry Andric InFlightAlloc::SegInfoMap SegInfos; 147349cc55cSDimitry Andric 148349cc55cSDimitry Andric ExecutorAddr NextSegAddr = AllocAddr; 149349cc55cSDimitry Andric for (auto &KV : BL.segments()) { 150349cc55cSDimitry Andric const auto &AG = KV.first; 151349cc55cSDimitry Andric auto &Seg = KV.second; 152349cc55cSDimitry Andric 15304eeddc0SDimitry Andric Seg.Addr = NextSegAddr; 154349cc55cSDimitry Andric KV.second.WorkingMem = BL.getGraph().allocateBuffer(Seg.ContentSize).data(); 155349cc55cSDimitry Andric NextSegAddr += ExecutorAddrDiff( 156349cc55cSDimitry Andric alignTo(Seg.ContentSize + Seg.ZeroFillSize, EPC.getPageSize())); 157349cc55cSDimitry Andric 158349cc55cSDimitry Andric auto &SegInfo = SegInfos[AG]; 159349cc55cSDimitry Andric SegInfo.ContentSize = Seg.ContentSize; 160349cc55cSDimitry Andric SegInfo.ZeroFillSize = Seg.ZeroFillSize; 161349cc55cSDimitry Andric SegInfo.Addr = ExecutorAddr(Seg.Addr); 162349cc55cSDimitry Andric SegInfo.WorkingMem = Seg.WorkingMem; 163349cc55cSDimitry Andric } 164349cc55cSDimitry Andric 165349cc55cSDimitry Andric if (auto Err = BL.apply()) 166349cc55cSDimitry Andric return OnAllocated(std::move(Err)); 167349cc55cSDimitry Andric 168349cc55cSDimitry Andric OnAllocated(std::make_unique<InFlightAlloc>(*this, BL.getGraph(), AllocAddr, 169349cc55cSDimitry Andric std::move(SegInfos))); 170349cc55cSDimitry Andric } 171349cc55cSDimitry Andric 172349cc55cSDimitry Andric } // end namespace orc 173349cc55cSDimitry Andric } // end namespace llvm 174