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