File indexing completed on 2026-05-10 08:43:50
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef LLVM_EXECUTIONENGINE_JITLINK_JITLINKMEMORYMANAGER_H
0014 #define LLVM_EXECUTIONENGINE_JITLINK_JITLINKMEMORYMANAGER_H
0015
0016 #include "llvm/ADT/FunctionExtras.h"
0017 #include "llvm/ADT/SmallVector.h"
0018 #include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h"
0019 #include "llvm/ExecutionEngine/Orc/Shared/AllocationActions.h"
0020 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
0021 #include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h"
0022 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
0023 #include "llvm/Support/Allocator.h"
0024 #include "llvm/Support/Error.h"
0025 #include "llvm/Support/MSVCErrorWorkarounds.h"
0026 #include "llvm/Support/Memory.h"
0027 #include "llvm/Support/RecyclingAllocator.h"
0028 #include "llvm/TargetParser/Triple.h"
0029
0030 #include <cassert>
0031 #include <cstdint>
0032 #include <future>
0033 #include <mutex>
0034
0035 namespace llvm {
0036 namespace jitlink {
0037
0038 class Block;
0039 class LinkGraph;
0040 class Section;
0041
0042
0043
0044
0045
0046 class JITLinkMemoryManager {
0047 public:
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 class FinalizedAlloc {
0059 friend class JITLinkMemoryManager;
0060
0061 static constexpr auto InvalidAddr = ~uint64_t(0);
0062
0063 public:
0064 FinalizedAlloc() = default;
0065 explicit FinalizedAlloc(orc::ExecutorAddr A) : A(A) {
0066 assert(A.getValue() != InvalidAddr &&
0067 "Explicitly creating an invalid allocation?");
0068 }
0069 FinalizedAlloc(const FinalizedAlloc &) = delete;
0070 FinalizedAlloc(FinalizedAlloc &&Other) : A(Other.A) {
0071 Other.A.setValue(InvalidAddr);
0072 }
0073 FinalizedAlloc &operator=(const FinalizedAlloc &) = delete;
0074 FinalizedAlloc &operator=(FinalizedAlloc &&Other) {
0075 assert(A.getValue() == InvalidAddr &&
0076 "Cannot overwrite active finalized allocation");
0077 std::swap(A, Other.A);
0078 return *this;
0079 }
0080 ~FinalizedAlloc() {
0081 assert(A.getValue() == InvalidAddr &&
0082 "Finalized allocation was not deallocated");
0083 }
0084
0085
0086
0087 explicit operator bool() const { return A.getValue() != InvalidAddr; }
0088
0089
0090
0091 orc::ExecutorAddr getAddress() const { return A; }
0092
0093
0094
0095
0096 orc::ExecutorAddr release() {
0097 orc::ExecutorAddr Tmp = A;
0098 A.setValue(InvalidAddr);
0099 return Tmp;
0100 }
0101
0102 private:
0103 orc::ExecutorAddr A{InvalidAddr};
0104 };
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121 class InFlightAlloc {
0122 public:
0123 using OnFinalizedFunction = unique_function<void(Expected<FinalizedAlloc>)>;
0124 using OnAbandonedFunction = unique_function<void(Error)>;
0125
0126 virtual ~InFlightAlloc();
0127
0128
0129 virtual void abandon(OnAbandonedFunction OnAbandoned) = 0;
0130
0131
0132 virtual void finalize(OnFinalizedFunction OnFinalized) = 0;
0133
0134
0135 Expected<FinalizedAlloc> finalize() {
0136 std::promise<MSVCPExpected<FinalizedAlloc>> FinalizeResultP;
0137 auto FinalizeResultF = FinalizeResultP.get_future();
0138 finalize([&](Expected<FinalizedAlloc> Result) {
0139 FinalizeResultP.set_value(std::move(Result));
0140 });
0141 return FinalizeResultF.get();
0142 }
0143 };
0144
0145
0146 using AllocResult = Expected<std::unique_ptr<InFlightAlloc>>;
0147
0148
0149 using OnAllocatedFunction = unique_function<void(AllocResult)>;
0150
0151
0152 using OnDeallocatedFunction = unique_function<void(Error)>;
0153
0154 virtual ~JITLinkMemoryManager();
0155
0156
0157
0158
0159
0160
0161
0162 virtual void allocate(const JITLinkDylib *JD, LinkGraph &G,
0163 OnAllocatedFunction OnAllocated) = 0;
0164
0165
0166 AllocResult allocate(const JITLinkDylib *JD, LinkGraph &G) {
0167 std::promise<MSVCPExpected<std::unique_ptr<InFlightAlloc>>> AllocResultP;
0168 auto AllocResultF = AllocResultP.get_future();
0169 allocate(JD, G, [&](AllocResult Alloc) {
0170 AllocResultP.set_value(std::move(Alloc));
0171 });
0172 return AllocResultF.get();
0173 }
0174
0175
0176
0177
0178
0179 virtual void deallocate(std::vector<FinalizedAlloc> Allocs,
0180 OnDeallocatedFunction OnDeallocated) = 0;
0181
0182
0183 void deallocate(FinalizedAlloc Alloc, OnDeallocatedFunction OnDeallocated) {
0184 std::vector<FinalizedAlloc> Allocs;
0185 Allocs.push_back(std::move(Alloc));
0186 deallocate(std::move(Allocs), std::move(OnDeallocated));
0187 }
0188
0189
0190 Error deallocate(std::vector<FinalizedAlloc> Allocs) {
0191 std::promise<MSVCPError> DeallocResultP;
0192 auto DeallocResultF = DeallocResultP.get_future();
0193 deallocate(std::move(Allocs),
0194 [&](Error Err) { DeallocResultP.set_value(std::move(Err)); });
0195 return DeallocResultF.get();
0196 }
0197
0198
0199 Error deallocate(FinalizedAlloc Alloc) {
0200 std::vector<FinalizedAlloc> Allocs;
0201 Allocs.push_back(std::move(Alloc));
0202 return deallocate(std::move(Allocs));
0203 }
0204 };
0205
0206
0207
0208
0209
0210
0211
0212
0213 class BasicLayout {
0214 public:
0215
0216
0217
0218
0219
0220
0221
0222
0223 class Segment {
0224 friend class BasicLayout;
0225
0226 public:
0227 Segment()
0228 : ContentSize(0), ZeroFillSize(0), Addr(0), WorkingMem(nullptr),
0229 NextWorkingMemOffset(0) {}
0230 Align Alignment;
0231 size_t ContentSize;
0232 uint64_t ZeroFillSize;
0233 orc::ExecutorAddr Addr;
0234 char *WorkingMem = nullptr;
0235
0236 private:
0237 size_t NextWorkingMemOffset;
0238 std::vector<Block *> ContentBlocks, ZeroFillBlocks;
0239 };
0240
0241
0242
0243
0244 struct ContiguousPageBasedLayoutSizes {
0245 uint64_t StandardSegs = 0;
0246 uint64_t FinalizeSegs = 0;
0247
0248 uint64_t total() const { return StandardSegs + FinalizeSegs; }
0249 };
0250
0251 private:
0252 using SegmentMap = orc::AllocGroupSmallMap<Segment>;
0253
0254 public:
0255 BasicLayout(LinkGraph &G);
0256
0257
0258 LinkGraph &getGraph() { return G; }
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269 Expected<ContiguousPageBasedLayoutSizes>
0270 getContiguousPageBasedLayoutSizes(uint64_t PageSize);
0271
0272
0273 iterator_range<SegmentMap::iterator> segments() {
0274 return {Segments.begin(), Segments.end()};
0275 }
0276
0277
0278 Error apply();
0279
0280
0281
0282
0283 orc::shared::AllocActions &graphAllocActions();
0284
0285 private:
0286 LinkGraph &G;
0287 SegmentMap Segments;
0288 };
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300 class SimpleSegmentAlloc {
0301 public:
0302
0303 struct Segment {
0304 Segment() = default;
0305 Segment(size_t ContentSize, Align ContentAlign)
0306 : ContentSize(ContentSize), ContentAlign(ContentAlign) {}
0307
0308 size_t ContentSize = 0;
0309 Align ContentAlign;
0310 };
0311
0312
0313 struct SegmentInfo {
0314 orc::ExecutorAddr Addr;
0315 MutableArrayRef<char> WorkingMem;
0316 };
0317
0318 using SegmentMap = orc::AllocGroupSmallMap<Segment>;
0319
0320 using OnCreatedFunction = unique_function<void(Expected<SimpleSegmentAlloc>)>;
0321
0322 using OnFinalizedFunction =
0323 JITLinkMemoryManager::InFlightAlloc::OnFinalizedFunction;
0324
0325 static void Create(JITLinkMemoryManager &MemMgr,
0326 std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
0327 const JITLinkDylib *JD, SegmentMap Segments,
0328 OnCreatedFunction OnCreated);
0329
0330 static Expected<SimpleSegmentAlloc>
0331 Create(JITLinkMemoryManager &MemMgr,
0332 std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,
0333 const JITLinkDylib *JD, SegmentMap Segments);
0334
0335 SimpleSegmentAlloc(SimpleSegmentAlloc &&);
0336 SimpleSegmentAlloc &operator=(SimpleSegmentAlloc &&);
0337 ~SimpleSegmentAlloc();
0338
0339
0340 SegmentInfo getSegInfo(orc::AllocGroup AG);
0341
0342
0343 void finalize(OnFinalizedFunction OnFinalized) {
0344 Alloc->finalize(std::move(OnFinalized));
0345 }
0346
0347
0348 Expected<JITLinkMemoryManager::FinalizedAlloc> finalize() {
0349 return Alloc->finalize();
0350 }
0351
0352 private:
0353 SimpleSegmentAlloc(
0354 std::unique_ptr<LinkGraph> G,
0355 orc::AllocGroupSmallMap<Block *> ContentBlocks,
0356 std::unique_ptr<JITLinkMemoryManager::InFlightAlloc> Alloc);
0357
0358 std::unique_ptr<LinkGraph> G;
0359 orc::AllocGroupSmallMap<Block *> ContentBlocks;
0360 std::unique_ptr<JITLinkMemoryManager::InFlightAlloc> Alloc;
0361 };
0362
0363
0364 class InProcessMemoryManager : public JITLinkMemoryManager {
0365 public:
0366 class IPInFlightAlloc;
0367
0368
0369 static Expected<std::unique_ptr<InProcessMemoryManager>> Create();
0370
0371
0372 InProcessMemoryManager(uint64_t PageSize) : PageSize(PageSize) {
0373 assert(isPowerOf2_64(PageSize) && "PageSize must be a power of 2");
0374 }
0375
0376 void allocate(const JITLinkDylib *JD, LinkGraph &G,
0377 OnAllocatedFunction OnAllocated) override;
0378
0379
0380 using JITLinkMemoryManager::allocate;
0381
0382 void deallocate(std::vector<FinalizedAlloc> Alloc,
0383 OnDeallocatedFunction OnDeallocated) override;
0384
0385
0386 using JITLinkMemoryManager::deallocate;
0387
0388 private:
0389
0390
0391 struct FinalizedAllocInfo {
0392 sys::MemoryBlock StandardSegments;
0393 std::vector<orc::shared::WrapperFunctionCall> DeallocActions;
0394 };
0395
0396 FinalizedAlloc createFinalizedAlloc(
0397 sys::MemoryBlock StandardSegments,
0398 std::vector<orc::shared::WrapperFunctionCall> DeallocActions);
0399
0400 uint64_t PageSize;
0401 std::mutex FinalizedAllocsMutex;
0402 RecyclingAllocator<BumpPtrAllocator, FinalizedAllocInfo> FinalizedAllocInfos;
0403 };
0404
0405 }
0406 }
0407
0408 #endif