blob: 2fdf9e8b7379b4445706e93242a9aac115913c0d [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
Chandler Carruth9a67b072017-06-06 11:06:56 +000010#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
Benjamin Kramer3bdcc8c2015-06-25 13:47:36 +000011#include "llvm/ADT/STLExtras.h"
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000012#include "llvm/ADT/SmallVector.h"
Joseph Tremoulet23d02f62016-01-23 18:36:01 +000013#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
14#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
15#include "llvm/ExecutionEngine/Orc/NullResolver.h"
Lang Hames67de5d22017-02-20 05:45:14 +000016#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
Joseph Tremoulet23d02f62016-01-23 18:36:01 +000017#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
Lang Hames26620222017-06-22 21:06:54 +000034typedef int MockMemoryBuffer;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000035
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 {
Lang Hames26620222017-06-22 21:06:54 +000039 std::shared_ptr<MockObjectFile>
40 operator()(std::shared_ptr<MockObjectFile> Obj) const {
41 return std::make_shared<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:
Lang Hames26620222017-06-22 21:06:54 +000053 typedef int ObjHandleT;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000054
55 MockBaseLayer() : MockSymbol(nullptr) { resetExpectations(); }
56
Lang Hames26620222017-06-22 21:06:54 +000057 template <typename ObjPtrT, typename MemoryManagerPtrT,
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000058 typename SymbolResolverPtrT>
Lang Hames26620222017-06-22 21:06:54 +000059 ObjHandleT addObject(ObjPtrT Obj, MemoryManagerPtrT MemMgr,
60 SymbolResolverPtrT Resolver) {
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000061 EXPECT_EQ(MockManager, *MemMgr) << "MM should pass through";
62 EXPECT_EQ(MockResolver, *Resolver) << "Resolver should pass through";
Lang Hames26620222017-06-22 21:06:54 +000063 EXPECT_EQ(MockObject + 1, *Obj) << "Transform should be applied";
64 LastCalled = "addObject";
65 MockObjHandle = 111;
66 return MockObjHandle;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000067 }
Lang Hames26620222017-06-22 21:06:54 +000068 template <typename ObjPtrT>
69 void expectAddObject(ObjPtrT Obj, MockMemoryManager *MemMgr,
70 MockSymbolResolver *Resolver) {
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000071 MockManager = *MemMgr;
72 MockResolver = *Resolver;
Lang Hames26620222017-06-22 21:06:54 +000073 MockObject = *Obj;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000074 }
Lang Hames26620222017-06-22 21:06:54 +000075 void verifyAddObject(ObjHandleT Returned) {
76 EXPECT_EQ("addObject", LastCalled);
77 EXPECT_EQ(MockObjHandle, Returned) << "Return should pass through";
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000078 resetExpectations();
79 }
80
Lang Hames26620222017-06-22 21:06:54 +000081 void removeObject(ObjHandleT H) {
82 EXPECT_EQ(MockObjHandle, H);
83 LastCalled = "removeObject";
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000084 }
Lang Hames26620222017-06-22 21:06:54 +000085 void expectRemoveObject(ObjHandleT H) { MockObjHandle = H; }
86 void verifyRemoveObject() {
87 EXPECT_EQ("removeObject", LastCalled);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000088 resetExpectations();
89 }
90
Lang Hamesad4a9112016-08-01 20:49:11 +000091 llvm::JITSymbol findSymbol(const std::string &Name,
92 bool ExportedSymbolsOnly) {
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000093 EXPECT_EQ(MockName, Name) << "Name should pass through";
94 EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
95 LastCalled = "findSymbol";
Lang Hamesad4a9112016-08-01 20:49:11 +000096 MockSymbol = llvm::JITSymbol(122, llvm::JITSymbolFlags::None);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +000097 return MockSymbol;
98 }
99 void expectFindSymbol(const std::string &Name, bool ExportedSymbolsOnly) {
100 MockName = Name;
101 MockBool = ExportedSymbolsOnly;
102 }
Lang Hamesad4a9112016-08-01 20:49:11 +0000103 void verifyFindSymbol(llvm::JITSymbol Returned) {
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000104 EXPECT_EQ("findSymbol", LastCalled);
105 EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
106 << "Return should pass through";
107 resetExpectations();
108 }
109
Lang Hames26620222017-06-22 21:06:54 +0000110 llvm::JITSymbol findSymbolIn(ObjHandleT H, const std::string &Name,
Lang Hamesad4a9112016-08-01 20:49:11 +0000111 bool ExportedSymbolsOnly) {
Lang Hames26620222017-06-22 21:06:54 +0000112 EXPECT_EQ(MockObjHandle, H) << "Handle should pass through";
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000113 EXPECT_EQ(MockName, Name) << "Name should pass through";
114 EXPECT_EQ(MockBool, ExportedSymbolsOnly) << "Flag should pass through";
115 LastCalled = "findSymbolIn";
Lang Hamesad4a9112016-08-01 20:49:11 +0000116 MockSymbol = llvm::JITSymbol(122, llvm::JITSymbolFlags::None);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000117 return MockSymbol;
118 }
Lang Hames26620222017-06-22 21:06:54 +0000119 void expectFindSymbolIn(ObjHandleT H, const std::string &Name,
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000120 bool ExportedSymbolsOnly) {
Lang Hames26620222017-06-22 21:06:54 +0000121 MockObjHandle = H;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000122 MockName = Name;
123 MockBool = ExportedSymbolsOnly;
124 }
Lang Hamesad4a9112016-08-01 20:49:11 +0000125 void verifyFindSymbolIn(llvm::JITSymbol Returned) {
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000126 EXPECT_EQ("findSymbolIn", LastCalled);
127 EXPECT_EQ(MockSymbol.getAddress(), Returned.getAddress())
128 << "Return should pass through";
129 resetExpectations();
130 }
131
Lang Hames26620222017-06-22 21:06:54 +0000132 void emitAndFinalize(ObjHandleT H) {
133 EXPECT_EQ(MockObjHandle, H) << "Handle should pass through";
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000134 LastCalled = "emitAndFinalize";
135 }
Lang Hames26620222017-06-22 21:06:54 +0000136 void expectEmitAndFinalize(ObjHandleT H) { MockObjHandle = H; }
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000137 void verifyEmitAndFinalize() {
138 EXPECT_EQ("emitAndFinalize", LastCalled);
139 resetExpectations();
140 }
141
Lang Hames26620222017-06-22 21:06:54 +0000142 void mapSectionAddress(ObjHandleT H, const void *LocalAddress,
Lang Hamesad4a9112016-08-01 20:49:11 +0000143 llvm::JITTargetAddress TargetAddr) {
Lang Hames26620222017-06-22 21:06:54 +0000144 EXPECT_EQ(MockObjHandle, H);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000145 EXPECT_EQ(MockLocalAddress, LocalAddress);
146 EXPECT_EQ(MockTargetAddress, TargetAddr);
147 LastCalled = "mapSectionAddress";
148 }
Lang Hames26620222017-06-22 21:06:54 +0000149 void expectMapSectionAddress(ObjHandleT H, const void *LocalAddress,
Lang Hamesad4a9112016-08-01 20:49:11 +0000150 llvm::JITTargetAddress TargetAddr) {
Lang Hames26620222017-06-22 21:06:54 +0000151 MockObjHandle = H;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000152 MockLocalAddress = LocalAddress;
153 MockTargetAddress = TargetAddr;
154 }
155 void verifyMapSectionAddress() {
156 EXPECT_EQ("mapSectionAddress", LastCalled);
157 resetExpectations();
158 }
159
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000160private:
161 // Backing fields for remembering parameter/return values
162 std::string LastCalled;
163 MockMemoryManager MockManager;
164 MockSymbolResolver MockResolver;
Lang Hames26620222017-06-22 21:06:54 +0000165 MockObjectFile MockObject;
166 ObjHandleT MockObjHandle;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000167 std::string MockName;
168 bool MockBool;
Lang Hamesad4a9112016-08-01 20:49:11 +0000169 llvm::JITSymbol MockSymbol;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000170 const void *MockLocalAddress;
Lang Hamesad4a9112016-08-01 20:49:11 +0000171 llvm::JITTargetAddress MockTargetAddress;
Lang Hames26620222017-06-22 21:06:54 +0000172 MockMemoryBuffer MockBuffer;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000173
174 // Clear remembered parameters between calls
175 void resetExpectations() {
176 LastCalled = "nothing";
177 MockManager = 0;
178 MockResolver = 0;
Lang Hames26620222017-06-22 21:06:54 +0000179 MockObject = 0;
180 MockObjHandle = 0;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000181 MockName = "bogus";
Lang Hamesad4a9112016-08-01 20:49:11 +0000182 MockSymbol = llvm::JITSymbol(nullptr);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000183 MockLocalAddress = nullptr;
184 MockTargetAddress = 0;
Lang Hames26620222017-06-22 21:06:54 +0000185 MockBuffer = 0;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000186 }
187};
188
189// Test each operation on ObjectTransformLayer.
190TEST(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,
Lang Hames26620222017-06-22 21:06:54 +0000200 std::function<std::shared_ptr<MockObjectFile>(
201 std::shared_ptr<MockObjectFile>)>>
202 T2(M, [](std::shared_ptr<MockObjectFile> Obj) {
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000203 ++(*Obj);
204 return Obj;
205 });
206
207 // Instantiate some mock objects to use below
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000208 MockMemoryManager MockManager = 233;
209 MockSymbolResolver MockResolver = 244;
210
Lang Hames26620222017-06-22 21:06:54 +0000211 // Test addObject with T1 (allocating)
212 auto Obj1 = std::make_shared<MockObjectFile>(211);
Benjamin Kramer3bdcc8c2015-06-25 13:47:36 +0000213 auto MM = llvm::make_unique<MockMemoryManager>(MockManager);
214 auto SR = llvm::make_unique<MockSymbolResolver>(MockResolver);
Lang Hames26620222017-06-22 21:06:54 +0000215 M.expectAddObject(Obj1, MM.get(), SR.get());
216 auto H = T1.addObject(std::move(Obj1), std::move(MM), std::move(SR));
217 M.verifyAddObject(H);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000218
Lang Hames26620222017-06-22 21:06:54 +0000219 // Test addObjectSet with T2 (mutating)
220 auto Obj2 = std::make_shared<MockObjectFile>(222);
221 M.expectAddObject(Obj2, &MockManager, &MockResolver);
222 H = T2.addObject(Obj2, &MockManager, &MockResolver);
223 M.verifyAddObject(H);
224 EXPECT_EQ(223, *Obj2) << "Expected mutation";
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000225
226 // Test removeObjectSet
Lang Hames26620222017-06-22 21:06:54 +0000227 M.expectRemoveObject(H);
228 T1.removeObject(H);
229 M.verifyRemoveObject();
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000230
231 // Test findSymbol
232 std::string Name = "foo";
233 bool ExportedOnly = true;
234 M.expectFindSymbol(Name, ExportedOnly);
Lang Hamesad4a9112016-08-01 20:49:11 +0000235 llvm::JITSymbol Symbol = T2.findSymbol(Name, ExportedOnly);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000236 M.verifyFindSymbol(Symbol);
237
238 // Test findSymbolIn
239 Name = "bar";
240 ExportedOnly = false;
241 M.expectFindSymbolIn(H, Name, ExportedOnly);
242 Symbol = T1.findSymbolIn(H, Name, ExportedOnly);
243 M.verifyFindSymbolIn(Symbol);
244
245 // Test emitAndFinalize
246 M.expectEmitAndFinalize(H);
247 T2.emitAndFinalize(H);
248 M.verifyEmitAndFinalize();
249
250 // Test mapSectionAddress
251 char Buffer[24];
Lang Hamesad4a9112016-08-01 20:49:11 +0000252 llvm::JITTargetAddress MockAddress = 255;
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000253 M.expectMapSectionAddress(H, Buffer, MockAddress);
254 T1.mapSectionAddress(H, Buffer, MockAddress);
255 M.verifyMapSectionAddress();
256
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000257 // Verify transform getter (non-const)
Lang Hames26620222017-06-22 21:06:54 +0000258 auto Mutatee = std::make_shared<MockObjectFile>(277);
259 auto Out = T2.getTransform()(Mutatee);
260 EXPECT_EQ(*Mutatee, *Out) << "Expected in-place transform";
261 EXPECT_EQ(278, *Mutatee) << "Expected incrementing transform";
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000262
263 // Verify transform getter (const)
Lang Hames26620222017-06-22 21:06:54 +0000264 auto OwnedObj = std::make_shared<MockObjectFile>(288);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000265 const auto &T1C = T1;
266 OwnedObj = T1C.getTransform()(std::move(OwnedObj));
267 EXPECT_EQ(289, *OwnedObj) << "Expected incrementing transform";
Joseph Tremoulet23d02f62016-01-23 18:36:01 +0000268
269 volatile bool RunStaticChecks = false;
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000270 if (!RunStaticChecks)
271 return;
Joseph Tremoulet23d02f62016-01-23 18:36:01 +0000272
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000273 // Make sure that ObjectTransformLayer implements the object layer concept
274 // correctly by sandwitching one between an ObjectLinkingLayer and an
275 // IRCompileLayer, verifying that it compiles if we have a call to the
Lang Hames26620222017-06-22 21:06:54 +0000276 // IRComileLayer's addModule that should call the transform layer's
277 // addObject, and also calling the other public transform layer methods
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000278 // directly to make sure the methods they intend to forward to exist on
279 // the ObjectLinkingLayer.
Joseph Tremoulet23d02f62016-01-23 18:36:01 +0000280
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000281 // We'll need a concrete MemoryManager class.
282 class NullManager : public llvm::RuntimeDyld::MemoryManager {
283 public:
284 uint8_t *allocateCodeSection(uintptr_t, unsigned, unsigned,
285 llvm::StringRef) override {
286 return nullptr;
287 }
288 uint8_t *allocateDataSection(uintptr_t, unsigned, unsigned, llvm::StringRef,
289 bool) override {
290 return nullptr;
291 }
292 void registerEHFrames(uint8_t *, uint64_t, size_t) override {}
Lang Hamesc936ac72017-05-09 21:32:18 +0000293 void deregisterEHFrames() override {}
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000294 bool finalizeMemory(std::string *) override { return false; }
295 };
Joseph Tremoulet23d02f62016-01-23 18:36:01 +0000296
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000297 // Construct the jit layers.
Lang Hames26620222017-06-22 21:06:54 +0000298 RTDyldObjectLinkingLayer BaseLayer;
299 auto IdentityTransform =
300 [](std::shared_ptr<llvm::object::OwningBinary<llvm::object::ObjectFile>>
301 Obj) {
302 return Obj;
303 };
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000304 ObjectTransformLayer<decltype(BaseLayer), decltype(IdentityTransform)>
305 TransformLayer(BaseLayer, IdentityTransform);
306 auto NullCompiler = [](llvm::Module &) {
Lang Hames26620222017-06-22 21:06:54 +0000307 return llvm::object::OwningBinary<llvm::object::ObjectFile>(nullptr,
308 nullptr);
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000309 };
Lang Hames26620222017-06-22 21:06:54 +0000310 IRCompileLayer<decltype(TransformLayer), decltype(NullCompiler)>
311 CompileLayer(TransformLayer, NullCompiler);
Joseph Tremoulet23d02f62016-01-23 18:36:01 +0000312
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000313 // Make sure that the calls from IRCompileLayer to ObjectTransformLayer
314 // compile.
315 NullResolver Resolver;
316 NullManager Manager;
Lang Hames2c19c1b2017-06-23 21:45:29 +0000317 CompileLayer.addModule(std::shared_ptr<llvm::Module>(), &Manager, &Resolver);
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000318
319 // Make sure that the calls from ObjectTransformLayer to ObjectLinkingLayer
320 // compile.
Lang Hames26620222017-06-22 21:06:54 +0000321 decltype(TransformLayer)::ObjHandleT H2;
322 TransformLayer.emitAndFinalize(H2);
323 TransformLayer.findSymbolIn(H2, Name, false);
Joseph Tremoulete1014a32016-02-03 17:11:24 +0000324 TransformLayer.findSymbol(Name, true);
Lang Hames26620222017-06-22 21:06:54 +0000325 TransformLayer.mapSectionAddress(H2, nullptr, 0);
326 TransformLayer.removeObject(H2);
Joseph Tremoulet7ff086c2015-06-25 13:35:22 +0000327}
328}