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