• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ADT/STLExtras.h"
11 #include "llvm/ADT/SmallVector.h"
12 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
13 #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
14 #include "llvm/ExecutionEngine/Orc/NullResolver.h"
15 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
16 #include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
17 #include "llvm/Object/ObjectFile.h"
18 #include "gtest/gtest.h"
19 
20 using namespace llvm::orc;
21 
22 namespace {
23 
24 // Stand-in for RuntimeDyld::MemoryManager
25 typedef int MockMemoryManager;
26 
27 // Stand-in for RuntimeDyld::SymbolResolver
28 typedef int MockSymbolResolver;
29 
30 // stand-in for object::ObjectFile
31 typedef int MockObjectFile;
32 
33 // stand-in for llvm::MemoryBuffer set
34 typedef int MockMemoryBufferSet;
35 
36 // Mock transform that operates on unique pointers to object files, and
37 // allocates new object files rather than mutating the given ones.
38 struct AllocatingTransform {
39   std::unique_ptr<MockObjectFile>
operator ()__anon500fff290111::AllocatingTransform40   operator()(std::unique_ptr<MockObjectFile> Obj) const {
41     return llvm::make_unique<MockObjectFile>(*Obj + 1);
42   }
43 };
44 
45 // Mock base layer for verifying behavior of transform layer.
46 // Each method "T foo(args)" is accompanied by two auxiliary methods:
47 //  - "void expectFoo(args)", to be called before calling foo on the transform
48 //      layer; saves values of args, which mock layer foo then verifies against.
49 // - "void verifyFoo(T)", to be called after foo, which verifies that the
50 //      transform layer called the base layer and forwarded any return value.
51 class MockBaseLayer {
52 public:
53   typedef int ObjSetHandleT;
54 
MockBaseLayer()55   MockBaseLayer() : MockSymbol(nullptr) { resetExpectations(); }
56 
57   template <typename ObjSetT, typename MemoryManagerPtrT,
58             typename SymbolResolverPtrT>
addObjectSet(ObjSetT Objects,MemoryManagerPtrT MemMgr,SymbolResolverPtrT Resolver)59   ObjSetHandleT addObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr,
60                              SymbolResolverPtrT Resolver) {
61     EXPECT_EQ(MockManager, *MemMgr) << "MM should pass through";
62     EXPECT_EQ(MockResolver, *Resolver) << "Resolver should pass through";
63     size_t I = 0;
64     for (auto &ObjPtr : Objects) {
65       EXPECT_EQ(MockObjects[I] + 1, *ObjPtr) << "Transform should be applied";
66       I++;
67     }
68     EXPECT_EQ(MockObjects.size(), I) << "Number of objects should match";
69     LastCalled = "addObjectSet";
70     MockObjSetHandle = 111;
71     return MockObjSetHandle;
72   }
73   template <typename ObjSetT>
expectAddObjectSet(ObjSetT & Objects,MockMemoryManager * MemMgr,MockSymbolResolver * Resolver)74   void expectAddObjectSet(ObjSetT &Objects, MockMemoryManager *MemMgr,
75                           MockSymbolResolver *Resolver) {
76     MockManager = *MemMgr;
77     MockResolver = *Resolver;
78     for (auto &ObjPtr : Objects) {
79       MockObjects.push_back(*ObjPtr);
80     }
81   }
verifyAddObjectSet(ObjSetHandleT Returned)82   void verifyAddObjectSet(ObjSetHandleT Returned) {
83     EXPECT_EQ("addObjectSet", LastCalled);
84     EXPECT_EQ(MockObjSetHandle, Returned) << "Return should pass through";
85     resetExpectations();
86   }
87 
removeObjectSet(ObjSetHandleT H)88   void removeObjectSet(ObjSetHandleT H) {
89     EXPECT_EQ(MockObjSetHandle, H);
90     LastCalled = "removeObjectSet";
91   }
expectRemoveObjectSet(ObjSetHandleT H)92   void expectRemoveObjectSet(ObjSetHandleT H) { MockObjSetHandle = H; }
verifyRemoveObjectSet()93   void verifyRemoveObjectSet() {
94     EXPECT_EQ("removeObjectSet", LastCalled);
95     resetExpectations();
96   }
97 
findSymbol(const std::string & Name,bool ExportedSymbolsOnly)98   JITSymbol findSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
99     EXPECT_EQ(MockName, Name) << "Name should pass through";
100     EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
101     LastCalled = "findSymbol";
102     MockSymbol = JITSymbol(122, llvm::JITSymbolFlags::None);
103     return MockSymbol;
104   }
expectFindSymbol(const std::string & Name,bool ExportedSymbolsOnly)105   void expectFindSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
106     MockName = Name;
107     MockBool = ExportedSymbolsOnly;
108   }
verifyFindSymbol(llvm::orc::JITSymbol Returned)109   void verifyFindSymbol(llvm::orc::JITSymbol Returned) {
110     EXPECT_EQ("findSymbol", LastCalled);
111     EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
112         << "Return should pass through";
113     resetExpectations();
114   }
115 
findSymbolIn(ObjSetHandleT H,const std::string & Name,bool ExportedSymbolsOnly)116   JITSymbol findSymbolIn(ObjSetHandleT H, const std::string &Name,
117                          bool ExportedSymbolsOnly) {
118     EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
119     EXPECT_EQ(MockName, Name) << "Name should pass through";
120     EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
121     LastCalled = "findSymbolIn";
122     MockSymbol = JITSymbol(122, llvm::JITSymbolFlags::None);
123     return MockSymbol;
124   }
expectFindSymbolIn(ObjSetHandleT H,const std::string & Name,bool ExportedSymbolsOnly)125   void expectFindSymbolIn(ObjSetHandleT H, const std::string &Name,
126                           bool ExportedSymbolsOnly) {
127     MockObjSetHandle = H;
128     MockName = Name;
129     MockBool = ExportedSymbolsOnly;
130   }
verifyFindSymbolIn(llvm::orc::JITSymbol Returned)131   void verifyFindSymbolIn(llvm::orc::JITSymbol Returned) {
132     EXPECT_EQ("findSymbolIn", LastCalled);
133     EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
134         << "Return should pass through";
135     resetExpectations();
136   }
137 
emitAndFinalize(ObjSetHandleT H)138   void emitAndFinalize(ObjSetHandleT H) {
139     EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
140     LastCalled = "emitAndFinalize";
141   }
expectEmitAndFinalize(ObjSetHandleT H)142   void expectEmitAndFinalize(ObjSetHandleT H) { MockObjSetHandle = H; }
verifyEmitAndFinalize()143   void verifyEmitAndFinalize() {
144     EXPECT_EQ("emitAndFinalize", LastCalled);
145     resetExpectations();
146   }
147 
mapSectionAddress(ObjSetHandleT H,const void * LocalAddress,TargetAddress TargetAddr)148   void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
149                          TargetAddress TargetAddr) {
150     EXPECT_EQ(MockObjSetHandle, H);
151     EXPECT_EQ(MockLocalAddress, LocalAddress);
152     EXPECT_EQ(MockTargetAddress, TargetAddr);
153     LastCalled = "mapSectionAddress";
154   }
expectMapSectionAddress(ObjSetHandleT H,const void * LocalAddress,TargetAddress TargetAddr)155   void expectMapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
156                                TargetAddress TargetAddr) {
157     MockObjSetHandle = H;
158     MockLocalAddress = LocalAddress;
159     MockTargetAddress = TargetAddr;
160   }
verifyMapSectionAddress()161   void verifyMapSectionAddress() {
162     EXPECT_EQ("mapSectionAddress", LastCalled);
163     resetExpectations();
164   }
165 
166 private:
167   // Backing fields for remembering parameter/return values
168   std::string LastCalled;
169   MockMemoryManager MockManager;
170   MockSymbolResolver MockResolver;
171   std::vector<MockObjectFile> MockObjects;
172   ObjSetHandleT MockObjSetHandle;
173   std::string MockName;
174   bool MockBool;
175   JITSymbol MockSymbol;
176   const void *MockLocalAddress;
177   TargetAddress MockTargetAddress;
178   MockMemoryBufferSet MockBufferSet;
179 
180   // Clear remembered parameters between calls
resetExpectations()181   void resetExpectations() {
182     LastCalled = "nothing";
183     MockManager = 0;
184     MockResolver = 0;
185     MockObjects.clear();
186     MockObjSetHandle = 0;
187     MockName = "bogus";
188     MockSymbol = JITSymbol(nullptr);
189     MockLocalAddress = nullptr;
190     MockTargetAddress = 0;
191     MockBufferSet = 0;
192   }
193 };
194 
195 // Test each operation on ObjectTransformLayer.
TEST(ObjectTransformLayerTest,Main)196 TEST(ObjectTransformLayerTest, Main) {
197   MockBaseLayer M;
198 
199   // Create one object transform layer using a transform (as a functor)
200   // that allocates new objects, and deals in unique pointers.
201   ObjectTransformLayer<MockBaseLayer, AllocatingTransform> T1(M);
202 
203   // Create a second object transform layer using a transform (as a lambda)
204   // that mutates objects in place, and deals in naked pointers
205   ObjectTransformLayer<MockBaseLayer,
206                        std::function<MockObjectFile *(MockObjectFile *)>>
207   T2(M, [](MockObjectFile *Obj) {
208     ++(*Obj);
209     return Obj;
210   });
211 
212   // Instantiate some mock objects to use below
213   MockObjectFile MockObject1 = 211;
214   MockObjectFile MockObject2 = 222;
215   MockMemoryManager MockManager = 233;
216   MockSymbolResolver MockResolver = 244;
217 
218   // Test addObjectSet with T1 (allocating, unique pointers)
219   std::vector<std::unique_ptr<MockObjectFile>> Objs1;
220   Objs1.push_back(llvm::make_unique<MockObjectFile>(MockObject1));
221   Objs1.push_back(llvm::make_unique<MockObjectFile>(MockObject2));
222   auto MM = llvm::make_unique<MockMemoryManager>(MockManager);
223   auto SR = llvm::make_unique<MockSymbolResolver>(MockResolver);
224   M.expectAddObjectSet(Objs1, MM.get(), SR.get());
225   auto H = T1.addObjectSet(std::move(Objs1), std::move(MM), std::move(SR));
226   M.verifyAddObjectSet(H);
227 
228   // Test addObjectSet with T2 (mutating, naked pointers)
229   llvm::SmallVector<MockObjectFile *, 2> Objs2Vec;
230   Objs2Vec.push_back(&MockObject1);
231   Objs2Vec.push_back(&MockObject2);
232   llvm::MutableArrayRef<MockObjectFile *> Objs2(Objs2Vec);
233   M.expectAddObjectSet(Objs2, &MockManager, &MockResolver);
234   H = T2.addObjectSet(Objs2, &MockManager, &MockResolver);
235   M.verifyAddObjectSet(H);
236   EXPECT_EQ(212, MockObject1) << "Expected mutation";
237   EXPECT_EQ(223, MockObject2) << "Expected mutation";
238 
239   // Test removeObjectSet
240   M.expectRemoveObjectSet(H);
241   T1.removeObjectSet(H);
242   M.verifyRemoveObjectSet();
243 
244   // Test findSymbol
245   std::string Name = "foo";
246   bool ExportedOnly = true;
247   M.expectFindSymbol(Name, ExportedOnly);
248   JITSymbol Symbol = T2.findSymbol(Name, ExportedOnly);
249   M.verifyFindSymbol(Symbol);
250 
251   // Test findSymbolIn
252   Name = "bar";
253   ExportedOnly = false;
254   M.expectFindSymbolIn(H, Name, ExportedOnly);
255   Symbol = T1.findSymbolIn(H, Name, ExportedOnly);
256   M.verifyFindSymbolIn(Symbol);
257 
258   // Test emitAndFinalize
259   M.expectEmitAndFinalize(H);
260   T2.emitAndFinalize(H);
261   M.verifyEmitAndFinalize();
262 
263   // Test mapSectionAddress
264   char Buffer[24];
265   TargetAddress MockAddress = 255;
266   M.expectMapSectionAddress(H, Buffer, MockAddress);
267   T1.mapSectionAddress(H, Buffer, MockAddress);
268   M.verifyMapSectionAddress();
269 
270   // Verify transform getter (non-const)
271   MockObjectFile Mutatee = 277;
272   MockObjectFile *Out = T2.getTransform()(&Mutatee);
273   EXPECT_EQ(&Mutatee, Out) << "Expected in-place transform";
274   EXPECT_EQ(278, Mutatee) << "Expected incrementing transform";
275 
276   // Verify transform getter (const)
277   auto OwnedObj = llvm::make_unique<MockObjectFile>(288);
278   const auto &T1C = T1;
279   OwnedObj = T1C.getTransform()(std::move(OwnedObj));
280   EXPECT_EQ(289, *OwnedObj) << "Expected incrementing transform";
281 
282   volatile bool RunStaticChecks = false;
283   if (!RunStaticChecks)
284     return;
285 
286   // Make sure that ObjectTransformLayer implements the object layer concept
287   // correctly by sandwitching one between an ObjectLinkingLayer and an
288   // IRCompileLayer, verifying that it compiles if we have a call to the
289   // IRComileLayer's addModuleSet that should call the transform layer's
290   // addObjectSet, and also calling the other public transform layer methods
291   // directly to make sure the methods they intend to forward to exist on
292   // the ObjectLinkingLayer.
293 
294   // We'll need a concrete MemoryManager class.
295   class NullManager : public llvm::RuntimeDyld::MemoryManager {
296   public:
297     uint8_t *allocateCodeSection(uintptr_t, unsigned, unsigned,
298                                  llvm::StringRef) override {
299       return nullptr;
300     }
301     uint8_t *allocateDataSection(uintptr_t, unsigned, unsigned, llvm::StringRef,
302                                  bool) override {
303       return nullptr;
304     }
305     void registerEHFrames(uint8_t *, uint64_t, size_t) override {}
306     void deregisterEHFrames(uint8_t *, uint64_t, size_t) override {}
307     bool finalizeMemory(std::string *) override { return false; }
308   };
309 
310   // Construct the jit layers.
311   ObjectLinkingLayer<> BaseLayer;
312   auto IdentityTransform = [](
313       std::unique_ptr<llvm::object::OwningBinary<llvm::object::ObjectFile>>
314           Obj) { return Obj; };
315   ObjectTransformLayer<decltype(BaseLayer), decltype(IdentityTransform)>
316       TransformLayer(BaseLayer, IdentityTransform);
317   auto NullCompiler = [](llvm::Module &) {
318     return llvm::object::OwningBinary<llvm::object::ObjectFile>();
319   };
320   IRCompileLayer<decltype(TransformLayer)> CompileLayer(TransformLayer,
321                                                         NullCompiler);
322 
323   // Make sure that the calls from IRCompileLayer to ObjectTransformLayer
324   // compile.
325   NullResolver Resolver;
326   NullManager Manager;
327   CompileLayer.addModuleSet(std::vector<llvm::Module *>(), &Manager, &Resolver);
328 
329   // Make sure that the calls from ObjectTransformLayer to ObjectLinkingLayer
330   // compile.
331   decltype(TransformLayer)::ObjSetHandleT ObjSet;
332   TransformLayer.emitAndFinalize(ObjSet);
333   TransformLayer.findSymbolIn(ObjSet, Name, false);
334   TransformLayer.findSymbol(Name, true);
335   TransformLayer.mapSectionAddress(ObjSet, nullptr, 0);
336   TransformLayer.removeObjectSet(ObjSet);
337 }
338 }
339