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