Home | History | Annotate | Download | only in MCJIT
      1 //===- MCJITObjectCacheTest.cpp - Unit tests for MCJIT object caching -----===//
      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/ADT/OwningPtr.h"
     11 #include "llvm/ADT/SmallVector.h"
     12 #include "llvm/ADT/StringMap.h"
     13 #include "llvm/ADT/StringSet.h"
     14 #include "llvm/ExecutionEngine/JIT.h"
     15 #include "llvm/ExecutionEngine/MCJIT.h"
     16 #include "llvm/ExecutionEngine/ObjectCache.h"
     17 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
     18 #include "MCJITTestBase.h"
     19 #include "gtest/gtest.h"
     20 
     21 using namespace llvm;
     22 
     23 namespace {
     24 
     25 class TestObjectCache : public ObjectCache {
     26 public:
     27   TestObjectCache() : DuplicateInserted(false) { }
     28 
     29   virtual ~TestObjectCache() {
     30     // Free any buffers we've allocated.
     31     SmallVectorImpl<MemoryBuffer *>::iterator it, end;
     32     end = AllocatedBuffers.end();
     33     for (it = AllocatedBuffers.begin(); it != end; ++it) {
     34       delete *it;
     35     }
     36     AllocatedBuffers.clear();
     37   }
     38 
     39   virtual void notifyObjectCompiled(const Module *M, const MemoryBuffer *Obj) {
     40     // If we've seen this module before, note that.
     41     const std::string ModuleID = M->getModuleIdentifier();
     42     if (ObjMap.find(ModuleID) != ObjMap.end())
     43       DuplicateInserted = true;
     44     // Store a copy of the buffer in our map.
     45     ObjMap[ModuleID] = copyBuffer(Obj);
     46   }
     47 
     48   virtual MemoryBuffer* getObject(const Module* M) {
     49     const MemoryBuffer* BufferFound = getObjectInternal(M);
     50     ModulesLookedUp.insert(M->getModuleIdentifier());
     51     if (!BufferFound)
     52       return NULL;
     53     // Our test cache wants to maintain ownership of its object buffers
     54     // so we make a copy here for the execution engine.
     55     return MemoryBuffer::getMemBufferCopy(BufferFound->getBuffer());
     56   }
     57 
     58   // Test-harness-specific functions
     59   bool wereDuplicatesInserted() { return DuplicateInserted; }
     60 
     61   bool wasModuleLookedUp(const Module *M) {
     62     return ModulesLookedUp.find(M->getModuleIdentifier())
     63                                       != ModulesLookedUp.end();
     64   }
     65 
     66   const MemoryBuffer* getObjectInternal(const Module* M) {
     67     // Look for the module in our map.
     68     const std::string ModuleID = M->getModuleIdentifier();
     69     StringMap<const MemoryBuffer *>::iterator it = ObjMap.find(ModuleID);
     70     if (it == ObjMap.end())
     71       return 0;
     72     return it->second;
     73   }
     74 
     75 private:
     76   MemoryBuffer *copyBuffer(const MemoryBuffer *Buf) {
     77     // Create a local copy of the buffer.
     78     MemoryBuffer *NewBuffer = MemoryBuffer::getMemBufferCopy(Buf->getBuffer());
     79     AllocatedBuffers.push_back(NewBuffer);
     80     return NewBuffer;
     81   }
     82 
     83   StringMap<const MemoryBuffer *> ObjMap;
     84   StringSet<>                     ModulesLookedUp;
     85   SmallVector<MemoryBuffer *, 2>  AllocatedBuffers;
     86   bool                            DuplicateInserted;
     87 };
     88 
     89 class MCJITObjectCacheTest : public testing::Test, public MCJITTestBase {
     90 protected:
     91 
     92   enum {
     93     OriginalRC = 6,
     94     ReplacementRC = 7
     95   };
     96 
     97   virtual void SetUp() {
     98     M.reset(createEmptyModule("<main>"));
     99     Main = insertMainFunction(M.get(), OriginalRC);
    100   }
    101 
    102   void compileAndRun(int ExpectedRC = OriginalRC) {
    103     // This function shouldn't be called until after SetUp.
    104     ASSERT_TRUE(TheJIT.isValid());
    105     ASSERT_TRUE(0 != Main);
    106 
    107     // We may be using a null cache, so ensure compilation is valid.
    108     TheJIT->finalizeObject();
    109     void *vPtr = TheJIT->getPointerToFunction(Main);
    110 
    111     EXPECT_TRUE(0 != vPtr)
    112       << "Unable to get pointer to main() from JIT";
    113 
    114     int (*FuncPtr)(void) = (int(*)(void))(intptr_t)vPtr;
    115     int returnCode = FuncPtr();
    116     EXPECT_EQ(returnCode, ExpectedRC);
    117   }
    118 
    119   Function *Main;
    120 };
    121 
    122 TEST_F(MCJITObjectCacheTest, SetNullObjectCache) {
    123   SKIP_UNSUPPORTED_PLATFORM;
    124 
    125   createJIT(M.take());
    126 
    127   TheJIT->setObjectCache(NULL);
    128 
    129   compileAndRun();
    130 }
    131 
    132 
    133 TEST_F(MCJITObjectCacheTest, VerifyBasicObjectCaching) {
    134   SKIP_UNSUPPORTED_PLATFORM;
    135 
    136   OwningPtr<TestObjectCache>  Cache(new TestObjectCache);
    137 
    138   // Save a copy of the module pointer before handing it off to MCJIT.
    139   const Module * SavedModulePointer = M.get();
    140 
    141   createJIT(M.take());
    142 
    143   TheJIT->setObjectCache(Cache.get());
    144 
    145   // Verify that our object cache does not contain the module yet.
    146   const MemoryBuffer *ObjBuffer = Cache->getObjectInternal(SavedModulePointer);
    147   EXPECT_EQ(0, ObjBuffer);
    148 
    149   compileAndRun();
    150 
    151   // Verify that MCJIT tried to look-up this module in the cache.
    152   EXPECT_TRUE(Cache->wasModuleLookedUp(SavedModulePointer));
    153 
    154   // Verify that our object cache now contains the module.
    155   ObjBuffer = Cache->getObjectInternal(SavedModulePointer);
    156   EXPECT_TRUE(0 != ObjBuffer);
    157 
    158   // Verify that the cache was only notified once.
    159   EXPECT_FALSE(Cache->wereDuplicatesInserted());
    160 }
    161 
    162 TEST_F(MCJITObjectCacheTest, VerifyLoadFromCache) {
    163   SKIP_UNSUPPORTED_PLATFORM;
    164 
    165   OwningPtr<TestObjectCache>  Cache(new TestObjectCache);
    166 
    167   // Compile this module with an MCJIT engine
    168   createJIT(M.take());
    169   TheJIT->setObjectCache(Cache.get());
    170   TheJIT->finalizeObject();
    171 
    172   // Destroy the MCJIT engine we just used
    173   TheJIT.reset();
    174 
    175   // Create a new memory manager.
    176   MM = new SectionMemoryManager;
    177 
    178   // Create a new module and save it. Use a different return code so we can
    179   // tell if MCJIT compiled this module or used the cache.
    180   M.reset(createEmptyModule("<main>"));
    181   Main = insertMainFunction(M.get(), ReplacementRC);
    182   const Module * SecondModulePointer = M.get();
    183 
    184   // Create a new MCJIT instance to load this module then execute it.
    185   createJIT(M.take());
    186   TheJIT->setObjectCache(Cache.get());
    187   compileAndRun();
    188 
    189   // Verify that MCJIT tried to look-up this module in the cache.
    190   EXPECT_TRUE(Cache->wasModuleLookedUp(SecondModulePointer));
    191 
    192   // Verify that MCJIT didn't try to cache this again.
    193   EXPECT_FALSE(Cache->wereDuplicatesInserted());
    194 }
    195 
    196 TEST_F(MCJITObjectCacheTest, VerifyNonLoadFromCache) {
    197   SKIP_UNSUPPORTED_PLATFORM;
    198 
    199   OwningPtr<TestObjectCache>  Cache(new TestObjectCache);
    200 
    201   // Compile this module with an MCJIT engine
    202   createJIT(M.take());
    203   TheJIT->setObjectCache(Cache.get());
    204   TheJIT->finalizeObject();
    205 
    206   // Destroy the MCJIT engine we just used
    207   TheJIT.reset();
    208 
    209   // Create a new memory manager.
    210   MM = new SectionMemoryManager;
    211 
    212   // Create a new module and save it. Use a different return code so we can
    213   // tell if MCJIT compiled this module or used the cache. Note that we use
    214   // a new module name here so the module shouldn't be found in the cache.
    215   M.reset(createEmptyModule("<not-main>"));
    216   Main = insertMainFunction(M.get(), ReplacementRC);
    217   const Module * SecondModulePointer = M.get();
    218 
    219   // Create a new MCJIT instance to load this module then execute it.
    220   createJIT(M.take());
    221   TheJIT->setObjectCache(Cache.get());
    222 
    223   // Verify that our object cache does not contain the module yet.
    224   const MemoryBuffer *ObjBuffer = Cache->getObjectInternal(SecondModulePointer);
    225   EXPECT_EQ(0, ObjBuffer);
    226 
    227   // Run the function and look for the replacement return code.
    228   compileAndRun(ReplacementRC);
    229 
    230   // Verify that MCJIT tried to look-up this module in the cache.
    231   EXPECT_TRUE(Cache->wasModuleLookedUp(SecondModulePointer));
    232 
    233   // Verify that our object cache now contains the module.
    234   ObjBuffer = Cache->getObjectInternal(SecondModulePointer);
    235   EXPECT_TRUE(0 != ObjBuffer);
    236 
    237   // Verify that MCJIT didn't try to cache this again.
    238   EXPECT_FALSE(Cache->wereDuplicatesInserted());
    239 }
    240 
    241 } // Namespace
    242 
    243