1 //===- RTDyldObjectLinkingLayerTest.cpp - RTDyld linking layer unit tests -===//
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/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
11 #include "OrcTestCommon.h"
12 #include "llvm/ExecutionEngine/ExecutionEngine.h"
13 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
14 #include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
15 #include "llvm/ExecutionEngine/Orc/Legacy.h"
16 #include "llvm/ExecutionEngine/Orc/NullResolver.h"
17 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
18 #include "llvm/IR/Constants.h"
19 #include "llvm/IR/LLVMContext.h"
20 #include "gtest/gtest.h"
21
22 using namespace llvm;
23 using namespace llvm::orc;
24
25 namespace {
26
27 class RTDyldObjectLinkingLayerExecutionTest : public testing::Test,
28 public OrcExecutionTest {
29
30 };
31
32 class SectionMemoryManagerWrapper : public SectionMemoryManager {
33 public:
34 int FinalizationCount = 0;
35 int NeedsToReserveAllocationSpaceCount = 0;
36
needsToReserveAllocationSpace()37 bool needsToReserveAllocationSpace() override {
38 ++NeedsToReserveAllocationSpaceCount;
39 return SectionMemoryManager::needsToReserveAllocationSpace();
40 }
41
finalizeMemory(std::string * ErrMsg=nullptr)42 bool finalizeMemory(std::string *ErrMsg = nullptr) override {
43 ++FinalizationCount;
44 return SectionMemoryManager::finalizeMemory(ErrMsg);
45 }
46 };
47
TEST(RTDyldObjectLinkingLayerTest,TestSetProcessAllSections)48 TEST(RTDyldObjectLinkingLayerTest, TestSetProcessAllSections) {
49 class MemoryManagerWrapper : public SectionMemoryManager {
50 public:
51 MemoryManagerWrapper(bool &DebugSeen) : DebugSeen(DebugSeen) {}
52 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
53 unsigned SectionID,
54 StringRef SectionName,
55 bool IsReadOnly) override {
56 if (SectionName == ".debug_str")
57 DebugSeen = true;
58 return SectionMemoryManager::allocateDataSection(Size, Alignment,
59 SectionID,
60 SectionName,
61 IsReadOnly);
62 }
63 private:
64 bool &DebugSeen;
65 };
66
67 bool DebugSectionSeen = false;
68 auto MM = std::make_shared<MemoryManagerWrapper>(DebugSectionSeen);
69
70 ExecutionSession ES(std::make_shared<SymbolStringPool>());
71
72 RTDyldObjectLinkingLayer ObjLayer(ES, [&MM](VModuleKey) {
73 return RTDyldObjectLinkingLayer::Resources{
74 MM, std::make_shared<NullResolver>()};
75 });
76
77 LLVMContext Context;
78 auto M = llvm::make_unique<Module>("", Context);
79 M->setTargetTriple("x86_64-unknown-linux-gnu");
80 Type *Int32Ty = IntegerType::get(Context, 32);
81 GlobalVariable *GV =
82 new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage,
83 ConstantInt::get(Int32Ty, 42), "foo");
84
85 GV->setSection(".debug_str");
86
87
88 // Initialize the native target in case this is the first unit test
89 // to try to build a TM.
90 OrcNativeTarget::initialize();
91 std::unique_ptr<TargetMachine> TM(
92 EngineBuilder().selectTarget(Triple(M->getTargetTriple()), "", "",
93 SmallVector<std::string, 1>()));
94 if (!TM)
95 return;
96
97 auto Obj = SimpleCompiler(*TM)(*M);
98
99 {
100 // Test with ProcessAllSections = false (the default).
101 auto K = ES.allocateVModule();
102 cantFail(ObjLayer.addObject(
103 K, MemoryBuffer::getMemBufferCopy(Obj->getBuffer())));
104 cantFail(ObjLayer.emitAndFinalize(K));
105 EXPECT_EQ(DebugSectionSeen, false)
106 << "Unexpected debug info section";
107 cantFail(ObjLayer.removeObject(K));
108 }
109
110 {
111 // Test with ProcessAllSections = true.
112 ObjLayer.setProcessAllSections(true);
113 auto K = ES.allocateVModule();
114 cantFail(ObjLayer.addObject(K, std::move(Obj)));
115 cantFail(ObjLayer.emitAndFinalize(K));
116 EXPECT_EQ(DebugSectionSeen, true)
117 << "Expected debug info section not seen";
118 cantFail(ObjLayer.removeObject(K));
119 }
120 }
121
TEST_F(RTDyldObjectLinkingLayerExecutionTest,NoDuplicateFinalization)122 TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
123 if (!SupportsJIT)
124 return;
125
126 ExecutionSession ES(std::make_shared<SymbolStringPool>());
127
128 auto MM = std::make_shared<SectionMemoryManagerWrapper>();
129
130 std::map<orc::VModuleKey, std::shared_ptr<orc::SymbolResolver>> Resolvers;
131
132 RTDyldObjectLinkingLayer ObjLayer(ES, [&](VModuleKey K) {
133 auto I = Resolvers.find(K);
134 assert(I != Resolvers.end() && "Missing resolver");
135 auto R = std::move(I->second);
136 Resolvers.erase(I);
137 return RTDyldObjectLinkingLayer::Resources{MM, std::move(R)};
138 });
139 SimpleCompiler Compile(*TM);
140
141 // Create a pair of modules that will trigger recursive finalization:
142 // Module 1:
143 // int bar() { return 42; }
144 // Module 2:
145 // int bar();
146 // int foo() { return bar(); }
147 //
148 // Verify that the memory manager is only finalized once (for Module 2).
149 // Failure suggests that finalize is being called on the inner RTDyld
150 // instance (for Module 1) which is unsafe, as it will prevent relocation of
151 // Module 2.
152
153 ModuleBuilder MB1(Context, "", "dummy");
154 {
155 MB1.getModule()->setDataLayout(TM->createDataLayout());
156 Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("bar");
157 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
158 IRBuilder<> Builder(BarEntry);
159 IntegerType *Int32Ty = IntegerType::get(Context, 32);
160 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
161 Builder.CreateRet(FourtyTwo);
162 }
163
164 auto Obj1 = Compile(*MB1.getModule());
165
166 ModuleBuilder MB2(Context, "", "dummy");
167 {
168 MB2.getModule()->setDataLayout(TM->createDataLayout());
169 Function *BarDecl = MB2.createFunctionDecl<int32_t(void)>("bar");
170 Function *FooImpl = MB2.createFunctionDecl<int32_t(void)>("foo");
171 BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl);
172 IRBuilder<> Builder(FooEntry);
173 Builder.CreateRet(Builder.CreateCall(BarDecl));
174 }
175 auto Obj2 = Compile(*MB2.getModule());
176
177 auto K1 = ES.allocateVModule();
178 Resolvers[K1] = std::make_shared<NullResolver>();
179 cantFail(ObjLayer.addObject(K1, std::move(Obj1)));
180
181 auto K2 = ES.allocateVModule();
182 auto LegacyLookup = [&](const std::string &Name) {
183 return ObjLayer.findSymbol(Name, true);
184 };
185
186 Resolvers[K2] = createSymbolResolver(
187 [&](const SymbolNameSet &Symbols) {
188 return cantFail(lookupFlagsWithLegacyFn(Symbols, LegacyLookup));
189 },
190 [&](std::shared_ptr<AsynchronousSymbolQuery> Query,
191 const SymbolNameSet &Symbols) {
192 return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
193 });
194
195 cantFail(ObjLayer.addObject(K2, std::move(Obj2)));
196 cantFail(ObjLayer.emitAndFinalize(K2));
197 cantFail(ObjLayer.removeObject(K2));
198
199 // Finalization of module 2 should trigger finalization of module 1.
200 // Verify that finalize on SMMW is only called once.
201 EXPECT_EQ(MM->FinalizationCount, 1)
202 << "Extra call to finalize";
203 }
204
TEST_F(RTDyldObjectLinkingLayerExecutionTest,NoPrematureAllocation)205 TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
206 if (!SupportsJIT)
207 return;
208
209 ExecutionSession ES(std::make_shared<SymbolStringPool>());
210
211 auto MM = std::make_shared<SectionMemoryManagerWrapper>();
212
213 RTDyldObjectLinkingLayer ObjLayer(ES, [&MM](VModuleKey K) {
214 return RTDyldObjectLinkingLayer::Resources{
215 MM, std::make_shared<NullResolver>()};
216 });
217 SimpleCompiler Compile(*TM);
218
219 // Create a pair of unrelated modules:
220 //
221 // Module 1:
222 // int foo() { return 42; }
223 // Module 2:
224 // int bar() { return 7; }
225 //
226 // Both modules will share a memory manager. We want to verify that the
227 // second object is not loaded before the first one is finalized. To do this
228 // in a portable way, we abuse the
229 // RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is
230 // called once per object before any sections are allocated.
231
232 ModuleBuilder MB1(Context, "", "dummy");
233 {
234 MB1.getModule()->setDataLayout(TM->createDataLayout());
235 Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("foo");
236 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
237 IRBuilder<> Builder(BarEntry);
238 IntegerType *Int32Ty = IntegerType::get(Context, 32);
239 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
240 Builder.CreateRet(FourtyTwo);
241 }
242
243 auto Obj1 = Compile(*MB1.getModule());
244
245 ModuleBuilder MB2(Context, "", "dummy");
246 {
247 MB2.getModule()->setDataLayout(TM->createDataLayout());
248 Function *BarImpl = MB2.createFunctionDecl<int32_t(void)>("bar");
249 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
250 IRBuilder<> Builder(BarEntry);
251 IntegerType *Int32Ty = IntegerType::get(Context, 32);
252 Value *Seven = ConstantInt::getSigned(Int32Ty, 7);
253 Builder.CreateRet(Seven);
254 }
255 auto Obj2 = Compile(*MB2.getModule());
256
257 auto K = ES.allocateVModule();
258 cantFail(ObjLayer.addObject(K, std::move(Obj1)));
259 cantFail(ObjLayer.addObject(ES.allocateVModule(), std::move(Obj2)));
260 cantFail(ObjLayer.emitAndFinalize(K));
261 cantFail(ObjLayer.removeObject(K));
262
263 // Only one call to needsToReserveAllocationSpace should have been made.
264 EXPECT_EQ(MM->NeedsToReserveAllocationSpaceCount, 1)
265 << "More than one call to needsToReserveAllocationSpace "
266 "(multiple unrelated objects loaded prior to finalization)";
267 }
268
TEST_F(RTDyldObjectLinkingLayerExecutionTest,TestNotifyLoadedSignature)269 TEST_F(RTDyldObjectLinkingLayerExecutionTest, TestNotifyLoadedSignature) {
270 ExecutionSession ES(std::make_shared<SymbolStringPool>());
271 RTDyldObjectLinkingLayer ObjLayer(
272 ES,
273 [](VModuleKey) {
274 return RTDyldObjectLinkingLayer::Resources{
275 nullptr, std::make_shared<NullResolver>()};
276 },
277 [](VModuleKey, const object::ObjectFile &obj,
278 const RuntimeDyld::LoadedObjectInfo &info) {});
279 }
280
281 } // end anonymous namespace
282