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 37 bool needsToReserveAllocationSpace() override { 38 ++NeedsToReserveAllocationSpaceCount; 39 return SectionMemoryManager::needsToReserveAllocationSpace(); 40 } 41 42 bool finalizeMemory(std::string *ErrMsg = nullptr) override { 43 ++FinalizationCount; 44 return SectionMemoryManager::finalizeMemory(ErrMsg); 45 } 46 }; 47 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; 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 122 TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoDuplicateFinalization) { 123 if (!SupportsJIT) 124 return; 125 126 ExecutionSession ES; 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( 189 getResponsibilitySetWithLegacyFn(Symbols, LegacyLookup)); 190 }, 191 [&](std::shared_ptr<AsynchronousSymbolQuery> Query, 192 const SymbolNameSet &Symbols) { 193 return lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup); 194 }); 195 196 cantFail(ObjLayer.addObject(K2, std::move(Obj2))); 197 cantFail(ObjLayer.emitAndFinalize(K2)); 198 cantFail(ObjLayer.removeObject(K2)); 199 200 // Finalization of module 2 should trigger finalization of module 1. 201 // Verify that finalize on SMMW is only called once. 202 EXPECT_EQ(MM->FinalizationCount, 1) 203 << "Extra call to finalize"; 204 } 205 206 TEST_F(RTDyldObjectLinkingLayerExecutionTest, NoPrematureAllocation) { 207 if (!SupportsJIT) 208 return; 209 210 ExecutionSession ES; 211 212 auto MM = std::make_shared<SectionMemoryManagerWrapper>(); 213 214 RTDyldObjectLinkingLayer ObjLayer(ES, [&MM](VModuleKey K) { 215 return RTDyldObjectLinkingLayer::Resources{ 216 MM, std::make_shared<NullResolver>()}; 217 }); 218 SimpleCompiler Compile(*TM); 219 220 // Create a pair of unrelated modules: 221 // 222 // Module 1: 223 // int foo() { return 42; } 224 // Module 2: 225 // int bar() { return 7; } 226 // 227 // Both modules will share a memory manager. We want to verify that the 228 // second object is not loaded before the first one is finalized. To do this 229 // in a portable way, we abuse the 230 // RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is 231 // called once per object before any sections are allocated. 232 233 ModuleBuilder MB1(Context, "", "dummy"); 234 { 235 MB1.getModule()->setDataLayout(TM->createDataLayout()); 236 Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("foo"); 237 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); 238 IRBuilder<> Builder(BarEntry); 239 IntegerType *Int32Ty = IntegerType::get(Context, 32); 240 Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42); 241 Builder.CreateRet(FourtyTwo); 242 } 243 244 auto Obj1 = Compile(*MB1.getModule()); 245 246 ModuleBuilder MB2(Context, "", "dummy"); 247 { 248 MB2.getModule()->setDataLayout(TM->createDataLayout()); 249 Function *BarImpl = MB2.createFunctionDecl<int32_t(void)>("bar"); 250 BasicBlock *BarEntry = BasicBlock::Create(Context, "entry", BarImpl); 251 IRBuilder<> Builder(BarEntry); 252 IntegerType *Int32Ty = IntegerType::get(Context, 32); 253 Value *Seven = ConstantInt::getSigned(Int32Ty, 7); 254 Builder.CreateRet(Seven); 255 } 256 auto Obj2 = Compile(*MB2.getModule()); 257 258 auto K = ES.allocateVModule(); 259 cantFail(ObjLayer.addObject(K, std::move(Obj1))); 260 cantFail(ObjLayer.addObject(ES.allocateVModule(), std::move(Obj2))); 261 cantFail(ObjLayer.emitAndFinalize(K)); 262 cantFail(ObjLayer.removeObject(K)); 263 264 // Only one call to needsToReserveAllocationSpace should have been made. 265 EXPECT_EQ(MM->NeedsToReserveAllocationSpaceCount, 1) 266 << "More than one call to needsToReserveAllocationSpace " 267 "(multiple unrelated objects loaded prior to finalization)"; 268 } 269 270 TEST_F(RTDyldObjectLinkingLayerExecutionTest, TestNotifyLoadedSignature) { 271 ExecutionSession ES; 272 RTDyldObjectLinkingLayer ObjLayer( 273 ES, 274 [](VModuleKey) { 275 return RTDyldObjectLinkingLayer::Resources{ 276 nullptr, std::make_shared<NullResolver>()}; 277 }, 278 [](VModuleKey, const object::ObjectFile &obj, 279 const RuntimeDyld::LoadedObjectInfo &info) {}); 280 } 281 282 } // end anonymous namespace 283