From 72780ed996fa2aaaf14923f82dcb719ea84fc23f Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Thu, 25 Apr 2013 03:47:41 +0000 Subject: [PATCH] Revert "Adding object caching support to MCJIT" This reverts commit 07f03923137a91e3cca5d7fc075a22f8c9baf33a. Looks like it broke the valgrind bot: http://lab.llvm.org:8011/builders/llvm-x86_64-linux-vg_leak/builds/649 llvm-svn: 180249 --- .../llvm/ExecutionEngine/ExecutionEngine.h | 7 - .../llvm/ExecutionEngine/ObjectCache.h | 54 ---- llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp | 69 ++--- llvm/lib/ExecutionEngine/MCJIT/MCJIT.h | 14 +- .../ExecutionEngine/MCJIT/CMakeLists.txt | 1 - .../MCJIT/MCJITObjectCacheTest.cpp | 240 ------------------ 6 files changed, 18 insertions(+), 367 deletions(-) delete mode 100644 llvm/include/llvm/ExecutionEngine/ObjectCache.h delete mode 100644 llvm/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp diff --git a/llvm/include/llvm/ExecutionEngine/ExecutionEngine.h b/llvm/include/llvm/ExecutionEngine/ExecutionEngine.h index 980075948404..733e64af0347 100644 --- a/llvm/include/llvm/ExecutionEngine/ExecutionEngine.h +++ b/llvm/include/llvm/ExecutionEngine/ExecutionEngine.h @@ -44,7 +44,6 @@ class JITMemoryManager; class MachineCodeInfo; class Module; class MutexGuard; -class ObjectCache; class DataLayout; class Triple; class Type; @@ -374,12 +373,6 @@ public: virtual void RegisterJITEventListener(JITEventListener *) {} virtual void UnregisterJITEventListener(JITEventListener *) {} - /// Sets the pre-compiled object cache. The ownership of the ObjectCache is - /// not changed. Supported by MCJIT but not JIT. - virtual void setObjectCache(ObjectCache *) { - llvm_unreachable("No support for an object cache"); - } - /// DisableLazyCompilation - When lazy compilation is off (the default), the /// JIT will eagerly compile every function reachable from the argument to /// getPointerToFunction. If lazy compilation is turned on, the JIT will only diff --git a/llvm/include/llvm/ExecutionEngine/ObjectCache.h b/llvm/include/llvm/ExecutionEngine/ObjectCache.h deleted file mode 100644 index 0bee86161bb7..000000000000 --- a/llvm/include/llvm/ExecutionEngine/ObjectCache.h +++ /dev/null @@ -1,54 +0,0 @@ -//===-- ObjectCache.h - Class definition for the ObjectCache -----C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_OBJECTCACHE_H -#define LLVM_LIB_EXECUTIONENGINE_OBJECTCACHE_H - -#include "llvm/Support/MemoryBuffer.h" - -namespace llvm { - -class Module; - -/// This is the base ObjectCache type which can be provided to an -/// ExecutionEngine for the purpose of avoiding compilation for Modules that -/// have already been compiled and an object file is available. -class ObjectCache { -public: - ObjectCache() { } - - virtual ~ObjectCache() { } - - /// notifyObjectCompiled - Provides a pointer to compiled code for Module M. - virtual void notifyObjectCompiled(const Module *M, const MemoryBuffer *Obj) = 0; - - /// getObjectCopy - Returns a pointer to a newly allocated MemoryBuffer that - /// contains the object which corresponds with Module M, or 0 if an object is - /// not available. The caller owns the MemoryBuffer returned by this function. - MemoryBuffer* getObjectCopy(const Module* M) { - const MemoryBuffer* Obj = getObject(M); - if (Obj) - return MemoryBuffer::getMemBufferCopy(Obj->getBuffer()); - else - return 0; - } - -protected: - /// getObject - Returns a pointer to a MemoryBuffer that contains an object - /// that corresponds with Module M, or 0 if an object is not available. - /// The pointer returned by this function is not suitable for loading because - /// the memory is read-only and owned by the ObjectCache. To retrieve an - /// owning pointer to a MemoryBuffer (which is suitable for calling - /// RuntimeDyld::loadObject() with) use getObjectCopy() instead. - virtual const MemoryBuffer* getObject(const Module* M) = 0; -}; - -} - -#endif diff --git a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp index 77ea07631c44..fee10e194355 100644 --- a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp +++ b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp @@ -52,7 +52,7 @@ ExecutionEngine *MCJIT::createJIT(Module *M, MCJIT::MCJIT(Module *m, TargetMachine *tm, RTDyldMemoryManager *MM, bool AllocateGVsWithCode) : ExecutionEngine(m), TM(tm), Ctx(0), MemMgr(MM), Dyld(MM), - IsLoaded(false), M(m), ObjCache(0) { + isCompiled(false), M(m) { setDataLayout(TM->getDataLayout()); } @@ -64,11 +64,7 @@ MCJIT::~MCJIT() { delete TM; } -void MCJIT::setObjectCache(ObjectCache* NewCache) { - ObjCache = NewCache; -} - -ObjectBufferStream* MCJIT::emitObject(Module *m) { +void MCJIT::emitObject(Module *m) { /// Currently, MCJIT only supports a single module and the module passed to /// this function call is expected to be the contained module. The module /// is passed as a parameter here to prepare for multiple module support in @@ -81,63 +77,30 @@ ObjectBufferStream* MCJIT::emitObject(Module *m) { // FIXME: Track compilation state on a per-module basis when multiple modules // are supported. // Re-compilation is not supported - assert(!IsLoaded); + if (isCompiled) + return; PassManager PM; PM.add(new DataLayout(*TM->getDataLayout())); // The RuntimeDyld will take ownership of this shortly - OwningPtr CompiledObject(new ObjectBufferStream()); + OwningPtr Buffer(new ObjectBufferStream()); // Turn the machine code intermediate representation into bytes in memory // that may be executed. - if (TM->addPassesToEmitMC(PM, Ctx, CompiledObject->getOStream(), false)) { + if (TM->addPassesToEmitMC(PM, Ctx, Buffer->getOStream(), false)) { report_fatal_error("Target does not support MC emission!"); } // Initialize passes. PM.run(*m); // Flush the output buffer to get the generated code into memory - CompiledObject->flush(); - - // If we have an object cache, tell it about the new object. - // Note that we're using the compiled image, not the loaded image (as below). - if (ObjCache) { - ObjCache->notifyObjectCompiled(m, CompiledObject->getMemBuffer()); - } - - return CompiledObject.take(); -} - -void MCJIT::loadObject(Module *M) { - - // Get a thread lock to make sure we aren't trying to load multiple times - MutexGuard locked(lock); - - // FIXME: Track compilation state on a per-module basis when multiple modules - // are supported. - // Re-compilation is not supported - if (IsLoaded) - return; - - OwningPtr ObjectToLoad; - // Try to load the pre-compiled object from cache if possible - if (0 != ObjCache) { - OwningPtr PreCompiledObject(ObjCache->getObjectCopy(M)); - if (0 != PreCompiledObject.get()) - ObjectToLoad.reset(new ObjectBuffer(PreCompiledObject.take())); - } - - // If the cache did not contain a suitable object, compile the object - if (!ObjectToLoad) { - ObjectToLoad.reset(emitObject(M)); - assert(ObjectToLoad.get() && "Compilation did not produce an object."); - } + Buffer->flush(); // Load the object into the dynamic linker. // handing off ownership of the buffer - LoadedObject.reset(Dyld.loadObject(ObjectToLoad.take())); + LoadedObject.reset(Dyld.loadObject(Buffer.take())); if (!LoadedObject) report_fatal_error(Dyld.getErrorString()); @@ -150,7 +113,7 @@ void MCJIT::loadObject(Module *M) { NotifyObjectEmitted(*LoadedObject); // FIXME: Add support for per-module compilation state - IsLoaded = true; + isCompiled = true; } // FIXME: Add a parameter to identify which object is being finalized when @@ -159,10 +122,10 @@ void MCJIT::loadObject(Module *M) { // protection in the interface. void MCJIT::finalizeObject() { // If the module hasn't been compiled, just do that. - if (!IsLoaded) { - // If the call to Dyld.resolveRelocations() is removed from loadObject() + if (!isCompiled) { + // If the call to Dyld.resolveRelocations() is removed from emitObject() // we'll need to do that here. - loadObject(M); + emitObject(M); // Set page permissions. MemMgr->applyPermissions(); @@ -188,8 +151,8 @@ void *MCJIT::getPointerToFunction(Function *F) { // dies. // FIXME: Add support for per-module compilation state - if (!IsLoaded) - loadObject(M); + if (!isCompiled) + emitObject(M); if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) { bool AbortOnFailure = !F->hasExternalWeakLinkage(); @@ -321,8 +284,8 @@ GenericValue MCJIT::runFunction(Function *F, void *MCJIT::getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure) { // FIXME: Add support for per-module compilation state - if (!IsLoaded) - loadObject(M); + if (!isCompiled) + emitObject(M); if (!isSymbolSearchingDisabled() && MemMgr) { void *ptr = MemMgr->getPointerToNamedFunction(Name, false); diff --git a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h index 8c4bf6e1dbc7..283a8e528118 100644 --- a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h +++ b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h @@ -12,7 +12,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/ObjectCache.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/PassManager.h" @@ -35,23 +34,16 @@ class MCJIT : public ExecutionEngine { SmallVector EventListeners; // FIXME: Add support for multiple modules - bool IsLoaded; + bool isCompiled; Module *M; OwningPtr LoadedObject; - // An optional ObjectCache to be notified of compiled objects and used to - // perform lookup of pre-compiled code to avoid re-compilation. - ObjectCache *ObjCache; - public: ~MCJIT(); /// @name ExecutionEngine interface implementation /// @{ - /// Sets the object manager that MCJIT should use to avoid compilation. - virtual void setObjectCache(ObjectCache *manager); - virtual void finalizeObject(); virtual void *getPointerToBasicBlock(BasicBlock *BB); @@ -110,9 +102,7 @@ protected: /// this function call is expected to be the contained module. The module /// is passed as a parameter here to prepare for multiple module support in /// the future. - ObjectBufferStream* emitObject(Module *M); - - void loadObject(Module *M); + void emitObject(Module *M); void NotifyObjectEmitted(const ObjectImage& Obj); void NotifyFreeingObject(const ObjectImage& Obj); diff --git a/llvm/unittests/ExecutionEngine/MCJIT/CMakeLists.txt b/llvm/unittests/ExecutionEngine/MCJIT/CMakeLists.txt index 9ffe6138ad76..c6b1f77e3e8b 100644 --- a/llvm/unittests/ExecutionEngine/MCJIT/CMakeLists.txt +++ b/llvm/unittests/ExecutionEngine/MCJIT/CMakeLists.txt @@ -10,7 +10,6 @@ set(LLVM_LINK_COMPONENTS set(MCJITTestsSources MCJITTest.cpp MCJITMemoryManagerTest.cpp - MCJITObjectCacheTest.cpp ) if(MSVC) diff --git a/llvm/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp b/llvm/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp deleted file mode 100644 index 0061e30e7a54..000000000000 --- a/llvm/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp +++ /dev/null @@ -1,240 +0,0 @@ -//===- 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::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::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 ObjMap; - StringSet<> ModulesLookedUp; - SmallVector AllocatedBuffers; - bool DuplicateInserted; -}; - -class MCJITObjectCacheTest : public testing::Test, public MCJITTestBase { -protected: - - enum { - OriginalRC = 6, - ReplacementRC = 7 - }; - - virtual void SetUp() { - M.reset(createEmptyModule("
")); - 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(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 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 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 = 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 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("")); - 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 -