1 //===------------------------ MemoryMapperTest.cpp ------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
15 using namespace llvm::orc
;
16 using namespace llvm::orc::shared
;
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
)); });
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
)); });
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
)); });
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
)); });
50 // A basic function to be used as both initializer/deinitializer
51 orc::shared::CWrapperFunctionResult
incrementWrapper(const char *ArgData
,
53 return WrapperFunction
<SPSError(SPSExecutorAddr
)>::handle(
55 [](ExecutorAddr A
) -> Error
{
56 *A
.toPtr
<int *>() += 1;
57 return Error::success();
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;
68 std::unique_ptr
<MemoryMapper
> Mapper
=
69 cantFail(InProcessMemoryMapper::Create());
71 // We will do two separate allocations
72 auto PageSize
= Mapper
->getPageSize();
73 auto TotalSize
= PageSize
* 2;
75 // Reserve address space
76 auto Mem1
= reserve(*Mapper
, TotalSize
);
77 EXPECT_THAT_ERROR(Mem1
.takeError(), Succeeded());
79 // Test string for memory transfer
80 std::string HW
= "Hello, world!";
83 // Provide working memory
84 char *WA1
= Mapper
->prepare(Mem1
->Start
, HW
.size() + 1);
85 std::strcpy(static_cast<char *>(WA1
), HW
.c_str());
88 // A structure to be passed to initialize
89 MemoryMapper::AllocInfo Alloc1
;
91 MemoryMapper::AllocInfo::SegInfo Seg1
;
93 Seg1
.ContentSize
= HW
.size();
94 Seg1
.ZeroFillSize
= PageSize
- Seg1
.ContentSize
;
95 Seg1
.Prot
= sys::Memory::MF_READ
| sys::Memory::MF_WRITE
;
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
)))});
109 char *WA2
= Mapper
->prepare(Mem1
->Start
+ PageSize
, HW
.size() + 1);
110 std::strcpy(static_cast<char *>(WA2
), HW
.c_str());
113 MemoryMapper::AllocInfo Alloc2
;
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
;
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
)))});
132 EXPECT_EQ(InitializeCounter
, 0);
133 EXPECT_EQ(DeinitializeCounter
, 0);
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 *>())));
140 EXPECT_EQ(InitializeCounter
, 1);
141 EXPECT_EQ(DeinitializeCounter
, 0);
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 *>())));
147 EXPECT_EQ(InitializeCounter
, 2);
148 EXPECT_EQ(DeinitializeCounter
, 0);
150 // Explicit deinitialization of first allocation
151 std::vector
<ExecutorAddr
> DeinitAddr
= {*Init1
};
152 EXPECT_THAT_ERROR(deinitialize(*Mapper
, DeinitAddr
), Succeeded());
154 EXPECT_EQ(InitializeCounter
, 2);
155 EXPECT_EQ(DeinitializeCounter
, 1);
157 // Test explicit release
159 auto Mem2
= reserve(*Mapper
, PageSize
);
160 EXPECT_THAT_ERROR(Mem2
.takeError(), Succeeded());
162 char *WA
= Mapper
->prepare(Mem2
->Start
, HW
.size() + 1);
163 std::strcpy(static_cast<char *>(WA
), HW
.c_str());
165 MemoryMapper::AllocInfo Alloc3
;
167 MemoryMapper::AllocInfo::SegInfo Seg3
;
169 Seg3
.ContentSize
= HW
.size();
170 Seg3
.ZeroFillSize
= PageSize
- Seg3
.ContentSize
;
171 Seg3
.Prot
= sys::Memory::MF_READ
| sys::Memory::MF_WRITE
;
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
)))});
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 *>())));
187 EXPECT_EQ(InitializeCounter
, 3);
188 EXPECT_EQ(DeinitializeCounter
, 1);
190 std::vector
<ExecutorAddr
> ReleaseAddrs
= {Mem2
->Start
};
191 EXPECT_THAT_ERROR(release(*Mapper
, ReleaseAddrs
), Succeeded());
193 EXPECT_EQ(InitializeCounter
, 3);
194 EXPECT_EQ(DeinitializeCounter
, 2);
198 // Implicit deinitialization by the destructor
199 EXPECT_EQ(InitializeCounter
, 3);
200 EXPECT_EQ(DeinitializeCounter
, 3);