123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- //===-- ObjectLinkingLayerTest.cpp - Unit tests for object linking layer --===//
- //
- // The LLVM Compiler Infrastructure
- //
- // This file is distributed under the University of Illinois Open Source
- // License. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- #include "OrcTestCommon.h"
- #include "llvm/ExecutionEngine/ExecutionEngine.h"
- #include "llvm/ExecutionEngine/SectionMemoryManager.h"
- #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
- #include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
- #include "llvm/ExecutionEngine/Orc/NullResolver.h"
- #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
- #include "llvm/IR/Constants.h"
- #include "llvm/IR/LLVMContext.h"
- #include "gtest/gtest.h"
- using namespace llvm;
- using namespace llvm::orc;
- namespace {
- class ObjectLinkingLayerExecutionTest : public testing::Test,
- public OrcExecutionTest {
- };
- class SectionMemoryManagerWrapper : public SectionMemoryManager {
- public:
- int FinalizationCount = 0;
- int NeedsToReserveAllocationSpaceCount = 0;
- bool needsToReserveAllocationSpace() override {
- ++NeedsToReserveAllocationSpaceCount;
- return SectionMemoryManager::needsToReserveAllocationSpace();
- }
- bool finalizeMemory(std::string *ErrMsg = nullptr) override {
- ++FinalizationCount;
- return SectionMemoryManager::finalizeMemory(ErrMsg);
- }
- };
- TEST(ObjectLinkingLayerTest, TestSetProcessAllSections) {
- class SectionMemoryManagerWrapper : public SectionMemoryManager {
- public:
- SectionMemoryManagerWrapper(bool &DebugSeen) : DebugSeen(DebugSeen) {}
- uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
- unsigned SectionID,
- StringRef SectionName,
- bool IsReadOnly) override {
- if (SectionName == ".debug_str")
- DebugSeen = true;
- return SectionMemoryManager::allocateDataSection(Size, Alignment,
- SectionID,
- SectionName,
- IsReadOnly);
- }
- private:
- bool DebugSeen;
- };
- ObjectLinkingLayer<> ObjLayer;
- auto M = llvm::make_unique<Module>("", getGlobalContext());
- M->setTargetTriple("x86_64-unknown-linux-gnu");
- Type *Int32Ty = IntegerType::get(getGlobalContext(), 32);
- GlobalVariable *GV =
- new GlobalVariable(*M, Int32Ty, false, GlobalValue::ExternalLinkage,
- ConstantInt::get(Int32Ty, 42), "foo");
- GV->setSection(".debug_str");
- std::unique_ptr<TargetMachine> TM(
- EngineBuilder().selectTarget(Triple(M->getTargetTriple()), "", "",
- SmallVector<std::string, 1>()));
- if (!TM)
- return;
- auto OwningObj = SimpleCompiler(*TM)(*M);
- std::vector<object::ObjectFile*> Objs;
- Objs.push_back(OwningObj.getBinary());
- bool DebugSectionSeen = false;
- SectionMemoryManagerWrapper SMMW(DebugSectionSeen);
- auto Resolver =
- createLambdaResolver(
- [](const std::string &Name) {
- return RuntimeDyld::SymbolInfo(nullptr);
- },
- [](const std::string &Name) {
- return RuntimeDyld::SymbolInfo(nullptr);
- });
- {
- // Test with ProcessAllSections = false (the default).
- auto H = ObjLayer.addObjectSet(Objs, &SMMW, &*Resolver);
- EXPECT_EQ(DebugSectionSeen, false)
- << "Unexpected debug info section";
- ObjLayer.removeObjectSet(H);
- }
- {
- // Test with ProcessAllSections = true.
- ObjLayer.setProcessAllSections(true);
- auto H = ObjLayer.addObjectSet(Objs, &SMMW, &*Resolver);
- EXPECT_EQ(DebugSectionSeen, true)
- << "Expected debug info section not seen";
- ObjLayer.removeObjectSet(H);
- }
- }
- TEST_F(ObjectLinkingLayerExecutionTest, NoDuplicateFinalization) {
- if (!TM)
- return;
- ObjectLinkingLayer<> ObjLayer;
- SimpleCompiler Compile(*TM);
- // Create a pair of modules that will trigger recursive finalization:
- // Module 1:
- // int bar() { return 42; }
- // Module 2:
- // int bar();
- // int foo() { return bar(); }
- //
- // Verify that the memory manager is only finalized once (for Module 2).
- // Failure suggests that finalize is being called on the inner RTDyld
- // instance (for Module 1) which is unsafe, as it will prevent relocation of
- // Module 2.
- ModuleBuilder MB1(getGlobalContext(), "", "dummy");
- {
- MB1.getModule()->setDataLayout(TM->createDataLayout());
- Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("bar");
- BasicBlock *BarEntry = BasicBlock::Create(getGlobalContext(), "entry",
- BarImpl);
- IRBuilder<> Builder(BarEntry);
- IntegerType *Int32Ty = IntegerType::get(getGlobalContext(), 32);
- Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
- Builder.CreateRet(FourtyTwo);
- }
- auto Obj1 = Compile(*MB1.getModule());
- std::vector<object::ObjectFile*> Obj1Set;
- Obj1Set.push_back(Obj1.getBinary());
- ModuleBuilder MB2(getGlobalContext(), "", "dummy");
- {
- MB2.getModule()->setDataLayout(TM->createDataLayout());
- Function *BarDecl = MB2.createFunctionDecl<int32_t(void)>("bar");
- Function *FooImpl = MB2.createFunctionDecl<int32_t(void)>("foo");
- BasicBlock *FooEntry = BasicBlock::Create(getGlobalContext(), "entry",
- FooImpl);
- IRBuilder<> Builder(FooEntry);
- Builder.CreateRet(Builder.CreateCall(BarDecl));
- }
- auto Obj2 = Compile(*MB2.getModule());
- std::vector<object::ObjectFile*> Obj2Set;
- Obj2Set.push_back(Obj2.getBinary());
- auto Resolver =
- createLambdaResolver(
- [&](const std::string &Name) {
- if (auto Sym = ObjLayer.findSymbol(Name, true))
- return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags());
- return RuntimeDyld::SymbolInfo(nullptr);
- },
- [](const std::string &Name) {
- return RuntimeDyld::SymbolInfo(nullptr);
- });
- SectionMemoryManagerWrapper SMMW;
- ObjLayer.addObjectSet(std::move(Obj1Set), &SMMW, &*Resolver);
- auto H = ObjLayer.addObjectSet(std::move(Obj2Set), &SMMW, &*Resolver);
- ObjLayer.emitAndFinalize(H);
- // Finalization of module 2 should trigger finalization of module 1.
- // Verify that finalize on SMMW is only called once.
- EXPECT_EQ(SMMW.FinalizationCount, 1)
- << "Extra call to finalize";
- }
- TEST_F(ObjectLinkingLayerExecutionTest, NoPrematureAllocation) {
- if (!TM)
- return;
- ObjectLinkingLayer<> ObjLayer;
- SimpleCompiler Compile(*TM);
- // Create a pair of unrelated modules:
- //
- // Module 1:
- // int foo() { return 42; }
- // Module 2:
- // int bar() { return 7; }
- //
- // Both modules will share a memory manager. We want to verify that the
- // second object is not loaded before the first one is finalized. To do this
- // in a portable way, we abuse the
- // RuntimeDyld::MemoryManager::needsToReserveAllocationSpace hook, which is
- // called once per object before any sections are allocated.
- ModuleBuilder MB1(getGlobalContext(), "", "dummy");
- {
- MB1.getModule()->setDataLayout(TM->createDataLayout());
- Function *BarImpl = MB1.createFunctionDecl<int32_t(void)>("foo");
- BasicBlock *BarEntry = BasicBlock::Create(getGlobalContext(), "entry",
- BarImpl);
- IRBuilder<> Builder(BarEntry);
- IntegerType *Int32Ty = IntegerType::get(getGlobalContext(), 32);
- Value *FourtyTwo = ConstantInt::getSigned(Int32Ty, 42);
- Builder.CreateRet(FourtyTwo);
- }
- auto Obj1 = Compile(*MB1.getModule());
- std::vector<object::ObjectFile*> Obj1Set;
- Obj1Set.push_back(Obj1.getBinary());
- ModuleBuilder MB2(getGlobalContext(), "", "dummy");
- {
- MB2.getModule()->setDataLayout(TM->createDataLayout());
- Function *BarImpl = MB2.createFunctionDecl<int32_t(void)>("bar");
- BasicBlock *BarEntry = BasicBlock::Create(getGlobalContext(), "entry",
- BarImpl);
- IRBuilder<> Builder(BarEntry);
- IntegerType *Int32Ty = IntegerType::get(getGlobalContext(), 32);
- Value *Seven = ConstantInt::getSigned(Int32Ty, 7);
- Builder.CreateRet(Seven);
- }
- auto Obj2 = Compile(*MB2.getModule());
- std::vector<object::ObjectFile*> Obj2Set;
- Obj2Set.push_back(Obj2.getBinary());
- SectionMemoryManagerWrapper SMMW;
- NullResolver NR;
- auto H = ObjLayer.addObjectSet(std::move(Obj1Set), &SMMW, &NR);
- ObjLayer.addObjectSet(std::move(Obj2Set), &SMMW, &NR);
- ObjLayer.emitAndFinalize(H);
- // Only one call to needsToReserveAllocationSpace should have been made.
- EXPECT_EQ(SMMW.NeedsToReserveAllocationSpaceCount, 1)
- << "More than one call to needsToReserveAllocationSpace "
- "(multiple unrelated objects loaded prior to finalization)";
- }
- } // end anonymous namespace
|