1 //===- ExecutionEngineTest.cpp - Unit tests for ExecutionEngine -----------===// 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/Interpreter.h" 11 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" 12 #include "llvm/IR/DerivedTypes.h" 13 #include "llvm/IR/GlobalVariable.h" 14 #include "llvm/IR/LLVMContext.h" 15 #include "llvm/IR/Module.h" 16 #include "llvm/Support/DynamicLibrary.h" 17 #include "llvm/Support/ManagedStatic.h" 18 #include "gtest/gtest.h" 19 20 using namespace llvm; 21 22 namespace { 23 24 class ExecutionEngineTest : public testing::Test { 25 private: 26 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 27 28 protected: 29 ExecutionEngineTest() { 30 auto Owner = make_unique<Module>("<main>", getGlobalContext()); 31 M = Owner.get(); 32 Engine.reset(EngineBuilder(std::move(Owner)).setErrorStr(&Error).create()); 33 } 34 35 virtual void SetUp() { 36 ASSERT_TRUE(Engine.get() != nullptr) << "EngineBuilder returned error: '" 37 << Error << "'"; 38 } 39 40 GlobalVariable *NewExtGlobal(Type *T, const Twine &Name) { 41 return new GlobalVariable(*M, T, false, // Not constant. 42 GlobalValue::ExternalLinkage, nullptr, Name); 43 } 44 45 std::string Error; 46 Module *M; // Owned by ExecutionEngine. 47 std::unique_ptr<ExecutionEngine> Engine; 48 }; 49 50 TEST_F(ExecutionEngineTest, ForwardGlobalMapping) { 51 GlobalVariable *G1 = 52 NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global1"); 53 int32_t Mem1 = 3; 54 Engine->addGlobalMapping(G1, &Mem1); 55 EXPECT_EQ(&Mem1, Engine->getPointerToGlobalIfAvailable(G1)); 56 int32_t Mem2 = 4; 57 Engine->updateGlobalMapping(G1, &Mem2); 58 EXPECT_EQ(&Mem2, Engine->getPointerToGlobalIfAvailable(G1)); 59 Engine->updateGlobalMapping(G1, nullptr); 60 EXPECT_EQ(nullptr, Engine->getPointerToGlobalIfAvailable(G1)); 61 Engine->updateGlobalMapping(G1, &Mem2); 62 EXPECT_EQ(&Mem2, Engine->getPointerToGlobalIfAvailable(G1)); 63 64 GlobalVariable *G2 = 65 NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global1"); 66 EXPECT_EQ(nullptr, Engine->getPointerToGlobalIfAvailable(G2)) 67 << "The NULL return shouldn't depend on having called" 68 << " updateGlobalMapping(..., NULL)"; 69 // Check that update...() can be called before add...(). 70 Engine->updateGlobalMapping(G2, &Mem1); 71 EXPECT_EQ(&Mem1, Engine->getPointerToGlobalIfAvailable(G2)); 72 EXPECT_EQ(&Mem2, Engine->getPointerToGlobalIfAvailable(G1)) 73 << "A second mapping shouldn't affect the first."; 74 } 75 76 TEST_F(ExecutionEngineTest, ReverseGlobalMapping) { 77 GlobalVariable *G1 = 78 NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global1"); 79 80 int32_t Mem1 = 3; 81 Engine->addGlobalMapping(G1, &Mem1); 82 EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem1)); 83 int32_t Mem2 = 4; 84 Engine->updateGlobalMapping(G1, &Mem2); 85 EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem1)); 86 EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem2)); 87 88 GlobalVariable *G2 = 89 NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global2"); 90 Engine->updateGlobalMapping(G2, &Mem1); 91 EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem1)); 92 EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem2)); 93 Engine->updateGlobalMapping(G1, nullptr); 94 EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem1)) 95 << "Removing one mapping doesn't affect a different one."; 96 EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem2)); 97 Engine->updateGlobalMapping(G2, &Mem2); 98 EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem1)); 99 EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem2)) 100 << "Once a mapping is removed, we can point another GV at the" 101 << " now-free address."; 102 } 103 104 TEST_F(ExecutionEngineTest, ClearModuleMappings) { 105 GlobalVariable *G1 = 106 NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global1"); 107 108 int32_t Mem1 = 3; 109 Engine->addGlobalMapping(G1, &Mem1); 110 EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem1)); 111 112 Engine->clearGlobalMappingsFromModule(M); 113 114 EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem1)); 115 116 GlobalVariable *G2 = 117 NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global2"); 118 // After clearing the module mappings, we can assign a new GV to the 119 // same address. 120 Engine->addGlobalMapping(G2, &Mem1); 121 EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem1)); 122 } 123 124 TEST_F(ExecutionEngineTest, DestructionRemovesGlobalMapping) { 125 GlobalVariable *G1 = 126 NewExtGlobal(Type::getInt32Ty(getGlobalContext()), "Global1"); 127 int32_t Mem1 = 3; 128 Engine->addGlobalMapping(G1, &Mem1); 129 // Make sure the reverse mapping is enabled. 130 EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem1)); 131 // When the GV goes away, the ExecutionEngine should remove any 132 // mappings that refer to it. 133 G1->eraseFromParent(); 134 EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem1)); 135 } 136 137 TEST_F(ExecutionEngineTest, LookupWithMangledName) { 138 int x; 139 llvm::sys::DynamicLibrary::AddSymbol("x", &x); 140 141 // Demonstrate that getSymbolAddress accepts mangled names and always strips 142 // the leading underscore. 143 EXPECT_EQ(reinterpret_cast<uint64_t>(&x), 144 RTDyldMemoryManager::getSymbolAddressInProcess("_x")); 145 } 146 147 TEST_F(ExecutionEngineTest, LookupWithMangledAndDemangledSymbol) { 148 int x; 149 int _x; 150 llvm::sys::DynamicLibrary::AddSymbol("x", &x); 151 llvm::sys::DynamicLibrary::AddSymbol("_x", &_x); 152 153 // Lookup the demangled name first, even if there's a demangled symbol that 154 // matches the input already. 155 EXPECT_EQ(reinterpret_cast<uint64_t>(&x), 156 RTDyldMemoryManager::getSymbolAddressInProcess("_x")); 157 } 158 159 TEST_F(ExecutionEngineTest, LookupwithDemangledName) { 160 int _x; 161 llvm::sys::DynamicLibrary::AddSymbol("_x", &_x); 162 163 // But do fallback to looking up a demangled name if there's no ambiguity 164 EXPECT_EQ(reinterpret_cast<uint64_t>(&_x), 165 RTDyldMemoryManager::getSymbolAddressInProcess("_x")); 166 } 167 168 } 169