diff --git a/include/llvm/ExecutionEngine/ExecutionEngine.h b/include/llvm/ExecutionEngine/ExecutionEngine.h index 83a672de2b6..ceac298655e 100644 --- a/include/llvm/ExecutionEngine/ExecutionEngine.h +++ b/include/llvm/ExecutionEngine/ExecutionEngine.h @@ -252,11 +252,14 @@ public: "EE!"); } - // finalizeObject - This method should be called after sections within an - // object have been relocated using mapSectionAddress. When this method is - // called the MCJIT execution engine will reapply relocations for a loaded - // object. This method has no effect for the legacy JIT engine or the - // interpeter. + /// finalizeObject - ensure the module is fully processed and is usable. + /// + /// It is the user-level function for completing the process of making the + /// object usable for execution. It should be called after sections within an + /// object have been relocated using mapSectionAddress. When this method is + /// called the MCJIT execution engine will reapply relocations for a loaded + /// object. This method has no effect for the legacy JIT engine or the + /// interpeter. virtual void finalizeObject() {} /// runStaticConstructorsDestructors - This method is used to execute all of diff --git a/include/llvm/ExecutionEngine/RuntimeDyld.h b/include/llvm/ExecutionEngine/RuntimeDyld.h index c6c126c6e24..7dba040961a 100644 --- a/include/llvm/ExecutionEngine/RuntimeDyld.h +++ b/include/llvm/ExecutionEngine/RuntimeDyld.h @@ -62,10 +62,12 @@ public: /// permissions can be applied. It is up to the memory manager implementation /// to decide whether or not to act on this method. The memory manager will /// typically allocate all sections as read-write and then apply specific - /// permissions when this method is called. + /// permissions when this method is called. Code sections cannot be executed + /// until this function has been called. In addition, any cache coherency + /// operations needed to reliably use the memory are also performed. /// /// Returns true if an error occurred, false otherwise. - virtual bool applyPermissions(std::string *ErrMsg = 0) = 0; + virtual bool finalizeMemory(std::string *ErrMsg = 0) = 0; /// Register the EH frames with the runtime so that c++ exceptions work. The /// default implementation does nothing. Look at SectionMemoryManager for one diff --git a/include/llvm/ExecutionEngine/SectionMemoryManager.h b/include/llvm/ExecutionEngine/SectionMemoryManager.h index 305a96619a0..fc8dacfcc09 100644 --- a/include/llvm/ExecutionEngine/SectionMemoryManager.h +++ b/include/llvm/ExecutionEngine/SectionMemoryManager.h @@ -33,7 +33,7 @@ namespace llvm { /// Any client using this memory manager MUST ensure that section-specific /// page permissions have been applied before attempting to execute functions /// in the JITed object. Permissions can be applied either by calling -/// MCJIT::finalizeObject or by calling SectionMemoryManager::applyPermissions +/// MCJIT::finalizeObject or by calling SectionMemoryManager::finalizeMemory /// directly. Clients of MCJIT should call MCJIT::finalizeObject. class SectionMemoryManager : public RTDyldMemoryManager { SectionMemoryManager(const SectionMemoryManager&) LLVM_DELETED_FUNCTION; @@ -60,17 +60,18 @@ public: unsigned SectionID, bool isReadOnly); - /// \brief Applies section-specific memory permissions. + /// \brief Update section-specific memory permissions and other attributes. /// /// This method is called when object loading is complete and section page /// permissions can be applied. It is up to the memory manager implementation /// to decide whether or not to act on this method. The memory manager will /// typically allocate all sections as read-write and then apply specific /// permissions when this method is called. Code sections cannot be executed - /// until this function has been called. + /// until this function has been called. In addition, any cache coherency + /// operations needed to reliably use the memory are also performed. /// /// \returns true if an error occurred, false otherwise. - virtual bool applyPermissions(std::string *ErrMsg = 0); + virtual bool finalizeMemory(std::string *ErrMsg = 0); void registerEHFrames(StringRef SectionData); @@ -89,7 +90,7 @@ public: /// explicit cache flush, otherwise JIT code manipulations (like resolved /// relocations) will get to the data cache but not to the instruction cache. /// - /// This method is called from applyPermissions. + /// This method is called from finalizeMemory. virtual void invalidateInstructionCache(); private: diff --git a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp index bf5680d832d..6a1db16a6a1 100644 --- a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp +++ b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp @@ -509,7 +509,7 @@ namespace { return (uint8_t*)DataAllocator.Allocate(Size, Alignment); } - bool applyPermissions(std::string *ErrMsg) { + bool finalizeMemory(std::string *ErrMsg) { return false; } diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/lib/ExecutionEngine/MCJIT/MCJIT.cpp index ced567205aa..e8619385635 100644 --- a/lib/ExecutionEngine/MCJIT/MCJIT.cpp +++ b/lib/ExecutionEngine/MCJIT/MCJIT.cpp @@ -178,7 +178,7 @@ void MCJIT::finalizeObject() { MemMgr->registerEHFrames(EHData); // Set page permissions. - MemMgr->applyPermissions(); + MemMgr->finalizeMemory(); } void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) { diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.h b/lib/ExecutionEngine/MCJIT/MCJIT.h index 7f247e2dee5..a899d4f4080 100644 --- a/lib/ExecutionEngine/MCJIT/MCJIT.h +++ b/lib/ExecutionEngine/MCJIT/MCJIT.h @@ -52,6 +52,13 @@ public: /// Sets the object manager that MCJIT should use to avoid compilation. virtual void setObjectCache(ObjectCache *manager); + /// finalizeObject - ensure the module is fully processed and is usable. + /// + /// It is the user-level function for completing the process of making the + /// object usable for execution. It should be called after sections within an + /// object have been relocated using mapSectionAddress. When this method is + /// called the MCJIT execution engine will reapply relocations for a loaded + /// object. virtual void finalizeObject(); virtual void *getPointerToBasicBlock(BasicBlock *BB); diff --git a/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp b/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp index bac77ce75f4..1bb0103f08e 100644 --- a/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp +++ b/lib/ExecutionEngine/MCJIT/SectionMemoryManager.cpp @@ -111,7 +111,7 @@ uint8_t *SectionMemoryManager::allocateSection(MemoryGroup &MemGroup, return (uint8_t*)Addr; } -bool SectionMemoryManager::applyPermissions(std::string *ErrMsg) +bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) { // FIXME: Should in-progress permissions be reverted if an error occurs? error_code ec; diff --git a/tools/lli/RecordingMemoryManager.h b/tools/lli/RecordingMemoryManager.h index f3d026f2419..b2919c39790 100644 --- a/tools/lli/RecordingMemoryManager.h +++ b/tools/lli/RecordingMemoryManager.h @@ -58,7 +58,7 @@ public: void *getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure = true); - bool applyPermissions(std::string *ErrMsg) { return false; } + bool finalizeMemory(std::string *ErrMsg) { return false; } // The following obsolete JITMemoryManager calls are stubbed out for // this model. diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index ead541a5b80..b68f2a08d92 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -69,7 +69,7 @@ public: return 0; } - bool applyPermissions(std::string *ErrMsg) { return false; } + bool finalizeMemory(std::string *ErrMsg) { return false; } // Invalidate instruction cache for sections with execute permissions. // Some platforms with separate data cache and instruction cache require diff --git a/unittests/ExecutionEngine/JIT/JITTest.cpp b/unittests/ExecutionEngine/JIT/JITTest.cpp index cf995aac7a1..f8d9da27550 100644 --- a/unittests/ExecutionEngine/JIT/JITTest.cpp +++ b/unittests/ExecutionEngine/JIT/JITTest.cpp @@ -127,7 +127,7 @@ public: unsigned SectionID) { return Base->allocateCodeSection(Size, Alignment, SectionID); } - virtual bool applyPermissions(std::string *ErrMsg) { return false; } + virtual bool finalizeMemory(std::string *ErrMsg) { return false; } virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) { return Base->allocateSpace(Size, Alignment); } diff --git a/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp index ab09acad0d3..9e0b35395e5 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp @@ -46,7 +46,7 @@ TEST(MCJITMemoryManagerTest, BasicAllocations) { } std::string Error; - EXPECT_FALSE(MemMgr->applyPermissions(&Error)); + EXPECT_FALSE(MemMgr->finalizeMemory(&Error)); } TEST(MCJITMemoryManagerTest, LargeAllocations) { @@ -79,7 +79,7 @@ TEST(MCJITMemoryManagerTest, LargeAllocations) { } std::string Error; - EXPECT_FALSE(MemMgr->applyPermissions(&Error)); + EXPECT_FALSE(MemMgr->finalizeMemory(&Error)); } TEST(MCJITMemoryManagerTest, ManyAllocations) { @@ -114,7 +114,7 @@ TEST(MCJITMemoryManagerTest, ManyAllocations) { } std::string Error; - EXPECT_FALSE(MemMgr->applyPermissions(&Error)); + EXPECT_FALSE(MemMgr->finalizeMemory(&Error)); } TEST(MCJITMemoryManagerTest, ManyVariedAllocations) { diff --git a/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp index abe8be450ae..32fc292496c 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITObjectCacheTest.cpp @@ -101,11 +101,10 @@ protected: ASSERT_TRUE(TheJIT.isValid()); ASSERT_TRUE(0 != Main); + // We may be using a null cache, so ensure compilation is valid. TheJIT->finalizeObject(); void *vPtr = TheJIT->getPointerToFunction(Main); - static_cast(MM)->invalidateInstructionCache(); - EXPECT_TRUE(0 != vPtr) << "Unable to get pointer to main() from JIT"; diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp index e9cf904b181..43a82984c45 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp @@ -34,6 +34,7 @@ namespace { /* TEST_F(MCJITTest, empty_module) { createJIT(M.take()); + TheJIT->finalizeObject(); //EXPECT_NE(0, TheJIT->getObjectImage()) // << "Unable to generate executable loaded object image"; } @@ -46,8 +47,7 @@ TEST_F(MCJITTest, global_variable) { GlobalValue *Global = insertGlobalInt32(M.get(), "test_global", initialValue); createJIT(M.take()); void *globalPtr = TheJIT->getPointerToGlobal(Global); - MM->applyPermissions(); - static_cast(MM)->invalidateInstructionCache(); + TheJIT->finalizeObject(); EXPECT_TRUE(0 != globalPtr) << "Unable to get pointer to global value from JIT"; @@ -61,8 +61,7 @@ TEST_F(MCJITTest, add_function) { Function *F = insertAddFunction(M.get()); createJIT(M.take()); void *addPtr = TheJIT->getPointerToFunction(F); - MM->applyPermissions(); - static_cast(MM)->invalidateInstructionCache(); + TheJIT->finalizeObject(); EXPECT_TRUE(0 != addPtr) << "Unable to get pointer to function from JIT"; @@ -79,8 +78,7 @@ TEST_F(MCJITTest, run_main) { Function *Main = insertMainFunction(M.get(), 6); createJIT(M.take()); void *vPtr = TheJIT->getPointerToFunction(Main); - MM->applyPermissions(); - static_cast(MM)->invalidateInstructionCache(); + TheJIT->finalizeObject(); EXPECT_TRUE(0 != vPtr) << "Unable to get pointer to main() from JIT"; @@ -102,8 +100,7 @@ TEST_F(MCJITTest, return_global) { createJIT(M.take()); void *rgvPtr = TheJIT->getPointerToFunction(ReturnGlobal); - MM->applyPermissions(); - static_cast(MM)->invalidateInstructionCache(); + TheJIT->finalizeObject(); EXPECT_TRUE(0 != rgvPtr); int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)rgvPtr; @@ -134,6 +131,7 @@ TEST_F(MCJITTest, increment_global) { createJIT(M.take()); void *gvPtr = TheJIT->getPointerToGlobal(GV); + TheJIT->finalizeObject(); EXPECT_EQ(initialNum, *(int32_t*)gvPtr); void *vPtr = TheJIT->getPointerToFunction(IncrementGlobal); @@ -150,6 +148,9 @@ TEST_F(MCJITTest, increment_global) { } */ +// PR16013: XFAIL this test on ARM, which currently can't handle multiple relocations. +#if !defined(__arm__) + TEST_F(MCJITTest, multiple_functions) { SKIP_UNSUPPORTED_PLATFORM; @@ -172,8 +173,7 @@ TEST_F(MCJITTest, multiple_functions) { createJIT(M.take()); void *vPtr = TheJIT->getPointerToFunction(Outer); - MM->applyPermissions(); - static_cast(MM)->invalidateInstructionCache(); + TheJIT->finalizeObject(); EXPECT_TRUE(0 != vPtr) << "Unable to get pointer to outer function from JIT"; @@ -182,6 +182,8 @@ TEST_F(MCJITTest, multiple_functions) { << "Incorrect result returned from function"; } +#endif /*!defined(__arm__)*/ + // FIXME: ExecutionEngine has no support empty modules /* TEST_F(MCJITTest, multiple_empty_modules) { @@ -219,6 +221,7 @@ TEST_F(MCJITTest, multiple_modules) { // get a function pointer in a module that was not used in EE construction void *vPtr = TheJIT->getPointerToFunction(Caller); + TheJIT->finalizeObject(); EXPECT_NE(0, vPtr) << "Unable to get pointer to caller function from JIT";