1 | //===---------------- MapperJITLinkMemoryManagerTest.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/MapperJITLinkMemoryManager.h" |
12 | |
13 | #include "llvm/ExecutionEngine/Orc/MemoryMapper.h" |
14 | #include "llvm/Testing/Support/Error.h" |
15 | |
16 | #include <vector> |
17 | |
18 | using namespace llvm; |
19 | using namespace llvm::jitlink; |
20 | using namespace llvm::orc; |
21 | using namespace llvm::orc::shared; |
22 | |
23 | namespace { |
24 | |
25 | class CounterMapper final : public MemoryMapper { |
26 | public: |
27 | CounterMapper(std::unique_ptr<MemoryMapper> Mapper) |
28 | : Mapper(std::move(Mapper)) {} |
29 | |
30 | unsigned int getPageSize() override { return Mapper->getPageSize(); } |
31 | |
32 | void reserve(size_t NumBytes, OnReservedFunction OnReserved) override { |
33 | ++ReserveCount; |
34 | return Mapper->reserve(NumBytes, OnReserved: std::move(OnReserved)); |
35 | } |
36 | |
37 | void initialize(AllocInfo &AI, OnInitializedFunction OnInitialized) override { |
38 | ++InitCount; |
39 | return Mapper->initialize(AI, OnInitialized: std::move(OnInitialized)); |
40 | } |
41 | |
42 | char *prepare(ExecutorAddr Addr, size_t ContentSize) override { |
43 | return Mapper->prepare(Addr, ContentSize); |
44 | } |
45 | |
46 | void deinitialize(ArrayRef<ExecutorAddr> Allocations, |
47 | OnDeinitializedFunction OnDeInitialized) override { |
48 | ++DeinitCount; |
49 | return Mapper->deinitialize(Allocations, OnDeInitialized: std::move(OnDeInitialized)); |
50 | } |
51 | |
52 | void release(ArrayRef<ExecutorAddr> Reservations, |
53 | OnReleasedFunction OnRelease) override { |
54 | ++ReleaseCount; |
55 | |
56 | return Mapper->release(Reservations, OnRelease: std::move(OnRelease)); |
57 | } |
58 | |
59 | int ReserveCount = 0, InitCount = 0, DeinitCount = 0, ReleaseCount = 0; |
60 | |
61 | private: |
62 | std::unique_ptr<MemoryMapper> Mapper; |
63 | }; |
64 | |
65 | TEST(MapperJITLinkMemoryManagerTest, InProcess) { |
66 | auto Mapper = std::make_unique<CounterMapper>( |
67 | args: cantFail(ValOrErr: InProcessMemoryMapper::Create())); |
68 | |
69 | auto *Counter = static_cast<CounterMapper *>(Mapper.get()); |
70 | |
71 | auto MemMgr = std::make_unique<MapperJITLinkMemoryManager>(args: 16 * 1024 * 1024, |
72 | args: std::move(Mapper)); |
73 | |
74 | EXPECT_EQ(Counter->ReserveCount, 0); |
75 | EXPECT_EQ(Counter->InitCount, 0); |
76 | |
77 | StringRef Hello = "hello" ; |
78 | auto SSA1 = jitlink::SimpleSegmentAlloc::Create( |
79 | MemMgr&: *MemMgr, JD: nullptr, Segments: {{MemProt::Read, {Hello.size(), Align(1)}}}); |
80 | EXPECT_THAT_EXPECTED(SSA1, Succeeded()); |
81 | |
82 | EXPECT_EQ(Counter->ReserveCount, 1); |
83 | EXPECT_EQ(Counter->InitCount, 0); |
84 | |
85 | auto SegInfo1 = SSA1->getSegInfo(AG: MemProt::Read); |
86 | memcpy(dest: SegInfo1.WorkingMem.data(), src: Hello.data(), n: Hello.size()); |
87 | |
88 | auto FA1 = SSA1->finalize(); |
89 | EXPECT_THAT_EXPECTED(FA1, Succeeded()); |
90 | |
91 | EXPECT_EQ(Counter->ReserveCount, 1); |
92 | EXPECT_EQ(Counter->InitCount, 1); |
93 | |
94 | auto SSA2 = jitlink::SimpleSegmentAlloc::Create( |
95 | MemMgr&: *MemMgr, JD: nullptr, Segments: {{MemProt::Read, {Hello.size(), Align(1)}}}); |
96 | EXPECT_THAT_EXPECTED(SSA2, Succeeded()); |
97 | |
98 | // last reservation should be reused |
99 | EXPECT_EQ(Counter->ReserveCount, 1); |
100 | EXPECT_EQ(Counter->InitCount, 1); |
101 | |
102 | auto SegInfo2 = SSA2->getSegInfo(AG: MemProt::Read); |
103 | memcpy(dest: SegInfo2.WorkingMem.data(), src: Hello.data(), n: Hello.size()); |
104 | auto FA2 = SSA2->finalize(); |
105 | EXPECT_THAT_EXPECTED(FA2, Succeeded()); |
106 | |
107 | EXPECT_EQ(Counter->ReserveCount, 1); |
108 | EXPECT_EQ(Counter->InitCount, 2); |
109 | |
110 | ExecutorAddr TargetAddr1(SegInfo1.Addr); |
111 | ExecutorAddr TargetAddr2(SegInfo2.Addr); |
112 | |
113 | const char *TargetMem1 = TargetAddr1.toPtr<const char *>(); |
114 | StringRef TargetHello1(TargetMem1, Hello.size()); |
115 | EXPECT_EQ(Hello, TargetHello1); |
116 | |
117 | const char *TargetMem2 = TargetAddr2.toPtr<const char *>(); |
118 | StringRef TargetHello2(TargetMem2, Hello.size()); |
119 | EXPECT_EQ(Hello, TargetHello2); |
120 | |
121 | EXPECT_EQ(Counter->DeinitCount, 0); |
122 | |
123 | auto Err2 = MemMgr->deallocate(Alloc: std::move(*FA1)); |
124 | EXPECT_THAT_ERROR(std::move(Err2), Succeeded()); |
125 | |
126 | EXPECT_EQ(Counter->DeinitCount, 1); |
127 | |
128 | auto Err3 = MemMgr->deallocate(Alloc: std::move(*FA2)); |
129 | EXPECT_THAT_ERROR(std::move(Err3), Succeeded()); |
130 | |
131 | EXPECT_EQ(Counter->DeinitCount, 2); |
132 | } |
133 | |
134 | TEST(MapperJITLinkMemoryManagerTest, Coalescing) { |
135 | auto Mapper = cantFail(ValOrErr: InProcessMemoryMapper::Create()); |
136 | auto MemMgr = std::make_unique<MapperJITLinkMemoryManager>(args: 16 * 1024 * 1024, |
137 | args: std::move(Mapper)); |
138 | |
139 | auto SSA1 = jitlink::SimpleSegmentAlloc::Create( |
140 | MemMgr&: *MemMgr, JD: nullptr, Segments: {{MemProt::Read, {1024, Align(1)}}}); |
141 | EXPECT_THAT_EXPECTED(SSA1, Succeeded()); |
142 | auto SegInfo1 = SSA1->getSegInfo(AG: MemProt::Read); |
143 | ExecutorAddr TargetAddr1(SegInfo1.Addr); |
144 | auto FA1 = SSA1->finalize(); |
145 | EXPECT_THAT_EXPECTED(FA1, Succeeded()); |
146 | |
147 | auto SSA2 = jitlink::SimpleSegmentAlloc::Create( |
148 | MemMgr&: *MemMgr, JD: nullptr, Segments: {{MemProt::Read, {1024, Align(1)}}}); |
149 | EXPECT_THAT_EXPECTED(SSA2, Succeeded()); |
150 | auto FA2 = SSA2->finalize(); |
151 | EXPECT_THAT_EXPECTED(FA2, Succeeded()); |
152 | |
153 | auto Err2 = MemMgr->deallocate(Alloc: std::move(*FA1)); |
154 | EXPECT_THAT_ERROR(std::move(Err2), Succeeded()); |
155 | |
156 | auto Err3 = MemMgr->deallocate(Alloc: std::move(*FA2)); |
157 | EXPECT_THAT_ERROR(std::move(Err3), Succeeded()); |
158 | |
159 | auto SSA3 = jitlink::SimpleSegmentAlloc::Create( |
160 | MemMgr&: *MemMgr, JD: nullptr, Segments: {{MemProt::Read, {2048, Align(1)}}}); |
161 | EXPECT_THAT_EXPECTED(SSA3, Succeeded()); |
162 | |
163 | auto SegInfo3 = SSA3->getSegInfo(AG: MemProt::Read); |
164 | ExecutorAddr TargetAddr3(SegInfo3.Addr); |
165 | |
166 | auto FA3 = SSA3->finalize(); |
167 | EXPECT_THAT_EXPECTED(FA3, Succeeded()); |
168 | |
169 | // previous two freed 1024 blocks should be fused to form a 2048 block |
170 | EXPECT_EQ(TargetAddr1, TargetAddr3); |
171 | |
172 | auto Err4 = MemMgr->deallocate(Alloc: std::move(*FA3)); |
173 | EXPECT_THAT_ERROR(std::move(Err4), Succeeded()); |
174 | } |
175 | |
176 | } // namespace |
177 | |