diff options
Diffstat (limited to 'unittests')
-rw-r--r-- | unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp | 11 | ||||
-rw-r--r-- | unittests/ExecutionEngine/JIT/JITTest.cpp | 160 |
2 files changed, 162 insertions, 9 deletions
diff --git a/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp b/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp index 87e3280..dda86fb 100644 --- a/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp +++ b/unittests/ExecutionEngine/JIT/JITEventListenerTest.cpp @@ -37,7 +37,6 @@ struct FunctionEmittedEvent { }; struct FunctionFreedEvent { unsigned Index; - const Function *F; void *Code; }; @@ -56,8 +55,8 @@ struct RecordingJITEventListener : public JITEventListener { EmittedEvents.push_back(Event); } - virtual void NotifyFreeingMachineCode(const Function &F, void *OldPtr) { - FunctionFreedEvent Event = {NextIndex++, &F, OldPtr}; + virtual void NotifyFreeingMachineCode(void *OldPtr) { + FunctionFreedEvent Event = {NextIndex++, OldPtr}; FreedEvents.push_back(Event); } }; @@ -116,11 +115,9 @@ TEST_F(JITEventListenerTest, Simple) { << " contain some bytes."; EXPECT_EQ(2U, Listener.FreedEvents[0].Index); - EXPECT_EQ(F1, Listener.FreedEvents[0].F); EXPECT_EQ(F1_addr, Listener.FreedEvents[0].Code); EXPECT_EQ(3U, Listener.FreedEvents[1].Index); - EXPECT_EQ(F2, Listener.FreedEvents[1].F); EXPECT_EQ(F2_addr, Listener.FreedEvents[1].Code); F1->eraseFromParent(); @@ -164,7 +161,6 @@ TEST_F(JITEventListenerTest, MultipleListenersDontInterfere) { << " contain some bytes."; EXPECT_EQ(1U, Listener1.FreedEvents[0].Index); - EXPECT_EQ(F2, Listener1.FreedEvents[0].F); EXPECT_EQ(F2_addr, Listener1.FreedEvents[0].Code); // Listener 2. @@ -186,7 +182,6 @@ TEST_F(JITEventListenerTest, MultipleListenersDontInterfere) { << " contain some bytes."; EXPECT_EQ(2U, Listener2.FreedEvents[0].Index); - EXPECT_EQ(F2, Listener2.FreedEvents[0].F); EXPECT_EQ(F2_addr, Listener2.FreedEvents[0].Code); // Listener 3. @@ -201,7 +196,6 @@ TEST_F(JITEventListenerTest, MultipleListenersDontInterfere) { << " contain some bytes."; EXPECT_EQ(1U, Listener3.FreedEvents[0].Index); - EXPECT_EQ(F2, Listener3.FreedEvents[0].F); EXPECT_EQ(F2_addr, Listener3.FreedEvents[0].Code); F1->eraseFromParent(); @@ -228,7 +222,6 @@ TEST_F(JITEventListenerTest, MatchesMachineCodeInfo) { EXPECT_EQ(MCI.size(), Listener.EmittedEvents[0].Size); EXPECT_EQ(1U, Listener.FreedEvents[0].Index); - EXPECT_EQ(F, Listener.FreedEvents[0].F); EXPECT_EQ(F_addr, Listener.FreedEvents[0].Code); } diff --git a/unittests/ExecutionEngine/JIT/JITTest.cpp b/unittests/ExecutionEngine/JIT/JITTest.cpp index e47a437..51b4aa1 100644 --- a/unittests/ExecutionEngine/JIT/JITTest.cpp +++ b/unittests/ExecutionEngine/JIT/JITTest.cpp @@ -9,6 +9,7 @@ #include "gtest/gtest.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/Assembly/Parser.h" #include "llvm/BasicBlock.h" #include "llvm/Constant.h" @@ -28,6 +29,8 @@ #include "llvm/Target/TargetSelect.h" #include "llvm/Type.h" +#include <vector> + using namespace llvm; namespace { @@ -47,13 +50,141 @@ Function *makeReturnGlobal(std::string Name, GlobalVariable *G, Module *M) { return F; } +std::string DumpFunction(const Function *F) { + std::string Result; + raw_string_ostream(Result) << "" << *F; + return Result; +} + +class RecordingJITMemoryManager : public JITMemoryManager { + const OwningPtr<JITMemoryManager> Base; +public: + RecordingJITMemoryManager() + : Base(JITMemoryManager::CreateDefaultMemManager()) { + } + + virtual void setMemoryWritable() { Base->setMemoryWritable(); } + virtual void setMemoryExecutable() { Base->setMemoryExecutable(); } + virtual void setPoisonMemory(bool poison) { Base->setPoisonMemory(poison); } + virtual void AllocateGOT() { Base->AllocateGOT(); } + virtual uint8_t *getGOTBase() const { return Base->getGOTBase(); } + virtual void SetDlsymTable(void *ptr) { Base->SetDlsymTable(ptr); } + virtual void *getDlsymTable() const { return Base->getDlsymTable(); } + struct StartFunctionBodyCall { + StartFunctionBodyCall(uint8_t *Result, const Function *F, + uintptr_t ActualSize, uintptr_t ActualSizeResult) + : Result(Result), F(F), F_dump(DumpFunction(F)), + ActualSize(ActualSize), ActualSizeResult(ActualSizeResult) {} + uint8_t *Result; + const Function *F; + std::string F_dump; + uintptr_t ActualSize; + uintptr_t ActualSizeResult; + }; + std::vector<StartFunctionBodyCall> startFunctionBodyCalls; + virtual uint8_t *startFunctionBody(const Function *F, + uintptr_t &ActualSize) { + uintptr_t InitialActualSize = ActualSize; + uint8_t *Result = Base->startFunctionBody(F, ActualSize); + startFunctionBodyCalls.push_back( + StartFunctionBodyCall(Result, F, InitialActualSize, ActualSize)); + return Result; + } + virtual uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize, + unsigned Alignment) { + return Base->allocateStub(F, StubSize, Alignment); + } + struct EndFunctionBodyCall { + EndFunctionBodyCall(const Function *F, uint8_t *FunctionStart, + uint8_t *FunctionEnd) + : F(F), F_dump(DumpFunction(F)), + FunctionStart(FunctionStart), FunctionEnd(FunctionEnd) {} + const Function *F; + std::string F_dump; + uint8_t *FunctionStart; + uint8_t *FunctionEnd; + }; + std::vector<EndFunctionBodyCall> endFunctionBodyCalls; + virtual void endFunctionBody(const Function *F, uint8_t *FunctionStart, + uint8_t *FunctionEnd) { + endFunctionBodyCalls.push_back( + EndFunctionBodyCall(F, FunctionStart, FunctionEnd)); + Base->endFunctionBody(F, FunctionStart, FunctionEnd); + } + virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) { + return Base->allocateSpace(Size, Alignment); + } + virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) { + return Base->allocateGlobal(Size, Alignment); + } + struct DeallocateFunctionBodyCall { + DeallocateFunctionBodyCall(const void *Body) : Body(Body) {} + const void *Body; + }; + std::vector<DeallocateFunctionBodyCall> deallocateFunctionBodyCalls; + virtual void deallocateFunctionBody(void *Body) { + deallocateFunctionBodyCalls.push_back(DeallocateFunctionBodyCall(Body)); + Base->deallocateFunctionBody(Body); + } + struct DeallocateExceptionTableCall { + DeallocateExceptionTableCall(const void *ET) : ET(ET) {} + const void *ET; + }; + std::vector<DeallocateExceptionTableCall> deallocateExceptionTableCalls; + virtual void deallocateExceptionTable(void *ET) { + deallocateExceptionTableCalls.push_back(DeallocateExceptionTableCall(ET)); + Base->deallocateExceptionTable(ET); + } + struct StartExceptionTableCall { + StartExceptionTableCall(uint8_t *Result, const Function *F, + uintptr_t ActualSize, uintptr_t ActualSizeResult) + : Result(Result), F(F), F_dump(DumpFunction(F)), + ActualSize(ActualSize), ActualSizeResult(ActualSizeResult) {} + uint8_t *Result; + const Function *F; + std::string F_dump; + uintptr_t ActualSize; + uintptr_t ActualSizeResult; + }; + std::vector<StartExceptionTableCall> startExceptionTableCalls; + virtual uint8_t* startExceptionTable(const Function* F, + uintptr_t &ActualSize) { + uintptr_t InitialActualSize = ActualSize; + uint8_t *Result = Base->startExceptionTable(F, ActualSize); + startExceptionTableCalls.push_back( + StartExceptionTableCall(Result, F, InitialActualSize, ActualSize)); + return Result; + } + struct EndExceptionTableCall { + EndExceptionTableCall(const Function *F, uint8_t *TableStart, + uint8_t *TableEnd, uint8_t* FrameRegister) + : F(F), F_dump(DumpFunction(F)), + TableStart(TableStart), TableEnd(TableEnd), + FrameRegister(FrameRegister) {} + const Function *F; + std::string F_dump; + uint8_t *TableStart; + uint8_t *TableEnd; + uint8_t *FrameRegister; + }; + std::vector<EndExceptionTableCall> endExceptionTableCalls; + virtual void endExceptionTable(const Function *F, uint8_t *TableStart, + uint8_t *TableEnd, uint8_t* FrameRegister) { + endExceptionTableCalls.push_back( + EndExceptionTableCall(F, TableStart, TableEnd, FrameRegister)); + return Base->endExceptionTable(F, TableStart, TableEnd, FrameRegister); + } +}; + class JITTest : public testing::Test { protected: virtual void SetUp() { M = new Module("<main>", Context); MP = new ExistingModuleProvider(M); + RJMM = new RecordingJITMemoryManager; std::string Error; TheJIT.reset(EngineBuilder(MP).setEngineKind(EngineKind::JIT) + .setJITMemoryManager(RJMM) .setErrorStr(&Error).create()); ASSERT_TRUE(TheJIT.get() != NULL) << Error; } @@ -70,6 +201,7 @@ class JITTest : public testing::Test { LLVMContext Context; Module *M; // Owned by MP. ModuleProvider *MP; // Owned by ExecutionEngine. + RecordingJITMemoryManager *RJMM; OwningPtr<ExecutionEngine> TheJIT; }; @@ -289,6 +421,34 @@ TEST_F(JITTest, ModuleDeletion) { Function *func = M->getFunction("main"); TheJIT->getPointerToFunction(func); TheJIT->deleteModuleProvider(MP); + + SmallPtrSet<const void*, 2> FunctionsDeallocated; + for (unsigned i = 0, e = RJMM->deallocateFunctionBodyCalls.size(); + i != e; ++i) { + FunctionsDeallocated.insert(RJMM->deallocateFunctionBodyCalls[i].Body); + } + for (unsigned i = 0, e = RJMM->startFunctionBodyCalls.size(); i != e; ++i) { + EXPECT_TRUE(FunctionsDeallocated.count( + RJMM->startFunctionBodyCalls[i].Result)) + << "Function leaked: \n" << RJMM->startFunctionBodyCalls[i].F_dump; + } + EXPECT_EQ(RJMM->startFunctionBodyCalls.size(), + RJMM->deallocateFunctionBodyCalls.size()); + + SmallPtrSet<const void*, 2> ExceptionTablesDeallocated; + for (unsigned i = 0, e = RJMM->deallocateExceptionTableCalls.size(); + i != e; ++i) { + ExceptionTablesDeallocated.insert( + RJMM->deallocateExceptionTableCalls[i].ET); + } + for (unsigned i = 0, e = RJMM->startExceptionTableCalls.size(); i != e; ++i) { + EXPECT_TRUE(ExceptionTablesDeallocated.count( + RJMM->startExceptionTableCalls[i].Result)) + << "Function's exception table leaked: \n" + << RJMM->startExceptionTableCalls[i].F_dump; + } + EXPECT_EQ(RJMM->startExceptionTableCalls.size(), + RJMM->deallocateExceptionTableCalls.size()); } // This code is copied from JITEventListenerTest, but it only runs once for all |