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