blob: 3f0f85b69a71d1e82814c4dba90ad7ed1bc4a2cf [file] [log] [blame]
Lang Hames079df9a2018-10-15 22:56:10 +00001//===- RTDyldObjectLinkingLayerTest.cpp - RTDyld linking layer unit tests -===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Lang Hames079df9a2018-10-15 22:56:10 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
10#include "OrcTestCommon.h"
11#include "llvm/ExecutionEngine/ExecutionEngine.h"
12#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
13#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
14#include "llvm/ExecutionEngine/Orc/Legacy.h"
15#include "llvm/ExecutionEngine/Orc/NullResolver.h"
16#include "llvm/ExecutionEngine/SectionMemoryManager.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
26class LegacyRTDyldObjectLinkingLayerExecutionTest : public testing::Test,
27 public OrcExecutionTest {
28
29};
30
31class SectionMemoryManagerWrapper : public SectionMemoryManager {
32public:
33 int FinalizationCount = 0;
34 int NeedsToReserveAllocationSpaceCount = 0;
35
36 bool needsToReserveAllocationSpace() override {
37 ++NeedsToReserveAllocationSpaceCount;
38 return SectionMemoryManager::needsToReserveAllocationSpace();
39 }
40
41 bool finalizeMemory(std::string *ErrMsg = nullptr) override {
42 ++FinalizationCount;
43 return SectionMemoryManager::finalizeMemory(ErrMsg);
44 }
45};
46
47TEST(LegacyRTDyldObjectLinkingLayerTest, TestSetProcessAllSections) {
48 class MemoryManagerWrapper : public SectionMemoryManager {
49 public:
50 MemoryManagerWrapper(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 bool DebugSectionSeen = false;
67 auto MM = std::make_shared<MemoryManagerWrapper>(DebugSectionSeen);
68
69 ExecutionSession ES;
70
Lang Hames17164542019-07-17 16:40:52 +000071 LegacyRTDyldObjectLinkingLayer ObjLayer(
72 AcknowledgeORCv1Deprecation, ES, [&MM](VModuleKey) {
73 return LegacyRTDyldObjectLinkingLayer::Resources{
74 MM, std::make_shared<NullResolver>()};
75 });
Lang Hames079df9a2018-10-15 22:56:10 +000076
77 LLVMContext Context;
Jonas Devlieghere0eaee542019-08-15 15:54:37 +000078 auto M = std::make_unique<Module>("", Context);
Lang Hames079df9a2018-10-15 22:56:10 +000079 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
122TEST_F(LegacyRTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
123 if (!SupportsJIT)
124 return;
125
James Y Knightc0044112019-01-13 16:09:28 +0000126 Type *Int32Ty = IntegerType::get(Context, 32);
127
Lang Hames079df9a2018-10-15 22:56:10 +0000128 ExecutionSession ES;
129
130 auto MM = std::make_shared<SectionMemoryManagerWrapper>();
131
132 std::map<orc::VModuleKey, std::shared_ptr<orc::SymbolResolver>> Resolvers;
133
Lang Hames17164542019-07-17 16:40:52 +0000134 LegacyRTDyldObjectLinkingLayer ObjLayer(
135 AcknowledgeORCv1Deprecation, ES, [&](VModuleKey K) {
136 auto I = Resolvers.find(K);
137 assert(I != Resolvers.end() && "Missing resolver");
138 auto R = std::move(I->second);
139 Resolvers.erase(I);
140 return LegacyRTDyldObjectLinkingLayer::Resources{MM, std::move(R)};
141 });
Lang Hames079df9a2018-10-15 22:56:10 +0000142 SimpleCompiler Compile(*TM);
143
144 // Create a pair of modules that will trigger recursive finalization:
145 // Module 1:
146 // int bar() { return 42; }
147 // Module 2:
148 // int bar();
149 // int foo() { return bar(); }
150 //
151 // Verify that the memory manager is only finalized once (for Module 2).
152 // Failure suggests that finalize is being called on the inner RTDyld
153 // instance (for Module 1) which is unsafe, as it will prevent relocation of
154 // Module 2.
155
156 ModuleBuilder MB1(Context, "", "dummy");
157 {
158 MB1.getModule()->setDataLayout(TM->createDataLayout());
James Y Knightc0044112019-01-13 16:09:28 +0000159 Function *BarImpl =
160 MB1.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "bar");
Lang Hames079df9a2018-10-15 22:56:10 +0000161 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
162 IRBuilder<> Builder(BarEntry);
163 IntegerType *Int32Ty = IntegerType::get(Context, 32);
164 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
165 Builder.CreateRet(FourtyTwo);
166 }
167
168 auto Obj1 = Compile(*MB1.getModule());
169
170 ModuleBuilder MB2(Context, "", "dummy");
171 {
172 MB2.getModule()->setDataLayout(TM->createDataLayout());
James Y Knightc0044112019-01-13 16:09:28 +0000173 Function *BarDecl =
174 MB2.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "bar");
175 Function *FooImpl =
176 MB2.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "foo");
Lang Hames079df9a2018-10-15 22:56:10 +0000177 BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl);
178 IRBuilder<> Builder(FooEntry);
179 Builder.CreateRet(Builder.CreateCall(BarDecl));
180 }
181 auto Obj2 = Compile(*MB2.getModule());
182
183 auto K1 = ES.allocateVModule();
184 Resolvers[K1] = std::make_shared<NullResolver>();
185 cantFail(ObjLayer.addObject(K1, std::move(Obj1)));
186
187 auto K2 = ES.allocateVModule();
188 auto LegacyLookup = [&](const std::string &Name) {
189 return ObjLayer.findSymbol(Name, true);
190 };
191
192 Resolvers[K2] = createSymbolResolver(
193 [&](const SymbolNameSet &Symbols) {
194 return cantFail(
195 getResponsibilitySetWithLegacyFn(Symbols, LegacyLookup));
196 },
197 [&](std::shared_ptr<AsynchronousSymbolQuery> Query,
198 const SymbolNameSet &Symbols) {
199 return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
200 });
201
202 cantFail(ObjLayer.addObject(K2, std::move(Obj2)));
203 cantFail(ObjLayer.emitAndFinalize(K2));
204 cantFail(ObjLayer.removeObject(K2));
205
206 // Finalization of module 2 should trigger finalization of module 1.
207 // Verify that finalize on SMMW is only called once.
208 EXPECT_EQ(MM->FinalizationCount, 1)
209 << "Extra call to finalize";
210}
211
212TEST_F(LegacyRTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
213 if (!SupportsJIT)
214 return;
215
James Y Knightc0044112019-01-13 16:09:28 +0000216 Type *Int32Ty = IntegerType::get(Context, 32);
217
Lang Hames079df9a2018-10-15 22:56:10 +0000218 ExecutionSession ES;
219
220 auto MM = std::make_shared<SectionMemoryManagerWrapper>();
221
Lang Hames17164542019-07-17 16:40:52 +0000222 LegacyRTDyldObjectLinkingLayer ObjLayer(
223 AcknowledgeORCv1Deprecation, ES, [&MM](VModuleKey K) {
224 return LegacyRTDyldObjectLinkingLayer::Resources{
225 MM, std::make_shared<NullResolver>()};
226 });
Lang Hames079df9a2018-10-15 22:56:10 +0000227 SimpleCompiler Compile(*TM);
228
229 // Create a pair of unrelated modules:
230 //
231 // Module 1:
232 // int foo() { return 42; }
233 // Module 2:
234 // int bar() { return 7; }
235 //
236 // Both modules will share a memory manager. We want to verify that the
237 // second object is not loaded before the first one is finalized. To do this
238 // in a portable way, we abuse the
239 // RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is
240 // called once per object before any sections are allocated.
241
242 ModuleBuilder MB1(Context, "", "dummy");
243 {
244 MB1.getModule()->setDataLayout(TM->createDataLayout());
James Y Knightc0044112019-01-13 16:09:28 +0000245 Function *BarImpl =
246 MB1.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "foo");
Lang Hames079df9a2018-10-15 22:56:10 +0000247 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
248 IRBuilder<> Builder(BarEntry);
249 IntegerType *Int32Ty = IntegerType::get(Context, 32);
250 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
251 Builder.CreateRet(FourtyTwo);
252 }
253
254 auto Obj1 = Compile(*MB1.getModule());
255
256 ModuleBuilder MB2(Context, "", "dummy");
257 {
258 MB2.getModule()->setDataLayout(TM->createDataLayout());
James Y Knightc0044112019-01-13 16:09:28 +0000259 Function *BarImpl =
260 MB2.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "bar");
Lang Hames079df9a2018-10-15 22:56:10 +0000261 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
262 IRBuilder<> Builder(BarEntry);
263 IntegerType *Int32Ty = IntegerType::get(Context, 32);
264 Value *Seven = ConstantInt::getSigned(Int32Ty, 7);
265 Builder.CreateRet(Seven);
266 }
267 auto Obj2 = Compile(*MB2.getModule());
268
269 auto K = ES.allocateVModule();
270 cantFail(ObjLayer.addObject(K, std::move(Obj1)));
271 cantFail(ObjLayer.addObject(ES.allocateVModule(), std::move(Obj2)));
272 cantFail(ObjLayer.emitAndFinalize(K));
273 cantFail(ObjLayer.removeObject(K));
274
275 // Only one call to needsToReserveAllocationSpace should have been made.
276 EXPECT_EQ(MM->NeedsToReserveAllocationSpaceCount, 1)
277 << "More than one call to needsToReserveAllocationSpace "
278 "(multiple unrelated objects loaded prior to finalization)";
279}
280
281TEST_F(LegacyRTDyldObjectLinkingLayerExecutionTest, TestNotifyLoadedSignature) {
282 ExecutionSession ES;
283 LegacyRTDyldObjectLinkingLayer ObjLayer(
Lang Hames17164542019-07-17 16:40:52 +0000284 AcknowledgeORCv1Deprecation, ES,
Lang Hames079df9a2018-10-15 22:56:10 +0000285 [](VModuleKey) {
286 return LegacyRTDyldObjectLinkingLayer::Resources{
287 nullptr, std::make_shared<NullResolver>()};
288 },
289 [](VModuleKey, const object::ObjectFile &obj,
290 const RuntimeDyld::LoadedObjectInfo &info) {});
291}
292
293} // end anonymous namespace