12ce73f13SLang Hames //===- SimpleExecuorMemoryManagare.cpp - Simple executor-side memory mgmt -===// 278b083dbSLang Hames // 378b083dbSLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 478b083dbSLang Hames // See https://llvm.org/LICENSE.txt for license information. 578b083dbSLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 678b083dbSLang Hames // 778b083dbSLang Hames //===----------------------------------------------------------------------===// 878b083dbSLang Hames 978b083dbSLang Hames #include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h" 1078b083dbSLang Hames 1178b083dbSLang Hames #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" 1278b083dbSLang Hames #include "llvm/Support/FormatVariadic.h" 1378b083dbSLang Hames 1478b083dbSLang Hames #define DEBUG_TYPE "orc" 1578b083dbSLang Hames 1678b083dbSLang Hames namespace llvm { 1778b083dbSLang Hames namespace orc { 1878b083dbSLang Hames namespace rt_bootstrap { 1978b083dbSLang Hames 2078b083dbSLang Hames SimpleExecutorMemoryManager::~SimpleExecutorMemoryManager() { 2178b083dbSLang Hames assert(Allocations.empty() && "shutdown not called?"); 2278b083dbSLang Hames } 2378b083dbSLang Hames 24ef391df2SLang Hames Expected<ExecutorAddr> SimpleExecutorMemoryManager::allocate(uint64_t Size) { 2578b083dbSLang Hames std::error_code EC; 2678b083dbSLang Hames auto MB = sys::Memory::allocateMappedMemory( 2778b083dbSLang Hames Size, 0, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC); 2878b083dbSLang Hames if (EC) 2978b083dbSLang Hames return errorCodeToError(EC); 3078b083dbSLang Hames std::lock_guard<std::mutex> Lock(M); 3178b083dbSLang Hames assert(!Allocations.count(MB.base()) && "Duplicate allocation addr"); 3278b083dbSLang Hames Allocations[MB.base()].Size = Size; 33ef391df2SLang Hames return ExecutorAddr::fromPtr(MB.base()); 3478b083dbSLang Hames } 3578b083dbSLang Hames 3678b083dbSLang Hames Error SimpleExecutorMemoryManager::finalize(tpctypes::FinalizeRequest &FR) { 37ef391df2SLang Hames ExecutorAddr Base(~0ULL); 38*12b2cc22SLang Hames std::vector<tpctypes::WrapperFunctionCall> DeallocationActions; 3978b083dbSLang Hames size_t SuccessfulFinalizationActions = 0; 4078b083dbSLang Hames 416498b0e9SLang Hames if (FR.Segments.empty()) { 426498b0e9SLang Hames // NOTE: Finalizing nothing is currently a no-op. Should it be an error? 436498b0e9SLang Hames if (FR.Actions.empty()) 446498b0e9SLang Hames return Error::success(); 456498b0e9SLang Hames else 466498b0e9SLang Hames return make_error<StringError>("Finalization actions attached to empty " 476498b0e9SLang Hames "finalization request", 486498b0e9SLang Hames inconvertibleErrorCode()); 496498b0e9SLang Hames } 506498b0e9SLang Hames 5178b083dbSLang Hames for (auto &Seg : FR.Segments) 5278b083dbSLang Hames Base = std::min(Base, Seg.Addr); 5378b083dbSLang Hames 5478b083dbSLang Hames for (auto &ActPair : FR.Actions) 5578b083dbSLang Hames if (ActPair.Deallocate.Func) 5678b083dbSLang Hames DeallocationActions.push_back(ActPair.Deallocate); 5778b083dbSLang Hames 5878b083dbSLang Hames // Get the Allocation for this finalization. 5978b083dbSLang Hames size_t AllocSize = 0; 6078b083dbSLang Hames { 6178b083dbSLang Hames std::lock_guard<std::mutex> Lock(M); 6278b083dbSLang Hames auto I = Allocations.find(Base.toPtr<void *>()); 6378b083dbSLang Hames if (I == Allocations.end()) 6478b083dbSLang Hames return make_error<StringError>("Attempt to finalize unrecognized " 6578b083dbSLang Hames "allocation " + 6678b083dbSLang Hames formatv("{0:x}", Base.getValue()), 6778b083dbSLang Hames inconvertibleErrorCode()); 6878b083dbSLang Hames AllocSize = I->second.Size; 6978b083dbSLang Hames I->second.DeallocationActions = std::move(DeallocationActions); 7078b083dbSLang Hames } 71ef391df2SLang Hames ExecutorAddr AllocEnd = Base + ExecutorAddrDiff(AllocSize); 7278b083dbSLang Hames 7378b083dbSLang Hames // Bail-out function: this will run deallocation actions corresponding to any 7478b083dbSLang Hames // completed finalization actions, then deallocate memory. 7578b083dbSLang Hames auto BailOut = [&](Error Err) { 7678b083dbSLang Hames std::pair<void *, Allocation> AllocToDestroy; 7778b083dbSLang Hames 7878b083dbSLang Hames // Get allocation to destory. 7978b083dbSLang Hames { 8078b083dbSLang Hames std::lock_guard<std::mutex> Lock(M); 8178b083dbSLang Hames auto I = Allocations.find(Base.toPtr<void *>()); 8278b083dbSLang Hames 8378b083dbSLang Hames // Check for missing allocation (effective a double free). 8478b083dbSLang Hames if (I == Allocations.end()) 8578b083dbSLang Hames return joinErrors( 8678b083dbSLang Hames std::move(Err), 8778b083dbSLang Hames make_error<StringError>("No allocation entry found " 8878b083dbSLang Hames "for " + 8978b083dbSLang Hames formatv("{0:x}", Base.getValue()), 9078b083dbSLang Hames inconvertibleErrorCode())); 9178b083dbSLang Hames AllocToDestroy = std::move(*I); 9278b083dbSLang Hames Allocations.erase(I); 9378b083dbSLang Hames } 9478b083dbSLang Hames 9578b083dbSLang Hames // Run deallocation actions for all completed finalization actions. 9678b083dbSLang Hames while (SuccessfulFinalizationActions) 97*12b2cc22SLang Hames Err = 98*12b2cc22SLang Hames joinErrors(std::move(Err), FR.Actions[--SuccessfulFinalizationActions] 99*12b2cc22SLang Hames .Deallocate.runWithSPSRet()); 10078b083dbSLang Hames 10178b083dbSLang Hames // Deallocate memory. 10278b083dbSLang Hames sys::MemoryBlock MB(AllocToDestroy.first, AllocToDestroy.second.Size); 10378b083dbSLang Hames if (auto EC = sys::Memory::releaseMappedMemory(MB)) 10478b083dbSLang Hames Err = joinErrors(std::move(Err), errorCodeToError(EC)); 10578b083dbSLang Hames 10678b083dbSLang Hames return Err; 10778b083dbSLang Hames }; 10878b083dbSLang Hames 10978b083dbSLang Hames // Copy content and apply permissions. 11078b083dbSLang Hames for (auto &Seg : FR.Segments) { 11178b083dbSLang Hames 11278b083dbSLang Hames // Check segment ranges. 11378b083dbSLang Hames if (LLVM_UNLIKELY(Seg.Size < Seg.Content.size())) 11478b083dbSLang Hames return BailOut(make_error<StringError>( 11578b083dbSLang Hames formatv("Segment {0:x} content size ({1:x} bytes) " 11678b083dbSLang Hames "exceeds segment size ({2:x} bytes)", 11778b083dbSLang Hames Seg.Addr.getValue(), Seg.Content.size(), Seg.Size), 11878b083dbSLang Hames inconvertibleErrorCode())); 119ef391df2SLang Hames ExecutorAddr SegEnd = Seg.Addr + ExecutorAddrDiff(Seg.Size); 12078b083dbSLang Hames if (LLVM_UNLIKELY(Seg.Addr < Base || SegEnd > AllocEnd)) 12178b083dbSLang Hames return BailOut(make_error<StringError>( 12278b083dbSLang Hames formatv("Segment {0:x} -- {1:x} crosses boundary of " 12378b083dbSLang Hames "allocation {2:x} -- {3:x}", 12478b083dbSLang Hames Seg.Addr.getValue(), SegEnd.getValue(), Base.getValue(), 12578b083dbSLang Hames AllocEnd.getValue()), 12678b083dbSLang Hames inconvertibleErrorCode())); 12778b083dbSLang Hames 12878b083dbSLang Hames char *Mem = Seg.Addr.toPtr<char *>(); 12978b083dbSLang Hames memcpy(Mem, Seg.Content.data(), Seg.Content.size()); 13078b083dbSLang Hames memset(Mem + Seg.Content.size(), 0, Seg.Size - Seg.Content.size()); 13178b083dbSLang Hames assert(Seg.Size <= std::numeric_limits<size_t>::max()); 13278b083dbSLang Hames if (auto EC = sys::Memory::protectMappedMemory( 13378b083dbSLang Hames {Mem, static_cast<size_t>(Seg.Size)}, 13478b083dbSLang Hames tpctypes::fromWireProtectionFlags(Seg.Prot))) 13578b083dbSLang Hames return BailOut(errorCodeToError(EC)); 13678b083dbSLang Hames if (Seg.Prot & tpctypes::WPF_Exec) 13778b083dbSLang Hames sys::Memory::InvalidateInstructionCache(Mem, Seg.Size); 13878b083dbSLang Hames } 13978b083dbSLang Hames 14078b083dbSLang Hames // Run finalization actions. 14178b083dbSLang Hames for (auto &ActPair : FR.Actions) { 142*12b2cc22SLang Hames if (auto Err = ActPair.Finalize.runWithSPSRet()) 14378b083dbSLang Hames return BailOut(std::move(Err)); 14478b083dbSLang Hames ++SuccessfulFinalizationActions; 14578b083dbSLang Hames } 14678b083dbSLang Hames 14778b083dbSLang Hames return Error::success(); 14878b083dbSLang Hames } 14978b083dbSLang Hames 15078b083dbSLang Hames Error SimpleExecutorMemoryManager::deallocate( 151ef391df2SLang Hames const std::vector<ExecutorAddr> &Bases) { 15278b083dbSLang Hames std::vector<std::pair<void *, Allocation>> AllocPairs; 15378b083dbSLang Hames AllocPairs.reserve(Bases.size()); 15478b083dbSLang Hames 15578b083dbSLang Hames // Get allocation to destory. 15678b083dbSLang Hames Error Err = Error::success(); 15778b083dbSLang Hames { 15878b083dbSLang Hames std::lock_guard<std::mutex> Lock(M); 15978b083dbSLang Hames for (auto &Base : Bases) { 16078b083dbSLang Hames auto I = Allocations.find(Base.toPtr<void *>()); 16178b083dbSLang Hames 16278b083dbSLang Hames // Check for missing allocation (effective a double free). 16378b083dbSLang Hames if (I != Allocations.end()) { 16478b083dbSLang Hames AllocPairs.push_back(std::move(*I)); 16578b083dbSLang Hames Allocations.erase(I); 16678b083dbSLang Hames } else 16778b083dbSLang Hames Err = joinErrors( 16878b083dbSLang Hames std::move(Err), 16978b083dbSLang Hames make_error<StringError>("No allocation entry found " 17078b083dbSLang Hames "for " + 17178b083dbSLang Hames formatv("{0:x}", Base.getValue()), 17278b083dbSLang Hames inconvertibleErrorCode())); 17378b083dbSLang Hames } 17478b083dbSLang Hames } 17578b083dbSLang Hames 17678b083dbSLang Hames while (!AllocPairs.empty()) { 17778b083dbSLang Hames auto &P = AllocPairs.back(); 17878b083dbSLang Hames Err = joinErrors(std::move(Err), deallocateImpl(P.first, P.second)); 17978b083dbSLang Hames AllocPairs.pop_back(); 18078b083dbSLang Hames } 18178b083dbSLang Hames 18278b083dbSLang Hames return Err; 18378b083dbSLang Hames } 18478b083dbSLang Hames 18578b083dbSLang Hames Error SimpleExecutorMemoryManager::shutdown() { 18678b083dbSLang Hames 18778b083dbSLang Hames AllocationsMap AM; 18878b083dbSLang Hames { 18978b083dbSLang Hames std::lock_guard<std::mutex> Lock(M); 19078b083dbSLang Hames AM = std::move(Allocations); 19178b083dbSLang Hames } 19278b083dbSLang Hames 19378b083dbSLang Hames Error Err = Error::success(); 19478b083dbSLang Hames for (auto &KV : AM) 19578b083dbSLang Hames Err = joinErrors(std::move(Err), deallocateImpl(KV.first, KV.second)); 19678b083dbSLang Hames return Err; 19778b083dbSLang Hames } 19878b083dbSLang Hames 19978b083dbSLang Hames void SimpleExecutorMemoryManager::addBootstrapSymbols( 200ef391df2SLang Hames StringMap<ExecutorAddr> &M) { 201ef391df2SLang Hames M[rt::SimpleExecutorMemoryManagerInstanceName] = ExecutorAddr::fromPtr(this); 20278b083dbSLang Hames M[rt::SimpleExecutorMemoryManagerReserveWrapperName] = 203ef391df2SLang Hames ExecutorAddr::fromPtr(&reserveWrapper); 20478b083dbSLang Hames M[rt::SimpleExecutorMemoryManagerFinalizeWrapperName] = 205ef391df2SLang Hames ExecutorAddr::fromPtr(&finalizeWrapper); 20678b083dbSLang Hames M[rt::SimpleExecutorMemoryManagerDeallocateWrapperName] = 207ef391df2SLang Hames ExecutorAddr::fromPtr(&deallocateWrapper); 20878b083dbSLang Hames } 20978b083dbSLang Hames 21078b083dbSLang Hames Error SimpleExecutorMemoryManager::deallocateImpl(void *Base, Allocation &A) { 21178b083dbSLang Hames Error Err = Error::success(); 21278b083dbSLang Hames 21378b083dbSLang Hames while (!A.DeallocationActions.empty()) { 214*12b2cc22SLang Hames Err = joinErrors(std::move(Err), 215*12b2cc22SLang Hames A.DeallocationActions.back().runWithSPSRet()); 21678b083dbSLang Hames A.DeallocationActions.pop_back(); 21778b083dbSLang Hames } 21878b083dbSLang Hames 21978b083dbSLang Hames sys::MemoryBlock MB(Base, A.Size); 22078b083dbSLang Hames if (auto EC = sys::Memory::releaseMappedMemory(MB)) 22178b083dbSLang Hames Err = joinErrors(std::move(Err), errorCodeToError(EC)); 22278b083dbSLang Hames 22378b083dbSLang Hames return Err; 22478b083dbSLang Hames } 22578b083dbSLang Hames 22678b083dbSLang Hames llvm::orc::shared::detail::CWrapperFunctionResult 22778b083dbSLang Hames SimpleExecutorMemoryManager::reserveWrapper(const char *ArgData, 22878b083dbSLang Hames size_t ArgSize) { 22978b083dbSLang Hames return shared::WrapperFunction< 23078b083dbSLang Hames rt::SPSSimpleExecutorMemoryManagerReserveSignature>:: 23178b083dbSLang Hames handle(ArgData, ArgSize, 23278b083dbSLang Hames shared::makeMethodWrapperHandler( 23378b083dbSLang Hames &SimpleExecutorMemoryManager::allocate)) 23478b083dbSLang Hames .release(); 23578b083dbSLang Hames } 23678b083dbSLang Hames 23778b083dbSLang Hames llvm::orc::shared::detail::CWrapperFunctionResult 23878b083dbSLang Hames SimpleExecutorMemoryManager::finalizeWrapper(const char *ArgData, 23978b083dbSLang Hames size_t ArgSize) { 24078b083dbSLang Hames return shared::WrapperFunction< 24178b083dbSLang Hames rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>:: 24278b083dbSLang Hames handle(ArgData, ArgSize, 24378b083dbSLang Hames shared::makeMethodWrapperHandler( 24478b083dbSLang Hames &SimpleExecutorMemoryManager::finalize)) 24578b083dbSLang Hames .release(); 24678b083dbSLang Hames } 24778b083dbSLang Hames 24878b083dbSLang Hames llvm::orc::shared::detail::CWrapperFunctionResult 24978b083dbSLang Hames SimpleExecutorMemoryManager::deallocateWrapper(const char *ArgData, 25078b083dbSLang Hames size_t ArgSize) { 25178b083dbSLang Hames return shared::WrapperFunction< 25278b083dbSLang Hames rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>:: 25378b083dbSLang Hames handle(ArgData, ArgSize, 25478b083dbSLang Hames shared::makeMethodWrapperHandler( 25578b083dbSLang Hames &SimpleExecutorMemoryManager::deallocate)) 25678b083dbSLang Hames .release(); 25778b083dbSLang Hames } 25878b083dbSLang Hames 25978b083dbSLang Hames } // namespace rt_bootstrap 26078b083dbSLang Hames } // end namespace orc 26178b083dbSLang Hames } // end namespace llvm 262