• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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