X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FExecutionEngine%2FJIT%2FJITMemoryManager.cpp;h=584b93f81502a367012540f8eef2d366c8d9960e;hb=7ad7c75048eb32f95eae04847908793e0183802f;hp=66aeb772ddc3770ef752e8cb6836433e3fbfab2b;hpb=fe1215ef935f182cdca28b4af655fa0bfa0f47e6;p=oota-llvm.git diff --git a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp index 66aeb772ddc..584b93f8150 100644 --- a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp +++ b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "jit" #include "llvm/ExecutionEngine/JITMemoryManager.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" @@ -40,6 +39,8 @@ using namespace llvm; +#define DEBUG_TYPE "jit" + STATISTIC(NumSlabs, "Number of slabs of memory allocated by the JIT"); JITMemoryManager::~JITMemoryManager() {} @@ -80,7 +81,7 @@ namespace { /// getFreeBlockBefore - If the block before this one is free, return it, /// otherwise return null. FreeRangeHeader *getFreeBlockBefore() const { - if (PrevAllocated) return 0; + if (PrevAllocated) return nullptr; intptr_t PrevSize = reinterpret_cast( const_cast(this))[-1]; return reinterpret_cast( @@ -174,7 +175,7 @@ FreeRangeHeader *MemoryRangeHeader::FreeBlock(FreeRangeHeader *FreeList) { // coalesce with it, update our notion of what the free list is. if (&FollowingFreeBlock == FreeList) { FreeList = FollowingFreeBlock.Next; - FreeListToReturn = 0; + FreeListToReturn = nullptr; assert(&FollowingFreeBlock != FreeList && "No tombstone block?"); } FollowingFreeBlock.RemoveFromFreeList(); @@ -269,13 +270,12 @@ namespace { class DefaultJITMemoryManager; - class JITSlabAllocator : public SlabAllocator { + class JITAllocator { DefaultJITMemoryManager &JMM; public: - JITSlabAllocator(DefaultJITMemoryManager &jmm) : JMM(jmm) { } - virtual ~JITSlabAllocator() { } - virtual MemSlab *Allocate(size_t Size); - virtual void Deallocate(MemSlab *Slab); + JITAllocator(DefaultJITMemoryManager &jmm) : JMM(jmm) { } + void *Allocate(size_t Size, size_t /*Alignment*/); + void Deallocate(void *Slab, size_t Size); }; /// DefaultJITMemoryManager - Manage memory for the JIT code generation. @@ -285,7 +285,21 @@ namespace { /// middle of emitting a function, and we don't know how large the function we /// are emitting is. class DefaultJITMemoryManager : public JITMemoryManager { + public: + /// DefaultCodeSlabSize - When we have to go map more memory, we allocate at + /// least this much unless more is requested. Currently, in 512k slabs. + static const size_t DefaultCodeSlabSize = 512 * 1024; + + /// DefaultSlabSize - Allocate globals and stubs into slabs of 64K (probably + /// 16 pages) unless we get an allocation above SizeThreshold. + static const size_t DefaultSlabSize = 64 * 1024; + + /// DefaultSizeThreshold - For any allocation larger than 16K (probably + /// 4 pages), we should allocate a separate slab to avoid wasted space at + /// the end of a normal slab. + static const size_t DefaultSizeThreshold = 16 * 1024; + private: // Whether to poison freed memory. bool PoisonMemory; @@ -299,9 +313,10 @@ namespace { // Memory slabs allocated by the JIT. We refer to them as slabs so we don't // confuse them with the blocks of memory described above. std::vector CodeSlabs; - JITSlabAllocator BumpSlabAllocator; - BumpPtrAllocator StubAllocator; - BumpPtrAllocator DataAllocator; + BumpPtrAllocatorImpl StubAllocator; + BumpPtrAllocatorImpl DataAllocator; // Circular list of free blocks. FreeRangeHeader *FreeMemoryList; @@ -318,37 +333,26 @@ namespace { /// last slab it allocated, so that subsequent allocations follow it. sys::MemoryBlock allocateNewSlab(size_t size); - /// DefaultCodeSlabSize - When we have to go map more memory, we allocate at - /// least this much unless more is requested. - static const size_t DefaultCodeSlabSize; - - /// DefaultSlabSize - Allocate data into slabs of this size unless we get - /// an allocation above SizeThreshold. - static const size_t DefaultSlabSize; - - /// DefaultSizeThreshold - For any allocation larger than this threshold, we - /// should allocate a separate slab. - static const size_t DefaultSizeThreshold; - /// getPointerToNamedFunction - This method returns the address of the /// specified function by using the dlsym function call. - virtual void *getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure = true); + void *getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure = true) override; - void AllocateGOT(); + void AllocateGOT() override; // Testing methods. - virtual bool CheckInvariants(std::string &ErrorStr); - size_t GetDefaultCodeSlabSize() { return DefaultCodeSlabSize; } - size_t GetDefaultDataSlabSize() { return DefaultSlabSize; } - size_t GetDefaultStubSlabSize() { return DefaultSlabSize; } - unsigned GetNumCodeSlabs() { return CodeSlabs.size(); } - unsigned GetNumDataSlabs() { return DataAllocator.GetNumSlabs(); } - unsigned GetNumStubSlabs() { return StubAllocator.GetNumSlabs(); } + bool CheckInvariants(std::string &ErrorStr) override; + size_t GetDefaultCodeSlabSize() override { return DefaultCodeSlabSize; } + size_t GetDefaultDataSlabSize() override { return DefaultSlabSize; } + size_t GetDefaultStubSlabSize() override { return DefaultSlabSize; } + unsigned GetNumCodeSlabs() override { return CodeSlabs.size(); } + unsigned GetNumDataSlabs() override { return DataAllocator.GetNumSlabs(); } + unsigned GetNumStubSlabs() override { return StubAllocator.GetNumSlabs(); } /// startFunctionBody - When a function starts, allocate a block of free /// executable memory, returning a pointer to it and its actual size. - uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize) { + uint8_t *startFunctionBody(const Function *F, + uintptr_t &ActualSize) override { FreeRangeHeader* candidateBlock = FreeMemoryList; FreeRangeHeader* head = FreeMemoryList; @@ -422,7 +426,7 @@ namespace { /// endFunctionBody - The function F is now allocated, and takes the memory /// in the range [FunctionStart,FunctionEnd). void endFunctionBody(const Function *F, uint8_t *FunctionStart, - uint8_t *FunctionEnd) { + uint8_t *FunctionEnd) override { assert(FunctionEnd > FunctionStart); assert(FunctionStart == (uint8_t *)(CurBlock+1) && "Mismatched function start/end!"); @@ -435,7 +439,7 @@ namespace { /// allocateSpace - Allocate a memory block of the given size. This method /// cannot be called between calls to startFunctionBody and endFunctionBody. - uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) { + uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) override { CurBlock = FreeMemoryList; FreeMemoryList = FreeMemoryList->AllocateBlock(); @@ -453,22 +457,27 @@ namespace { /// allocateStub - Allocate memory for a function stub. uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize, - unsigned Alignment) { + unsigned Alignment) override { return (uint8_t*)StubAllocator.Allocate(StubSize, Alignment); } /// allocateGlobal - Allocate memory for a global. - uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) { + uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) override { return (uint8_t*)DataAllocator.Allocate(Size, Alignment); } /// allocateCodeSection - Allocate memory for a code section. uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID) { + unsigned SectionID, + StringRef SectionName) override { // Grow the required block size to account for the block header Size += sizeof(*CurBlock); - // FIXME: Alignement handling. + // Alignment handling. + if (!Alignment) + Alignment = 16; + Size += Alignment - 1; + FreeRangeHeader* candidateBlock = FreeMemoryList; FreeRangeHeader* head = FreeMemoryList; FreeRangeHeader* iter = head->Next; @@ -500,40 +509,22 @@ namespace { FreeMemoryList = candidateBlock->AllocateBlock(); // Release the memory at the end of this block that isn't needed. FreeMemoryList = CurBlock->TrimAllocationToSize(FreeMemoryList, Size); - return (uint8_t *)(CurBlock + 1); + uintptr_t unalignedAddr = (uintptr_t)CurBlock + sizeof(*CurBlock); + return (uint8_t*)RoundUpToAlignment((uint64_t)unalignedAddr, Alignment); } /// allocateDataSection - Allocate memory for a data section. uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, bool IsReadOnly) { + unsigned SectionID, StringRef SectionName, + bool IsReadOnly) override { return (uint8_t*)DataAllocator.Allocate(Size, Alignment); } - bool applyPermissions(std::string *ErrMsg) { + bool finalizeMemory(std::string *ErrMsg) override { return false; } - /// startExceptionTable - Use startFunctionBody to allocate memory for the - /// function's exception table. - uint8_t* startExceptionTable(const Function* F, uintptr_t &ActualSize) { - return startFunctionBody(F, ActualSize); - } - - /// endExceptionTable - The exception table of F is now allocated, - /// and takes the memory in the range [TableStart,TableEnd). - void endExceptionTable(const Function *F, uint8_t *TableStart, - uint8_t *TableEnd, uint8_t* FrameRegister) { - assert(TableEnd > TableStart); - assert(TableStart == (uint8_t *)(CurBlock+1) && - "Mismatched table start/end!"); - - uintptr_t BlockSize = TableEnd - (uint8_t *)CurBlock; - - // Release the memory at the end of this block that isn't needed. - FreeMemoryList =CurBlock->TrimAllocationToSize(FreeMemoryList, BlockSize); - } - - uint8_t *getGOTBase() const { + uint8_t *getGOTBase() const override { return GOTBase; } @@ -553,63 +544,49 @@ namespace { /// deallocateFunctionBody - Deallocate all memory for the specified /// function body. - void deallocateFunctionBody(void *Body) { + void deallocateFunctionBody(void *Body) override { if (Body) deallocateBlock(Body); } - /// deallocateExceptionTable - Deallocate memory for the specified - /// exception table. - void deallocateExceptionTable(void *ET) { - if (ET) deallocateBlock(ET); - } - /// setMemoryWritable - When code generation is in progress, /// the code pages may need permissions changed. - void setMemoryWritable() - { + void setMemoryWritable() override { for (unsigned i = 0, e = CodeSlabs.size(); i != e; ++i) sys::Memory::setWritable(CodeSlabs[i]); } /// setMemoryExecutable - When code generation is done and we're ready to /// start execution, the code pages may need permissions changed. - void setMemoryExecutable() - { + void setMemoryExecutable() override { for (unsigned i = 0, e = CodeSlabs.size(); i != e; ++i) sys::Memory::setExecutable(CodeSlabs[i]); } /// setPoisonMemory - Controls whether we write garbage over freed memory. /// - void setPoisonMemory(bool poison) { + void setPoisonMemory(bool poison) override { PoisonMemory = poison; } }; } -MemSlab *JITSlabAllocator::Allocate(size_t Size) { +void *JITAllocator::Allocate(size_t Size, size_t /*Alignment*/) { sys::MemoryBlock B = JMM.allocateNewSlab(Size); - MemSlab *Slab = (MemSlab*)B.base(); - Slab->Size = B.size(); - Slab->NextPtr = 0; - return Slab; + return B.base(); } -void JITSlabAllocator::Deallocate(MemSlab *Slab) { - sys::MemoryBlock B(Slab, Slab->Size); +void JITAllocator::Deallocate(void *Slab, size_t Size) { + sys::MemoryBlock B(Slab, Size); sys::Memory::ReleaseRWX(B); } DefaultJITMemoryManager::DefaultJITMemoryManager() - : + : #ifdef NDEBUG - PoisonMemory(false), + PoisonMemory(false), #else - PoisonMemory(true), + PoisonMemory(true), #endif - LastSlab(0, 0), - BumpSlabAllocator(*this), - StubAllocator(DefaultSlabSize, DefaultSizeThreshold, BumpSlabAllocator), - DataAllocator(DefaultSlabSize, DefaultSizeThreshold, BumpSlabAllocator) { + LastSlab(nullptr, 0), StubAllocator(*this), DataAllocator(*this) { // Allocate space for code. sys::MemoryBlock MemBlock = allocateNewSlab(DefaultCodeSlabSize); @@ -662,11 +639,11 @@ DefaultJITMemoryManager::DefaultJITMemoryManager() // Start out with the freelist pointing to Mem0. FreeMemoryList = Mem0; - GOTBase = NULL; + GOTBase = nullptr; } void DefaultJITMemoryManager::AllocateGOT() { - assert(GOTBase == 0 && "Cannot allocate the got multiple times"); + assert(!GOTBase && "Cannot allocate the got multiple times"); GOTBase = new uint8_t[sizeof(void*) * 8192]; HasGOT = true; } @@ -681,9 +658,9 @@ DefaultJITMemoryManager::~DefaultJITMemoryManager() { sys::MemoryBlock DefaultJITMemoryManager::allocateNewSlab(size_t size) { // Allocate a new block close to the last one. std::string ErrMsg; - sys::MemoryBlock *LastSlabPtr = LastSlab.base() ? &LastSlab : 0; + sys::MemoryBlock *LastSlabPtr = LastSlab.base() ? &LastSlab : nullptr; sys::MemoryBlock B = sys::Memory::AllocateRWX(size, LastSlabPtr, &ErrMsg); - if (B.base() == 0) { + if (!B.base()) { report_fatal_error("Allocation failed when allocating new memory in the" " JIT\n" + Twine(ErrMsg)); } @@ -744,7 +721,7 @@ bool DefaultJITMemoryManager::CheckInvariants(std::string &ErrorStr) { char *End = Start + I->size(); // Check each memory range. - for (MemoryRangeHeader *Hdr = (MemoryRangeHeader*)Start, *LastHdr = NULL; + for (MemoryRangeHeader *Hdr = (MemoryRangeHeader*)Start, *LastHdr = nullptr; Start <= (char*)Hdr && (char*)Hdr < End; Hdr = &Hdr->getBlockAfter()) { if (Hdr->ThisAllocated == 0) { @@ -814,7 +791,7 @@ static void runAtExitHandlers() { // not inlined, and hiding their real definitions in a separate archive file // that the dynamic linker can't see. For more info, search for // 'libc_nonshared.a' on Google, or read http://llvm.org/PR274. -#if defined(__linux__) +#if defined(__linux__) && defined(__GLIBC__) /* stat functions are redirecting to __xstat with a version number. On x86-64 * linking with libc_nonshared.a and -Wl,--export-dynamic doesn't make 'stat' * available as an exported symbol, so we have to add it explicitly. @@ -913,7 +890,7 @@ void *DefaultJITMemoryManager::getPointerToNamedFunction(const std::string &Name report_fatal_error("Program used external function '"+Name+ "' which could not be resolved!"); } - return 0; + return nullptr; } @@ -922,11 +899,6 @@ JITMemoryManager *JITMemoryManager::CreateDefaultMemManager() { return new DefaultJITMemoryManager(); } -// Allocate memory for code in 512K slabs. -const size_t DefaultJITMemoryManager::DefaultCodeSlabSize = 512 * 1024; - -// Allocate globals and stubs in slabs of 64K. (probably 16 pages) -const size_t DefaultJITMemoryManager::DefaultSlabSize = 64 * 1024; - -// Waste at most 16K at the end of each bump slab. (probably 4 pages) -const size_t DefaultJITMemoryManager::DefaultSizeThreshold = 16 * 1024; +const size_t DefaultJITMemoryManager::DefaultCodeSlabSize; +const size_t DefaultJITMemoryManager::DefaultSlabSize; +const size_t DefaultJITMemoryManager::DefaultSizeThreshold;