xref: /llvm-project/llvm/unittests/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManagerTest.cpp (revision 6641d29b70993bce6dbd7e0e0f1040753d38842f)
1 //===-------------- EPCGenericJITLinkMemoryManagerTest.cpp ----------------===//
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 #include "OrcTestCommon.h"
10 
11 #include "llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h"
12 
13 #include "llvm/ADT/DenseMap.h"
14 #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
15 #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
16 #include "llvm/Support/FormatVariadic.h"
17 #include "llvm/Support/Memory.h"
18 #include "llvm/Testing/Support/Error.h"
19 
20 #include <limits>
21 #include <vector>
22 
23 using namespace llvm;
24 using namespace llvm::orc;
25 using namespace llvm::orc::shared;
26 
27 namespace {
28 
29 class SimpleAllocator {
30 public:
31   Expected<ExecutorAddr> reserve(uint64_t Size) {
32     std::error_code EC;
33     auto MB = sys::Memory::allocateMappedMemory(
34         Size, 0, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
35     if (EC)
36       return errorCodeToError(EC);
37     Blocks[MB.base()] = sys::OwningMemoryBlock(std::move(MB));
38     return ExecutorAddr::fromPtr(MB.base());
39   }
40 
41   Error finalize(tpctypes::FinalizeRequest FR) {
42     for (auto &Seg : FR.Segments) {
43       char *Mem = Seg.Addr.toPtr<char *>();
44       memcpy(Mem, Seg.Content.data(), Seg.Content.size());
45       memset(Mem + Seg.Content.size(), 0, Seg.Size - Seg.Content.size());
46       assert(Seg.Size <= std::numeric_limits<size_t>::max());
47       if (auto EC = sys::Memory::protectMappedMemory(
48               {Mem, static_cast<size_t>(Seg.Size)},
49               tpctypes::fromWireProtectionFlags(Seg.Prot)))
50         return errorCodeToError(EC);
51       if (Seg.Prot & tpctypes::WPF_Exec)
52         sys::Memory::InvalidateInstructionCache(Mem, Seg.Size);
53     }
54     return Error::success();
55   }
56 
57   Error deallocate(std::vector<ExecutorAddr> &Bases) {
58     Error Err = Error::success();
59     for (auto &Base : Bases) {
60       auto I = Blocks.find(Base.toPtr<void *>());
61       if (I == Blocks.end()) {
62         Err = joinErrors(
63             std::move(Err),
64             make_error<StringError>("No allocation for " +
65                                         formatv("{0:x}", Base.getValue()),
66                                     inconvertibleErrorCode()));
67         continue;
68       }
69       auto MB = std::move(I->second);
70       Blocks.erase(I);
71       auto MBToRelease = MB.getMemoryBlock();
72       if (auto EC = sys::Memory::releaseMappedMemory(MBToRelease))
73         Err = joinErrors(std::move(Err), errorCodeToError(EC));
74     }
75     return Err;
76   }
77 
78 private:
79   DenseMap<void *, sys::OwningMemoryBlock> Blocks;
80 };
81 
82 llvm::orc::shared::detail::CWrapperFunctionResult
83 testReserve(const char *ArgData, size_t ArgSize) {
84   return WrapperFunction<rt::SPSSimpleExecutorMemoryManagerReserveSignature>::
85       handle(ArgData, ArgSize,
86              makeMethodWrapperHandler(&SimpleAllocator::reserve))
87           .release();
88 }
89 
90 llvm::orc::shared::detail::CWrapperFunctionResult
91 testFinalize(const char *ArgData, size_t ArgSize) {
92   return WrapperFunction<rt::SPSSimpleExecutorMemoryManagerFinalizeSignature>::
93       handle(ArgData, ArgSize,
94              makeMethodWrapperHandler(&SimpleAllocator::finalize))
95           .release();
96 }
97 
98 llvm::orc::shared::detail::CWrapperFunctionResult
99 testDeallocate(const char *ArgData, size_t ArgSize) {
100   return WrapperFunction<
101              rt::SPSSimpleExecutorMemoryManagerDeallocateSignature>::
102       handle(ArgData, ArgSize,
103              makeMethodWrapperHandler(&SimpleAllocator::deallocate))
104           .release();
105 }
106 
107 TEST(EPCGenericJITLinkMemoryManagerTest, AllocFinalizeFree) {
108   auto SelfEPC = cantFail(SelfExecutorProcessControl::Create());
109   SimpleAllocator SA;
110 
111   EPCGenericJITLinkMemoryManager::SymbolAddrs SAs;
112   SAs.Allocator = ExecutorAddr::fromPtr(&SA);
113   SAs.Reserve = ExecutorAddr::fromPtr(&testReserve);
114   SAs.Finalize = ExecutorAddr::fromPtr(&testFinalize);
115   SAs.Deallocate = ExecutorAddr::fromPtr(&testDeallocate);
116 
117   auto MemMgr = std::make_unique<EPCGenericJITLinkMemoryManager>(*SelfEPC, SAs);
118 
119   jitlink::JITLinkMemoryManager::SegmentsRequestMap SRM;
120   StringRef Hello = "hello";
121   SRM[sys::Memory::MF_READ] = {8, Hello.size(), 8};
122   auto Alloc = MemMgr->allocate(nullptr, SRM);
123   EXPECT_THAT_EXPECTED(Alloc, Succeeded());
124 
125   MutableArrayRef<char> WorkingMem =
126       (*Alloc)->getWorkingMemory(sys::Memory::MF_READ);
127   memcpy(WorkingMem.data(), Hello.data(), Hello.size());
128 
129   auto Err = (*Alloc)->finalize();
130   EXPECT_THAT_ERROR(std::move(Err), Succeeded());
131 
132   ExecutorAddr TargetAddr((*Alloc)->getTargetMemory(sys::Memory::MF_READ));
133 
134   const char *TargetMem = TargetAddr.toPtr<const char *>();
135   EXPECT_NE(TargetMem, WorkingMem.data());
136   StringRef TargetHello(TargetMem, Hello.size());
137   EXPECT_EQ(Hello, TargetHello);
138 
139   auto Err2 = (*Alloc)->deallocate();
140   EXPECT_THAT_ERROR(std::move(Err2), Succeeded());
141 }
142 
143 } // namespace
144