1349cc55cSDimitry Andric //===- SimpleExecuorMemoryManagare.cpp - Simple executor-side memory mgmt -===// 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/TargetProcess/SimpleExecutorMemoryManager.h" 10349cc55cSDimitry Andric 11349cc55cSDimitry Andric #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" 12349cc55cSDimitry Andric #include "llvm/Support/FormatVariadic.h" 13349cc55cSDimitry Andric 14349cc55cSDimitry Andric #define DEBUG_TYPE "orc" 15349cc55cSDimitry Andric 16349cc55cSDimitry Andric namespace llvm { 17349cc55cSDimitry Andric namespace orc { 18349cc55cSDimitry Andric namespace rt_bootstrap { 19349cc55cSDimitry Andric 20349cc55cSDimitry Andric SimpleExecutorMemoryManager::~SimpleExecutorMemoryManager() { 21349cc55cSDimitry Andric assert(Allocations.empty() && "shutdown not called?"); 22349cc55cSDimitry Andric } 23349cc55cSDimitry Andric 24349cc55cSDimitry Andric Expected<ExecutorAddr> SimpleExecutorMemoryManager::allocate(uint64_t Size) { 25349cc55cSDimitry Andric std::error_code EC; 26349cc55cSDimitry Andric auto MB = sys::Memory::allocateMappedMemory( 2704eeddc0SDimitry Andric Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC); 28349cc55cSDimitry Andric if (EC) 29349cc55cSDimitry Andric return errorCodeToError(EC); 30349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 31349cc55cSDimitry Andric assert(!Allocations.count(MB.base()) && "Duplicate allocation addr"); 32349cc55cSDimitry Andric Allocations[MB.base()].Size = Size; 33349cc55cSDimitry Andric return ExecutorAddr::fromPtr(MB.base()); 34349cc55cSDimitry Andric } 35349cc55cSDimitry Andric 36349cc55cSDimitry Andric Error SimpleExecutorMemoryManager::finalize(tpctypes::FinalizeRequest &FR) { 37349cc55cSDimitry Andric ExecutorAddr Base(~0ULL); 3804eeddc0SDimitry Andric std::vector<shared::WrapperFunctionCall> DeallocationActions; 39349cc55cSDimitry Andric size_t SuccessfulFinalizationActions = 0; 40349cc55cSDimitry Andric 41349cc55cSDimitry Andric if (FR.Segments.empty()) { 42349cc55cSDimitry Andric // NOTE: Finalizing nothing is currently a no-op. Should it be an error? 43349cc55cSDimitry Andric if (FR.Actions.empty()) 44349cc55cSDimitry Andric return Error::success(); 45349cc55cSDimitry Andric else 46349cc55cSDimitry Andric return make_error<StringError>("Finalization actions attached to empty " 47349cc55cSDimitry Andric "finalization request", 48349cc55cSDimitry Andric inconvertibleErrorCode()); 49349cc55cSDimitry Andric } 50349cc55cSDimitry Andric 51349cc55cSDimitry Andric for (auto &Seg : FR.Segments) 52349cc55cSDimitry Andric Base = std::min(Base, Seg.Addr); 53349cc55cSDimitry Andric 54349cc55cSDimitry Andric for (auto &ActPair : FR.Actions) 5504eeddc0SDimitry Andric if (ActPair.Dealloc) 5604eeddc0SDimitry Andric DeallocationActions.push_back(ActPair.Dealloc); 57349cc55cSDimitry Andric 58349cc55cSDimitry Andric // Get the Allocation for this finalization. 59349cc55cSDimitry Andric size_t AllocSize = 0; 60349cc55cSDimitry Andric { 61349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 62349cc55cSDimitry Andric auto I = Allocations.find(Base.toPtr<void *>()); 63349cc55cSDimitry Andric if (I == Allocations.end()) 64349cc55cSDimitry Andric return make_error<StringError>("Attempt to finalize unrecognized " 65349cc55cSDimitry Andric "allocation " + 66349cc55cSDimitry Andric formatv("{0:x}", Base.getValue()), 67349cc55cSDimitry Andric inconvertibleErrorCode()); 68349cc55cSDimitry Andric AllocSize = I->second.Size; 69349cc55cSDimitry Andric I->second.DeallocationActions = std::move(DeallocationActions); 70349cc55cSDimitry Andric } 71349cc55cSDimitry Andric ExecutorAddr AllocEnd = Base + ExecutorAddrDiff(AllocSize); 72349cc55cSDimitry Andric 73349cc55cSDimitry Andric // Bail-out function: this will run deallocation actions corresponding to any 74349cc55cSDimitry Andric // completed finalization actions, then deallocate memory. 75349cc55cSDimitry Andric auto BailOut = [&](Error Err) { 76349cc55cSDimitry Andric std::pair<void *, Allocation> AllocToDestroy; 77349cc55cSDimitry Andric 78*0fca6ea1SDimitry Andric // Get allocation to destroy. 79349cc55cSDimitry Andric { 80349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 81349cc55cSDimitry Andric auto I = Allocations.find(Base.toPtr<void *>()); 82349cc55cSDimitry Andric 83349cc55cSDimitry Andric // Check for missing allocation (effective a double free). 84349cc55cSDimitry Andric if (I == Allocations.end()) 85349cc55cSDimitry Andric return joinErrors( 86349cc55cSDimitry Andric std::move(Err), 87349cc55cSDimitry Andric make_error<StringError>("No allocation entry found " 88349cc55cSDimitry Andric "for " + 89349cc55cSDimitry Andric formatv("{0:x}", Base.getValue()), 90349cc55cSDimitry Andric inconvertibleErrorCode())); 91349cc55cSDimitry Andric AllocToDestroy = std::move(*I); 92349cc55cSDimitry Andric Allocations.erase(I); 93349cc55cSDimitry Andric } 94349cc55cSDimitry Andric 95349cc55cSDimitry Andric // Run deallocation actions for all completed finalization actions. 96349cc55cSDimitry Andric while (SuccessfulFinalizationActions) 97349cc55cSDimitry Andric Err = 98349cc55cSDimitry Andric joinErrors(std::move(Err), FR.Actions[--SuccessfulFinalizationActions] 9904eeddc0SDimitry Andric .Dealloc.runWithSPSRetErrorMerged()); 100349cc55cSDimitry Andric 101349cc55cSDimitry Andric // Deallocate memory. 102349cc55cSDimitry Andric sys::MemoryBlock MB(AllocToDestroy.first, AllocToDestroy.second.Size); 103349cc55cSDimitry Andric if (auto EC = sys::Memory::releaseMappedMemory(MB)) 104349cc55cSDimitry Andric Err = joinErrors(std::move(Err), errorCodeToError(EC)); 105349cc55cSDimitry Andric 106349cc55cSDimitry Andric return Err; 107349cc55cSDimitry Andric }; 108349cc55cSDimitry Andric 109349cc55cSDimitry Andric // Copy content and apply permissions. 110349cc55cSDimitry Andric for (auto &Seg : FR.Segments) { 111349cc55cSDimitry Andric 112349cc55cSDimitry Andric // Check segment ranges. 113349cc55cSDimitry Andric if (LLVM_UNLIKELY(Seg.Size < Seg.Content.size())) 114349cc55cSDimitry Andric return BailOut(make_error<StringError>( 115349cc55cSDimitry Andric formatv("Segment {0:x} content size ({1:x} bytes) " 116349cc55cSDimitry Andric "exceeds segment size ({2:x} bytes)", 117349cc55cSDimitry Andric Seg.Addr.getValue(), Seg.Content.size(), Seg.Size), 118349cc55cSDimitry Andric inconvertibleErrorCode())); 119349cc55cSDimitry Andric ExecutorAddr SegEnd = Seg.Addr + ExecutorAddrDiff(Seg.Size); 120349cc55cSDimitry Andric if (LLVM_UNLIKELY(Seg.Addr < Base || SegEnd > AllocEnd)) 121349cc55cSDimitry Andric return BailOut(make_error<StringError>( 122349cc55cSDimitry Andric formatv("Segment {0:x} -- {1:x} crosses boundary of " 123349cc55cSDimitry Andric "allocation {2:x} -- {3:x}", 124349cc55cSDimitry Andric Seg.Addr.getValue(), SegEnd.getValue(), Base.getValue(), 125349cc55cSDimitry Andric AllocEnd.getValue()), 126349cc55cSDimitry Andric inconvertibleErrorCode())); 127349cc55cSDimitry Andric 128349cc55cSDimitry Andric char *Mem = Seg.Addr.toPtr<char *>(); 129fcaf7f86SDimitry Andric if (!Seg.Content.empty()) 130349cc55cSDimitry Andric memcpy(Mem, Seg.Content.data(), Seg.Content.size()); 131349cc55cSDimitry Andric memset(Mem + Seg.Content.size(), 0, Seg.Size - Seg.Content.size()); 132349cc55cSDimitry Andric assert(Seg.Size <= std::numeric_limits<size_t>::max()); 133349cc55cSDimitry Andric if (auto EC = sys::Memory::protectMappedMemory( 134349cc55cSDimitry Andric {Mem, static_cast<size_t>(Seg.Size)}, 13506c3fb27SDimitry Andric toSysMemoryProtectionFlags(Seg.RAG.Prot))) 136349cc55cSDimitry Andric return BailOut(errorCodeToError(EC)); 13706c3fb27SDimitry Andric if ((Seg.RAG.Prot & MemProt::Exec) == MemProt::Exec) 138349cc55cSDimitry Andric sys::Memory::InvalidateInstructionCache(Mem, Seg.Size); 139349cc55cSDimitry Andric } 140349cc55cSDimitry Andric 141349cc55cSDimitry Andric // Run finalization actions. 142349cc55cSDimitry Andric for (auto &ActPair : FR.Actions) { 14304eeddc0SDimitry Andric if (auto Err = ActPair.Finalize.runWithSPSRetErrorMerged()) 144349cc55cSDimitry Andric return BailOut(std::move(Err)); 145349cc55cSDimitry Andric ++SuccessfulFinalizationActions; 146349cc55cSDimitry Andric } 147349cc55cSDimitry Andric 148349cc55cSDimitry Andric return Error::success(); 149349cc55cSDimitry Andric } 150349cc55cSDimitry Andric 151349cc55cSDimitry Andric Error SimpleExecutorMemoryManager::deallocate( 152349cc55cSDimitry Andric const std::vector<ExecutorAddr> &Bases) { 153349cc55cSDimitry Andric std::vector<std::pair<void *, Allocation>> AllocPairs; 154349cc55cSDimitry Andric AllocPairs.reserve(Bases.size()); 155349cc55cSDimitry Andric 156*0fca6ea1SDimitry Andric // Get allocation to destroy. 157349cc55cSDimitry Andric Error Err = Error::success(); 158349cc55cSDimitry Andric { 159349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 160349cc55cSDimitry Andric for (auto &Base : Bases) { 161349cc55cSDimitry Andric auto I = Allocations.find(Base.toPtr<void *>()); 162349cc55cSDimitry Andric 163349cc55cSDimitry Andric // Check for missing allocation (effective a double free). 164349cc55cSDimitry Andric if (I != Allocations.end()) { 165349cc55cSDimitry Andric AllocPairs.push_back(std::move(*I)); 166349cc55cSDimitry Andric Allocations.erase(I); 167349cc55cSDimitry Andric } else 168349cc55cSDimitry Andric Err = joinErrors( 169349cc55cSDimitry Andric std::move(Err), 170349cc55cSDimitry Andric make_error<StringError>("No allocation entry found " 171349cc55cSDimitry Andric "for " + 172349cc55cSDimitry Andric formatv("{0:x}", Base.getValue()), 173349cc55cSDimitry Andric inconvertibleErrorCode())); 174349cc55cSDimitry Andric } 175349cc55cSDimitry Andric } 176349cc55cSDimitry Andric 177349cc55cSDimitry Andric while (!AllocPairs.empty()) { 178349cc55cSDimitry Andric auto &P = AllocPairs.back(); 179349cc55cSDimitry Andric Err = joinErrors(std::move(Err), deallocateImpl(P.first, P.second)); 180349cc55cSDimitry Andric AllocPairs.pop_back(); 181349cc55cSDimitry Andric } 182349cc55cSDimitry Andric 183349cc55cSDimitry Andric return Err; 184349cc55cSDimitry Andric } 185349cc55cSDimitry Andric 186349cc55cSDimitry Andric Error SimpleExecutorMemoryManager::shutdown() { 187349cc55cSDimitry Andric 188349cc55cSDimitry Andric AllocationsMap AM; 189349cc55cSDimitry Andric { 190349cc55cSDimitry Andric std::lock_guard<std::mutex> Lock(M); 191349cc55cSDimitry Andric AM = std::move(Allocations); 192349cc55cSDimitry Andric } 193349cc55cSDimitry Andric 194349cc55cSDimitry Andric Error Err = Error::success(); 195349cc55cSDimitry Andric for (auto &KV : AM) 196349cc55cSDimitry Andric Err = joinErrors(std::move(Err), deallocateImpl(KV.first, KV.second)); 197349cc55cSDimitry Andric return Err; 198349cc55cSDimitry Andric } 199349cc55cSDimitry Andric 200349cc55cSDimitry Andric void SimpleExecutorMemoryManager::addBootstrapSymbols( 201349cc55cSDimitry Andric StringMap<ExecutorAddr> &M) { 202349cc55cSDimitry Andric M[rt::SimpleExecutorMemoryManagerInstanceName] = ExecutorAddr::fromPtr(this); 203349cc55cSDimitry Andric M[rt::SimpleExecutorMemoryManagerReserveWrapperName] = 204349cc55cSDimitry Andric ExecutorAddr::fromPtr(&reserveWrapper); 205349cc55cSDimitry Andric M[rt::SimpleExecutorMemoryManagerFinalizeWrapperName] = 206349cc55cSDimitry Andric ExecutorAddr::fromPtr(&finalizeWrapper); 207349cc55cSDimitry Andric M[rt::SimpleExecutorMemoryManagerDeallocateWrapperName] = 208349cc55cSDimitry Andric ExecutorAddr::fromPtr(&deallocateWrapper); 209349cc55cSDimitry Andric } 210349cc55cSDimitry Andric 211349cc55cSDimitry Andric Error SimpleExecutorMemoryManager::deallocateImpl(void *Base, Allocation &A) { 212349cc55cSDimitry Andric Error Err = Error::success(); 213349cc55cSDimitry Andric 214349cc55cSDimitry Andric while (!A.DeallocationActions.empty()) { 215349cc55cSDimitry Andric Err = joinErrors(std::move(Err), 21604eeddc0SDimitry Andric A.DeallocationActions.back().runWithSPSRetErrorMerged()); 217349cc55cSDimitry Andric A.DeallocationActions.pop_back(); 218349cc55cSDimitry Andric } 219349cc55cSDimitry Andric 220349cc55cSDimitry Andric sys::MemoryBlock MB(Base, A.Size); 221349cc55cSDimitry Andric if (auto EC = sys::Memory::releaseMappedMemory(MB)) 222349cc55cSDimitry Andric Err = joinErrors(std::move(Err), errorCodeToError(EC)); 223349cc55cSDimitry Andric 224349cc55cSDimitry Andric return Err; 225349cc55cSDimitry Andric } 226349cc55cSDimitry Andric 227349cc55cSDimitry Andric llvm::orc::shared::CWrapperFunctionResult 228349cc55cSDimitry Andric SimpleExecutorMemoryManager::reserveWrapper(const char *ArgData, 229349cc55cSDimitry Andric size_t ArgSize) { 230349cc55cSDimitry Andric return shared::WrapperFunction< 231349cc55cSDimitry Andric rt::SPSSimpleExecutorMemoryManagerReserveSignature>:: 232349cc55cSDimitry Andric handle(ArgData, ArgSize, 233349cc55cSDimitry Andric shared::makeMethodWrapperHandler( 234349cc55cSDimitry Andric &SimpleExecutorMemoryManager::allocate)) 235349cc55cSDimitry Andric .release(); 236349cc55cSDimitry Andric } 237349cc55cSDimitry Andric 238349cc55cSDimitry Andric llvm::orc::shared::CWrapperFunctionResult 239349cc55cSDimitry Andric SimpleExecutorMemoryManager::finalizeWrapper(const char *ArgData, 240349cc55cSDimitry Andric size_t ArgSize) { 241349cc55cSDimitry Andric return shared::WrapperFunction< 242349cc55cSDimitry Andric rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>:: 243349cc55cSDimitry Andric handle(ArgData, ArgSize, 244349cc55cSDimitry Andric shared::makeMethodWrapperHandler( 245349cc55cSDimitry Andric &SimpleExecutorMemoryManager::finalize)) 246349cc55cSDimitry Andric .release(); 247349cc55cSDimitry Andric } 248349cc55cSDimitry Andric 249349cc55cSDimitry Andric llvm::orc::shared::CWrapperFunctionResult 250349cc55cSDimitry Andric SimpleExecutorMemoryManager::deallocateWrapper(const char *ArgData, 251349cc55cSDimitry Andric size_t ArgSize) { 252349cc55cSDimitry Andric return shared::WrapperFunction< 253349cc55cSDimitry Andric rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>:: 254349cc55cSDimitry Andric handle(ArgData, ArgSize, 255349cc55cSDimitry Andric shared::makeMethodWrapperHandler( 256349cc55cSDimitry Andric &SimpleExecutorMemoryManager::deallocate)) 257349cc55cSDimitry Andric .release(); 258349cc55cSDimitry Andric } 259349cc55cSDimitry Andric 260349cc55cSDimitry Andric } // namespace rt_bootstrap 261349cc55cSDimitry Andric } // end namespace orc 262349cc55cSDimitry Andric } // end namespace llvm 263