blob: f4267c95be0332dcb42a864e65cf4f730974826a [file] [log] [blame]
Lang Hames5f7fcef2015-10-29 03:53:42 +00001//===-- ObjectLinkingLayerTest.cpp - Unit tests for object linking layer --===//
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
Lang Hames859d73c2016-01-09 19:50:40 +000010#include "OrcTestCommon.h"
Lang Hames5f7fcef2015-10-29 03:53:42 +000011#include "llvm/ExecutionEngine/ExecutionEngine.h"
12#include "llvm/ExecutionEngine/SectionMemoryManager.h"
13#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
14#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
Lang Hames2fe7acb2016-01-19 21:06:38 +000015#include "llvm/ExecutionEngine/Orc/NullResolver.h"
Lang Hames5f7fcef2015-10-29 03:53:42 +000016#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
17#include "llvm/IR/Constants.h"
18#include "llvm/IR/LLVMContext.h"
19#include "gtest/gtest.h"
20
21using namespace llvm;
22using namespace llvm::orc;
23
24namespace {
25
Lang Hames859d73c2016-01-09 19:50:40 +000026class ObjectLinkingLayerExecutionTest : public testing::Test,
27 public OrcExecutionTest {
28};
29
NAKAMURA Takumi96e30312016-01-10 15:56:49 +000030class SectionMemoryManagerWrapper : public SectionMemoryManager {
31public:
32 int FinalizationCount = 0;
Lang Hames2fe7acb2016-01-19 21:06:38 +000033 int NeedsToReserveAllocationSpaceCount = 0;
34
35 bool needsToReserveAllocationSpace() override {
36 ++NeedsToReserveAllocationSpaceCount;
37 return SectionMemoryManager::needsToReserveAllocationSpace();
38 }
39
NAKAMURA Takumi96e30312016-01-10 15:56:49 +000040 bool finalizeMemory(std::string *ErrMsg = 0) override {
41 ++FinalizationCount;
42 return SectionMemoryManager::finalizeMemory(ErrMsg);
43 }
44};
45
Lang Hames5f7fcef2015-10-29 03:53:42 +000046TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) {
47
48 class SectionMemoryManagerWrapper : public SectionMemoryManager {
49 public:
50 SectionMemoryManagerWrapper(bool &DebugSeen) : DebugSeen(DebugSeen) {}
51 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
52 unsigned SectionID,
53 StringRef SectionName,
54 bool IsReadOnly) override {
55 if (SectionName == ".debug_str")
56 DebugSeen = true;
57 return SectionMemoryManager::allocateDataSection(Size, Alignment,
58 SectionID,
59 SectionName,
60 IsReadOnly);
61 }
62 private:
63 bool DebugSeen;
64 };
65
66 ObjectLinkingLayer<> ObjLayer;
67
68 auto M = llvm::make_unique<Module>("", getGlobalContext());
69 M->setTargetTriple("x86_64-unknown-linux-gnu");
70 Type *Int32Ty = IntegerType::get(getGlobalContext(), 32);
71 GlobalVariable *GV =
72 new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage,
73 ConstantInt::get(Int32Ty, 42), "foo");
74
75 GV->setSection(".debug_str");
76
77 std::unique_ptr<TargetMachine> TM(
78 EngineBuilder().selectTarget(Triple(M->getTargetTriple()), "", "",
79 SmallVector<std::string, 1>()));
80 if (!TM)
81 return;
82
83 auto OwningObj = SimpleCompiler(*TM)(*M);
84 std::vector<object::ObjectFile*> Objs;
85 Objs.push_back(OwningObj.getBinary());
86
87 bool DebugSectionSeen = false;
88 SectionMemoryManagerWrapper SMMW(DebugSectionSeen);
89 auto Resolver =
90 createLambdaResolver(
91 [](const std::string &Name) {
92 return RuntimeDyld::SymbolInfo(nullptr);
93 },
94 [](const std::string &Name) {
95 return RuntimeDyld::SymbolInfo(nullptr);
96 });
97
98 {
99 // Test with ProcessAllSections = false (the default).
100 auto H = ObjLayer.addObjectSet(Objs, &SMMW, &*Resolver);
101 EXPECT_EQ(DebugSectionSeen, false)
102 << "Unexpected debug info section";
103 ObjLayer.removeObjectSet(H);
104 }
105
106 {
107 // Test with ProcessAllSections = true.
108 ObjLayer.setProcessAllSections(true);
109 auto H = ObjLayer.addObjectSet(Objs, &SMMW, &*Resolver);
110 EXPECT_EQ(DebugSectionSeen, true)
111 << "Expected debug info section not seen";
112 ObjLayer.removeObjectSet(H);
113 }
114}
115
Lang Hames859d73c2016-01-09 19:50:40 +0000116
117TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
118
119 if (!TM)
120 return;
121
Lang Hames859d73c2016-01-09 19:50:40 +0000122 ObjectLinkingLayer<> ObjLayer;
123 SimpleCompiler Compile(*TM);
124
125 // Create a pair of modules that will trigger recursive finalization:
126 // Module 1:
127 // int bar() { return 42; }
128 // Module 2:
129 // int bar();
130 // int foo() { return bar(); }
Lang Hames133f1532016-01-18 01:00:19 +0000131 //
132 // Verify that the memory manager is only finalized once (for Module 2).
133 // Failure suggests that finalize is being called on the inner RTDyld
134 // instance (for Module 1) which is unsafe, as it will prevent relocation of
135 // Module 2.
Lang Hames859d73c2016-01-09 19:50:40 +0000136
137 ModuleBuilder MB1(getGlobalContext(), "", "dummy");
138 {
139 MB1.getModule()->setDataLayout(TM->createDataLayout());
140 Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("bar");
141 BasicBlock *BarEntry = BasicBlock::Create(getGlobalContext(), "entry",
142 BarImpl);
143 IRBuilder<> Builder(BarEntry);
144 IntegerType *Int32Ty = IntegerType::get(getGlobalContext(), 32);
145 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
146 Builder.CreateRet(FourtyTwo);
147 }
148
149 auto Obj1 = Compile(*MB1.getModule());
150 std::vector<object::ObjectFile*> Obj1Set;
151 Obj1Set.push_back(Obj1.getBinary());
152
153 ModuleBuilder MB2(getGlobalContext(), "", "dummy");
154 {
155 MB2.getModule()->setDataLayout(TM->createDataLayout());
156 Function *BarDecl = MB2.createFunctionDecl<int32_t(void)>("bar");
157 Function *FooImpl = MB2.createFunctionDecl<int32_t(void)>("foo");
158 BasicBlock *FooEntry = BasicBlock::Create(getGlobalContext(), "entry",
159 FooImpl);
160 IRBuilder<> Builder(FooEntry);
161 Builder.CreateRet(Builder.CreateCall(BarDecl));
162 }
163 auto Obj2 = Compile(*MB2.getModule());
164 std::vector<object::ObjectFile*> Obj2Set;
165 Obj2Set.push_back(Obj2.getBinary());
166
167 auto Resolver =
168 createLambdaResolver(
169 [&](const std::string &Name) {
170 if (auto Sym = ObjLayer.findSymbol(Name, true))
171 return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags());
172 return RuntimeDyld::SymbolInfo(nullptr);
173 },
174 [](const std::string &Name) {
175 return RuntimeDyld::SymbolInfo(nullptr);
176 });
177
178 SectionMemoryManagerWrapper SMMW;
179 ObjLayer.addObjectSet(std::move(Obj1Set), &SMMW, &*Resolver);
180 auto H = ObjLayer.addObjectSet(std::move(Obj2Set), &SMMW, &*Resolver);
181 ObjLayer.emitAndFinalize(H);
182
183 // Finalization of module 2 should trigger finalization of module 1.
184 // Verify that finalize on SMMW is only called once.
185 EXPECT_EQ(SMMW.FinalizationCount, 1)
186 << "Extra call to finalize";
187}
188
Lang Hames2fe7acb2016-01-19 21:06:38 +0000189TEST_F(ObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
190
191 if (!TM)
192 return;
193
194 ObjectLinkingLayer<> ObjLayer;
195 SimpleCompiler Compile(*TM);
196
197 // Create a pair of unrelated modules:
198 //
199 // Module 1:
200 // int foo() { return 42; }
201 // Module 2:
202 // int bar() { return 7; }
203 //
204 // Both modules will share a memory manager. We want to verify that the
205 // second object is not loaded before the first one is finalized. To do this
206 // in a portable way, we abuse the
207 // RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is
208 // called once per object before any sections are allocated.
209
210 ModuleBuilder MB1(getGlobalContext(), "", "dummy");
211 {
212 MB1.getModule()->setDataLayout(TM->createDataLayout());
213 Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("foo");
214 BasicBlock *BarEntry = BasicBlock::Create(getGlobalContext(), "entry",
215 BarImpl);
216 IRBuilder<> Builder(BarEntry);
217 IntegerType *Int32Ty = IntegerType::get(getGlobalContext(), 32);
218 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
219 Builder.CreateRet(FourtyTwo);
220 }
221
222 auto Obj1 = Compile(*MB1.getModule());
223 std::vector<object::ObjectFile*> Obj1Set;
224 Obj1Set.push_back(Obj1.getBinary());
225
226 ModuleBuilder MB2(getGlobalContext(), "", "dummy");
227 {
228 MB2.getModule()->setDataLayout(TM->createDataLayout());
229 Function *BarImpl = MB2.createFunctionDecl<int32_t(void)>("bar");
230 BasicBlock *BarEntry = BasicBlock::Create(getGlobalContext(), "entry",
231 BarImpl);
232 IRBuilder<> Builder(BarEntry);
233 IntegerType *Int32Ty = IntegerType::get(getGlobalContext(), 32);
234 Value *Seven = ConstantInt::getSigned(Int32Ty, 7);
235 Builder.CreateRet(Seven);
236 }
237 auto Obj2 = Compile(*MB2.getModule());
238 std::vector<object::ObjectFile*> Obj2Set;
239 Obj2Set.push_back(Obj2.getBinary());
240
241 SectionMemoryManagerWrapper SMMW;
242 NullResolver NR;
243 auto H = ObjLayer.addObjectSet(std::move(Obj1Set), &SMMW, &NR);
244 ObjLayer.addObjectSet(std::move(Obj2Set), &SMMW, &NR);
245 ObjLayer.emitAndFinalize(H);
246
247 // Only one call to needsToReserveAllocationSpace should have been made.
248 EXPECT_EQ(SMMW.NeedsToReserveAllocationSpaceCount, 1)
249 << "More than one call to needsToReserveAllocationSpace "
250 "(multiple unrelated objects loaded prior to finalization)";
251}
252
Lang Hames5f7fcef2015-10-29 03:53:42 +0000253}