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