179fbee3cSAnubhab Ghosh //===------------------------ MemoryMapperTest.cpp ------------------------===//
279fbee3cSAnubhab Ghosh //
379fbee3cSAnubhab Ghosh // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
479fbee3cSAnubhab Ghosh // See https://llvm.org/LICENSE.txt for license information.
579fbee3cSAnubhab Ghosh // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
679fbee3cSAnubhab Ghosh //
779fbee3cSAnubhab Ghosh //===----------------------------------------------------------------------===//
879fbee3cSAnubhab Ghosh
979fbee3cSAnubhab Ghosh #include "llvm/ExecutionEngine/Orc/MemoryMapper.h"
1079fbee3cSAnubhab Ghosh #include "llvm/Support/Process.h"
1179fbee3cSAnubhab Ghosh #include "llvm/Testing/Support/Error.h"
1279fbee3cSAnubhab Ghosh #include "gtest/gtest.h"
1379fbee3cSAnubhab Ghosh
1479fbee3cSAnubhab Ghosh using namespace llvm;
1579fbee3cSAnubhab Ghosh using namespace llvm::orc;
1679fbee3cSAnubhab Ghosh using namespace llvm::orc::shared;
1779fbee3cSAnubhab Ghosh
1879fbee3cSAnubhab Ghosh namespace {
1979fbee3cSAnubhab Ghosh
reserve(MemoryMapper & M,size_t NumBytes)2079fbee3cSAnubhab Ghosh Expected<ExecutorAddrRange> reserve(MemoryMapper &M, size_t NumBytes) {
2179fbee3cSAnubhab Ghosh std::promise<MSVCPExpected<ExecutorAddrRange>> P;
2279fbee3cSAnubhab Ghosh auto F = P.get_future();
2379fbee3cSAnubhab Ghosh M.reserve(NumBytes, [&](auto R) { P.set_value(std::move(R)); });
2479fbee3cSAnubhab Ghosh return F.get();
2579fbee3cSAnubhab Ghosh }
2679fbee3cSAnubhab Ghosh
initialize(MemoryMapper & M,MemoryMapper::AllocInfo & AI)2779fbee3cSAnubhab Ghosh Expected<ExecutorAddr> initialize(MemoryMapper &M,
2879fbee3cSAnubhab Ghosh MemoryMapper::AllocInfo &AI) {
2979fbee3cSAnubhab Ghosh std::promise<MSVCPExpected<ExecutorAddr>> P;
3079fbee3cSAnubhab Ghosh auto F = P.get_future();
3179fbee3cSAnubhab Ghosh M.initialize(AI, [&](auto R) { P.set_value(std::move(R)); });
3279fbee3cSAnubhab Ghosh return F.get();
3379fbee3cSAnubhab Ghosh }
3479fbee3cSAnubhab Ghosh
deinitialize(MemoryMapper & M,const std::vector<ExecutorAddr> & Allocations)3579fbee3cSAnubhab Ghosh Error deinitialize(MemoryMapper &M,
3679fbee3cSAnubhab Ghosh const std::vector<ExecutorAddr> &Allocations) {
3779fbee3cSAnubhab Ghosh std::promise<MSVCPError> P;
3879fbee3cSAnubhab Ghosh auto F = P.get_future();
3979fbee3cSAnubhab Ghosh M.deinitialize(Allocations, [&](auto R) { P.set_value(std::move(R)); });
4079fbee3cSAnubhab Ghosh return F.get();
4179fbee3cSAnubhab Ghosh }
4279fbee3cSAnubhab Ghosh
release(MemoryMapper & M,const std::vector<ExecutorAddr> & Reservations)4379fbee3cSAnubhab Ghosh Error release(MemoryMapper &M, const std::vector<ExecutorAddr> &Reservations) {
4479fbee3cSAnubhab Ghosh std::promise<MSVCPError> P;
4579fbee3cSAnubhab Ghosh auto F = P.get_future();
4679fbee3cSAnubhab Ghosh M.release(Reservations, [&](auto R) { P.set_value(std::move(R)); });
4779fbee3cSAnubhab Ghosh return F.get();
4879fbee3cSAnubhab Ghosh }
4979fbee3cSAnubhab Ghosh
5079fbee3cSAnubhab Ghosh // A basic function to be used as both initializer/deinitializer
incrementWrapper(const char * ArgData,size_t ArgSize)5179fbee3cSAnubhab Ghosh orc::shared::CWrapperFunctionResult incrementWrapper(const char *ArgData,
5279fbee3cSAnubhab Ghosh size_t ArgSize) {
5379fbee3cSAnubhab Ghosh return WrapperFunction<SPSError(SPSExecutorAddr)>::handle(
5479fbee3cSAnubhab Ghosh ArgData, ArgSize,
5579fbee3cSAnubhab Ghosh [](ExecutorAddr A) -> Error {
5679fbee3cSAnubhab Ghosh *A.toPtr<int *>() += 1;
5779fbee3cSAnubhab Ghosh return Error::success();
5879fbee3cSAnubhab Ghosh })
5979fbee3cSAnubhab Ghosh .release();
6079fbee3cSAnubhab Ghosh }
6179fbee3cSAnubhab Ghosh
TEST(MemoryMapperTest,InitializeDeinitialize)6279fbee3cSAnubhab Ghosh TEST(MemoryMapperTest, InitializeDeinitialize) {
6379fbee3cSAnubhab Ghosh // These counters are used to track how many times the initializer and
6479fbee3cSAnubhab Ghosh // deinitializer functions are called
6579fbee3cSAnubhab Ghosh int InitializeCounter = 0;
6679fbee3cSAnubhab Ghosh int DeinitializeCounter = 0;
6779fbee3cSAnubhab Ghosh {
6879fbee3cSAnubhab Ghosh std::unique_ptr<MemoryMapper> Mapper =
694fcf8434SAnubhab Ghosh cantFail(InProcessMemoryMapper::Create());
7079fbee3cSAnubhab Ghosh
7179fbee3cSAnubhab Ghosh // We will do two separate allocations
724fcf8434SAnubhab Ghosh auto PageSize = Mapper->getPageSize();
7379fbee3cSAnubhab Ghosh auto TotalSize = PageSize * 2;
7479fbee3cSAnubhab Ghosh
7579fbee3cSAnubhab Ghosh // Reserve address space
7679fbee3cSAnubhab Ghosh auto Mem1 = reserve(*Mapper, TotalSize);
7779fbee3cSAnubhab Ghosh EXPECT_THAT_ERROR(Mem1.takeError(), Succeeded());
7879fbee3cSAnubhab Ghosh
7979fbee3cSAnubhab Ghosh // Test string for memory transfer
8079fbee3cSAnubhab Ghosh std::string HW = "Hello, world!";
8179fbee3cSAnubhab Ghosh
8279fbee3cSAnubhab Ghosh {
8379fbee3cSAnubhab Ghosh // Provide working memory
8479fbee3cSAnubhab Ghosh char *WA1 = Mapper->prepare(Mem1->Start, HW.size() + 1);
8579fbee3cSAnubhab Ghosh std::strcpy(static_cast<char *>(WA1), HW.c_str());
8679fbee3cSAnubhab Ghosh }
8779fbee3cSAnubhab Ghosh
8879fbee3cSAnubhab Ghosh // A structure to be passed to initialize
8979fbee3cSAnubhab Ghosh MemoryMapper::AllocInfo Alloc1;
9079fbee3cSAnubhab Ghosh {
9179fbee3cSAnubhab Ghosh MemoryMapper::AllocInfo::SegInfo Seg1;
9279fbee3cSAnubhab Ghosh Seg1.Offset = 0;
9379fbee3cSAnubhab Ghosh Seg1.ContentSize = HW.size();
9479fbee3cSAnubhab Ghosh Seg1.ZeroFillSize = PageSize - Seg1.ContentSize;
95*d3d9f7caSLang Hames Seg1.AG = MemProt::Read | MemProt::Write;
9679fbee3cSAnubhab Ghosh
9779fbee3cSAnubhab Ghosh Alloc1.MappingBase = Mem1->Start;
9879fbee3cSAnubhab Ghosh Alloc1.Segments.push_back(Seg1);
9979fbee3cSAnubhab Ghosh Alloc1.Actions.push_back(
10079fbee3cSAnubhab Ghosh {cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
10179fbee3cSAnubhab Ghosh ExecutorAddr::fromPtr(incrementWrapper),
10279fbee3cSAnubhab Ghosh ExecutorAddr::fromPtr(&InitializeCounter))),
10379fbee3cSAnubhab Ghosh cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
10479fbee3cSAnubhab Ghosh ExecutorAddr::fromPtr(incrementWrapper),
10579fbee3cSAnubhab Ghosh ExecutorAddr::fromPtr(&DeinitializeCounter)))});
10679fbee3cSAnubhab Ghosh }
10779fbee3cSAnubhab Ghosh
10879fbee3cSAnubhab Ghosh {
10979fbee3cSAnubhab Ghosh char *WA2 = Mapper->prepare(Mem1->Start + PageSize, HW.size() + 1);
11079fbee3cSAnubhab Ghosh std::strcpy(static_cast<char *>(WA2), HW.c_str());
11179fbee3cSAnubhab Ghosh }
11279fbee3cSAnubhab Ghosh
11379fbee3cSAnubhab Ghosh MemoryMapper::AllocInfo Alloc2;
11479fbee3cSAnubhab Ghosh {
11579fbee3cSAnubhab Ghosh MemoryMapper::AllocInfo::SegInfo Seg2;
11679fbee3cSAnubhab Ghosh Seg2.Offset = PageSize;
11779fbee3cSAnubhab Ghosh Seg2.ContentSize = HW.size();
11879fbee3cSAnubhab Ghosh Seg2.ZeroFillSize = PageSize - Seg2.ContentSize;
119*d3d9f7caSLang Hames Seg2.AG = MemProt::Read | MemProt::Write;
12079fbee3cSAnubhab Ghosh
12179fbee3cSAnubhab Ghosh Alloc2.MappingBase = Mem1->Start;
12279fbee3cSAnubhab Ghosh Alloc2.Segments.push_back(Seg2);
12379fbee3cSAnubhab Ghosh Alloc2.Actions.push_back(
12479fbee3cSAnubhab Ghosh {cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
12579fbee3cSAnubhab Ghosh ExecutorAddr::fromPtr(incrementWrapper),
12679fbee3cSAnubhab Ghosh ExecutorAddr::fromPtr(&InitializeCounter))),
12779fbee3cSAnubhab Ghosh cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
12879fbee3cSAnubhab Ghosh ExecutorAddr::fromPtr(incrementWrapper),
12979fbee3cSAnubhab Ghosh ExecutorAddr::fromPtr(&DeinitializeCounter)))});
13079fbee3cSAnubhab Ghosh }
13179fbee3cSAnubhab Ghosh
13279fbee3cSAnubhab Ghosh EXPECT_EQ(InitializeCounter, 0);
13379fbee3cSAnubhab Ghosh EXPECT_EQ(DeinitializeCounter, 0);
13479fbee3cSAnubhab Ghosh
13579fbee3cSAnubhab Ghosh // Set memory protections and run initializers
13679fbee3cSAnubhab Ghosh auto Init1 = initialize(*Mapper, Alloc1);
13779fbee3cSAnubhab Ghosh EXPECT_THAT_ERROR(Init1.takeError(), Succeeded());
13879fbee3cSAnubhab Ghosh EXPECT_EQ(HW, std::string(static_cast<char *>(Init1->toPtr<char *>())));
13979fbee3cSAnubhab Ghosh
14079fbee3cSAnubhab Ghosh EXPECT_EQ(InitializeCounter, 1);
14179fbee3cSAnubhab Ghosh EXPECT_EQ(DeinitializeCounter, 0);
14279fbee3cSAnubhab Ghosh
14379fbee3cSAnubhab Ghosh auto Init2 = initialize(*Mapper, Alloc2);
14479fbee3cSAnubhab Ghosh EXPECT_THAT_ERROR(Init2.takeError(), Succeeded());
14579fbee3cSAnubhab Ghosh EXPECT_EQ(HW, std::string(static_cast<char *>(Init2->toPtr<char *>())));
14679fbee3cSAnubhab Ghosh
14779fbee3cSAnubhab Ghosh EXPECT_EQ(InitializeCounter, 2);
14879fbee3cSAnubhab Ghosh EXPECT_EQ(DeinitializeCounter, 0);
14979fbee3cSAnubhab Ghosh
15079fbee3cSAnubhab Ghosh // Explicit deinitialization of first allocation
15179fbee3cSAnubhab Ghosh std::vector<ExecutorAddr> DeinitAddr = {*Init1};
15279fbee3cSAnubhab Ghosh EXPECT_THAT_ERROR(deinitialize(*Mapper, DeinitAddr), Succeeded());
15379fbee3cSAnubhab Ghosh
15479fbee3cSAnubhab Ghosh EXPECT_EQ(InitializeCounter, 2);
15579fbee3cSAnubhab Ghosh EXPECT_EQ(DeinitializeCounter, 1);
15679fbee3cSAnubhab Ghosh
15779fbee3cSAnubhab Ghosh // Test explicit release
15879fbee3cSAnubhab Ghosh {
15979fbee3cSAnubhab Ghosh auto Mem2 = reserve(*Mapper, PageSize);
16079fbee3cSAnubhab Ghosh EXPECT_THAT_ERROR(Mem2.takeError(), Succeeded());
16179fbee3cSAnubhab Ghosh
16279fbee3cSAnubhab Ghosh char *WA = Mapper->prepare(Mem2->Start, HW.size() + 1);
16379fbee3cSAnubhab Ghosh std::strcpy(static_cast<char *>(WA), HW.c_str());
16479fbee3cSAnubhab Ghosh
16579fbee3cSAnubhab Ghosh MemoryMapper::AllocInfo Alloc3;
16679fbee3cSAnubhab Ghosh {
16779fbee3cSAnubhab Ghosh MemoryMapper::AllocInfo::SegInfo Seg3;
16879fbee3cSAnubhab Ghosh Seg3.Offset = 0;
16979fbee3cSAnubhab Ghosh Seg3.ContentSize = HW.size();
17079fbee3cSAnubhab Ghosh Seg3.ZeroFillSize = PageSize - Seg3.ContentSize;
171*d3d9f7caSLang Hames Seg3.AG = MemProt::Read | MemProt::Write;
17279fbee3cSAnubhab Ghosh
17379fbee3cSAnubhab Ghosh Alloc3.MappingBase = Mem2->Start;
17479fbee3cSAnubhab Ghosh Alloc3.Segments.push_back(Seg3);
17579fbee3cSAnubhab Ghosh Alloc3.Actions.push_back(
17679fbee3cSAnubhab Ghosh {cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
17779fbee3cSAnubhab Ghosh ExecutorAddr::fromPtr(incrementWrapper),
17879fbee3cSAnubhab Ghosh ExecutorAddr::fromPtr(&InitializeCounter))),
17979fbee3cSAnubhab Ghosh cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddr>>(
18079fbee3cSAnubhab Ghosh ExecutorAddr::fromPtr(incrementWrapper),
18179fbee3cSAnubhab Ghosh ExecutorAddr::fromPtr(&DeinitializeCounter)))});
18279fbee3cSAnubhab Ghosh }
18379fbee3cSAnubhab Ghosh auto Init3 = initialize(*Mapper, Alloc3);
18479fbee3cSAnubhab Ghosh EXPECT_THAT_ERROR(Init3.takeError(), Succeeded());
18579fbee3cSAnubhab Ghosh EXPECT_EQ(HW, std::string(static_cast<char *>(Init3->toPtr<char *>())));
18679fbee3cSAnubhab Ghosh
18779fbee3cSAnubhab Ghosh EXPECT_EQ(InitializeCounter, 3);
18879fbee3cSAnubhab Ghosh EXPECT_EQ(DeinitializeCounter, 1);
18979fbee3cSAnubhab Ghosh
19079fbee3cSAnubhab Ghosh std::vector<ExecutorAddr> ReleaseAddrs = {Mem2->Start};
19179fbee3cSAnubhab Ghosh EXPECT_THAT_ERROR(release(*Mapper, ReleaseAddrs), Succeeded());
19279fbee3cSAnubhab Ghosh
19379fbee3cSAnubhab Ghosh EXPECT_EQ(InitializeCounter, 3);
19479fbee3cSAnubhab Ghosh EXPECT_EQ(DeinitializeCounter, 2);
19579fbee3cSAnubhab Ghosh }
19679fbee3cSAnubhab Ghosh }
19779fbee3cSAnubhab Ghosh
19879fbee3cSAnubhab Ghosh // Implicit deinitialization by the destructor
19979fbee3cSAnubhab Ghosh EXPECT_EQ(InitializeCounter, 3);
20079fbee3cSAnubhab Ghosh EXPECT_EQ(DeinitializeCounter, 3);
20179fbee3cSAnubhab Ghosh }
20279fbee3cSAnubhab Ghosh
20379fbee3cSAnubhab Ghosh } // namespace
204