diff options
author | Jeffrey Yasskin <jyasskin@google.com> | 2009-10-27 00:03:05 +0000 |
---|---|---|
committer | Jeffrey Yasskin <jyasskin@google.com> | 2009-10-27 00:03:05 +0000 |
commit | 7a9034c4db248fe8b8cb82762881b51b221988d3 (patch) | |
tree | 730343fa9578d5b2ea0637b4cf330070aab8c0f7 /unittests/ExecutionEngine/JIT/JITTest.cpp | |
parent | f2becca90b832cc02345fba063b9b439b2be33ad (diff) |
Automatically do the equivalent of freeMachineCodeForFunction(F) when F is
being destroyed. This allows users to run global optimizations like globaldce
even after some functions have been jitted.
This patch also removes the Function* parameter to
JITEventListener::NotifyFreeingMachineCode() since it can cause that to be
called when the Function is partially destroyed. This change will be even more
helpful later when I think we'll want to allow machine code to actually outlive
its Function.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@85182 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests/ExecutionEngine/JIT/JITTest.cpp')
-rw-r--r-- | unittests/ExecutionEngine/JIT/JITTest.cpp | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/unittests/ExecutionEngine/JIT/JITTest.cpp b/unittests/ExecutionEngine/JIT/JITTest.cpp index e47a4370ae..51b4aa1193 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 |