1 //===- ObjectTransformLayerTest.cpp - Unit tests for ObjectTransformLayer -===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/ADT/SmallVector.h"
13 #include "gtest/gtest.h"
15 using namespace llvm::orc;
19 // Stand-in for RuntimeDyld::MemoryManager
20 typedef int MockMemoryManager;
22 // Stand-in for RuntimeDyld::SymbolResolver
23 typedef int MockSymbolResolver;
25 // stand-in for object::ObjectFile
26 typedef int MockObjectFile;
28 // stand-in for llvm::MemoryBuffer set
29 typedef int MockMemoryBufferSet;
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>
35 operator()(std::unique_ptr<MockObjectFile> Obj) const {
36 return llvm::make_unique<MockObjectFile>(*Obj + 1);
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.
48 typedef int ObjSetHandleT;
50 MockBaseLayer() : MockSymbol(nullptr) { resetExpectations(); }
52 template <typename ObjSetT, typename MemoryManagerPtrT,
53 typename SymbolResolverPtrT>
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";
59 for (auto &ObjPtr : Objects) {
60 EXPECT_EQ(MockObjects[I++] + 1, *ObjPtr) << "Transform should be applied";
62 EXPECT_EQ(MockObjects.size(), I) << "Number of objects should match";
63 LastCalled = "addObjectSet";
64 MockObjSetHandle = 111;
65 return MockObjSetHandle;
67 template <typename ObjSetT>
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);
76 void verifyAddObjectSet(ObjSetHandleT Returned) {
77 EXPECT_EQ("addObjectSet", LastCalled);
78 EXPECT_EQ(MockObjSetHandle, Returned) << "Return should pass through";
82 void removeObjectSet(ObjSetHandleT H) {
83 EXPECT_EQ(MockObjSetHandle, H);
84 LastCalled = "removeObjectSet";
86 void expectRemoveObjectSet(ObjSetHandleT H) { MockObjSetHandle = H; }
87 void verifyRemoveObjectSet() {
88 EXPECT_EQ("removeObjectSet", LastCalled);
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);
99 void expectFindSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
101 MockBool = ExportedSymbolsOnly;
103 void verifyFindSymbol(llvm::orc::JITSymbol Returned) {
104 EXPECT_EQ("findSymbol", LastCalled);
105 EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
106 << "Return should pass through";
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);
119 void expectFindSymbolIn(ObjSetHandleT H, const std::string &Name,
120 bool ExportedSymbolsOnly) {
121 MockObjSetHandle = H;
123 MockBool = ExportedSymbolsOnly;
125 void verifyFindSymbolIn(llvm::orc::JITSymbol Returned) {
126 EXPECT_EQ("findSymbolIn", LastCalled);
127 EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
128 << "Return should pass through";
132 void emitAndFinalize(ObjSetHandleT H) {
133 EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
134 LastCalled = "emitAndFinalize";
136 void expectEmitAndFinalize(ObjSetHandleT H) { MockObjSetHandle = H; }
137 void verifyEmitAndFinalize() {
138 EXPECT_EQ("emitAndFinalize", LastCalled);
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";
149 void expectMapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
150 TargetAddress TargetAddr) {
151 MockObjSetHandle = H;
152 MockLocalAddress = LocalAddress;
153 MockTargetAddress = TargetAddr;
155 void verifyMapSectionAddress() {
156 EXPECT_EQ("mapSectionAddress", LastCalled);
160 template <typename OwningMBSet>
161 void takeOwnershipOfBuffers(ObjSetHandleT H, OwningMBSet MBs) {
162 EXPECT_EQ(MockObjSetHandle, H);
163 EXPECT_EQ(MockBufferSet, *MBs);
164 LastCalled = "takeOwnershipOfBuffers";
166 void expectTakeOwnershipOfBuffers(ObjSetHandleT H, MockMemoryBufferSet *MBs) {
167 MockObjSetHandle = H;
168 MockBufferSet = *MBs;
170 void verifyTakeOwnershipOfBuffers() {
171 EXPECT_EQ("takeOwnershipOfBuffers", LastCalled);
176 // Backing fields for remembering parameter/return values
177 std::string LastCalled;
178 MockMemoryManager MockManager;
179 MockSymbolResolver MockResolver;
180 std::vector<MockObjectFile> MockObjects;
181 ObjSetHandleT MockObjSetHandle;
182 std::string MockName;
184 JITSymbol MockSymbol;
185 const void *MockLocalAddress;
186 TargetAddress MockTargetAddress;
187 MockMemoryBufferSet MockBufferSet;
189 // Clear remembered parameters between calls
190 void resetExpectations() {
191 LastCalled = "nothing";
195 MockObjSetHandle = 0;
197 MockSymbol = JITSymbol(nullptr);
198 MockLocalAddress = nullptr;
199 MockTargetAddress = 0;
204 // Test each operation on ObjectTransformLayer.
205 TEST(ObjectTransformLayerTest, Main) {
208 // Create one object transform layer using a transform (as a functor)
209 // that allocates new objects, and deals in unique pointers.
210 ObjectTransformLayer<MockBaseLayer, AllocatingTransform> T1(M);
212 // Create a second object transform layer using a transform (as a lambda)
213 // that mutates objects in place, and deals in naked pointers
214 ObjectTransformLayer<MockBaseLayer,
215 std::function<MockObjectFile *(MockObjectFile *)>>
216 T2(M, [](MockObjectFile *Obj) {
221 // Instantiate some mock objects to use below
222 MockObjectFile MockObject1 = 211;
223 MockObjectFile MockObject2 = 222;
224 MockMemoryManager MockManager = 233;
225 MockSymbolResolver MockResolver = 244;
227 // Test addObjectSet with T1 (allocating, unique pointers)
228 std::vector<std::unique_ptr<MockObjectFile>> Objs1;
229 Objs1.push_back(llvm::make_unique<MockObjectFile>(MockObject1));
230 Objs1.push_back(llvm::make_unique<MockObjectFile>(MockObject2));
231 auto MM = llvm::make_unique<MockMemoryManager>(MockManager);
232 auto SR = llvm::make_unique<MockSymbolResolver>(MockResolver);
233 M.expectAddObjectSet(Objs1, MM.get(), SR.get());
234 auto H = T1.addObjectSet(Objs1, std::move(MM), std::move(SR));
235 M.verifyAddObjectSet(H);
237 // Test addObjectSet with T2 (mutating, naked pointers)
238 llvm::SmallVector<MockObjectFile *, 2> Objs2;
239 Objs2.push_back(&MockObject1);
240 Objs2.push_back(&MockObject2);
241 M.expectAddObjectSet(Objs2, &MockManager, &MockResolver);
242 H = T2.addObjectSet(Objs2, &MockManager, &MockResolver);
243 M.verifyAddObjectSet(H);
244 EXPECT_EQ(212, MockObject1) << "Expected mutation";
245 EXPECT_EQ(223, MockObject2) << "Expected mutation";
247 // Test removeObjectSet
248 M.expectRemoveObjectSet(H);
249 T1.removeObjectSet(H);
250 M.verifyRemoveObjectSet();
253 std::string Name = "foo";
254 bool ExportedOnly = true;
255 M.expectFindSymbol(Name, ExportedOnly);
256 JITSymbol Symbol = T2.findSymbol(Name, ExportedOnly);
257 M.verifyFindSymbol(Symbol);
261 ExportedOnly = false;
262 M.expectFindSymbolIn(H, Name, ExportedOnly);
263 Symbol = T1.findSymbolIn(H, Name, ExportedOnly);
264 M.verifyFindSymbolIn(Symbol);
266 // Test emitAndFinalize
267 M.expectEmitAndFinalize(H);
268 T2.emitAndFinalize(H);
269 M.verifyEmitAndFinalize();
271 // Test mapSectionAddress
273 TargetAddress MockAddress = 255;
274 M.expectMapSectionAddress(H, Buffer, MockAddress);
275 T1.mapSectionAddress(H, Buffer, MockAddress);
276 M.verifyMapSectionAddress();
278 // Test takeOwnershipOfBuffers, using unique pointer to buffer set
279 auto MockBufferSetPtr = llvm::make_unique<MockMemoryBufferSet>(366);
280 M.expectTakeOwnershipOfBuffers(H, MockBufferSetPtr.get());
281 T2.takeOwnershipOfBuffers(H, std::move(MockBufferSetPtr));
282 M.verifyTakeOwnershipOfBuffers();
284 // Test takeOwnershipOfBuffers, using naked pointer to buffer set
285 MockMemoryBufferSet MockBufferSet = 266;
286 M.expectTakeOwnershipOfBuffers(H, &MockBufferSet);
287 T1.takeOwnershipOfBuffers(H, &MockBufferSet);
288 M.verifyTakeOwnershipOfBuffers();
290 // Verify transform getter (non-const)
291 MockObjectFile Mutatee = 277;
292 MockObjectFile *Out = T2.getTransform()(&Mutatee);
293 EXPECT_EQ(&Mutatee, Out) << "Expected in-place transform";
294 EXPECT_EQ(278, Mutatee) << "Expected incrementing transform";
296 // Verify transform getter (const)
297 auto OwnedObj = llvm::make_unique<MockObjectFile>(288);
298 const auto &T1C = T1;
299 OwnedObj = T1C.getTransform()(std::move(OwnedObj));
300 EXPECT_EQ(289, *OwnedObj) << "Expected incrementing transform";