blob: 63b85dc82ca84afed076514c41b8b1dd51d78c63 [file] [log] [blame]
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +00001//===- 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
Benjamin Kramer3bdcc8c2015-06-25 13:47:36 +000010#include "llvm/ADT/STLExtras.h"
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000011#include "llvm/ADT/SmallVector.h"
Joseph Tremoulet23d02f62016-01-23 18:36:01 +000012#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"
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000018#include "gtest/gtest.h"
19
20using namespace llvm::orc;
21
22namespace {
23
24// Stand-in for RuntimeDyld::MemoryManager
25typedef int MockMemoryManager;
26
27// Stand-in for RuntimeDyld::SymbolResolver
28typedef int MockSymbolResolver;
29
30// stand-in for object::ObjectFile
31typedef int MockObjectFile;
32
33// stand-in for llvm::MemoryBuffer set
34typedef 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.
38struct AllocatingTransform {
39 std::unique_ptr<MockObjectFile>
40 operator()(std::unique_ptr<MockObjectFile> Obj) const {
Benjamin Kramer3bdcc8c2015-06-25 13:47:36 +000041 return llvm::make_unique<MockObjectFile>(*Obj + 1);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000042 }
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.
51class MockBaseLayer {
52public:
53 typedef int ObjSetHandleT;
54
55 MockBaseLayer() : MockSymbol(nullptr) { resetExpectations(); }
56
57 template <typename ObjSetT, typename MemoryManagerPtrT,
58 typename SymbolResolverPtrT>
Joseph Tremoulet23d02f62016-01-23 18:36:01 +000059 ObjSetHandleT addObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr,
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000060 SymbolResolverPtrT Resolver) {
61 EXPECT_EQ(MockManager, *MemMgr) << "MM should pass through";
62 EXPECT_EQ(MockResolver, *Resolver) << "Resolver should pass through";
Benjamin Kramer3bdcc8c2015-06-25 13:47:36 +000063 size_t I = 0;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000064 for (auto &ObjPtr : Objects) {
Justin Lebar07538002016-07-13 18:27:49 +000065 EXPECT_EQ(MockObjects[I] + 1, *ObjPtr) << "Transform should be applied";
66 I++;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000067 }
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>
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 }
82 void verifyAddObjectSet(ObjSetHandleT Returned) {
83 EXPECT_EQ("addObjectSet", LastCalled);
84 EXPECT_EQ(MockObjSetHandle, Returned) << "Return should pass through";
85 resetExpectations();
86 }
87
88 void removeObjectSet(ObjSetHandleT H) {
89 EXPECT_EQ(MockObjSetHandle, H);
90 LastCalled = "removeObjectSet";
91 }
92 void expectRemoveObjectSet(ObjSetHandleT H) { MockObjSetHandle = H; }
93 void verifyRemoveObjectSet() {
94 EXPECT_EQ("removeObjectSet", LastCalled);
95 resetExpectations();
96 }
97
Lang Hamesad4a9112016-08-01 20:49:11 +000098 llvm::JITSymbol findSymbol(const std::string &Name,
99 bool ExportedSymbolsOnly) {
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000100 EXPECT_EQ(MockName, Name) << "Name should pass through";
101 EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
102 LastCalled = "findSymbol";
Lang Hamesad4a9112016-08-01 20:49:11 +0000103 MockSymbol = llvm::JITSymbol(122, llvm::JITSymbolFlags::None);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000104 return MockSymbol;
105 }
106 void expectFindSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
107 MockName = Name;
108 MockBool = ExportedSymbolsOnly;
109 }
Lang Hamesad4a9112016-08-01 20:49:11 +0000110 void verifyFindSymbol(llvm::JITSymbol Returned) {
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000111 EXPECT_EQ("findSymbol", LastCalled);
112 EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
113 << "Return should pass through";
114 resetExpectations();
115 }
116
Lang Hamesad4a9112016-08-01 20:49:11 +0000117 llvm::JITSymbol findSymbolIn(ObjSetHandleT H, const std::string &Name,
118 bool ExportedSymbolsOnly) {
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000119 EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
120 EXPECT_EQ(MockName, Name) << "Name should pass through";
121 EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
122 LastCalled = "findSymbolIn";
Lang Hamesad4a9112016-08-01 20:49:11 +0000123 MockSymbol = llvm::JITSymbol(122, llvm::JITSymbolFlags::None);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000124 return MockSymbol;
125 }
126 void expectFindSymbolIn(ObjSetHandleT H, const std::string &Name,
127 bool ExportedSymbolsOnly) {
128 MockObjSetHandle = H;
129 MockName = Name;
130 MockBool = ExportedSymbolsOnly;
131 }
Lang Hamesad4a9112016-08-01 20:49:11 +0000132 void verifyFindSymbolIn(llvm::JITSymbol Returned) {
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000133 EXPECT_EQ("findSymbolIn", LastCalled);
134 EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
135 << "Return should pass through";
136 resetExpectations();
137 }
138
139 void emitAndFinalize(ObjSetHandleT H) {
140 EXPECT_EQ(MockObjSetHandle, H) << "Handle should pass through";
141 LastCalled = "emitAndFinalize";
142 }
143 void expectEmitAndFinalize(ObjSetHandleT H) { MockObjSetHandle = H; }
144 void verifyEmitAndFinalize() {
145 EXPECT_EQ("emitAndFinalize", LastCalled);
146 resetExpectations();
147 }
148
149 void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
Lang Hamesad4a9112016-08-01 20:49:11 +0000150 llvm::JITTargetAddress TargetAddr) {
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000151 EXPECT_EQ(MockObjSetHandle, H);
152 EXPECT_EQ(MockLocalAddress, LocalAddress);
153 EXPECT_EQ(MockTargetAddress, TargetAddr);
154 LastCalled = "mapSectionAddress";
155 }
156 void expectMapSectionAddress(ObjSetHandleT H, const void *LocalAddress,
Lang Hamesad4a9112016-08-01 20:49:11 +0000157 llvm::JITTargetAddress TargetAddr) {
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000158 MockObjSetHandle = H;
159 MockLocalAddress = LocalAddress;
160 MockTargetAddress = TargetAddr;
161 }
162 void verifyMapSectionAddress() {
163 EXPECT_EQ("mapSectionAddress", LastCalled);
164 resetExpectations();
165 }
166
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000167private:
168 // Backing fields for remembering parameter/return values
169 std::string LastCalled;
170 MockMemoryManager MockManager;
171 MockSymbolResolver MockResolver;
172 std::vector<MockObjectFile> MockObjects;
173 ObjSetHandleT MockObjSetHandle;
174 std::string MockName;
175 bool MockBool;
Lang Hamesad4a9112016-08-01 20:49:11 +0000176 llvm::JITSymbol MockSymbol;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000177 const void *MockLocalAddress;
Lang Hamesad4a9112016-08-01 20:49:11 +0000178 llvm::JITTargetAddress MockTargetAddress;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000179 MockMemoryBufferSet MockBufferSet;
180
181 // Clear remembered parameters between calls
182 void resetExpectations() {
183 LastCalled = "nothing";
184 MockManager = 0;
185 MockResolver = 0;
186 MockObjects.clear();
187 MockObjSetHandle = 0;
188 MockName = "bogus";
Lang Hamesad4a9112016-08-01 20:49:11 +0000189 MockSymbol = llvm::JITSymbol(nullptr);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000190 MockLocalAddress = nullptr;
191 MockTargetAddress = 0;
192 MockBufferSet = 0;
193 }
194};
195
196// Test each operation on ObjectTransformLayer.
197TEST(ObjectTransformLayerTest, Main) {
198 MockBaseLayer M;
199
200 // Create one object transform layer using a transform (as a functor)
201 // that allocates new objects, and deals in unique pointers.
202 ObjectTransformLayer<MockBaseLayer, AllocatingTransform> T1(M);
203
204 // Create a second object transform layer using a transform (as a lambda)
205 // that mutates objects in place, and deals in naked pointers
206 ObjectTransformLayer<MockBaseLayer,
207 std::function<MockObjectFile *(MockObjectFile *)>>
208 T2(M, [](MockObjectFile *Obj) {
209 ++(*Obj);
210 return Obj;
211 });
212
213 // Instantiate some mock objects to use below
214 MockObjectFile MockObject1 = 211;
215 MockObjectFile MockObject2 = 222;
216 MockMemoryManager MockManager = 233;
217 MockSymbolResolver MockResolver = 244;
218
219 // Test addObjectSet with T1 (allocating, unique pointers)
220 std::vector<std::unique_ptr<MockObjectFile>> Objs1;
Benjamin Kramer3bdcc8c2015-06-25 13:47:36 +0000221 Objs1.push_back(llvm::make_unique<MockObjectFile>(MockObject1));
222 Objs1.push_back(llvm::make_unique<MockObjectFile>(MockObject2));
223 auto MM = llvm::make_unique<MockMemoryManager>(MockManager);
224 auto SR = llvm::make_unique<MockSymbolResolver>(MockResolver);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000225 M.expectAddObjectSet(Objs1, MM.get(), SR.get());
Joseph Tremoulet23d02f62016-01-23 18:36:01 +0000226 auto H = T1.addObjectSet(std::move(Objs1), std::move(MM), std::move(SR));
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000227 M.verifyAddObjectSet(H);
228
229 // Test addObjectSet with T2 (mutating, naked pointers)
Joseph Tremoulet23d02f62016-01-23 18:36:01 +0000230 llvm::SmallVector<MockObjectFile *, 2> Objs2Vec;
231 Objs2Vec.push_back(&MockObject1);
232 Objs2Vec.push_back(&MockObject2);
233 llvm::MutableArrayRef<MockObjectFile *> Objs2(Objs2Vec);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000234 M.expectAddObjectSet(Objs2, &MockManager, &MockResolver);
235 H = T2.addObjectSet(Objs2, &MockManager, &MockResolver);
236 M.verifyAddObjectSet(H);
237 EXPECT_EQ(212, MockObject1) << "Expected mutation";
238 EXPECT_EQ(223, MockObject2) << "Expected mutation";
239
240 // Test removeObjectSet
241 M.expectRemoveObjectSet(H);
242 T1.removeObjectSet(H);
243 M.verifyRemoveObjectSet();
244
245 // Test findSymbol
246 std::string Name = "foo";
247 bool ExportedOnly = true;
248 M.expectFindSymbol(Name, ExportedOnly);
Lang Hamesad4a9112016-08-01 20:49:11 +0000249 llvm::JITSymbol Symbol = T2.findSymbol(Name, ExportedOnly);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000250 M.verifyFindSymbol(Symbol);
251
252 // Test findSymbolIn
253 Name = "bar";
254 ExportedOnly = false;
255 M.expectFindSymbolIn(H, Name, ExportedOnly);
256 Symbol = T1.findSymbolIn(H, Name, ExportedOnly);
257 M.verifyFindSymbolIn(Symbol);
258
259 // Test emitAndFinalize
260 M.expectEmitAndFinalize(H);
261 T2.emitAndFinalize(H);
262 M.verifyEmitAndFinalize();
263
264 // Test mapSectionAddress
265 char Buffer[24];
Lang Hamesad4a9112016-08-01 20:49:11 +0000266 llvm::JITTargetAddress MockAddress = 255;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000267 M.expectMapSectionAddress(H, Buffer, MockAddress);
268 T1.mapSectionAddress(H, Buffer, MockAddress);
269 M.verifyMapSectionAddress();
270
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000271 // Verify transform getter (non-const)
272 MockObjectFile Mutatee = 277;
273 MockObjectFile *Out = T2.getTransform()(&Mutatee);
274 EXPECT_EQ(&Mutatee, Out) << "Expected in-place transform";
275 EXPECT_EQ(278, Mutatee) << "Expected incrementing transform";
276
277 // Verify transform getter (const)
Benjamin Kramer3bdcc8c2015-06-25 13:47:36 +0000278 auto OwnedObj = llvm::make_unique<MockObjectFile>(288);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000279 const auto &T1C = T1;
280 OwnedObj = T1C.getTransform()(std::move(OwnedObj));
281 EXPECT_EQ(289, *OwnedObj) << "Expected incrementing transform";
Joseph Tremoulet23d02f62016-01-23 18:36:01 +0000282
283 volatile bool RunStaticChecks = false;
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000284 if (!RunStaticChecks)
285 return;
Joseph Tremoulet23d02f62016-01-23 18:36:01 +0000286
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000287 // Make sure that ObjectTransformLayer implements the object layer concept
288 // correctly by sandwitching one between an ObjectLinkingLayer and an
289 // IRCompileLayer, verifying that it compiles if we have a call to the
290 // IRComileLayer's addModuleSet that should call the transform layer's
291 // addObjectSet, and also calling the other public transform layer methods
292 // directly to make sure the methods they intend to forward to exist on
293 // the ObjectLinkingLayer.
Joseph Tremoulet23d02f62016-01-23 18:36:01 +0000294
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000295 // We'll need a concrete MemoryManager class.
296 class NullManager : public llvm::RuntimeDyld::MemoryManager {
297 public:
298 uint8_t *allocateCodeSection(uintptr_t, unsigned, unsigned,
299 llvm::StringRef) override {
300 return nullptr;
301 }
302 uint8_t *allocateDataSection(uintptr_t, unsigned, unsigned, llvm::StringRef,
303 bool) override {
304 return nullptr;
305 }
306 void registerEHFrames(uint8_t *, uint64_t, size_t) override {}
307 void deregisterEHFrames(uint8_t *, uint64_t, size_t) override {}
308 bool finalizeMemory(std::string *) override { return false; }
309 };
Joseph Tremoulet23d02f62016-01-23 18:36:01 +0000310
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000311 // Construct the jit layers.
312 ObjectLinkingLayer<> BaseLayer;
313 auto IdentityTransform = [](
314 std::unique_ptr<llvm::object::OwningBinary<llvm::object::ObjectFile>>
315 Obj) { return Obj; };
316 ObjectTransformLayer<decltype(BaseLayer), decltype(IdentityTransform)>
317 TransformLayer(BaseLayer, IdentityTransform);
318 auto NullCompiler = [](llvm::Module &) {
319 return llvm::object::OwningBinary<llvm::object::ObjectFile>();
320 };
321 IRCompileLayer<decltype(TransformLayer)> CompileLayer(TransformLayer,
322 NullCompiler);
Joseph Tremoulet23d02f62016-01-23 18:36:01 +0000323
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000324 // Make sure that the calls from IRCompileLayer to ObjectTransformLayer
325 // compile.
326 NullResolver Resolver;
327 NullManager Manager;
328 CompileLayer.addModuleSet(std::vector<llvm::Module *>(), &Manager, &Resolver);
329
330 // Make sure that the calls from ObjectTransformLayer to ObjectLinkingLayer
331 // compile.
332 decltype(TransformLayer)::ObjSetHandleT ObjSet;
333 TransformLayer.emitAndFinalize(ObjSet);
334 TransformLayer.findSymbolIn(ObjSet, Name, false);
335 TransformLayer.findSymbol(Name, true);
336 TransformLayer.mapSectionAddress(ObjSet, nullptr, 0);
337 TransformLayer.removeObjectSet(ObjSet);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000338}
339}