[llvm] [cmake] Add possibility to use ChooseMSVCCRT.cmake when include LLVM library
[llvm-core.git] / unittests / ExecutionEngine / Orc / LegacyRTDyldObjectLinkingLayerTest.cpp
blob3f0f85b69a71d1e82814c4dba90ad7ed1bc4a2cf
1 //===- RTDyldObjectLinkingLayerTest.cpp - RTDyld linking layer unit tests -===//
2 //
3 // 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
6 //
7 //===----------------------------------------------------------------------===//
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"
21 using namespace llvm;
22 using namespace llvm::orc;
24 namespace {
26 class LegacyRTDyldObjectLinkingLayerExecutionTest : public testing::Test,
27 public OrcExecutionTest {
31 class SectionMemoryManagerWrapper : public SectionMemoryManager {
32 public:
33 int FinalizationCount = 0;
34 int NeedsToReserveAllocationSpaceCount = 0;
36 bool needsToReserveAllocationSpace() override {
37 ++NeedsToReserveAllocationSpaceCount;
38 return SectionMemoryManager::needsToReserveAllocationSpace();
41 bool finalizeMemory(std::string *ErrMsg = nullptr) override {
42 ++FinalizationCount;
43 return SectionMemoryManager::finalizeMemory(ErrMsg);
47 TEST(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);
62 private:
63 bool &DebugSeen;
66 bool DebugSectionSeen = false;
67 auto MM = std::make_shared<MemoryManagerWrapper>(DebugSectionSeen);
69 ExecutionSession ES;
71 LegacyRTDyldObjectLinkingLayer ObjLayer(
72 AcknowledgeORCv1Deprecation, ES, [&MM](VModuleKey) {
73 return LegacyRTDyldObjectLinkingLayer::Resources{
74 MM, std::make_shared<NullResolver>()};
75 });
77 LLVMContext Context;
78 auto M = std::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");
85 GV->setSection(".debug_str");
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;
97 auto Obj = SimpleCompiler(*TM)(*M);
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));
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));
122 TEST_F(LegacyRTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
123 if (!SupportsJIT)
124 return;
126 Type *Int32Ty = IntegerType::get(Context, 32);
128 ExecutionSession ES;
130 auto MM = std::make_shared<SectionMemoryManagerWrapper>();
132 std::map<orc::VModuleKey, std::shared_ptr<orc::SymbolResolver>> Resolvers;
134 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)};
142 SimpleCompiler Compile(*TM);
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(); }
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.
156 ModuleBuilder MB1(Context, "", "dummy");
158 MB1.getModule()->setDataLayout(TM->createDataLayout());
159 Function *BarImpl =
160 MB1.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "bar");
161 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);
168 auto Obj1 = Compile(*MB1.getModule());
170 ModuleBuilder MB2(Context, "", "dummy");
172 MB2.getModule()->setDataLayout(TM->createDataLayout());
173 Function *BarDecl =
174 MB2.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "bar");
175 Function *FooImpl =
176 MB2.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "foo");
177 BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl);
178 IRBuilder<> Builder(FooEntry);
179 Builder.CreateRet(Builder.CreateCall(BarDecl));
181 auto Obj2 = Compile(*MB2.getModule());
183 auto K1 = ES.allocateVModule();
184 Resolvers[K1] = std::make_shared<NullResolver>();
185 cantFail(ObjLayer.addObject(K1, std::move(Obj1)));
187 auto K2 = ES.allocateVModule();
188 auto LegacyLookup = [&](const std::string &Name) {
189 return ObjLayer.findSymbol(Name, true);
192 Resolvers[K2] = createSymbolResolver(
193 [&](const SymbolNameSet &Symbols) {
194 return cantFail(
195 getResponsibilitySetWithLegacyFn(Symbols, LegacyLookup));
197 [&](std::shared_ptr<AsynchronousSymbolQuery> Query,
198 const SymbolNameSet &Symbols) {
199 return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
202 cantFail(ObjLayer.addObject(K2, std::move(Obj2)));
203 cantFail(ObjLayer.emitAndFinalize(K2));
204 cantFail(ObjLayer.removeObject(K2));
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";
212 TEST_F(LegacyRTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
213 if (!SupportsJIT)
214 return;
216 Type *Int32Ty = IntegerType::get(Context, 32);
218 ExecutionSession ES;
220 auto MM = std::make_shared<SectionMemoryManagerWrapper>();
222 LegacyRTDyldObjectLinkingLayer ObjLayer(
223 AcknowledgeORCv1Deprecation, ES, [&MM](VModuleKey K) {
224 return LegacyRTDyldObjectLinkingLayer::Resources{
225 MM, std::make_shared<NullResolver>()};
227 SimpleCompiler Compile(*TM);
229 // Create a pair of unrelated modules:
231 // Module 1:
232 // int foo() { return 42; }
233 // Module 2:
234 // int bar() { return 7; }
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.
242 ModuleBuilder MB1(Context, "", "dummy");
244 MB1.getModule()->setDataLayout(TM->createDataLayout());
245 Function *BarImpl =
246 MB1.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "foo");
247 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);
254 auto Obj1 = Compile(*MB1.getModule());
256 ModuleBuilder MB2(Context, "", "dummy");
258 MB2.getModule()->setDataLayout(TM->createDataLayout());
259 Function *BarImpl =
260 MB2.createFunctionDecl(FunctionType::get(Int32Ty, {}, false), "bar");
261 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);
267 auto Obj2 = Compile(*MB2.getModule());
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));
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)";
281 TEST_F(LegacyRTDyldObjectLinkingLayerExecutionTest, TestNotifyLoadedSignature) {
282 ExecutionSession ES;
283 LegacyRTDyldObjectLinkingLayer ObjLayer(
284 AcknowledgeORCv1Deprecation, ES,
285 [](VModuleKey) {
286 return LegacyRTDyldObjectLinkingLayer::Resources{
287 nullptr, std::make_shared<NullResolver>()};
289 [](VModuleKey, const object::ObjectFile &obj,
290 const RuntimeDyld::LoadedObjectInfo &info) {});
293 } // end anonymous namespace