123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- //===- 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 "MCJITTestBase.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 "gtest/gtest.h"
- using namespace llvm;
- namespace {
- class TestObjectCache : public ObjectCache {
- public:
- TestObjectCache() : DuplicateInserted(false) { }
- 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);
- }
- virtual std::unique_ptr<MemoryBuffer> getObject(const Module* M) {
- const MemoryBuffer* BufferFound = getObjectInternal(M);
- ModulesLookedUp.insert(M->getModuleIdentifier());
- if (!BufferFound)
- return nullptr;
- // Our test cache wants to maintain ownership of its object buffers
- // so we make a copy here for the execution engine.
- return std::unique_ptr<MemoryBuffer>(
- MemoryBuffer::getMemBufferCopy(BufferFound->getBuffer()));
- }
- // 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 nullptr;
- return it->second;
- }
- private:
- MemoryBuffer *copyBuffer(const MemoryBuffer *Buf) {
- // Create a local copy of the buffer.
- std::unique_ptr<MemoryBuffer> NewBuffer(
- MemoryBuffer::getMemBufferCopy(Buf->getBuffer()));
- MemoryBuffer *Ret = NewBuffer.get();
- AllocatedBuffers.push_back(std::move(NewBuffer));
- return Ret;
- }
- StringMap<const MemoryBuffer *> ObjMap;
- StringSet<> ModulesLookedUp;
- SmallVector<std::unique_ptr<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(bool(TheJIT));
- ASSERT_TRUE(nullptr != Main);
- // We may be using a null cache, so ensure compilation is valid.
- TheJIT->finalizeObject();
- void *vPtr = TheJIT->getPointerToFunction(Main);
- EXPECT_TRUE(nullptr != 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(std::move(M));
- TheJIT->setObjectCache(nullptr);
- compileAndRun();
- }
- TEST_F(MCJITObjectCacheTest, VerifyBasicObjectCaching) {
- SKIP_UNSUPPORTED_PLATFORM;
- std::unique_ptr<TestObjectCache> Cache(new TestObjectCache);
- // Save a copy of the module pointer before handing it off to MCJIT.
- const Module * SavedModulePointer = M.get();
- createJIT(std::move(M));
- TheJIT->setObjectCache(Cache.get());
- // Verify that our object cache does not contain the module yet.
- const MemoryBuffer *ObjBuffer = Cache->getObjectInternal(SavedModulePointer);
- EXPECT_EQ(nullptr, 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(nullptr != ObjBuffer);
- // Verify that the cache was only notified once.
- EXPECT_FALSE(Cache->wereDuplicatesInserted());
- }
- TEST_F(MCJITObjectCacheTest, VerifyLoadFromCache) {
- SKIP_UNSUPPORTED_PLATFORM;
- std::unique_ptr<TestObjectCache> Cache(new TestObjectCache);
- // Compile this module with an MCJIT engine
- createJIT(std::move(M));
- 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(std::move(M));
- 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;
- std::unique_ptr<TestObjectCache> Cache(new TestObjectCache);
- // Compile this module with an MCJIT engine
- createJIT(std::move(M));
- 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(std::move(M));
- TheJIT->setObjectCache(Cache.get());
- // Verify that our object cache does not contain the module yet.
- const MemoryBuffer *ObjBuffer = Cache->getObjectInternal(SecondModulePointer);
- EXPECT_EQ(nullptr, 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(nullptr != ObjBuffer);
- // Verify that MCJIT didn't try to cache this again.
- EXPECT_FALSE(Cache->wereDuplicatesInserted());
- }
- } // Namespace
|