diff options
author | Andrew Kaylor <andrew.kaylor@intel.com> | 2013-04-25 21:02:36 +0000 |
---|---|---|
committer | Andrew Kaylor <andrew.kaylor@intel.com> | 2013-04-25 21:02:36 +0000 |
commit | 1c489455ea5fac43a5f20911dfb5486630eb0160 (patch) | |
tree | 7509bd6098207003a8a9bd73c0a86ec7e4aacfcf /unittests | |
parent | 29fce9ad39636d38f43add5d7c23e83d9d1cc249 (diff) |
Re-enabling MCJIT object caching with memory leak fixed
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@180575 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests')
-rw-r--r-- | unittests/ExecutionEngine/MCJIT/CMakeLists.txt | 1 | ||||
-rw-r--r-- | unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp | 240 |
2 files changed, 241 insertions, 0 deletions
diff --git a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt index c6b1f77e3e..9ffe6138ad 100644 --- a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt +++ b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt @@ -10,6 +10,7 @@ set(LLVM_LINK_COMPONENTS set(MCJITTestsSources MCJITTest.cpp MCJITMemoryManagerTest.cpp + MCJITObjectCacheTest.cpp ) if(MSVC) diff --git a/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp new file mode 100644 index 0000000000..0061e30e7a --- /dev/null +++ b/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp @@ -0,0 +1,240 @@ +//===- MCJITObjectCacheTest.cpp - Unit tests for MCJIT object caching -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ExecutionEngine/JIT.h" +#include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/ExecutionEngine/ObjectCache.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "MCJITTestBase.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class TestObjectCache : public ObjectCache { +public: + TestObjectCache() : DuplicateInserted(false) { } + + virtual ~TestObjectCache() { + // Free any buffers we've allocated. + SmallVector<MemoryBuffer *, 2>::iterator it, end; + end = AllocatedBuffers.end(); + for (it = AllocatedBuffers.begin(); it != end; ++it) { + delete *it; + } + AllocatedBuffers.clear(); + } + + virtual void notifyObjectCompiled(const Module *M, const MemoryBuffer *Obj) { + // If we've seen this module before, note that. + const std::string ModuleID = M->getModuleIdentifier(); + if (ObjMap.find(ModuleID) != ObjMap.end()) + DuplicateInserted = true; + // Store a copy of the buffer in our map. + ObjMap[ModuleID] = copyBuffer(Obj); + } + + // Test-harness-specific functions + bool wereDuplicatesInserted() { return DuplicateInserted; } + + bool wasModuleLookedUp(const Module *M) { + return ModulesLookedUp.find(M->getModuleIdentifier()) + != ModulesLookedUp.end(); + } + + const MemoryBuffer* getObjectInternal(const Module* M) { + // Look for the module in our map. + const std::string ModuleID = M->getModuleIdentifier(); + StringMap<const MemoryBuffer *>::iterator it = ObjMap.find(ModuleID); + if (it == ObjMap.end()) + return 0; + return it->second; + } + +protected: + virtual const MemoryBuffer* getObject(const Module* M) { + const MemoryBuffer* BufferFound = getObjectInternal(M); + ModulesLookedUp.insert(M->getModuleIdentifier()); + return BufferFound; + } + +private: + MemoryBuffer *copyBuffer(const MemoryBuffer *Buf) { + // Create a local copy of the buffer. + MemoryBuffer *NewBuffer = MemoryBuffer::getMemBufferCopy(Buf->getBuffer()); + AllocatedBuffers.push_back(NewBuffer); + return NewBuffer; + } + + StringMap<const MemoryBuffer *> ObjMap; + StringSet<> ModulesLookedUp; + SmallVector<MemoryBuffer *, 2> AllocatedBuffers; + bool DuplicateInserted; +}; + +class MCJITObjectCacheTest : public testing::Test, public MCJITTestBase { +protected: + + enum { + OriginalRC = 6, + ReplacementRC = 7 + }; + + virtual void SetUp() { + M.reset(createEmptyModule("<main>")); + Main = insertMainFunction(M.get(), OriginalRC); + } + + void compileAndRun(int ExpectedRC = OriginalRC) { + // This function shouldn't be called until after SetUp. + ASSERT_TRUE(0 != TheJIT); + ASSERT_TRUE(0 != Main); + + TheJIT->finalizeObject(); + void *vPtr = TheJIT->getPointerToFunction(Main); + + static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache(); + + EXPECT_TRUE(0 != vPtr) + << "Unable to get pointer to main() from JIT"; + + int (*FuncPtr)(void) = (int(*)(void))(intptr_t)vPtr; + int returnCode = FuncPtr(); + EXPECT_EQ(returnCode, ExpectedRC); + } + + Function *Main; +}; + +TEST_F(MCJITObjectCacheTest, SetNullObjectCache) { + SKIP_UNSUPPORTED_PLATFORM; + + createJIT(M.take()); + + TheJIT->setObjectCache(NULL); + + compileAndRun(); +} + + +TEST_F(MCJITObjectCacheTest, VerifyBasicObjectCaching) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<TestObjectCache> Cache(new TestObjectCache); + + // Save a copy of the module pointer before handing it off to MCJIT. + const Module * SavedModulePointer = M.get(); + + createJIT(M.take()); + + TheJIT->setObjectCache(Cache.get()); + + // Verify that our object cache does not contain the module yet. + const MemoryBuffer *ObjBuffer = Cache->getObjectInternal(SavedModulePointer); + EXPECT_EQ(0, ObjBuffer); + + compileAndRun(); + + // Verify that MCJIT tried to look-up this module in the cache. + EXPECT_TRUE(Cache->wasModuleLookedUp(SavedModulePointer)); + + // Verify that our object cache now contains the module. + ObjBuffer = Cache->getObjectInternal(SavedModulePointer); + EXPECT_TRUE(0 != ObjBuffer); + + // Verify that the cache was only notified once. + EXPECT_FALSE(Cache->wereDuplicatesInserted()); +} + +TEST_F(MCJITObjectCacheTest, VerifyLoadFromCache) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<TestObjectCache> Cache(new TestObjectCache); + + // Compile this module with an MCJIT engine + createJIT(M.take()); + TheJIT->setObjectCache(Cache.get()); + TheJIT->finalizeObject(); + + // Destroy the MCJIT engine we just used + TheJIT.reset(); + + // Create a new memory manager. + MM = new SectionMemoryManager; + + // Create a new module and save it. Use a different return code so we can + // tell if MCJIT compiled this module or used the cache. + M.reset(createEmptyModule("<main>")); + Main = insertMainFunction(M.get(), ReplacementRC); + const Module * SecondModulePointer = M.get(); + + // Create a new MCJIT instance to load this module then execute it. + createJIT(M.take()); + TheJIT->setObjectCache(Cache.get()); + compileAndRun(); + + // Verify that MCJIT tried to look-up this module in the cache. + EXPECT_TRUE(Cache->wasModuleLookedUp(SecondModulePointer)); + + // Verify that MCJIT didn't try to cache this again. + EXPECT_FALSE(Cache->wereDuplicatesInserted()); +} + +TEST_F(MCJITObjectCacheTest, VerifyNonLoadFromCache) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<TestObjectCache> Cache(new TestObjectCache); + + // Compile this module with an MCJIT engine + createJIT(M.take()); + TheJIT->setObjectCache(Cache.get()); + TheJIT->finalizeObject(); + + // Destroy the MCJIT engine we just used + TheJIT.reset(); + + // Create a new memory manager. + MM = new SectionMemoryManager; + + // Create a new module and save it. Use a different return code so we can + // tell if MCJIT compiled this module or used the cache. Note that we use + // a new module name here so the module shouldn't be found in the cache. + M.reset(createEmptyModule("<not-main>")); + Main = insertMainFunction(M.get(), ReplacementRC); + const Module * SecondModulePointer = M.get(); + + // Create a new MCJIT instance to load this module then execute it. + createJIT(M.take()); + TheJIT->setObjectCache(Cache.get()); + + // Verify that our object cache does not contain the module yet. + const MemoryBuffer *ObjBuffer = Cache->getObjectInternal(SecondModulePointer); + EXPECT_EQ(0, ObjBuffer); + + // Run the function and look for the replacement return code. + compileAndRun(ReplacementRC); + + // Verify that MCJIT tried to look-up this module in the cache. + EXPECT_TRUE(Cache->wasModuleLookedUp(SecondModulePointer)); + + // Verify that our object cache now contains the module. + ObjBuffer = Cache->getObjectInternal(SecondModulePointer); + EXPECT_TRUE(0 != ObjBuffer); + + // Verify that MCJIT didn't try to cache this again. + EXPECT_FALSE(Cache->wereDuplicatesInserted()); +} + +} // Namespace + |