1 //===- SimpleExecuorMemoryManagare.cpp - Simple executor-side memory mgmt -===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h" 10 11 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" 12 #include "llvm/Support/FormatVariadic.h" 13 14 #define DEBUG_TYPE "orc" 15 16 namespace llvm { 17 namespace orc { 18 namespace rt_bootstrap { 19 20 SimpleExecutorMemoryManager::~SimpleExecutorMemoryManager() { 21 assert(Allocations.empty() && "shutdown not called?"); 22 } 23 24 Expected<ExecutorAddress> SimpleExecutorMemoryManager::allocate(uint64_t Size) { 25 std::error_code EC; 26 auto MB = sys::Memory::allocateMappedMemory( 27 Size, 0, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC); 28 if (EC) 29 return errorCodeToError(EC); 30 std::lock_guard<std::mutex> Lock(M); 31 assert(!Allocations.count(MB.base()) && "Duplicate allocation addr"); 32 Allocations[MB.base()].Size = Size; 33 return ExecutorAddress::fromPtr(MB.base()); 34 } 35 36 Error SimpleExecutorMemoryManager::finalize(tpctypes::FinalizeRequest &FR) { 37 ExecutorAddress Base(~0ULL); 38 std::vector<tpctypes::SupportFunctionCall> DeallocationActions; 39 size_t SuccessfulFinalizationActions = 0; 40 41 for (auto &Seg : FR.Segments) 42 Base = std::min(Base, Seg.Addr); 43 44 for (auto &ActPair : FR.Actions) 45 if (ActPair.Deallocate.Func) 46 DeallocationActions.push_back(ActPair.Deallocate); 47 48 // Get the Allocation for this finalization. 49 size_t AllocSize = 0; 50 { 51 std::lock_guard<std::mutex> Lock(M); 52 auto I = Allocations.find(Base.toPtr<void *>()); 53 if (I == Allocations.end()) 54 return make_error<StringError>("Attempt to finalize unrecognized " 55 "allocation " + 56 formatv("{0:x}", Base.getValue()), 57 inconvertibleErrorCode()); 58 AllocSize = I->second.Size; 59 I->second.DeallocationActions = std::move(DeallocationActions); 60 } 61 ExecutorAddress AllocEnd = Base + ExecutorAddrDiff(AllocSize); 62 63 // Bail-out function: this will run deallocation actions corresponding to any 64 // completed finalization actions, then deallocate memory. 65 auto BailOut = [&](Error Err) { 66 std::pair<void *, Allocation> AllocToDestroy; 67 68 // Get allocation to destory. 69 { 70 std::lock_guard<std::mutex> Lock(M); 71 auto I = Allocations.find(Base.toPtr<void *>()); 72 73 // Check for missing allocation (effective a double free). 74 if (I == Allocations.end()) 75 return joinErrors( 76 std::move(Err), 77 make_error<StringError>("No allocation entry found " 78 "for " + 79 formatv("{0:x}", Base.getValue()), 80 inconvertibleErrorCode())); 81 AllocToDestroy = std::move(*I); 82 Allocations.erase(I); 83 } 84 85 // Run deallocation actions for all completed finalization actions. 86 while (SuccessfulFinalizationActions) 87 Err = joinErrors( 88 std::move(Err), 89 FR.Actions[--SuccessfulFinalizationActions].Deallocate.run()); 90 91 // Deallocate memory. 92 sys::MemoryBlock MB(AllocToDestroy.first, AllocToDestroy.second.Size); 93 if (auto EC = sys::Memory::releaseMappedMemory(MB)) 94 Err = joinErrors(std::move(Err), errorCodeToError(EC)); 95 96 return Err; 97 }; 98 99 // Copy content and apply permissions. 100 for (auto &Seg : FR.Segments) { 101 102 // Check segment ranges. 103 if (LLVM_UNLIKELY(Seg.Size < Seg.Content.size())) 104 return BailOut(make_error<StringError>( 105 formatv("Segment {0:x} content size ({1:x} bytes) " 106 "exceeds segment size ({2:x} bytes)", 107 Seg.Addr.getValue(), Seg.Content.size(), Seg.Size), 108 inconvertibleErrorCode())); 109 ExecutorAddress SegEnd = Seg.Addr + ExecutorAddrDiff(Seg.Size); 110 if (LLVM_UNLIKELY(Seg.Addr < Base || SegEnd > AllocEnd)) 111 return BailOut(make_error<StringError>( 112 formatv("Segment {0:x} -- {1:x} crosses boundary of " 113 "allocation {2:x} -- {3:x}", 114 Seg.Addr.getValue(), SegEnd.getValue(), Base.getValue(), 115 AllocEnd.getValue()), 116 inconvertibleErrorCode())); 117 118 char *Mem = Seg.Addr.toPtr<char *>(); 119 memcpy(Mem, Seg.Content.data(), Seg.Content.size()); 120 memset(Mem + Seg.Content.size(), 0, Seg.Size - Seg.Content.size()); 121 assert(Seg.Size <= std::numeric_limits<size_t>::max()); 122 if (auto EC = sys::Memory::protectMappedMemory( 123 {Mem, static_cast<size_t>(Seg.Size)}, 124 tpctypes::fromWireProtectionFlags(Seg.Prot))) 125 return BailOut(errorCodeToError(EC)); 126 if (Seg.Prot & tpctypes::WPF_Exec) 127 sys::Memory::InvalidateInstructionCache(Mem, Seg.Size); 128 } 129 130 // Run finalization actions. 131 for (auto &ActPair : FR.Actions) { 132 if (auto Err = ActPair.Finalize.run()) 133 return BailOut(std::move(Err)); 134 ++SuccessfulFinalizationActions; 135 } 136 137 return Error::success(); 138 } 139 140 Error SimpleExecutorMemoryManager::deallocate( 141 const std::vector<ExecutorAddress> &Bases) { 142 std::vector<std::pair<void *, Allocation>> AllocPairs; 143 AllocPairs.reserve(Bases.size()); 144 145 // Get allocation to destory. 146 Error Err = Error::success(); 147 { 148 std::lock_guard<std::mutex> Lock(M); 149 for (auto &Base : Bases) { 150 auto I = Allocations.find(Base.toPtr<void *>()); 151 152 // Check for missing allocation (effective a double free). 153 if (I != Allocations.end()) { 154 AllocPairs.push_back(std::move(*I)); 155 Allocations.erase(I); 156 } else 157 Err = joinErrors( 158 std::move(Err), 159 make_error<StringError>("No allocation entry found " 160 "for " + 161 formatv("{0:x}", Base.getValue()), 162 inconvertibleErrorCode())); 163 } 164 } 165 166 while (!AllocPairs.empty()) { 167 auto &P = AllocPairs.back(); 168 Err = joinErrors(std::move(Err), deallocateImpl(P.first, P.second)); 169 AllocPairs.pop_back(); 170 } 171 172 return Err; 173 } 174 175 Error SimpleExecutorMemoryManager::shutdown() { 176 177 AllocationsMap AM; 178 { 179 std::lock_guard<std::mutex> Lock(M); 180 AM = std::move(Allocations); 181 } 182 183 Error Err = Error::success(); 184 for (auto &KV : AM) 185 Err = joinErrors(std::move(Err), deallocateImpl(KV.first, KV.second)); 186 return Err; 187 } 188 189 void SimpleExecutorMemoryManager::addBootstrapSymbols( 190 StringMap<ExecutorAddress> &M) { 191 M[rt::SimpleExecutorMemoryManagerInstanceName] = 192 ExecutorAddress::fromPtr(this); 193 M[rt::SimpleExecutorMemoryManagerReserveWrapperName] = 194 ExecutorAddress::fromPtr(&reserveWrapper); 195 M[rt::SimpleExecutorMemoryManagerFinalizeWrapperName] = 196 ExecutorAddress::fromPtr(&finalizeWrapper); 197 M[rt::SimpleExecutorMemoryManagerDeallocateWrapperName] = 198 ExecutorAddress::fromPtr(&deallocateWrapper); 199 } 200 201 Error SimpleExecutorMemoryManager::deallocateImpl(void *Base, Allocation &A) { 202 Error Err = Error::success(); 203 204 while (!A.DeallocationActions.empty()) { 205 Err = joinErrors(std::move(Err), A.DeallocationActions.back().run()); 206 A.DeallocationActions.pop_back(); 207 } 208 209 sys::MemoryBlock MB(Base, A.Size); 210 if (auto EC = sys::Memory::releaseMappedMemory(MB)) 211 Err = joinErrors(std::move(Err), errorCodeToError(EC)); 212 213 return Err; 214 } 215 216 llvm::orc::shared::detail::CWrapperFunctionResult 217 SimpleExecutorMemoryManager::reserveWrapper(const char *ArgData, 218 size_t ArgSize) { 219 return shared::WrapperFunction< 220 rt::SPSSimpleExecutorMemoryManagerReserveSignature>:: 221 handle(ArgData, ArgSize, 222 shared::makeMethodWrapperHandler( 223 &SimpleExecutorMemoryManager::allocate)) 224 .release(); 225 } 226 227 llvm::orc::shared::detail::CWrapperFunctionResult 228 SimpleExecutorMemoryManager::finalizeWrapper(const char *ArgData, 229 size_t ArgSize) { 230 return shared::WrapperFunction< 231 rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>:: 232 handle(ArgData, ArgSize, 233 shared::makeMethodWrapperHandler( 234 &SimpleExecutorMemoryManager::finalize)) 235 .release(); 236 } 237 238 llvm::orc::shared::detail::CWrapperFunctionResult 239 SimpleExecutorMemoryManager::deallocateWrapper(const char *ArgData, 240 size_t ArgSize) { 241 return shared::WrapperFunction< 242 rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>:: 243 handle(ArgData, ArgSize, 244 shared::makeMethodWrapperHandler( 245 &SimpleExecutorMemoryManager::deallocate)) 246 .release(); 247 } 248 249 } // namespace rt_bootstrap 250 } // end namespace orc 251 } // end namespace llvm 252