1 //===- RTDyldObjectLinkingLayerTest.cpp - RTDyld linking layer unit tests -===//
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
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"
22 using namespace llvm::orc
;
26 class LegacyRTDyldObjectLinkingLayerExecutionTest
: public testing::Test
,
27 public OrcExecutionTest
{
31 class SectionMemoryManagerWrapper
: public SectionMemoryManager
{
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
{
43 return SectionMemoryManager::finalizeMemory(ErrMsg
);
47 TEST(LegacyRTDyldObjectLinkingLayerTest
, TestSetProcessAllSections
) {
48 class MemoryManagerWrapper
: public SectionMemoryManager
{
50 MemoryManagerWrapper(bool &DebugSeen
) : DebugSeen(DebugSeen
) {}
51 uint8_t *allocateDataSection(uintptr_t Size
, unsigned Alignment
,
53 StringRef SectionName
,
54 bool IsReadOnly
) override
{
55 if (SectionName
== ".debug_str")
57 return SectionMemoryManager::allocateDataSection(Size
, Alignment
,
66 bool DebugSectionSeen
= false;
67 auto MM
= std::make_shared
<MemoryManagerWrapper
>(DebugSectionSeen
);
71 LegacyRTDyldObjectLinkingLayer
ObjLayer(
72 AcknowledgeORCv1Deprecation
, ES
, [&MM
](VModuleKey
) {
73 return LegacyRTDyldObjectLinkingLayer::Resources
{
74 MM
, std::make_shared
<NullResolver
>()};
78 auto M
= std::make_unique
<Module
>("", Context
);
79 M
->setTargetTriple("x86_64-unknown-linux-gnu");
80 Type
*Int32Ty
= IntegerType::get(Context
, 32);
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>()));
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
) {
126 Type
*Int32Ty
= IntegerType::get(Context
, 32);
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
);
140 return LegacyRTDyldObjectLinkingLayer::Resources
{MM
, std::move(R
)};
142 SimpleCompiler
Compile(*TM
);
144 // Create a pair of modules that will trigger recursive finalization:
146 // int bar() { return 42; }
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
156 ModuleBuilder
MB1(Context
, "", "dummy");
158 MB1
.getModule()->setDataLayout(TM
->createDataLayout());
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());
174 MB2
.createFunctionDecl(FunctionType::get(Int32Ty
, {}, false), "bar");
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
) {
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
) {
216 Type
*Int32Ty
= IntegerType::get(Context
, 32);
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:
232 // int foo() { return 42; }
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());
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());
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
) {
283 LegacyRTDyldObjectLinkingLayer
ObjLayer(
284 AcknowledgeORCv1Deprecation
, ES
,
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