LLVM 22.0.0git
SimpleExecutorMemoryManager.cpp
Go to the documentation of this file.
1//===- SimpleExecuorMemoryManagare.cpp - Simple executor-side memory mgmt -===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
10
11#include "llvm/ADT/ScopeExit.h"
14
15#define DEBUG_TYPE "orc"
16
17namespace llvm {
18namespace orc {
19namespace rt_bootstrap {
20
22 assert(Slabs.empty() && "shutdown not called?");
23}
24
26 std::error_code EC;
29 if (EC)
30 return errorCodeToError(EC);
31 std::lock_guard<std::mutex> Lock(M);
32 assert(!Slabs.count(MB.base()) && "Duplicate allocation addr");
33 Slabs[MB.base()].Size = Size;
34 return ExecutorAddr::fromPtr(MB.base());
35}
36
39 std::vector<shared::WrapperFunctionCall> DeallocationActions;
40
41 if (FR.Segments.empty()) {
42 if (FR.Actions.empty())
43 return make_error<StringError>("Finalization request is empty",
45 else
46 return make_error<StringError>("Finalization actions attached to empty "
47 "finalization request",
49 }
50
51 ExecutorAddrRange RR(FR.Segments.front().Addr, FR.Segments.front().Addr);
52
53 std::vector<sys::MemoryBlock> MBsToReset;
54 auto ResetMBs = make_scope_exit([&]() {
55 for (auto &MB : MBsToReset)
59 RR.size());
60 });
61
62 // Copy content and apply permissions.
63 for (auto &Seg : FR.Segments) {
64 RR.Start = std::min(RR.Start, Seg.Addr);
65 RR.End = std::max(RR.End, Seg.Addr + Seg.Size);
66
67 // Check segment ranges.
68 if (LLVM_UNLIKELY(Seg.Size < Seg.Content.size()))
70 formatv("Segment {0:x} content size ({1:x} bytes) "
71 "exceeds segment size ({2:x} bytes)",
72 Seg.Addr.getValue(), Seg.Content.size(), Seg.Size),
74 ExecutorAddr SegEnd = Seg.Addr + ExecutorAddrDiff(Seg.Size);
75 if (LLVM_UNLIKELY(Seg.Addr < RR.Start || SegEnd > RR.End))
77 formatv("Segment {0:x} -- {1:x} crosses boundary of "
78 "allocation {2:x} -- {3:x}",
79 Seg.Addr, SegEnd, RR.Start, RR.End),
81
82 char *Mem = Seg.Addr.toPtr<char *>();
83 if (!Seg.Content.empty())
84 memcpy(Mem, Seg.Content.data(), Seg.Content.size());
85 memset(Mem + Seg.Content.size(), 0, Seg.Size - Seg.Content.size());
86 assert(Seg.Size <= std::numeric_limits<size_t>::max());
87
88 sys::MemoryBlock MB(Mem, Seg.Size);
90 MB, toSysMemoryProtectionFlags(Seg.RAG.Prot)))
91 return errorCodeToError(EC);
92
93 MBsToReset.push_back(MB);
94
95 if ((Seg.RAG.Prot & MemProt::Exec) == MemProt::Exec)
97 }
98
99 auto DeallocActions = runFinalizeActions(FR.Actions);
100 if (!DeallocActions)
101 return DeallocActions.takeError();
102
103 {
104 std::lock_guard<std::mutex> Lock(M);
105 auto Region = createRegionInfo(RR, "In initialize");
106 if (!Region)
107 return Region.takeError();
108 Region->DeallocActions = std::move(*DeallocActions);
109 }
110
111 // Successful initialization.
112 ResetMBs.release();
113
114 return RR.Start;
115}
116
118 const std::vector<ExecutorAddr> &InitKeys) {
119 Error Err = Error::success();
120
121 for (auto &KeyAddr : llvm::reverse(InitKeys)) {
122 std::vector<shared::WrapperFunctionCall> DeallocActions;
123 {
124 std::scoped_lock<std::mutex> Lock(M);
125 auto Slab = getSlabInfo(KeyAddr, "In deinitialize");
126 if (!Slab) {
127 Err = joinErrors(std::move(Err), Slab.takeError());
128 continue;
129 }
130
131 auto RI = getRegionInfo(*Slab, KeyAddr, "In deinitialize");
132 if (!RI) {
133 Err = joinErrors(std::move(Err), RI.takeError());
134 continue;
135 }
136
137 DeallocActions = std::move(RI->DeallocActions);
138 }
139
140 Err = joinErrors(std::move(Err),
141 runDeallocActions(std::move(DeallocActions)));
142 }
143
144 return Err;
145}
146
148 const std::vector<ExecutorAddr> &Bases) {
149 Error Err = Error::success();
150
151 // TODO: Prohibit new initializations within the slabs being removed?
152 for (auto &Base : llvm::reverse(Bases)) {
153 std::vector<shared::WrapperFunctionCall> DeallocActions;
155
156 {
157 std::scoped_lock<std::mutex> Lock(M);
158
159 auto SlabI = Slabs.find(Base.toPtr<void *>());
160 if (SlabI == Slabs.end()) {
161 Err = joinErrors(
162 std::move(Err),
163 make_error<StringError>("In release, " + formatv("{0:x}", Base) +
164 " is not part of any reserved "
165 "address range",
167 continue;
168 }
169
170 auto &Slab = SlabI->second;
171
172 for (auto &[Addr, Region] : Slab.Regions)
173 llvm::copy(Region.DeallocActions, back_inserter(DeallocActions));
174
175 MB = {Base.toPtr<void *>(), Slab.Size};
176
177 Slabs.erase(SlabI);
178 }
179
180 Err = joinErrors(std::move(Err), runDeallocActions(DeallocActions));
181 if (auto EC = sys::Memory::releaseMappedMemory(MB))
182 Err = joinErrors(std::move(Err), errorCodeToError(EC));
183 }
184
185 return Err;
186}
187
189
190 // TODO: Prevent new allocations during shutdown.
191 std::vector<ExecutorAddr> Bases;
192 {
193 std::scoped_lock<std::mutex> Lock(M);
194 for (auto &[Base, Slab] : Slabs)
195 Bases.push_back(ExecutorAddr::fromPtr(Base));
196 }
197
198 return release(Bases);
199}
200
213
215SimpleExecutorMemoryManager::getSlabInfo(ExecutorAddr A, StringRef Context) {
216 auto MakeBadSlabError = [&]() {
218 Context + ", address " + formatv("{0:x}", A) +
219 " is not part of any reserved address range",
221 };
222
223 auto I = Slabs.upper_bound(A.toPtr<void *>());
224 if (I == Slabs.begin())
225 return MakeBadSlabError();
226 --I;
227 if (!ExecutorAddrRange(ExecutorAddr::fromPtr(I->first), I->second.Size)
228 .contains(A))
229 return MakeBadSlabError();
230
231 return I->second;
232}
233
235SimpleExecutorMemoryManager::getSlabInfo(ExecutorAddrRange R,
236 StringRef Context) {
237 auto MakeBadSlabError = [&]() {
239 Context + ", range " + formatv("{0:x}", R) +
240 " is not part of any reserved address range",
242 };
243
244 auto I = Slabs.upper_bound(R.Start.toPtr<void *>());
245 if (I == Slabs.begin())
246 return MakeBadSlabError();
247 --I;
248 if (!ExecutorAddrRange(ExecutorAddr::fromPtr(I->first), I->second.Size)
249 .contains(R))
250 return MakeBadSlabError();
251
252 return I->second;
253}
254
255Expected<SimpleExecutorMemoryManager::RegionInfo &>
256SimpleExecutorMemoryManager::createRegionInfo(ExecutorAddrRange R,
257 StringRef Context) {
258
259 auto Slab = getSlabInfo(R, Context);
260 if (!Slab)
261 return Slab.takeError();
262
263 auto MakeBadRegionError = [&](ExecutorAddrRange Other, bool Prev) {
264 return make_error<StringError>(Context + ", region " + formatv("{0:x}", R) +
265 " overlaps " +
266 (Prev ? "previous" : "following") +
267 " region " + formatv("{0:x}", Other),
269 };
270
271 auto I = Slab->Regions.upper_bound(R.Start);
272 if (I != Slab->Regions.begin()) {
273 auto J = std::prev(I);
274 ExecutorAddrRange PrevRange(J->first, J->second.Size);
275 if (PrevRange.overlaps(R))
276 return MakeBadRegionError(PrevRange, true);
277 }
278 if (I != Slab->Regions.end()) {
279 ExecutorAddrRange NextRange(I->first, I->second.Size);
280 if (NextRange.overlaps(R))
281 return MakeBadRegionError(NextRange, false);
282 }
283
284 auto &RInfo = Slab->Regions[R.Start];
285 RInfo.Size = R.size();
286 return RInfo;
287}
288
289Expected<SimpleExecutorMemoryManager::RegionInfo &>
290SimpleExecutorMemoryManager::getRegionInfo(SlabInfo &Slab, ExecutorAddr A,
291 StringRef Context) {
292 auto I = Slab.Regions.find(A);
293 if (I == Slab.Regions.end())
295 Context + ", address " + formatv("{0:x}", A) +
296 " does not correspond to the start of any initialized region",
298
299 return I->second;
300}
301
302Expected<SimpleExecutorMemoryManager::RegionInfo &>
303SimpleExecutorMemoryManager::getRegionInfo(ExecutorAddr A, StringRef Context) {
304 auto Slab = getSlabInfo(A, Context);
305 if (!Slab)
306 return Slab.takeError();
307
308 return getRegionInfo(*Slab, A, Context);
309}
310
311llvm::orc::shared::CWrapperFunctionResult
312SimpleExecutorMemoryManager::reserveWrapper(const char *ArgData,
313 size_t ArgSize) {
314 return shared::WrapperFunction<rt::SPSSimpleRemoteMemoryMapReserveSignature>::
315 handle(ArgData, ArgSize,
318 .release();
319}
320
321llvm::orc::shared::CWrapperFunctionResult
322SimpleExecutorMemoryManager::initializeWrapper(const char *ArgData,
323 size_t ArgSize) {
324 return shared::
325 WrapperFunction<rt::SPSSimpleRemoteMemoryMapInitializeSignature>::handle(
326 ArgData, ArgSize,
329 .release();
330}
331
332llvm::orc::shared::CWrapperFunctionResult
333SimpleExecutorMemoryManager::deinitializeWrapper(const char *ArgData,
334 size_t ArgSize) {
335 return shared::WrapperFunction<
337 handle(ArgData, ArgSize,
340 .release();
341}
342
343llvm::orc::shared::CWrapperFunctionResult
344SimpleExecutorMemoryManager::releaseWrapper(const char *ArgData,
345 size_t ArgSize) {
346 return shared::WrapperFunction<rt::SPSSimpleRemoteMemoryMapReleaseSignature>::
347 handle(ArgData, ArgSize,
350 .release();
351}
352
353} // namespace rt_bootstrap
354} // end namespace orc
355} // end namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
#define LLVM_UNLIKELY(EXPR)
Definition Compiler.h:336
#define I(x, y, z)
Definition MD5.cpp:58
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition StringMap.h:133
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
Represents an address in the executor process.
static ExecutorAddr fromPtr(T *Ptr, UnwrapFn &&Unwrap=UnwrapFn())
Create an ExecutorAddr from the given pointer.
std::enable_if_t< std::is_pointer< T >::value, T > toPtr(WrapFn &&Wrap=WrapFn()) const
Cast this ExecutorAddr to a pointer of the given type.
Error deinitialize(const std::vector< ExecutorAddr > &InitKeys)
Error release(const std::vector< ExecutorAddr > &Bases)
Expected< ExecutorAddr > initialize(tpctypes::FinalizeRequest &FR)
void addBootstrapSymbols(StringMap< ExecutorAddr > &M) override
This class encapsulates the notion of a memory block which has an address and a size.
Definition Memory.h:33
static LLVM_ABI std::error_code protectMappedMemory(const MemoryBlock &Block, unsigned Flags)
This method sets the protection flags for a block of memory to the state specified by /p Flags.
static LLVM_ABI std::error_code releaseMappedMemory(MemoryBlock &Block)
This method releases a block of memory that was allocated with the allocateMappedMemory method.
static LLVM_ABI void InvalidateInstructionCache(const void *Addr, size_t Len)
InvalidateInstructionCache - Before the JIT can run a block of code that has been emitted it must inv...
static LLVM_ABI MemoryBlock allocateMappedMemory(size_t NumBytes, const MemoryBlock *const NearBlock, unsigned Flags, std::error_code &EC)
This method allocates a block of memory that is suitable for loading dynamically generated code (e....
LLVM_ABI const char * SimpleExecutorMemoryManagerInitializeWrapperName
LLVM_ABI const char * SimpleExecutorMemoryManagerReserveWrapperName
LLVM_ABI const char * SimpleExecutorMemoryManagerReleaseWrapperName
LLVM_ABI const char * SimpleExecutorMemoryManagerDeinitializeWrapperName
shared::SPSError( shared::SPSExecutorAddr, shared::SPSSequence< shared::SPSExecutorAddr >) SPSSimpleRemoteMemoryMapDeinitializeSignature
LLVM_ABI const char * SimpleExecutorMemoryManagerInstanceName
MethodWrapperHandler< RetT, ClassT, ArgTs... > makeMethodWrapperHandler(RetT(ClassT::*Method)(ArgTs...))
Create a MethodWrapperHandler object from the given method pointer.
uint64_t ExecutorAddrDiff
sys::Memory::ProtectionFlags toSysMemoryProtectionFlags(MemProt MP)
Convert a MemProt value to a corresponding sys::Memory::ProtectionFlags value.
Definition MemoryFlags.h:44
This is an optimization pass for GlobalISel generic memory operations.
detail::scope_exit< std::decay_t< Callable > > make_scope_exit(Callable &&F)
Definition ScopeExit.h:59
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:98
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
auto reverse(ContainerTy &&C)
Definition STLExtras.h:406
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition Error.h:442
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
@ Other
Any other memory.
Definition ModRef.h:68
OutputIt copy(R &&Range, OutputIt Out)
Definition STLExtras.h:1835
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition Error.cpp:111
Represents an address range in the exceutor process.
ExecutorAddrDiff size() const
bool contains(ExecutorAddr Addr) const
std::vector< SegFinalizeRequest > Segments