MCJITObjectCacheTest.cpp 7.2 KB

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