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
~SimpleExecutorMemoryManager()20349cc55cSDimitry Andric SimpleExecutorMemoryManager::~SimpleExecutorMemoryManager() {
21349cc55cSDimitry Andric assert(Allocations.empty() && "shutdown not called?");
22349cc55cSDimitry Andric }
23349cc55cSDimitry Andric
allocate(uint64_t Size)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
finalize(tpctypes::FinalizeRequest & FR)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
78349cc55cSDimitry Andric // Get allocation to destory.
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)},
135*fe013be4SDimitry Andric toSysMemoryProtectionFlags(Seg.RAG.Prot)))
136349cc55cSDimitry Andric return BailOut(errorCodeToError(EC));
137*fe013be4SDimitry 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
deallocate(const std::vector<ExecutorAddr> & Bases)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
156349cc55cSDimitry Andric // Get allocation to destory.
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
shutdown()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
addBootstrapSymbols(StringMap<ExecutorAddr> & M)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
deallocateImpl(void * Base,Allocation & A)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
reserveWrapper(const char * ArgData,size_t ArgSize)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
finalizeWrapper(const char * ArgData,size_t ArgSize)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
deallocateWrapper(const char * ArgData,size_t ArgSize)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