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