Home | History | Annotate | Download | only in ExecutionEngine
      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/ADT/STLExtras.h"
     13 #include "llvm/IR/DerivedTypes.h"
     14 #include "llvm/IR/GlobalVariable.h"
     15 #include "llvm/IR/LLVMContext.h"
     16 #include "llvm/IR/Module.h"
     17 #include "llvm/Support/DynamicLibrary.h"
     18 #include "llvm/Support/ManagedStatic.h"
     19 #include "gtest/gtest.h"
     20 
     21 using namespace llvm;
     22 
     23 namespace {
     24 
     25 class ExecutionEngineTest : public testing::Test {
     26 private:
     27   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
     28 
     29 protected:
     30   ExecutionEngineTest() {
     31     auto Owner = make_unique<Module>("<main>", Context);
     32     M = Owner.get();
     33     Engine.reset(EngineBuilder(std::move(Owner)).setErrorStr(&Error).create());
     34   }
     35 
     36   void SetUp() override {
     37     ASSERT_TRUE(Engine.get() != nullptr) << "EngineBuilder returned error: '"
     38       << Error << "'";
     39   }
     40 
     41   GlobalVariable *NewExtGlobal(Type *T, const Twine &Name) {
     42     return new GlobalVariable(*M, T, false,  // Not constant.
     43                               GlobalValue::ExternalLinkage, nullptr, Name);
     44   }
     45 
     46   std::string Error;
     47   LLVMContext Context;
     48   Module *M;  // Owned by ExecutionEngine.
     49   std::unique_ptr<ExecutionEngine> Engine;
     50 };
     51 
     52 TEST_F(ExecutionEngineTest, ForwardGlobalMapping) {
     53   GlobalVariable *G1 = NewExtGlobal(Type::getInt32Ty(Context), "Global1");
     54   int32_t Mem1 = 3;
     55   Engine->addGlobalMapping(G1, &Mem1);
     56   EXPECT_EQ(&Mem1, Engine->getPointerToGlobalIfAvailable(G1));
     57   EXPECT_EQ(&Mem1, Engine->getPointerToGlobalIfAvailable("Global1"));
     58   int32_t Mem2 = 4;
     59   Engine->updateGlobalMapping(G1, &Mem2);
     60   EXPECT_EQ(&Mem2, Engine->getPointerToGlobalIfAvailable(G1));
     61   Engine->updateGlobalMapping(G1, nullptr);
     62   EXPECT_EQ(nullptr, Engine->getPointerToGlobalIfAvailable(G1));
     63   Engine->updateGlobalMapping(G1, &Mem2);
     64   EXPECT_EQ(&Mem2, Engine->getPointerToGlobalIfAvailable(G1));
     65 
     66   GlobalVariable *G2 = NewExtGlobal(Type::getInt32Ty(Context), "Global1");
     67   EXPECT_EQ(nullptr, Engine->getPointerToGlobalIfAvailable(G2))
     68     << "The NULL return shouldn't depend on having called"
     69     << " updateGlobalMapping(..., NULL)";
     70   // Check that update...() can be called before add...().
     71   Engine->updateGlobalMapping(G2, &Mem1);
     72   EXPECT_EQ(&Mem1, Engine->getPointerToGlobalIfAvailable(G2));
     73   EXPECT_EQ(&Mem2, Engine->getPointerToGlobalIfAvailable(G1))
     74     << "A second mapping shouldn't affect the first.";
     75 }
     76 
     77 TEST_F(ExecutionEngineTest, ReverseGlobalMapping) {
     78   GlobalVariable *G1 = NewExtGlobal(Type::getInt32Ty(Context), "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 = NewExtGlobal(Type::getInt32Ty(Context), "Global2");
     89   Engine->updateGlobalMapping(G2, &Mem1);
     90   EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem1));
     91   EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem2));
     92   Engine->updateGlobalMapping(G1, nullptr);
     93   EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem1))
     94     << "Removing one mapping doesn't affect a different one.";
     95   EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem2));
     96   Engine->updateGlobalMapping(G2, &Mem2);
     97   EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem1));
     98   EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem2))
     99     << "Once a mapping is removed, we can point another GV at the"
    100     << " now-free address.";
    101 }
    102 
    103 TEST_F(ExecutionEngineTest, ClearModuleMappings) {
    104   GlobalVariable *G1 = NewExtGlobal(Type::getInt32Ty(Context), "Global1");
    105 
    106   int32_t Mem1 = 3;
    107   Engine->addGlobalMapping(G1, &Mem1);
    108   EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem1));
    109 
    110   Engine->clearGlobalMappingsFromModule(M);
    111 
    112   EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem1));
    113 
    114   GlobalVariable *G2 = NewExtGlobal(Type::getInt32Ty(Context), "Global2");
    115   // After clearing the module mappings, we can assign a new GV to the
    116   // same address.
    117   Engine->addGlobalMapping(G2, &Mem1);
    118   EXPECT_EQ(G2, Engine->getGlobalValueAtAddress(&Mem1));
    119 }
    120 
    121 TEST_F(ExecutionEngineTest, DestructionRemovesGlobalMapping) {
    122   GlobalVariable *G1 = NewExtGlobal(Type::getInt32Ty(Context), "Global1");
    123   int32_t Mem1 = 3;
    124   Engine->addGlobalMapping(G1, &Mem1);
    125   // Make sure the reverse mapping is enabled.
    126   EXPECT_EQ(G1, Engine->getGlobalValueAtAddress(&Mem1));
    127   // When the GV goes away, the ExecutionEngine should remove any
    128   // mappings that refer to it.
    129   G1->eraseFromParent();
    130   EXPECT_EQ(nullptr, Engine->getGlobalValueAtAddress(&Mem1));
    131 }
    132 
    133 TEST_F(ExecutionEngineTest, LookupWithMangledAndDemangledSymbol) {
    134   int x;
    135   int _x;
    136   llvm::sys::DynamicLibrary::AddSymbol("x", &x);
    137   llvm::sys::DynamicLibrary::AddSymbol("_x", &_x);
    138 
    139   // RTDyldMemoryManager::getSymbolAddressInProcess expects a mangled symbol,
    140   // but DynamicLibrary is a wrapper for dlsym, which expects the unmangled C
    141   // symbol name. This test verifies that getSymbolAddressInProcess strips the
    142   // leading '_' on Darwin, but not on other platforms.
    143 #ifdef __APPLE__
    144   EXPECT_EQ(reinterpret_cast<uint64_t>(&x),
    145             RTDyldMemoryManager::getSymbolAddressInProcess("_x"));
    146 #else
    147   EXPECT_EQ(reinterpret_cast<uint64_t>(&_x),
    148             RTDyldMemoryManager::getSymbolAddressInProcess("_x"));
    149 #endif
    150 }
    151 
    152 }
    153