LLVM 22.0.0git
JITLinkMemoryManager.h
Go to the documentation of this file.
1//===-- JITLinkMemoryManager.h - JITLink mem manager interface --*- C++ -*-===//
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//
9// Contains the JITLinkMemoryManager interface.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_EXECUTIONENGINE_JITLINK_JITLINKMEMORYMANAGER_H
14#define LLVM_EXECUTIONENGINE_JITLINK_JITLINKMEMORYMANAGER_H
15
25#include "llvm/Support/Error.h"
27#include "llvm/Support/Memory.h"
30
31#include <cassert>
32#include <cstdint>
33#include <future>
34#include <mutex>
35
36namespace llvm {
37namespace jitlink {
38
39class Block;
40class LinkGraph;
41class Section;
42
43/// Manages allocations of JIT memory.
44///
45/// Instances of this class may be accessed concurrently from multiple threads
46/// and their implemetations should include any necessary synchronization.
48public:
49
50 /// Represents a finalized allocation.
51 ///
52 /// Finalized allocations must be passed to the
53 /// JITLinkMemoryManager:deallocate method prior to being destroyed.
54 ///
55 /// The interpretation of the Address associated with the finalized allocation
56 /// is up to the memory manager implementation. Common options are using the
57 /// base address of the allocation, or the address of a memory management
58 /// object that tracks the allocation.
61
62 static constexpr auto InvalidAddr = ~uint64_t(0);
63
64 public:
65 FinalizedAlloc() = default;
67 assert(A.getValue() != InvalidAddr &&
68 "Explicitly creating an invalid allocation?");
69 }
70 FinalizedAlloc(const FinalizedAlloc &) = delete;
72 Other.A.setValue(InvalidAddr);
73 }
76 assert(A.getValue() == InvalidAddr &&
77 "Cannot overwrite active finalized allocation");
78 std::swap(A, Other.A);
79 return *this;
80 }
82 assert(A.getValue() == InvalidAddr &&
83 "Finalized allocation was not deallocated");
84 }
85
86 /// FinalizedAllocs convert to false for default-constructed, and
87 /// true otherwise. Default-constructed allocs need not be deallocated.
88 explicit operator bool() const { return A.getValue() != InvalidAddr; }
89
90 /// Returns the address associated with this finalized allocation.
91 /// The allocation is unmodified.
92 orc::ExecutorAddr getAddress() const { return A; }
93
94 /// Returns the address associated with this finalized allocation and
95 /// resets this object to the default state.
96 /// This should only be used by allocators when deallocating memory.
98 orc::ExecutorAddr Tmp = A;
99 A.setValue(InvalidAddr);
100 return Tmp;
101 }
102
103 private:
104 orc::ExecutorAddr A{InvalidAddr};
105 };
106
107 /// Represents an allocation which has not been finalized yet.
108 ///
109 /// InFlightAllocs manage both executor memory allocations and working
110 /// memory allocations.
111 ///
112 /// On finalization, the InFlightAlloc should transfer the content of
113 /// working memory into executor memory, apply memory protections, and
114 /// run any finalization functions.
115 ///
116 /// Working memory should be kept alive at least until one of the following
117 /// happens: (1) the InFlightAlloc instance is destroyed, (2) the
118 /// InFlightAlloc is abandoned, (3) finalized target memory is destroyed.
119 ///
120 /// If abandon is called then working memory and executor memory should both
121 /// be freed.
123 public:
126
127 virtual ~InFlightAlloc();
128
129 /// Called prior to finalization if the allocation should be abandoned.
130 virtual void abandon(OnAbandonedFunction OnAbandoned) = 0;
131
132 /// Called to transfer working memory to the target and apply finalization.
133 virtual void finalize(OnFinalizedFunction OnFinalized) = 0;
134
135 /// Synchronous convenience version of finalize.
137 std::promise<MSVCPExpected<FinalizedAlloc>> FinalizeResultP;
138 auto FinalizeResultF = FinalizeResultP.get_future();
140 FinalizeResultP.set_value(std::move(Result));
141 });
142 return FinalizeResultF.get();
143 }
144 };
145
146 /// Typedef for the argument to be passed to OnAllocatedFunction.
148
149 /// Called when allocation has been completed.
151
152 /// Called when deallocation has completed.
154
156
157 /// Start the allocation process.
158 ///
159 /// If the initial allocation is successful then the OnAllocated function will
160 /// be called with a std::unique_ptr<InFlightAlloc> value. If the assocation
161 /// is unsuccessful then the OnAllocated function will be called with an
162 /// Error.
163 virtual void allocate(const JITLinkDylib *JD, LinkGraph &G,
164 OnAllocatedFunction OnAllocated) = 0;
165
166 /// Convenience function for blocking allocation.
168 std::promise<MSVCPExpected<std::unique_ptr<InFlightAlloc>>> AllocResultP;
169 auto AllocResultF = AllocResultP.get_future();
170 allocate(JD, G, [&](AllocResult Alloc) {
171 AllocResultP.set_value(std::move(Alloc));
172 });
173 return AllocResultF.get();
174 }
175
176 /// Deallocate a list of allocation objects.
177 ///
178 /// Dealloc actions will be run in reverse order (from the end of the vector
179 /// to the start).
180 virtual void deallocate(std::vector<FinalizedAlloc> Allocs,
181 OnDeallocatedFunction OnDeallocated) = 0;
182
183 /// Convenience function for deallocation of a single alloc.
185 std::vector<FinalizedAlloc> Allocs;
186 Allocs.push_back(std::move(Alloc));
187 deallocate(std::move(Allocs), std::move(OnDeallocated));
188 }
189
190 /// Convenience function for blocking deallocation.
191 Error deallocate(std::vector<FinalizedAlloc> Allocs) {
192 std::promise<MSVCPError> DeallocResultP;
193 auto DeallocResultF = DeallocResultP.get_future();
194 deallocate(std::move(Allocs),
195 [&](Error Err) { DeallocResultP.set_value(std::move(Err)); });
196 return DeallocResultF.get();
197 }
198
199 /// Convenience function for blocking deallocation of a single alloc.
201 std::vector<FinalizedAlloc> Allocs;
202 Allocs.push_back(std::move(Alloc));
203 return deallocate(std::move(Allocs));
204 }
205};
206
207/// BasicLayout simplifies the implementation of JITLinkMemoryManagers.
208///
209/// BasicLayout groups Sections into Segments based on their memory protection
210/// and deallocation policies. JITLinkMemoryManagers can construct a BasicLayout
211/// from a Graph, and then assign working memory and addresses to each of the
212/// Segments. These addreses will be mapped back onto the Graph blocks in
213/// the apply method.
215public:
216 /// The Alignment, ContentSize and ZeroFillSize of each segment will be
217 /// pre-filled from the Graph. Clients must set the Addr and WorkingMem fields
218 /// prior to calling apply.
219 //
220 // FIXME: The C++98 initializer is an attempt to work around compile failures
221 // due to http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1397.
222 // We should be able to switch this back to member initialization once that
223 // issue is fixed.
224 class Segment {
225 friend class BasicLayout;
226
227 public:
228 Segment() = default;
230 size_t ContentSize = 0;
233 char *WorkingMem = nullptr;
234
235 private:
236 size_t NextWorkingMemOffset = 0;
237 std::vector<Block *> ContentBlocks, ZeroFillBlocks;
238 };
239
240 /// A convenience class that further groups segments based on memory
241 /// deallocation policy. This allows clients to make two slab allocations:
242 /// one for all standard segments, and one for all finalize segments.
246
248 };
249
250private:
251 using SegmentMap = orc::AllocGroupSmallMap<Segment>;
252
253public:
255
256 /// Return a reference to the graph this allocation was created from.
257 LinkGraph &getGraph() { return G; }
258
259 /// Returns the total number of required to allocate all segments (with each
260 /// segment padded out to page size) for all standard segments, and all
261 /// finalize segments.
262 ///
263 /// This is a convenience function for the common case where the segments will
264 /// be allocated contiguously.
265 ///
266 /// This function will return an error if any segment has an alignment that
267 /// is higher than a page.
270
271 /// Returns an iterator over the segments of the layout.
273 return {Segments.begin(), Segments.end()};
274 }
275
276 /// Apply the layout to the graph.
278
279 /// Returns a reference to the AllocActions in the graph.
280 /// This convenience function saves callers from having to #include
281 /// LinkGraph.h if all they need are allocation actions.
283
284private:
285 LinkGraph &G;
286 SegmentMap Segments;
287};
288
289/// A utility class for making simple allocations using JITLinkMemoryManager.
290///
291/// SimpleSegementAlloc takes a mapping of AllocGroups to Segments and uses
292/// this to create a LinkGraph with one Section (containing one Block) per
293/// Segment. Clients can obtain a pointer to the working memory and executor
294/// address of that block using the Segment's AllocGroup. Once memory has been
295/// populated, clients can call finalize to finalize the memory.
296///
297/// Note: Segments with MemLifetime::NoAlloc are not permitted, since they would
298/// not be useful, and their presence is likely to indicate a bug.
300public:
301 /// Describes a segment to be allocated.
302 struct Segment {
303 Segment() = default;
306
307 size_t ContentSize = 0;
309 };
310
311 /// Describes the segment working memory and executor address.
312 struct SegmentInfo {
315 };
316
318
320
323
324 LLVM_ABI static void Create(JITLinkMemoryManager &MemMgr,
325 std::shared_ptr<orc::SymbolStringPool> SSP,
326 Triple TT, const JITLinkDylib *JD,
327 SegmentMap Segments, OnCreatedFunction OnCreated);
328
331 std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
332 const JITLinkDylib *JD, SegmentMap Segments);
333
337
338 /// Returns the SegmentInfo for the given group.
340
341 /// Finalize all groups (async version).
342 void finalize(OnFinalizedFunction OnFinalized) {
343 Alloc->finalize(std::move(OnFinalized));
344 }
345
346 /// Finalize all groups.
348 return Alloc->finalize();
349 }
350
351private:
353 std::unique_ptr<LinkGraph> G,
355 std::unique_ptr<JITLinkMemoryManager::InFlightAlloc> Alloc);
356
357 std::unique_ptr<LinkGraph> G;
359 std::unique_ptr<JITLinkMemoryManager::InFlightAlloc> Alloc;
360};
361
362/// A JITLinkMemoryManager that allocates in-process memory.
364public:
365 class IPInFlightAlloc;
366
367 /// Attempts to auto-detect the host page size.
369
370 /// Create an instance using the given page size.
372 assert(isPowerOf2_64(PageSize) && "PageSize must be a power of 2");
373 }
374
375 void allocate(const JITLinkDylib *JD, LinkGraph &G,
376 OnAllocatedFunction OnAllocated) override;
377
378 // Use overloads from base class.
379 using JITLinkMemoryManager::allocate;
380
381 void deallocate(std::vector<FinalizedAlloc> Alloc,
382 OnDeallocatedFunction OnDeallocated) override;
383
384 // Use overloads from base class.
385 using JITLinkMemoryManager::deallocate;
386
387private:
388 // FIXME: Use an in-place array instead of a vector for DeallocActions.
389 // There shouldn't need to be a heap alloc for this.
390 struct FinalizedAllocInfo {
391 sys::MemoryBlock StandardSegments;
392 std::vector<orc::shared::WrapperFunctionCall> DeallocActions;
393 };
394
395 FinalizedAlloc createFinalizedAlloc(
396 sys::MemoryBlock StandardSegments,
397 std::vector<orc::shared::WrapperFunctionCall> DeallocActions);
398
400 std::mutex FinalizedAllocsMutex;
402};
403
404} // end namespace jitlink
405} // end namespace llvm
406
407#endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINKMEMORYMANAGER_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
arc branch finalize
This file defines the BumpPtrAllocator interface.
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
#define LLVM_ABI
Definition: Compiler.h:213
std::optional< std::vector< StOtherPiece > > Other
Definition: ELFYAML.cpp:1328
This file provides a collection of function (or more generally, callable) type erasure utilities supp...
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)
#define G(x, y, z)
Definition: MD5.cpp:56
This file defines the SmallVector class.
Lightweight error class with error context and mandatory checking.
Definition: Error.h:159
Tagged union holding either a T or a Error.
Definition: Error.h:485
reference get()
Returns a reference to the stored T value.
Definition: Error.h:582
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition: ArrayRef.h:303
RecyclingAllocator - This class wraps an Allocator, adding the functionality of recycling deleted obj...
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:47
A range adaptor for a pair of iterators.
A specialized small-map for AllocGroups.
Definition: MemoryFlags.h:165
A pair of memory protections and allocation policies.
Definition: MemoryFlags.h:110
Represents an address in the executor process.
This class encapsulates the notion of a memory block which has an address and a size.
Definition: Memory.h:33
unique_function is a type-erasing functor similar to std::function.
std::vector< AllocActionCallPair > AllocActions
A vector of allocation actions to be run for this allocation.
NodeAddr< BlockNode * > Block
Definition: RDFGraph.h:392
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition: MathExtras.h:293
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:858
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39