AMDGPU: Mark test as XFAIL in expensive_checks builds
[llvm-project.git] / llvm / lib / ExecutionEngine / Orc / EPCGenericRTDyldMemoryManager.cpp
blob060f17c957ef9659ed1c0b37fad6b10f7a74a1f3
1 //===----- EPCGenericRTDyldMemoryManager.cpp - EPC-bbasde MemMgr -----===//
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 //===----------------------------------------------------------------------===//
9 #include "llvm/ExecutionEngine/Orc/EPCGenericRTDyldMemoryManager.h"
10 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
11 #include "llvm/Support/Alignment.h"
12 #include "llvm/Support/FormatVariadic.h"
14 #define DEBUG_TYPE "orc"
16 using namespace llvm::orc::shared;
18 namespace llvm {
19 namespace orc {
21 Expected<std::unique_ptr<EPCGenericRTDyldMemoryManager>>
22 EPCGenericRTDyldMemoryManager::CreateWithDefaultBootstrapSymbols(
23 ExecutorProcessControl &EPC) {
24 SymbolAddrs SAs;
25 if (auto Err = EPC.getBootstrapSymbols(
26 {{SAs.Instance, rt::SimpleExecutorMemoryManagerInstanceName},
27 {SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
28 {SAs.Finalize, rt::SimpleExecutorMemoryManagerFinalizeWrapperName},
29 {SAs.Deallocate,
30 rt::SimpleExecutorMemoryManagerDeallocateWrapperName},
31 {SAs.RegisterEHFrame, rt::RegisterEHFrameSectionWrapperName},
32 {SAs.DeregisterEHFrame, rt::DeregisterEHFrameSectionWrapperName}}))
33 return std::move(Err);
34 return std::make_unique<EPCGenericRTDyldMemoryManager>(EPC, std::move(SAs));
37 EPCGenericRTDyldMemoryManager::EPCGenericRTDyldMemoryManager(
38 ExecutorProcessControl &EPC, SymbolAddrs SAs)
39 : EPC(EPC), SAs(std::move(SAs)) {
40 LLVM_DEBUG(dbgs() << "Created remote allocator " << (void *)this << "\n");
43 EPCGenericRTDyldMemoryManager::~EPCGenericRTDyldMemoryManager() {
44 LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << (void *)this << "\n");
45 if (!ErrMsg.empty())
46 errs() << "Destroying with existing errors:\n" << ErrMsg << "\n";
48 Error Err = Error::success();
49 if (auto Err2 = EPC.callSPSWrapper<
50 rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>(
51 SAs.Reserve, Err, SAs.Instance, FinalizedAllocs)) {
52 // FIXME: Report errors through EPC once that functionality is available.
53 logAllUnhandledErrors(std::move(Err2), errs(), "");
54 return;
57 if (Err)
58 logAllUnhandledErrors(std::move(Err), errs(), "");
61 uint8_t *EPCGenericRTDyldMemoryManager::allocateCodeSection(
62 uintptr_t Size, unsigned Alignment, unsigned SectionID,
63 StringRef SectionName) {
64 std::lock_guard<std::mutex> Lock(M);
65 LLVM_DEBUG({
66 dbgs() << "Allocator " << (void *)this << " allocating code section "
67 << SectionName << ": size = " << formatv("{0:x}", Size)
68 << " bytes, alignment = " << Alignment << "\n";
69 });
70 auto &Seg = Unmapped.back().CodeAllocs;
71 Seg.emplace_back(Size, Alignment);
72 return reinterpret_cast<uint8_t *>(
73 alignAddr(Seg.back().Contents.get(), Align(Alignment)));
76 uint8_t *EPCGenericRTDyldMemoryManager::allocateDataSection(
77 uintptr_t Size, unsigned Alignment, unsigned SectionID,
78 StringRef SectionName, bool IsReadOnly) {
79 std::lock_guard<std::mutex> Lock(M);
80 LLVM_DEBUG({
81 dbgs() << "Allocator " << (void *)this << " allocating "
82 << (IsReadOnly ? "ro" : "rw") << "-data section " << SectionName
83 << ": size = " << formatv("{0:x}", Size) << " bytes, alignment "
84 << Alignment << ")\n";
85 });
87 auto &Seg =
88 IsReadOnly ? Unmapped.back().RODataAllocs : Unmapped.back().RWDataAllocs;
90 Seg.emplace_back(Size, Alignment);
91 return reinterpret_cast<uint8_t *>(
92 alignAddr(Seg.back().Contents.get(), Align(Alignment)));
95 void EPCGenericRTDyldMemoryManager::reserveAllocationSpace(
96 uintptr_t CodeSize, Align CodeAlign, uintptr_t RODataSize,
97 Align RODataAlign, uintptr_t RWDataSize, Align RWDataAlign) {
100 std::lock_guard<std::mutex> Lock(M);
101 // If there's already an error then bail out.
102 if (!ErrMsg.empty())
103 return;
105 if (CodeAlign > EPC.getPageSize()) {
106 ErrMsg = "Invalid code alignment in reserveAllocationSpace";
107 return;
109 if (RODataAlign > EPC.getPageSize()) {
110 ErrMsg = "Invalid ro-data alignment in reserveAllocationSpace";
111 return;
113 if (RWDataAlign > EPC.getPageSize()) {
114 ErrMsg = "Invalid rw-data alignment in reserveAllocationSpace";
115 return;
119 uint64_t TotalSize = 0;
120 TotalSize += alignTo(CodeSize, EPC.getPageSize());
121 TotalSize += alignTo(RODataSize, EPC.getPageSize());
122 TotalSize += alignTo(RWDataSize, EPC.getPageSize());
124 LLVM_DEBUG({
125 dbgs() << "Allocator " << (void *)this << " reserving "
126 << formatv("{0:x}", TotalSize) << " bytes.\n";
129 Expected<ExecutorAddr> TargetAllocAddr((ExecutorAddr()));
130 if (auto Err = EPC.callSPSWrapper<
131 rt::SPSSimpleExecutorMemoryManagerReserveSignature>(
132 SAs.Reserve, TargetAllocAddr, SAs.Instance, TotalSize)) {
133 std::lock_guard<std::mutex> Lock(M);
134 ErrMsg = toString(std::move(Err));
135 return;
137 if (!TargetAllocAddr) {
138 std::lock_guard<std::mutex> Lock(M);
139 ErrMsg = toString(TargetAllocAddr.takeError());
140 return;
143 std::lock_guard<std::mutex> Lock(M);
144 Unmapped.push_back(SectionAllocGroup());
145 Unmapped.back().RemoteCode = {
146 *TargetAllocAddr, ExecutorAddrDiff(alignTo(CodeSize, EPC.getPageSize()))};
147 Unmapped.back().RemoteROData = {
148 Unmapped.back().RemoteCode.End,
149 ExecutorAddrDiff(alignTo(RODataSize, EPC.getPageSize()))};
150 Unmapped.back().RemoteRWData = {
151 Unmapped.back().RemoteROData.End,
152 ExecutorAddrDiff(alignTo(RWDataSize, EPC.getPageSize()))};
155 bool EPCGenericRTDyldMemoryManager::needsToReserveAllocationSpace() {
156 return true;
159 void EPCGenericRTDyldMemoryManager::registerEHFrames(uint8_t *Addr,
160 uint64_t LoadAddr,
161 size_t Size) {
162 LLVM_DEBUG({
163 dbgs() << "Allocator " << (void *)this << " added unfinalized eh-frame "
164 << formatv("[ {0:x} {1:x} ]", LoadAddr, LoadAddr + Size) << "\n";
166 std::lock_guard<std::mutex> Lock(M);
167 // Bail out early if there's already an error.
168 if (!ErrMsg.empty())
169 return;
171 ExecutorAddr LA(LoadAddr);
172 for (auto &SecAllocGroup : llvm::reverse(Unfinalized)) {
173 if (SecAllocGroup.RemoteCode.contains(LA) ||
174 SecAllocGroup.RemoteROData.contains(LA) ||
175 SecAllocGroup.RemoteRWData.contains(LA)) {
176 SecAllocGroup.UnfinalizedEHFrames.push_back({LA, Size});
177 return;
180 ErrMsg = "eh-frame does not lie inside unfinalized alloc";
183 void EPCGenericRTDyldMemoryManager::deregisterEHFrames() {
184 // This is a no-op for us: We've registered a deallocation action for it.
187 void EPCGenericRTDyldMemoryManager::notifyObjectLoaded(
188 RuntimeDyld &Dyld, const object::ObjectFile &Obj) {
189 std::lock_guard<std::mutex> Lock(M);
190 LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " applied mappings:\n");
191 for (auto &ObjAllocs : Unmapped) {
192 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs,
193 ObjAllocs.RemoteCode.Start);
194 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs,
195 ObjAllocs.RemoteROData.Start);
196 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs,
197 ObjAllocs.RemoteRWData.Start);
198 Unfinalized.push_back(std::move(ObjAllocs));
200 Unmapped.clear();
203 bool EPCGenericRTDyldMemoryManager::finalizeMemory(std::string *ErrMsg) {
204 LLVM_DEBUG(dbgs() << "Allocator " << (void *)this << " finalizing:\n");
206 // If there's an error then bail out here.
207 std::vector<SectionAllocGroup> SecAllocGroups;
209 std::lock_guard<std::mutex> Lock(M);
210 if (ErrMsg && !this->ErrMsg.empty()) {
211 *ErrMsg = std::move(this->ErrMsg);
212 return true;
214 std::swap(SecAllocGroups, Unfinalized);
217 // Loop over unfinalized objects to make finalization requests.
218 for (auto &SecAllocGroup : SecAllocGroups) {
220 MemProt SegMemProts[3] = {MemProt::Read | MemProt::Exec, MemProt::Read,
221 MemProt::Read | MemProt::Write};
223 ExecutorAddrRange *RemoteAddrs[3] = {&SecAllocGroup.RemoteCode,
224 &SecAllocGroup.RemoteROData,
225 &SecAllocGroup.RemoteRWData};
227 std::vector<SectionAlloc> *SegSections[3] = {&SecAllocGroup.CodeAllocs,
228 &SecAllocGroup.RODataAllocs,
229 &SecAllocGroup.RWDataAllocs};
231 tpctypes::FinalizeRequest FR;
232 std::unique_ptr<char[]> AggregateContents[3];
234 for (unsigned I = 0; I != 3; ++I) {
235 FR.Segments.push_back({});
236 auto &Seg = FR.Segments.back();
237 Seg.RAG = SegMemProts[I];
238 Seg.Addr = RemoteAddrs[I]->Start;
239 for (auto &SecAlloc : *SegSections[I]) {
240 Seg.Size = alignTo(Seg.Size, SecAlloc.Align);
241 Seg.Size += SecAlloc.Size;
243 AggregateContents[I] = std::make_unique<char[]>(Seg.Size);
244 size_t SecOffset = 0;
245 for (auto &SecAlloc : *SegSections[I]) {
246 SecOffset = alignTo(SecOffset, SecAlloc.Align);
247 memcpy(&AggregateContents[I][SecOffset],
248 reinterpret_cast<const char *>(
249 alignAddr(SecAlloc.Contents.get(), Align(SecAlloc.Align))),
250 SecAlloc.Size);
251 SecOffset += SecAlloc.Size;
252 // FIXME: Can we reset SecAlloc.Content here, now that it's copied into
253 // the aggregated content?
255 Seg.Content = {AggregateContents[I].get(), SecOffset};
258 for (auto &Frame : SecAllocGroup.UnfinalizedEHFrames)
259 FR.Actions.push_back(
260 {cantFail(
261 WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
262 SAs.RegisterEHFrame, Frame)),
263 cantFail(
264 WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
265 SAs.DeregisterEHFrame, Frame))});
267 // We'll also need to make an extra allocation for the eh-frame wrapper call
268 // arguments.
269 Error FinalizeErr = Error::success();
270 if (auto Err = EPC.callSPSWrapper<
271 rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>(
272 SAs.Finalize, FinalizeErr, SAs.Instance, std::move(FR))) {
273 std::lock_guard<std::mutex> Lock(M);
274 this->ErrMsg = toString(std::move(Err));
275 dbgs() << "Serialization error: " << this->ErrMsg << "\n";
276 if (ErrMsg)
277 *ErrMsg = this->ErrMsg;
278 return true;
280 if (FinalizeErr) {
281 std::lock_guard<std::mutex> Lock(M);
282 this->ErrMsg = toString(std::move(FinalizeErr));
283 dbgs() << "Finalization error: " << this->ErrMsg << "\n";
284 if (ErrMsg)
285 *ErrMsg = this->ErrMsg;
286 return true;
290 return false;
293 void EPCGenericRTDyldMemoryManager::mapAllocsToRemoteAddrs(
294 RuntimeDyld &Dyld, std::vector<SectionAlloc> &Allocs,
295 ExecutorAddr NextAddr) {
296 for (auto &Alloc : Allocs) {
297 NextAddr.setValue(alignTo(NextAddr.getValue(), Alloc.Align));
298 LLVM_DEBUG({
299 dbgs() << " " << static_cast<void *>(Alloc.Contents.get()) << " -> "
300 << format("0x%016" PRIx64, NextAddr.getValue()) << "\n";
302 Dyld.mapSectionAddress(reinterpret_cast<const void *>(alignAddr(
303 Alloc.Contents.get(), Align(Alloc.Align))),
304 NextAddr.getValue());
305 Alloc.RemoteAddr = NextAddr;
306 // Only advance NextAddr if it was non-null to begin with,
307 // otherwise leave it as null.
308 if (NextAddr)
309 NextAddr += ExecutorAddrDiff(Alloc.Size);
313 } // end namespace orc
314 } // end namespace llvm