1 //===- SimpleExecuorMemoryManagare.cpp - Simple executor-side memory mgmt -===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/TargetProcess/SimpleExecutorMemoryManager.h"
11 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
12 #include "llvm/Support/FormatVariadic.h"
14 #define DEBUG_TYPE "orc"
18 namespace rt_bootstrap
{
20 SimpleExecutorMemoryManager::~SimpleExecutorMemoryManager() {
21 assert(Allocations
.empty() && "shutdown not called?");
24 Expected
<ExecutorAddr
> SimpleExecutorMemoryManager::allocate(uint64_t Size
) {
26 auto MB
= sys::Memory::allocateMappedMemory(
27 Size
, nullptr, sys::Memory::MF_READ
| sys::Memory::MF_WRITE
, 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 ExecutorAddr::fromPtr(MB
.base());
36 Error
SimpleExecutorMemoryManager::finalize(tpctypes::FinalizeRequest
&FR
) {
37 ExecutorAddr
Base(~0ULL);
38 std::vector
<shared::WrapperFunctionCall
> DeallocationActions
;
39 size_t SuccessfulFinalizationActions
= 0;
41 if (FR
.Segments
.empty()) {
42 // NOTE: Finalizing nothing is currently a no-op. Should it be an error?
43 if (FR
.Actions
.empty())
44 return Error::success();
46 return make_error
<StringError
>("Finalization actions attached to empty "
47 "finalization request",
48 inconvertibleErrorCode());
51 for (auto &Seg
: FR
.Segments
)
52 Base
= std::min(Base
, Seg
.Addr
);
54 for (auto &ActPair
: FR
.Actions
)
56 DeallocationActions
.push_back(ActPair
.Dealloc
);
58 // Get the Allocation for this finalization.
61 std::lock_guard
<std::mutex
> Lock(M
);
62 auto I
= Allocations
.find(Base
.toPtr
<void *>());
63 if (I
== Allocations
.end())
64 return make_error
<StringError
>("Attempt to finalize unrecognized "
66 formatv("{0:x}", Base
.getValue()),
67 inconvertibleErrorCode());
68 AllocSize
= I
->second
.Size
;
69 I
->second
.DeallocationActions
= std::move(DeallocationActions
);
71 ExecutorAddr AllocEnd
= Base
+ ExecutorAddrDiff(AllocSize
);
73 // Bail-out function: this will run deallocation actions corresponding to any
74 // completed finalization actions, then deallocate memory.
75 auto BailOut
= [&](Error Err
) {
76 std::pair
<void *, Allocation
> AllocToDestroy
;
78 // Get allocation to destroy.
80 std::lock_guard
<std::mutex
> Lock(M
);
81 auto I
= Allocations
.find(Base
.toPtr
<void *>());
83 // Check for missing allocation (effective a double free).
84 if (I
== Allocations
.end())
87 make_error
<StringError
>("No allocation entry found "
89 formatv("{0:x}", Base
.getValue()),
90 inconvertibleErrorCode()));
91 AllocToDestroy
= std::move(*I
);
95 // Run deallocation actions for all completed finalization actions.
96 while (SuccessfulFinalizationActions
)
98 joinErrors(std::move(Err
), FR
.Actions
[--SuccessfulFinalizationActions
]
99 .Dealloc
.runWithSPSRetErrorMerged());
101 // Deallocate memory.
102 sys::MemoryBlock
MB(AllocToDestroy
.first
, AllocToDestroy
.second
.Size
);
103 if (auto EC
= sys::Memory::releaseMappedMemory(MB
))
104 Err
= joinErrors(std::move(Err
), errorCodeToError(EC
));
109 // Copy content and apply permissions.
110 for (auto &Seg
: FR
.Segments
) {
112 // Check segment ranges.
113 if (LLVM_UNLIKELY(Seg
.Size
< Seg
.Content
.size()))
114 return BailOut(make_error
<StringError
>(
115 formatv("Segment {0:x} content size ({1:x} bytes) "
116 "exceeds segment size ({2:x} bytes)",
117 Seg
.Addr
.getValue(), Seg
.Content
.size(), Seg
.Size
),
118 inconvertibleErrorCode()));
119 ExecutorAddr SegEnd
= Seg
.Addr
+ ExecutorAddrDiff(Seg
.Size
);
120 if (LLVM_UNLIKELY(Seg
.Addr
< Base
|| SegEnd
> AllocEnd
))
121 return BailOut(make_error
<StringError
>(
122 formatv("Segment {0:x} -- {1:x} crosses boundary of "
123 "allocation {2:x} -- {3:x}",
124 Seg
.Addr
.getValue(), SegEnd
.getValue(), Base
.getValue(),
125 AllocEnd
.getValue()),
126 inconvertibleErrorCode()));
128 char *Mem
= Seg
.Addr
.toPtr
<char *>();
129 if (!Seg
.Content
.empty())
130 memcpy(Mem
, Seg
.Content
.data(), Seg
.Content
.size());
131 memset(Mem
+ Seg
.Content
.size(), 0, Seg
.Size
- Seg
.Content
.size());
132 assert(Seg
.Size
<= std::numeric_limits
<size_t>::max());
133 if (auto EC
= sys::Memory::protectMappedMemory(
134 {Mem
, static_cast<size_t>(Seg
.Size
)},
135 toSysMemoryProtectionFlags(Seg
.RAG
.Prot
)))
136 return BailOut(errorCodeToError(EC
));
137 if ((Seg
.RAG
.Prot
& MemProt::Exec
) == MemProt::Exec
)
138 sys::Memory::InvalidateInstructionCache(Mem
, Seg
.Size
);
141 // Run finalization actions.
142 for (auto &ActPair
: FR
.Actions
) {
143 if (auto Err
= ActPair
.Finalize
.runWithSPSRetErrorMerged())
144 return BailOut(std::move(Err
));
145 ++SuccessfulFinalizationActions
;
148 return Error::success();
151 Error
SimpleExecutorMemoryManager::deallocate(
152 const std::vector
<ExecutorAddr
> &Bases
) {
153 std::vector
<std::pair
<void *, Allocation
>> AllocPairs
;
154 AllocPairs
.reserve(Bases
.size());
156 // Get allocation to destroy.
157 Error Err
= Error::success();
159 std::lock_guard
<std::mutex
> Lock(M
);
160 for (auto &Base
: Bases
) {
161 auto I
= Allocations
.find(Base
.toPtr
<void *>());
163 // Check for missing allocation (effective a double free).
164 if (I
!= Allocations
.end()) {
165 AllocPairs
.push_back(std::move(*I
));
166 Allocations
.erase(I
);
170 make_error
<StringError
>("No allocation entry found "
172 formatv("{0:x}", Base
.getValue()),
173 inconvertibleErrorCode()));
177 while (!AllocPairs
.empty()) {
178 auto &P
= AllocPairs
.back();
179 Err
= joinErrors(std::move(Err
), deallocateImpl(P
.first
, P
.second
));
180 AllocPairs
.pop_back();
186 Error
SimpleExecutorMemoryManager::shutdown() {
190 std::lock_guard
<std::mutex
> Lock(M
);
191 AM
= std::move(Allocations
);
194 Error Err
= Error::success();
196 Err
= joinErrors(std::move(Err
), deallocateImpl(KV
.first
, KV
.second
));
200 void SimpleExecutorMemoryManager::addBootstrapSymbols(
201 StringMap
<ExecutorAddr
> &M
) {
202 M
[rt::SimpleExecutorMemoryManagerInstanceName
] = ExecutorAddr::fromPtr(this);
203 M
[rt::SimpleExecutorMemoryManagerReserveWrapperName
] =
204 ExecutorAddr::fromPtr(&reserveWrapper
);
205 M
[rt::SimpleExecutorMemoryManagerFinalizeWrapperName
] =
206 ExecutorAddr::fromPtr(&finalizeWrapper
);
207 M
[rt::SimpleExecutorMemoryManagerDeallocateWrapperName
] =
208 ExecutorAddr::fromPtr(&deallocateWrapper
);
211 Error
SimpleExecutorMemoryManager::deallocateImpl(void *Base
, Allocation
&A
) {
212 Error Err
= Error::success();
214 while (!A
.DeallocationActions
.empty()) {
215 Err
= joinErrors(std::move(Err
),
216 A
.DeallocationActions
.back().runWithSPSRetErrorMerged());
217 A
.DeallocationActions
.pop_back();
220 sys::MemoryBlock
MB(Base
, A
.Size
);
221 if (auto EC
= sys::Memory::releaseMappedMemory(MB
))
222 Err
= joinErrors(std::move(Err
), errorCodeToError(EC
));
227 llvm::orc::shared::CWrapperFunctionResult
228 SimpleExecutorMemoryManager::reserveWrapper(const char *ArgData
,
230 return shared::WrapperFunction
<
231 rt::SPSSimpleExecutorMemoryManagerReserveSignature
>::
232 handle(ArgData
, ArgSize
,
233 shared::makeMethodWrapperHandler(
234 &SimpleExecutorMemoryManager::allocate
))
238 llvm::orc::shared::CWrapperFunctionResult
239 SimpleExecutorMemoryManager::finalizeWrapper(const char *ArgData
,
241 return shared::WrapperFunction
<
242 rt::SPSSimpleExecutorMemoryManagerFinalizeSignature
>::
243 handle(ArgData
, ArgSize
,
244 shared::makeMethodWrapperHandler(
245 &SimpleExecutorMemoryManager::finalize
))
249 llvm::orc::shared::CWrapperFunctionResult
250 SimpleExecutorMemoryManager::deallocateWrapper(const char *ArgData
,
252 return shared::WrapperFunction
<
253 rt::SPSSimpleExecutorMemoryManagerDeallocateSignature
>::
254 handle(ArgData
, ArgSize
,
255 shared::makeMethodWrapperHandler(
256 &SimpleExecutorMemoryManager::deallocate
))
260 } // namespace rt_bootstrap
261 } // end namespace orc
262 } // end namespace llvm