MCJITObjectCacheTest.cpp 7.4 KB

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