1 //===------------------------ MemoryMapperTest.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 "llvm/ExecutionEngine/Orc/MemoryMapper.h" 10 #include "llvm/Support/Process.h" 11 #include "llvm/Testing/Support/Error.h" 12 #include "gtest/gtest.h" 13 14 using namespace llvm; 15 using namespace llvm::orc; 16 using namespace llvm::orc::shared; 17 18 namespace { 19 20 Expected<ExecutorAddrRange> reserve(MemoryMapper &M, size_t NumBytes) { 21 std::promise<MSVCPExpected<ExecutorAddrRange>> P; 22 auto F = P.get_future(); 23 M.reserve(NumBytes, [&](auto R) { P.set_value(std::move(R)); }); 24 return F.get(); 25 } 26 27 Expected<ExecutorAddr> initialize(MemoryMapper &M, 28 MemoryMapper::AllocInfo &AI) { 29 std::promise<MSVCPExpected<ExecutorAddr>> P; 30 auto F = P.get_future(); 31 M.initialize(AI, [&](auto R) { P.set_value(std::move(R)); }); 32 return F.get(); 33 } 34 35 Error deinitialize(MemoryMapper &M, 36 const std::vector<ExecutorAddr> &Allocations) { 37 std::promise<MSVCPError> P; 38 auto F = P.get_future(); 39 M.deinitialize(Allocations, [&](auto R) { P.set_value(std::move(R)); }); 40 return F.get(); 41 } 42 43 Error release(MemoryMapper &M, const std::vector<ExecutorAddr> &Reservations) { 44 std::promise<MSVCPError> P; 45 auto F = P.get_future(); 46 M.release(Reservations, [&](auto R) { P.set_value(std::move(R)); }); 47 return F.get(); 48 } 49 50 // A basic function to be used as both initializer/deinitializer 51 orc::shared::CWrapperFunctionResult incrementWrapper(const char *ArgData, 52 size_t ArgSize) { 53 return WrapperFunction<SPSError(SPSExecutorAddr)>::handle( 54 ArgData, ArgSize, 55 [](ExecutorAddr A) -> Error { 56 *A.toPtr<int *>() += 1; 57 return Error::success(); 58 }) 59 .release(); 60 } 61 62 TEST(MemoryMapperTest, InitializeDeinitialize) { 63 // These counters are used to track how many times the initializer and 64 // deinitializer functions are called 65 int InitializeCounter = 0; 66 int DeinitializeCounter = 0; 67 { 68 std::unique_ptr<MemoryMapper> Mapper = 69 std::make_unique<InProcessMemoryMapper>(); 70 71 // We will do two separate allocations 72 auto PageSize = cantFail(sys::Process::getPageSize()); 73 auto TotalSize = PageSize * 2; 74 75 // Reserve address space 76 auto Mem1 = reserve(*Mapper, TotalSize); 77 EXPECT_THAT_ERROR(Mem1.takeError(), Succeeded()); 78 79 // Test string for memory transfer 80 std::string HW = "Hello, world!"; 81 82 { 83 // Provide working memory 84 char *WA1 = Mapper->prepare(Mem1->Start, HW.size() + 1); 85 std::strcpy(static_cast<char *>(WA1), HW.c_str()); 86 } 87 88 // A structure to be passed to initialize 89 MemoryMapper::AllocInfo Alloc1; 90 { 91 MemoryMapper::AllocInfo::SegInfo Seg1; 92 Seg1.Offset = 0; 93 Seg1.ContentSize = HW.size(); 94 Seg1.ZeroFillSize = PageSize - Seg1.ContentSize; 95 Seg1.Prot = sys::Memory::MF_READ | sys::Memory::MF_WRITE; 96 97 Alloc1.MappingBase = Mem1->Start; 98 Alloc1.Segments.push_back(Seg1); 99 Alloc1.Actions.push_back( 100 {cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( 101 ExecutorAddr::fromPtr(incrementWrapper), 102 ExecutorAddr::fromPtr(&InitializeCounter))), 103 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( 104 ExecutorAddr::fromPtr(incrementWrapper), 105 ExecutorAddr::fromPtr(&DeinitializeCounter)))}); 106 } 107 108 { 109 char *WA2 = Mapper->prepare(Mem1->Start + PageSize, HW.size() + 1); 110 std::strcpy(static_cast<char *>(WA2), HW.c_str()); 111 } 112 113 MemoryMapper::AllocInfo Alloc2; 114 { 115 MemoryMapper::AllocInfo::SegInfo Seg2; 116 Seg2.Offset = PageSize; 117 Seg2.ContentSize = HW.size(); 118 Seg2.ZeroFillSize = PageSize - Seg2.ContentSize; 119 Seg2.Prot = sys::Memory::MF_READ | sys::Memory::MF_WRITE; 120 121 Alloc2.MappingBase = Mem1->Start; 122 Alloc2.Segments.push_back(Seg2); 123 Alloc2.Actions.push_back( 124 {cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( 125 ExecutorAddr::fromPtr(incrementWrapper), 126 ExecutorAddr::fromPtr(&InitializeCounter))), 127 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( 128 ExecutorAddr::fromPtr(incrementWrapper), 129 ExecutorAddr::fromPtr(&DeinitializeCounter)))}); 130 } 131 132 EXPECT_EQ(InitializeCounter, 0); 133 EXPECT_EQ(DeinitializeCounter, 0); 134 135 // Set memory protections and run initializers 136 auto Init1 = initialize(*Mapper, Alloc1); 137 EXPECT_THAT_ERROR(Init1.takeError(), Succeeded()); 138 EXPECT_EQ(HW, std::string(static_cast<char *>(Init1->toPtr<char *>()))); 139 140 EXPECT_EQ(InitializeCounter, 1); 141 EXPECT_EQ(DeinitializeCounter, 0); 142 143 auto Init2 = initialize(*Mapper, Alloc2); 144 EXPECT_THAT_ERROR(Init2.takeError(), Succeeded()); 145 EXPECT_EQ(HW, std::string(static_cast<char *>(Init2->toPtr<char *>()))); 146 147 EXPECT_EQ(InitializeCounter, 2); 148 EXPECT_EQ(DeinitializeCounter, 0); 149 150 // Explicit deinitialization of first allocation 151 std::vector<ExecutorAddr> DeinitAddr = {*Init1}; 152 EXPECT_THAT_ERROR(deinitialize(*Mapper, DeinitAddr), Succeeded()); 153 154 EXPECT_EQ(InitializeCounter, 2); 155 EXPECT_EQ(DeinitializeCounter, 1); 156 157 // Test explicit release 158 { 159 auto Mem2 = reserve(*Mapper, PageSize); 160 EXPECT_THAT_ERROR(Mem2.takeError(), Succeeded()); 161 162 char *WA = Mapper->prepare(Mem2->Start, HW.size() + 1); 163 std::strcpy(static_cast<char *>(WA), HW.c_str()); 164 165 MemoryMapper::AllocInfo Alloc3; 166 { 167 MemoryMapper::AllocInfo::SegInfo Seg3; 168 Seg3.Offset = 0; 169 Seg3.ContentSize = HW.size(); 170 Seg3.ZeroFillSize = PageSize - Seg3.ContentSize; 171 Seg3.Prot = sys::Memory::MF_READ | sys::Memory::MF_WRITE; 172 173 Alloc3.MappingBase = Mem2->Start; 174 Alloc3.Segments.push_back(Seg3); 175 Alloc3.Actions.push_back( 176 {cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( 177 ExecutorAddr::fromPtr(incrementWrapper), 178 ExecutorAddr::fromPtr(&InitializeCounter))), 179 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>( 180 ExecutorAddr::fromPtr(incrementWrapper), 181 ExecutorAddr::fromPtr(&DeinitializeCounter)))}); 182 } 183 auto Init3 = initialize(*Mapper, Alloc3); 184 EXPECT_THAT_ERROR(Init3.takeError(), Succeeded()); 185 EXPECT_EQ(HW, std::string(static_cast<char *>(Init3->toPtr<char *>()))); 186 187 EXPECT_EQ(InitializeCounter, 3); 188 EXPECT_EQ(DeinitializeCounter, 1); 189 190 std::vector<ExecutorAddr> ReleaseAddrs = {Mem2->Start}; 191 EXPECT_THAT_ERROR(release(*Mapper, ReleaseAddrs), Succeeded()); 192 193 EXPECT_EQ(InitializeCounter, 3); 194 EXPECT_EQ(DeinitializeCounter, 2); 195 } 196 } 197 198 // Implicit deinitialization by the destructor 199 EXPECT_EQ(InitializeCounter, 3); 200 EXPECT_EQ(DeinitializeCounter, 3); 201 } 202 203 } // namespace 204