[Orc] Move some code up into the JITCompileCallbackManager base class. NFC.
[oota-llvm.git] / unittests / ExecutionEngine / Orc / ObjectTransformLayerTest.cpp
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>
35   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
50   MockBaseLayer() : MockSymbol(nullptr) { resetExpectations(); }
51
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";
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>
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   }
76   void verifyAddObjectSet(ObjSetHandleT Returned) {
77     EXPECT_EQ("addObjectSet", LastCalled);
78     EXPECT_EQ(MockObjSetHandle, Returned) << "Return should pass through";
79     resetExpectations();
80   }
81
82   void removeObjectSet(ObjSetHandleT H) {
83     EXPECT_EQ(MockObjSetHandle, H);
84     LastCalled = "removeObjectSet";
85   }
86   void expectRemoveObjectSet(ObjSetHandleT H) { MockObjSetHandle = H; }
87   void verifyRemoveObjectSet() {
88     EXPECT_EQ("removeObjectSet", LastCalled);
89     resetExpectations();
90   }
91
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   }
99   void expectFindSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
100     MockName = Name;
101     MockBool = ExportedSymbolsOnly;
102   }
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
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   }
119   void expectFindSymbolIn(ObjSetHandleT H, const std::string &Name,
120                           bool ExportedSymbolsOnly) {
121     MockObjSetHandle = H;
122     MockName = Name;
123     MockBool = ExportedSymbolsOnly;
124   }
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
132   void emitAndFinalize(ObjSetHandleT H) {
133     EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
134     LastCalled = "emitAndFinalize";
135   }
136   void expectEmitAndFinalize(ObjSetHandleT H) { MockObjSetHandle = H; }
137   void verifyEmitAndFinalize() {
138     EXPECT_EQ("emitAndFinalize", LastCalled);
139     resetExpectations();
140   }
141
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   }
149   void expectMapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
150                                TargetAddress TargetAddr) {
151     MockObjSetHandle = H;
152     MockLocalAddress = LocalAddress;
153     MockTargetAddress = TargetAddr;
154   }
155   void verifyMapSectionAddress() {
156     EXPECT_EQ("mapSectionAddress", LastCalled);
157     resetExpectations();
158   }
159
160   template <typename OwningMBSet>
161   void takeOwnershipOfBuffers(ObjSetHandleT H, OwningMBSet MBs) {
162     EXPECT_EQ(MockObjSetHandle, H);
163     EXPECT_EQ(MockBufferSet, *MBs);
164     LastCalled = "takeOwnershipOfBuffers";
165   }
166   void expectTakeOwnershipOfBuffers(ObjSetHandleT H, MockMemoryBufferSet *MBs) {
167     MockObjSetHandle = H;
168     MockBufferSet = *MBs;
169   }
170   void verifyTakeOwnershipOfBuffers() {
171     EXPECT_EQ("takeOwnershipOfBuffers", LastCalled);
172     resetExpectations();
173   }
174
175 private:
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;
183   bool MockBool;
184   JITSymbol MockSymbol;
185   const void *MockLocalAddress;
186   TargetAddress MockTargetAddress;
187   MockMemoryBufferSet MockBufferSet;
188
189   // Clear remembered parameters between calls
190   void resetExpectations() {
191     LastCalled = "nothing";
192     MockManager = 0;
193     MockResolver = 0;
194     MockObjects.clear();
195     MockObjSetHandle = 0;
196     MockName = "bogus";
197     MockSymbol = JITSymbol(nullptr);
198     MockLocalAddress = nullptr;
199     MockTargetAddress = 0;
200     MockBufferSet = 0;
201   }
202 };
203
204 // Test each operation on ObjectTransformLayer.
205 TEST(ObjectTransformLayerTest, Main) {
206   MockBaseLayer M;
207
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);
211
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) {
217     ++(*Obj);
218     return Obj;
219   });
220
221   // Instantiate some mock objects to use below
222   MockObjectFile MockObject1 = 211;
223   MockObjectFile MockObject2 = 222;
224   MockMemoryManager MockManager = 233;
225   MockSymbolResolver MockResolver = 244;
226
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);
236
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";
246
247   // Test removeObjectSet
248   M.expectRemoveObjectSet(H);
249   T1.removeObjectSet(H);
250   M.verifyRemoveObjectSet();
251
252   // Test findSymbol
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);
258
259   // Test findSymbolIn
260   Name = "bar";
261   ExportedOnly = false;
262   M.expectFindSymbolIn(H, Name, ExportedOnly);
263   Symbol = T1.findSymbolIn(H, Name, ExportedOnly);
264   M.verifyFindSymbolIn(Symbol);
265
266   // Test emitAndFinalize
267   M.expectEmitAndFinalize(H);
268   T2.emitAndFinalize(H);
269   M.verifyEmitAndFinalize();
270
271   // Test mapSectionAddress
272   char Buffer[24];
273   TargetAddress MockAddress = 255;
274   M.expectMapSectionAddress(H, Buffer, MockAddress);
275   T1.mapSectionAddress(H, Buffer, MockAddress);
276   M.verifyMapSectionAddress();
277
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();
283
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();
289
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";
295
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";
301 }
302 }