1 //===---- EPCGenericJITLinkMemoryManager.cpp -- Mem management via EPC ----===//
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/EPCGenericJITLinkMemoryManager.h"
11 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
12 #include "llvm/ExecutionEngine/Orc/LookupAndRecordAddrs.h"
13 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
17 using namespace llvm::jitlink
;
22 class EPCGenericJITLinkMemoryManager::InFlightAlloc
23 : public jitlink::JITLinkMemoryManager::InFlightAlloc
{
26 // FIXME: The C++98 initializer is an attempt to work around compile failures
27 // due to http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1397.
28 // We should be able to switch this back to member initialization once that
31 SegInfo() : WorkingMem(nullptr), ContentSize(0), ZeroFillSize(0) {}
36 uint64_t ZeroFillSize
;
39 using SegInfoMap
= AllocGroupSmallMap
<SegInfo
>;
41 InFlightAlloc(EPCGenericJITLinkMemoryManager
&Parent
, LinkGraph
&G
,
42 ExecutorAddr AllocAddr
, SegInfoMap Segs
)
43 : Parent(Parent
), G(G
), AllocAddr(AllocAddr
), Segs(std::move(Segs
)) {}
45 void finalize(OnFinalizedFunction OnFinalize
) override
{
46 tpctypes::FinalizeRequest FR
;
47 for (auto &KV
: Segs
) {
48 assert(KV
.second
.ContentSize
<= std::numeric_limits
<size_t>::max());
49 FR
.Segments
.push_back(tpctypes::SegFinalizeRequest
{
52 alignTo(KV
.second
.ContentSize
+ KV
.second
.ZeroFillSize
,
53 Parent
.EPC
.getPageSize()),
54 {KV
.second
.WorkingMem
, static_cast<size_t>(KV
.second
.ContentSize
)}});
57 // Transfer allocation actions.
58 std::swap(FR
.Actions
, G
.allocActions());
60 Parent
.EPC
.callSPSWrapperAsync
<
61 rt::SPSSimpleExecutorMemoryManagerFinalizeSignature
>(
63 [OnFinalize
= std::move(OnFinalize
), AllocAddr
= this->AllocAddr
](
64 Error SerializationErr
, Error FinalizeErr
) mutable {
65 // FIXME: Release abandoned alloc.
66 if (SerializationErr
) {
67 cantFail(std::move(FinalizeErr
));
68 OnFinalize(std::move(SerializationErr
));
69 } else if (FinalizeErr
)
70 OnFinalize(std::move(FinalizeErr
));
72 OnFinalize(FinalizedAlloc(AllocAddr
));
74 Parent
.SAs
.Allocator
, std::move(FR
));
77 void abandon(OnAbandonedFunction OnAbandoned
) override
{
78 // FIXME: Return memory to pool instead.
79 Parent
.EPC
.callSPSWrapperAsync
<
80 rt::SPSSimpleExecutorMemoryManagerDeallocateSignature
>(
81 Parent
.SAs
.Deallocate
,
82 [OnAbandoned
= std::move(OnAbandoned
)](Error SerializationErr
,
83 Error DeallocateErr
) mutable {
84 if (SerializationErr
) {
85 cantFail(std::move(DeallocateErr
));
86 OnAbandoned(std::move(SerializationErr
));
88 OnAbandoned(std::move(DeallocateErr
));
90 Parent
.SAs
.Allocator
, ArrayRef
<ExecutorAddr
>(AllocAddr
));
94 EPCGenericJITLinkMemoryManager
&Parent
;
96 ExecutorAddr AllocAddr
;
100 void EPCGenericJITLinkMemoryManager::allocate(const JITLinkDylib
*JD
,
102 OnAllocatedFunction OnAllocated
) {
105 auto Pages
= BL
.getContiguousPageBasedLayoutSizes(EPC
.getPageSize());
107 return OnAllocated(Pages
.takeError());
109 EPC
.callSPSWrapperAsync
<rt::SPSSimpleExecutorMemoryManagerReserveSignature
>(
111 [this, BL
= std::move(BL
), OnAllocated
= std::move(OnAllocated
)](
112 Error SerializationErr
, Expected
<ExecutorAddr
> AllocAddr
) mutable {
113 if (SerializationErr
) {
114 cantFail(AllocAddr
.takeError());
115 return OnAllocated(std::move(SerializationErr
));
118 return OnAllocated(AllocAddr
.takeError());
120 completeAllocation(*AllocAddr
, std::move(BL
), std::move(OnAllocated
));
122 SAs
.Allocator
, Pages
->total());
125 void EPCGenericJITLinkMemoryManager::deallocate(
126 std::vector
<FinalizedAlloc
> Allocs
, OnDeallocatedFunction OnDeallocated
) {
127 EPC
.callSPSWrapperAsync
<
128 rt::SPSSimpleExecutorMemoryManagerDeallocateSignature
>(
130 [OnDeallocated
= std::move(OnDeallocated
)](Error SerErr
,
131 Error DeallocErr
) mutable {
133 cantFail(std::move(DeallocErr
));
134 OnDeallocated(std::move(SerErr
));
136 OnDeallocated(std::move(DeallocErr
));
138 SAs
.Allocator
, Allocs
);
139 for (auto &A
: Allocs
)
143 void EPCGenericJITLinkMemoryManager::completeAllocation(
144 ExecutorAddr AllocAddr
, BasicLayout BL
, OnAllocatedFunction OnAllocated
) {
146 InFlightAlloc::SegInfoMap SegInfos
;
148 ExecutorAddr NextSegAddr
= AllocAddr
;
149 for (auto &KV
: BL
.segments()) {
150 const auto &AG
= KV
.first
;
151 auto &Seg
= KV
.second
;
153 Seg
.Addr
= NextSegAddr
;
154 KV
.second
.WorkingMem
= BL
.getGraph().allocateBuffer(Seg
.ContentSize
).data();
155 NextSegAddr
+= ExecutorAddrDiff(
156 alignTo(Seg
.ContentSize
+ Seg
.ZeroFillSize
, EPC
.getPageSize()));
158 auto &SegInfo
= SegInfos
[AG
];
159 SegInfo
.ContentSize
= Seg
.ContentSize
;
160 SegInfo
.ZeroFillSize
= Seg
.ZeroFillSize
;
161 SegInfo
.Addr
= Seg
.Addr
;
162 SegInfo
.WorkingMem
= Seg
.WorkingMem
;
165 if (auto Err
= BL
.apply())
166 return OnAllocated(std::move(Err
));
168 OnAllocated(std::make_unique
<InFlightAlloc
>(*this, BL
.getGraph(), AllocAddr
,
169 std::move(SegInfos
)));
172 } // end namespace orc
173 } // end namespace llvm