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