blob: 772ed5e706d47711eff45a08cada3ba388a8840e [file] [log] [blame]
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +00001//===- ObjectTransformLayerTest.cpp - Unit tests for ObjectTransformLayer -===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
11#include "llvm/ADT/SmallVector.h"
12#include "gtest/gtest.h"
13
14using namespace llvm::orc;
15
16namespace {
17
18// Stand-in for RuntimeDyld::MemoryManager
19typedef int MockMemoryManager;
20
21// Stand-in for RuntimeDyld::SymbolResolver
22typedef int MockSymbolResolver;
23
24// stand-in for object::ObjectFile
25typedef int MockObjectFile;
26
27// stand-in for llvm::MemoryBuffer set
28typedef int MockMemoryBufferSet;
29
30// Mock transform that operates on unique pointers to object files, and
31// allocates new object files rather than mutating the given ones.
32struct AllocatingTransform {
33 std::unique_ptr<MockObjectFile>
34 operator()(std::unique_ptr<MockObjectFile> Obj) const {
35 return std::make_unique<MockObjectFile>(*Obj + 1);
36 }
37};
38
39// Mock base layer for verifying behavior of transform layer.
40// Each method "T foo(args)" is accompanied by two auxiliary methods:
41// - "void expectFoo(args)", to be called before calling foo on the transform
42// layer; saves values of args, which mock layer foo then verifies against.
43// - "void verifyFoo(T)", to be called after foo, which verifies that the
44// transform layer called the base layer and forwarded any return value.
45class MockBaseLayer {
46public:
47 typedef int ObjSetHandleT;
48
49 MockBaseLayer() : MockSymbol(nullptr) { resetExpectations(); }
50
51 template <typename ObjSetT, typename MemoryManagerPtrT,
52 typename SymbolResolverPtrT>
53 ObjSetHandleT addObjectSet(ObjSetT &Objects, MemoryManagerPtrT MemMgr,
54 SymbolResolverPtrT Resolver) {
55 EXPECT_EQ(MockManager, *MemMgr) << "MM should pass through";
56 EXPECT_EQ(MockResolver, *Resolver) << "Resolver should pass through";
57 int I = 0;
58 for (auto &ObjPtr : Objects) {
59 EXPECT_EQ(MockObjects[I++] + 1, *ObjPtr) << "Transform should be applied";
60 }
61 EXPECT_EQ(MockObjects.size(), I) << "Number of objects should match";
62 LastCalled = "addObjectSet";
63 MockObjSetHandle = 111;
64 return MockObjSetHandle;
65 }
66 template <typename ObjSetT>
67 void expectAddObjectSet(ObjSetT &Objects, MockMemoryManager *MemMgr,
68 MockSymbolResolver *Resolver) {
69 MockManager = *MemMgr;
70 MockResolver = *Resolver;
71 for (auto &ObjPtr : Objects) {
72 MockObjects.push_back(*ObjPtr);
73 }
74 }
75 void verifyAddObjectSet(ObjSetHandleT Returned) {
76 EXPECT_EQ("addObjectSet", LastCalled);
77 EXPECT_EQ(MockObjSetHandle, Returned) << "Return should pass through";
78 resetExpectations();
79 }
80
81 void removeObjectSet(ObjSetHandleT H) {
82 EXPECT_EQ(MockObjSetHandle, H);
83 LastCalled = "removeObjectSet";
84 }
85 void expectRemoveObjectSet(ObjSetHandleT H) { MockObjSetHandle = H; }
86 void verifyRemoveObjectSet() {
87 EXPECT_EQ("removeObjectSet", LastCalled);
88 resetExpectations();
89 }
90
91 JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
92 EXPECT_EQ(MockName, Name) << "Name should pass through";
93 EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
94 LastCalled = "findSymbol";
95 MockSymbol = JITSymbol(122, llvm::JITSymbolFlags::None);
96 return MockSymbol;
97 }
98 void expectFindSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
99 MockName = Name;
100 MockBool = ExportedSymbolsOnly;
101 }
102 void verifyFindSymbol(llvm::orc::JITSymbol Returned) {
103 EXPECT_EQ("findSymbol", LastCalled);
104 EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
105 << "Return should pass through";
106 resetExpectations();
107 }
108
109 JITSymbol findSymbolIn(ObjSetHandleT H, const std::string &Name,
110 bool ExportedSymbolsOnly) {
111 EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
112 EXPECT_EQ(MockName, Name) << "Name should pass through";
113 EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
114 LastCalled = "findSymbolIn";
115 MockSymbol = JITSymbol(122, llvm::JITSymbolFlags::None);
116 return MockSymbol;
117 }
118 void expectFindSymbolIn(ObjSetHandleT H, const std::string &Name,
119 bool ExportedSymbolsOnly) {
120 MockObjSetHandle = H;
121 MockName = Name;
122 MockBool = ExportedSymbolsOnly;
123 }
124 void verifyFindSymbolIn(llvm::orc::JITSymbol Returned) {
125 EXPECT_EQ("findSymbolIn", LastCalled);
126 EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
127 << "Return should pass through";
128 resetExpectations();
129 }
130
131 void emitAndFinalize(ObjSetHandleT H) {
132 EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
133 LastCalled = "emitAndFinalize";
134 }
135 void expectEmitAndFinalize(ObjSetHandleT H) { MockObjSetHandle = H; }
136 void verifyEmitAndFinalize() {
137 EXPECT_EQ("emitAndFinalize", LastCalled);
138 resetExpectations();
139 }
140
141 void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
142 TargetAddress TargetAddr) {
143 EXPECT_EQ(MockObjSetHandle, H);
144 EXPECT_EQ(MockLocalAddress, LocalAddress);
145 EXPECT_EQ(MockTargetAddress, TargetAddr);
146 LastCalled = "mapSectionAddress";
147 }
148 void expectMapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
149 TargetAddress TargetAddr) {
150 MockObjSetHandle = H;
151 MockLocalAddress = LocalAddress;
152 MockTargetAddress = TargetAddr;
153 }
154 void verifyMapSectionAddress() {
155 EXPECT_EQ("mapSectionAddress", LastCalled);
156 resetExpectations();
157 }
158
159 template <typename OwningMBSet>
160 void takeOwnershipOfBuffers(ObjSetHandleT H, OwningMBSet MBs) {
161 EXPECT_EQ(MockObjSetHandle, H);
162 EXPECT_EQ(MockBufferSet, *MBs);
163 LastCalled = "takeOwnershipOfBuffers";
164 }
165 void expectTakeOwnershipOfBuffers(ObjSetHandleT H, MockMemoryBufferSet *MBs) {
166 MockObjSetHandle = H;
167 MockBufferSet = *MBs;
168 }
169 void verifyTakeOwnershipOfBuffers() {
170 EXPECT_EQ("takeOwnershipOfBuffers", LastCalled);
171 resetExpectations();
172 }
173
174private:
175 // Backing fields for remembering parameter/return values
176 std::string LastCalled;
177 MockMemoryManager MockManager;
178 MockSymbolResolver MockResolver;
179 std::vector<MockObjectFile> MockObjects;
180 ObjSetHandleT MockObjSetHandle;
181 std::string MockName;
182 bool MockBool;
183 JITSymbol MockSymbol;
184 const void *MockLocalAddress;
185 TargetAddress MockTargetAddress;
186 MockMemoryBufferSet MockBufferSet;
187
188 // Clear remembered parameters between calls
189 void resetExpectations() {
190 LastCalled = "nothing";
191 MockManager = 0;
192 MockResolver = 0;
193 MockObjects.clear();
194 MockObjSetHandle = 0;
195 MockName = "bogus";
196 MockSymbol = JITSymbol(nullptr);
197 MockLocalAddress = nullptr;
198 MockTargetAddress = 0;
199 MockBufferSet = 0;
200 }
201};
202
203// Test each operation on ObjectTransformLayer.
204TEST(ObjectTransformLayerTest, Main) {
205 MockBaseLayer M;
206
207 // Create one object transform layer using a transform (as a functor)
208 // that allocates new objects, and deals in unique pointers.
209 ObjectTransformLayer<MockBaseLayer, AllocatingTransform> T1(M);
210
211 // Create a second object transform layer using a transform (as a lambda)
212 // that mutates objects in place, and deals in naked pointers
213 ObjectTransformLayer<MockBaseLayer,
214 std::function<MockObjectFile *(MockObjectFile *)>>
215 T2(M, [](MockObjectFile *Obj) {
216 ++(*Obj);
217 return Obj;
218 });
219
220 // Instantiate some mock objects to use below
221 MockObjectFile MockObject1 = 211;
222 MockObjectFile MockObject2 = 222;
223 MockMemoryManager MockManager = 233;
224 MockSymbolResolver MockResolver = 244;
225
226 // Test addObjectSet with T1 (allocating, unique pointers)
227 std::vector<std::unique_ptr<MockObjectFile>> Objs1;
228 Objs1.push_back(std::make_unique<MockObjectFile>(MockObject1));
229 Objs1.push_back(std::make_unique<MockObjectFile>(MockObject2));
230 auto MM = std::make_unique<MockMemoryManager>(MockManager);
231 auto SR = std::make_unique<MockSymbolResolver>(MockResolver);
232 M.expectAddObjectSet(Objs1, MM.get(), SR.get());
233 auto H = T1.addObjectSet(Objs1, std::move(MM), std::move(SR));
234 M.verifyAddObjectSet(H);
235
236 // Test addObjectSet with T2 (mutating, naked pointers)
237 llvm::SmallVector<MockObjectFile *, 2> Objs2;
238 Objs2.push_back(&MockObject1);
239 Objs2.push_back(&MockObject2);
240 M.expectAddObjectSet(Objs2, &MockManager, &MockResolver);
241 H = T2.addObjectSet(Objs2, &MockManager, &MockResolver);
242 M.verifyAddObjectSet(H);
243 EXPECT_EQ(212, MockObject1) << "Expected mutation";
244 EXPECT_EQ(223, MockObject2) << "Expected mutation";
245
246 // Test removeObjectSet
247 M.expectRemoveObjectSet(H);
248 T1.removeObjectSet(H);
249 M.verifyRemoveObjectSet();
250
251 // Test findSymbol
252 std::string Name = "foo";
253 bool ExportedOnly = true;
254 M.expectFindSymbol(Name, ExportedOnly);
255 JITSymbol Symbol = T2.findSymbol(Name, ExportedOnly);
256 M.verifyFindSymbol(Symbol);
257
258 // Test findSymbolIn
259 Name = "bar";
260 ExportedOnly = false;
261 M.expectFindSymbolIn(H, Name, ExportedOnly);
262 Symbol = T1.findSymbolIn(H, Name, ExportedOnly);
263 M.verifyFindSymbolIn(Symbol);
264
265 // Test emitAndFinalize
266 M.expectEmitAndFinalize(H);
267 T2.emitAndFinalize(H);
268 M.verifyEmitAndFinalize();
269
270 // Test mapSectionAddress
271 char Buffer[24];
272 TargetAddress MockAddress = 255;
273 M.expectMapSectionAddress(H, Buffer, MockAddress);
274 T1.mapSectionAddress(H, Buffer, MockAddress);
275 M.verifyMapSectionAddress();
276
277 // Test takeOwnershipOfBuffers, using unique pointer to buffer set
278 auto MockBufferSetPtr = std::make_unique<MockMemoryBufferSet>(366);
279 M.expectTakeOwnershipOfBuffers(H, MockBufferSetPtr.get());
280 T2.takeOwnershipOfBuffers(H, std::move(MockBufferSetPtr));
281 M.verifyTakeOwnershipOfBuffers();
282
283 // Test takeOwnershipOfBuffers, using naked pointer to buffer set
284 MockMemoryBufferSet MockBufferSet = 266;
285 M.expectTakeOwnershipOfBuffers(H, &MockBufferSet);
286 T1.takeOwnershipOfBuffers(H, &MockBufferSet);
287 M.verifyTakeOwnershipOfBuffers();
288
289 // Verify transform getter (non-const)
290 MockObjectFile Mutatee = 277;
291 MockObjectFile *Out = T2.getTransform()(&Mutatee);
292 EXPECT_EQ(&Mutatee, Out) << "Expected in-place transform";
293 EXPECT_EQ(278, Mutatee) << "Expected incrementing transform";
294
295 // Verify transform getter (const)
296 auto OwnedObj = std::make_unique<MockObjectFile>(288);
297 const auto &T1C = T1;
298 OwnedObj = T1C.getTransform()(std::move(OwnedObj));
299 EXPECT_EQ(289, *OwnedObj) << "Expected incrementing transform";
300}
301}