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/Shared/OrcRTBridge.h"
16 using namespace llvm::jitlink
;
21 class EPCGenericJITLinkMemoryManager::InFlightAlloc
22 : public jitlink::JITLinkMemoryManager::InFlightAlloc
{
25 // FIXME: The C++98 initializer is an attempt to work around compile failures
26 // due to http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1397.
27 // We should be able to switch this back to member initialization once that
30 SegInfo() : WorkingMem(nullptr), ContentSize(0), ZeroFillSize(0) {}
35 uint64_t ZeroFillSize
;
38 using SegInfoMap
= AllocGroupSmallMap
<SegInfo
>;
40 InFlightAlloc(EPCGenericJITLinkMemoryManager
&Parent
, LinkGraph
&G
,
41 ExecutorAddr AllocAddr
, SegInfoMap Segs
)
42 : Parent(Parent
), G(G
), AllocAddr(AllocAddr
), Segs(std::move(Segs
)) {}
44 void finalize(OnFinalizedFunction OnFinalize
) override
{
45 tpctypes::FinalizeRequest FR
;
46 for (auto &KV
: Segs
) {
47 assert(KV
.second
.ContentSize
<= std::numeric_limits
<size_t>::max());
48 FR
.Segments
.push_back(tpctypes::SegFinalizeRequest
{
51 alignTo(KV
.second
.ContentSize
+ KV
.second
.ZeroFillSize
,
52 Parent
.EPC
.getPageSize()),
53 {KV
.second
.WorkingMem
, static_cast<size_t>(KV
.second
.ContentSize
)}});
56 // Transfer allocation actions.
57 std::swap(FR
.Actions
, G
.allocActions());
59 Parent
.EPC
.callSPSWrapperAsync
<
60 rt::SPSSimpleExecutorMemoryManagerFinalizeSignature
>(
62 [OnFinalize
= std::move(OnFinalize
), AllocAddr
= this->AllocAddr
](
63 Error SerializationErr
, Error FinalizeErr
) mutable {
64 // FIXME: Release abandoned alloc.
65 if (SerializationErr
) {
66 cantFail(std::move(FinalizeErr
));
67 OnFinalize(std::move(SerializationErr
));
68 } else if (FinalizeErr
)
69 OnFinalize(std::move(FinalizeErr
));
71 OnFinalize(FinalizedAlloc(AllocAddr
));
73 Parent
.SAs
.Allocator
, std::move(FR
));
76 void abandon(OnAbandonedFunction OnAbandoned
) override
{
77 // FIXME: Return memory to pool instead.
78 Parent
.EPC
.callSPSWrapperAsync
<
79 rt::SPSSimpleExecutorMemoryManagerDeallocateSignature
>(
80 Parent
.SAs
.Deallocate
,
81 [OnAbandoned
= std::move(OnAbandoned
)](Error SerializationErr
,
82 Error DeallocateErr
) mutable {
83 if (SerializationErr
) {
84 cantFail(std::move(DeallocateErr
));
85 OnAbandoned(std::move(SerializationErr
));
87 OnAbandoned(std::move(DeallocateErr
));
89 Parent
.SAs
.Allocator
, ArrayRef
<ExecutorAddr
>(AllocAddr
));
93 EPCGenericJITLinkMemoryManager
&Parent
;
95 ExecutorAddr AllocAddr
;
99 void EPCGenericJITLinkMemoryManager::allocate(const JITLinkDylib
*JD
,
101 OnAllocatedFunction OnAllocated
) {
104 auto Pages
= BL
.getContiguousPageBasedLayoutSizes(EPC
.getPageSize());
106 return OnAllocated(Pages
.takeError());
108 EPC
.callSPSWrapperAsync
<rt::SPSSimpleExecutorMemoryManagerReserveSignature
>(
110 [this, BL
= std::move(BL
), OnAllocated
= std::move(OnAllocated
)](
111 Error SerializationErr
, Expected
<ExecutorAddr
> AllocAddr
) mutable {
112 if (SerializationErr
) {
113 cantFail(AllocAddr
.takeError());
114 return OnAllocated(std::move(SerializationErr
));
117 return OnAllocated(AllocAddr
.takeError());
119 completeAllocation(*AllocAddr
, std::move(BL
), std::move(OnAllocated
));
121 SAs
.Allocator
, Pages
->total());
124 void EPCGenericJITLinkMemoryManager::deallocate(
125 std::vector
<FinalizedAlloc
> Allocs
, OnDeallocatedFunction OnDeallocated
) {
126 EPC
.callSPSWrapperAsync
<
127 rt::SPSSimpleExecutorMemoryManagerDeallocateSignature
>(
129 [OnDeallocated
= std::move(OnDeallocated
)](Error SerErr
,
130 Error DeallocErr
) mutable {
132 cantFail(std::move(DeallocErr
));
133 OnDeallocated(std::move(SerErr
));
135 OnDeallocated(std::move(DeallocErr
));
137 SAs
.Allocator
, Allocs
);
138 for (auto &A
: Allocs
)
142 void EPCGenericJITLinkMemoryManager::completeAllocation(
143 ExecutorAddr AllocAddr
, BasicLayout BL
, OnAllocatedFunction OnAllocated
) {
145 InFlightAlloc::SegInfoMap SegInfos
;
147 ExecutorAddr NextSegAddr
= AllocAddr
;
148 for (auto &KV
: BL
.segments()) {
149 const auto &AG
= KV
.first
;
150 auto &Seg
= KV
.second
;
152 Seg
.Addr
= NextSegAddr
;
153 KV
.second
.WorkingMem
= BL
.getGraph().allocateBuffer(Seg
.ContentSize
).data();
154 NextSegAddr
+= ExecutorAddrDiff(
155 alignTo(Seg
.ContentSize
+ Seg
.ZeroFillSize
, EPC
.getPageSize()));
157 auto &SegInfo
= SegInfos
[AG
];
158 SegInfo
.ContentSize
= Seg
.ContentSize
;
159 SegInfo
.ZeroFillSize
= Seg
.ZeroFillSize
;
160 SegInfo
.Addr
= Seg
.Addr
;
161 SegInfo
.WorkingMem
= Seg
.WorkingMem
;
164 if (auto Err
= BL
.apply())
165 return OnAllocated(std::move(Err
));
167 OnAllocated(std::make_unique
<InFlightAlloc
>(*this, BL
.getGraph(), AllocAddr
,
168 std::move(SegInfos
)));
171 } // end namespace orc
172 } // end namespace llvm