• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- ObjectLinkingLayerTest.cpp - Unit tests for object linking layer --===//
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 "OrcTestCommon.h"
11 #include "llvm/ExecutionEngine/ExecutionEngine.h"
12 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
13 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
14 #include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
15 #include "llvm/ExecutionEngine/Orc/NullResolver.h"
16 #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
17 #include "llvm/IR/Constants.h"
18 #include "llvm/IR/LLVMContext.h"
19 #include "gtest/gtest.h"
20 
21 using namespace llvm;
22 using namespace llvm::orc;
23 
24 namespace {
25 
26 class ObjectLinkingLayerExecutionTest : public testing::Test,
27                                         public OrcExecutionTest {
28 
29 };
30 
31 class SectionMemoryManagerWrapper : public SectionMemoryManager {
32 public:
33   int FinalizationCount = 0;
34   int NeedsToReserveAllocationSpaceCount = 0;
35 
needsToReserveAllocationSpace()36   bool needsToReserveAllocationSpace() override {
37     ++NeedsToReserveAllocationSpaceCount;
38     return SectionMemoryManager::needsToReserveAllocationSpace();
39   }
40 
finalizeMemory(std::string * ErrMsg=nullptr)41   bool finalizeMemory(std::string *ErrMsg = nullptr) override {
42     ++FinalizationCount;
43     return SectionMemoryManager::finalizeMemory(ErrMsg);
44   }
45 };
46 
TEST(ObjectLinkingLayerTest,TestSetProcessAllSections)47 TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) {
48   class SectionMemoryManagerWrapper : public SectionMemoryManager {
49   public:
50     SectionMemoryManagerWrapper(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   ObjectLinkingLayer<> ObjLayer;
67 
68   LLVMContext Context;
69   auto M = llvm::make_unique<Module>("", Context);
70   M->setTargetTriple("x86_64-unknown-linux-gnu");
71   Type *Int32Ty = IntegerType::get(Context, 32);
72   GlobalVariable *GV =
73     new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage,
74                          ConstantInt::get(Int32Ty, 42), "foo");
75 
76   GV->setSection(".debug_str");
77 
78   std::unique_ptr<TargetMachine> TM(
79     EngineBuilder().selectTarget(Triple(M->getTargetTriple()), "", "",
80                                  SmallVector<std::string, 1>()));
81   if (!TM)
82     return;
83 
84   auto OwningObj = SimpleCompiler(*TM)(*M);
85   std::vector<object::ObjectFile*> Objs;
86   Objs.push_back(OwningObj.getBinary());
87 
88   bool DebugSectionSeen = false;
89   SectionMemoryManagerWrapper SMMW(DebugSectionSeen);
90   auto Resolver =
91     createLambdaResolver(
92       [](const std::string &Name) {
93         return RuntimeDyld::SymbolInfo(nullptr);
94       },
95       [](const std::string &Name) {
96         return RuntimeDyld::SymbolInfo(nullptr);
97       });
98 
99   {
100     // Test with ProcessAllSections = false (the default).
101     auto H = ObjLayer.addObjectSet(Objs, &SMMW, &*Resolver);
102     EXPECT_EQ(DebugSectionSeen, false)
103       << "Unexpected debug info section";
104     ObjLayer.removeObjectSet(H);
105   }
106 
107   {
108     // Test with ProcessAllSections = true.
109     ObjLayer.setProcessAllSections(true);
110     auto H = ObjLayer.addObjectSet(Objs, &SMMW, &*Resolver);
111     EXPECT_EQ(DebugSectionSeen, true)
112       << "Expected debug info section not seen";
113     ObjLayer.removeObjectSet(H);
114   }
115 }
116 
TEST_F(ObjectLinkingLayerExecutionTest,NoDuplicateFinalization)117 TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
118   if (!TM)
119     return;
120 
121   ObjectLinkingLayer<> ObjLayer;
122   SimpleCompiler Compile(*TM);
123 
124   // Create a pair of modules that will trigger recursive finalization:
125   // Module 1:
126   //   int bar() { return 42; }
127   // Module 2:
128   //   int bar();
129   //   int foo() { return bar(); }
130   //
131   // Verify that the memory manager is only finalized once (for Module 2).
132   // Failure suggests that finalize is being called on the inner RTDyld
133   // instance (for Module 1) which is unsafe, as it will prevent relocation of
134   // Module 2.
135 
136   ModuleBuilder MB1(Context, "", "dummy");
137   {
138     MB1.getModule()->setDataLayout(TM->createDataLayout());
139     Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("bar");
140     BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
141     IRBuilder<> Builder(BarEntry);
142     IntegerType *Int32Ty = IntegerType::get(Context, 32);
143     Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
144     Builder.CreateRet(FourtyTwo);
145   }
146 
147   auto Obj1 = Compile(*MB1.getModule());
148   std::vector<object::ObjectFile*> Obj1Set;
149   Obj1Set.push_back(Obj1.getBinary());
150 
151   ModuleBuilder MB2(Context, "", "dummy");
152   {
153     MB2.getModule()->setDataLayout(TM->createDataLayout());
154     Function *BarDecl = MB2.createFunctionDecl<int32_t(void)>("bar");
155     Function *FooImpl = MB2.createFunctionDecl<int32_t(void)>("foo");
156     BasicBlock *FooEntry = BasicBlock::Create(Context, "entry", FooImpl);
157     IRBuilder<> Builder(FooEntry);
158     Builder.CreateRet(Builder.CreateCall(BarDecl));
159   }
160   auto Obj2 = Compile(*MB2.getModule());
161   std::vector<object::ObjectFile*> Obj2Set;
162   Obj2Set.push_back(Obj2.getBinary());
163 
164   auto Resolver =
165     createLambdaResolver(
166       [&](const std::string &Name) {
167         if (auto Sym = ObjLayer.findSymbol(Name, true))
168           return Sym.toRuntimeDyldSymbol();
169         return RuntimeDyld::SymbolInfo(nullptr);
170       },
171       [](const std::string &Name) {
172         return RuntimeDyld::SymbolInfo(nullptr);
173       });
174 
175   SectionMemoryManagerWrapper SMMW;
176   ObjLayer.addObjectSet(std::move(Obj1Set), &SMMW, &*Resolver);
177   auto H = ObjLayer.addObjectSet(std::move(Obj2Set), &SMMW, &*Resolver);
178   ObjLayer.emitAndFinalize(H);
179 
180   // Finalization of module 2 should trigger finalization of module 1.
181   // Verify that finalize on SMMW is only called once.
182   EXPECT_EQ(SMMW.FinalizationCount, 1)
183       << "Extra call to finalize";
184 }
185 
TEST_F(ObjectLinkingLayerExecutionTest,NoPrematureAllocation)186 TEST_F(ObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
187   if (!TM)
188     return;
189 
190   ObjectLinkingLayer<> ObjLayer;
191   SimpleCompiler Compile(*TM);
192 
193   // Create a pair of unrelated modules:
194   //
195   // Module 1:
196   //   int foo() { return 42; }
197   // Module 2:
198   //   int bar() { return 7; }
199   //
200   // Both modules will share a memory manager. We want to verify that the
201   // second object is not loaded before the first one is finalized. To do this
202   // in a portable way, we abuse the
203   // RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is
204   // called once per object before any sections are allocated.
205 
206   ModuleBuilder MB1(Context, "", "dummy");
207   {
208     MB1.getModule()->setDataLayout(TM->createDataLayout());
209     Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("foo");
210     BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
211     IRBuilder<> Builder(BarEntry);
212     IntegerType *Int32Ty = IntegerType::get(Context, 32);
213     Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
214     Builder.CreateRet(FourtyTwo);
215   }
216 
217   auto Obj1 = Compile(*MB1.getModule());
218   std::vector<object::ObjectFile*> Obj1Set;
219   Obj1Set.push_back(Obj1.getBinary());
220 
221   ModuleBuilder MB2(Context, "", "dummy");
222   {
223     MB2.getModule()->setDataLayout(TM->createDataLayout());
224     Function *BarImpl = MB2.createFunctionDecl<int32_t(void)>("bar");
225     BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl);
226     IRBuilder<> Builder(BarEntry);
227     IntegerType *Int32Ty = IntegerType::get(Context, 32);
228     Value *Seven = ConstantInt::getSigned(Int32Ty, 7);
229     Builder.CreateRet(Seven);
230   }
231   auto Obj2 = Compile(*MB2.getModule());
232   std::vector<object::ObjectFile*> Obj2Set;
233   Obj2Set.push_back(Obj2.getBinary());
234 
235   SectionMemoryManagerWrapper SMMW;
236   NullResolver NR;
237   auto H = ObjLayer.addObjectSet(std::move(Obj1Set), &SMMW, &NR);
238   ObjLayer.addObjectSet(std::move(Obj2Set), &SMMW, &NR);
239   ObjLayer.emitAndFinalize(H);
240 
241   // Only one call to needsToReserveAllocationSpace should have been made.
242   EXPECT_EQ(SMMW.NeedsToReserveAllocationSpaceCount, 1)
243       << "More than one call to needsToReserveAllocationSpace "
244          "(multiple unrelated objects loaded prior to finalization)";
245 }
246 
247 } // end anonymous namespace
248