14 #define DEBUG_TYPE "jit"
19 #include "llvm/Config/config.h"
33 #if defined(__linux__)
34 #if defined(HAVE_SYS_STAT_H)
43 STATISTIC(NumSlabs,
"Number of slabs of memory allocated by the JIT");
56 struct FreeRangeHeader;
57 struct MemoryRangeHeader {
60 unsigned ThisAllocated : 1;
65 unsigned PrevAllocated : 1;
69 uintptr_t BlockSize : (
sizeof(
intptr_t)*CHAR_BIT - 2);
74 MemoryRangeHeader &getBlockAfter()
const {
75 return *
reinterpret_cast<MemoryRangeHeader *
>(
76 reinterpret_cast<char*
>(
77 const_cast<MemoryRangeHeader *
>(
this))+BlockSize);
82 FreeRangeHeader *getFreeBlockBefore()
const {
83 if (PrevAllocated)
return 0;
85 const_cast<MemoryRangeHeader *
>(
this))[-1];
86 return reinterpret_cast<FreeRangeHeader *
>(
87 reinterpret_cast<char*
>(
88 const_cast<MemoryRangeHeader *
>(
this))-PrevSize);
93 FreeRangeHeader *FreeBlock(FreeRangeHeader *FreeList);
98 FreeRangeHeader *TrimAllocationToSize(FreeRangeHeader *FreeList,
105 struct FreeRangeHeader :
public MemoryRangeHeader {
106 FreeRangeHeader *Prev;
107 FreeRangeHeader *Next;
111 static unsigned getMinBlockSize() {
112 return sizeof(FreeRangeHeader)+
sizeof(
intptr_t);
117 void SetEndOfBlockSizeMarker() {
118 void *EndOfBlock = (
char*)
this + BlockSize;
119 ((
intptr_t *)EndOfBlock)[-1] = BlockSize;
122 FreeRangeHeader *RemoveFromFreeList() {
123 assert(Next->Prev ==
this && Prev->Next ==
this &&
"Freelist broken!");
125 return Prev->Next = Next;
128 void AddToFreeList(FreeRangeHeader *FreeList) {
130 Prev = FreeList->Prev;
137 void GrowBlock(uintptr_t NewSize);
141 FreeRangeHeader *AllocateBlock();
148 FreeRangeHeader *FreeRangeHeader::AllocateBlock() {
149 assert(!ThisAllocated && !getBlockAfter().PrevAllocated &&
150 "Cannot allocate an allocated block!");
153 getBlockAfter().PrevAllocated = 1;
156 return RemoveFromFreeList();
163 FreeRangeHeader *MemoryRangeHeader::FreeBlock(FreeRangeHeader *FreeList) {
164 MemoryRangeHeader *FollowingBlock = &getBlockAfter();
165 assert(ThisAllocated &&
"This block is already free!");
166 assert(FollowingBlock->PrevAllocated &&
"Flags out of sync!");
168 FreeRangeHeader *FreeListToReturn = FreeList;
171 if (!FollowingBlock->ThisAllocated) {
172 FreeRangeHeader &FollowingFreeBlock = *(FreeRangeHeader *)FollowingBlock;
175 if (&FollowingFreeBlock == FreeList) {
176 FreeList = FollowingFreeBlock.Next;
177 FreeListToReturn = 0;
178 assert(&FollowingFreeBlock != FreeList &&
"No tombstone block?");
180 FollowingFreeBlock.RemoveFromFreeList();
183 BlockSize += FollowingFreeBlock.BlockSize;
184 FollowingBlock = &FollowingFreeBlock.getBlockAfter();
188 FollowingBlock->PrevAllocated = 1;
191 assert(FollowingBlock->ThisAllocated &&
"Missed coalescing?");
193 if (FreeRangeHeader *PrevFreeBlock = getFreeBlockBefore()) {
194 PrevFreeBlock->GrowBlock(PrevFreeBlock->BlockSize + BlockSize);
195 return FreeListToReturn ? FreeListToReturn : PrevFreeBlock;
199 FreeRangeHeader &FreeBlock = *(FreeRangeHeader*)
this;
200 FollowingBlock->PrevAllocated = 0;
201 FreeBlock.ThisAllocated = 0;
204 FreeBlock.AddToFreeList(FreeList);
208 FreeBlock.SetEndOfBlockSizeMarker();
209 return FreeListToReturn ? FreeListToReturn : &FreeBlock;
214 void FreeRangeHeader::GrowBlock(uintptr_t NewSize) {
215 assert(NewSize > BlockSize &&
"Not growing block?");
217 SetEndOfBlockSizeMarker();
218 getBlockAfter().PrevAllocated = 0;
224 FreeRangeHeader *MemoryRangeHeader::
225 TrimAllocationToSize(FreeRangeHeader *FreeList, uint64_t NewSize) {
226 assert(ThisAllocated && getBlockAfter().PrevAllocated &&
227 "Cannot deallocate part of an allocated block!");
230 NewSize = std::max<uint64_t>(FreeRangeHeader::getMinBlockSize(), NewSize);
233 unsigned HeaderAlign = __alignof(FreeRangeHeader);
234 NewSize = (NewSize+ (HeaderAlign-1)) & ~(HeaderAlign-1);
238 assert(NewSize <= BlockSize &&
239 "Allocating more space from this block than exists!");
243 if (BlockSize <= NewSize+FreeRangeHeader::getMinBlockSize())
248 MemoryRangeHeader &FormerNextBlock = getBlockAfter();
254 FreeRangeHeader &NewNextBlock = (FreeRangeHeader &)getBlockAfter();
255 NewNextBlock.BlockSize = (
char*)&FormerNextBlock - (
char*)&NewNextBlock;
256 NewNextBlock.ThisAllocated = 0;
257 NewNextBlock.PrevAllocated = 1;
258 NewNextBlock.SetEndOfBlockSizeMarker();
259 FormerNextBlock.PrevAllocated = 0;
260 NewNextBlock.AddToFreeList(FreeList);
261 return &NewNextBlock;
270 class DefaultJITMemoryManager;
273 DefaultJITMemoryManager &JMM;
275 JITSlabAllocator(DefaultJITMemoryManager &jmm) : JMM(jmm) { }
276 virtual ~JITSlabAllocator() { }
277 virtual MemSlab *Allocate(
size_t Size);
278 virtual void Deallocate(
MemSlab *Slab);
301 std::vector<sys::MemoryBlock> CodeSlabs;
302 JITSlabAllocator BumpSlabAllocator;
307 FreeRangeHeader *FreeMemoryList;
310 MemoryRangeHeader *CurBlock;
314 DefaultJITMemoryManager();
315 ~DefaultJITMemoryManager();
323 static const size_t DefaultCodeSlabSize;
327 static const size_t DefaultSlabSize;
331 static const size_t DefaultSizeThreshold;
336 bool AbortOnFailure =
true);
341 virtual bool CheckInvariants(std::string &ErrorStr);
342 size_t GetDefaultCodeSlabSize() {
return DefaultCodeSlabSize; }
343 size_t GetDefaultDataSlabSize() {
return DefaultSlabSize; }
344 size_t GetDefaultStubSlabSize() {
return DefaultSlabSize; }
345 unsigned GetNumCodeSlabs() {
return CodeSlabs.size(); }
346 unsigned GetNumDataSlabs() {
return DataAllocator.GetNumSlabs(); }
347 unsigned GetNumStubSlabs() {
return StubAllocator.GetNumSlabs(); }
351 uint8_t *startFunctionBody(
const Function *
F, uintptr_t &ActualSize) {
353 FreeRangeHeader* candidateBlock = FreeMemoryList;
354 FreeRangeHeader* head = FreeMemoryList;
355 FreeRangeHeader* iter = head->Next;
357 uintptr_t largest = candidateBlock->BlockSize;
360 while (iter != head) {
361 if (iter->BlockSize > largest) {
362 largest = iter->BlockSize;
363 candidateBlock = iter;
368 largest = largest -
sizeof(MemoryRangeHeader);
372 if (largest < ActualSize ||
373 largest <= FreeRangeHeader::getMinBlockSize()) {
374 DEBUG(
dbgs() <<
"JIT: Allocating another slab of memory for function.");
375 candidateBlock = allocateNewCodeSlab((
size_t)ActualSize);
379 CurBlock = candidateBlock;
382 FreeMemoryList = candidateBlock->AllocateBlock();
383 ActualSize = CurBlock->BlockSize -
sizeof(MemoryRangeHeader);
384 return (uint8_t *)(CurBlock + 1);
390 FreeRangeHeader *allocateNewCodeSlab(
size_t MinSize) {
394 size_t PaddedMin = MinSize + 2 *
sizeof(MemoryRangeHeader);
395 size_t SlabSize = std::max(DefaultCodeSlabSize, PaddedMin);
397 CodeSlabs.push_back(B);
398 char *MemBase = (
char*)(B.
base());
402 MemoryRangeHeader *EndBlock =
403 (MemoryRangeHeader*)(MemBase + B.
size()) - 1;
404 EndBlock->ThisAllocated = 1;
405 EndBlock->PrevAllocated = 0;
406 EndBlock->BlockSize =
sizeof(MemoryRangeHeader);
409 FreeRangeHeader *NewBlock = (FreeRangeHeader*)MemBase;
410 NewBlock->ThisAllocated = 0;
412 NewBlock->PrevAllocated = 1;
413 NewBlock->BlockSize = (uintptr_t)EndBlock - (uintptr_t)NewBlock;
414 NewBlock->SetEndOfBlockSizeMarker();
415 NewBlock->AddToFreeList(FreeMemoryList);
417 assert(NewBlock->BlockSize -
sizeof(MemoryRangeHeader) >= MinSize &&
418 "The block was too small!");
424 void endFunctionBody(
const Function *F, uint8_t *FunctionStart,
425 uint8_t *FunctionEnd) {
426 assert(FunctionEnd > FunctionStart);
427 assert(FunctionStart == (uint8_t *)(CurBlock+1) &&
428 "Mismatched function start/end!");
430 uintptr_t BlockSize = FunctionEnd - (uint8_t *)CurBlock;
433 FreeMemoryList =CurBlock->TrimAllocationToSize(FreeMemoryList, BlockSize);
438 uint8_t *allocateSpace(
intptr_t Size,
unsigned Alignment) {
439 CurBlock = FreeMemoryList;
440 FreeMemoryList = FreeMemoryList->AllocateBlock();
442 uint8_t *result = (uint8_t *)(CurBlock + 1);
444 if (Alignment == 0) Alignment = 1;
445 result = (uint8_t*)(((
intptr_t)result+Alignment-1) &
448 uintptr_t BlockSize = result + Size - (uint8_t *)CurBlock;
449 FreeMemoryList =CurBlock->TrimAllocationToSize(FreeMemoryList, BlockSize);
455 uint8_t *allocateStub(
const GlobalValue* F,
unsigned StubSize,
456 unsigned Alignment) {
457 return (uint8_t*)StubAllocator.Allocate(StubSize, Alignment);
461 uint8_t *allocateGlobal(uintptr_t Size,
unsigned Alignment) {
462 return (uint8_t*)DataAllocator.Allocate(Size, Alignment);
466 uint8_t *allocateCodeSection(uintptr_t Size,
unsigned Alignment,
467 unsigned SectionID,
StringRef SectionName) {
469 Size +=
sizeof(*CurBlock);
474 Size += Alignment - 1;
476 FreeRangeHeader* candidateBlock = FreeMemoryList;
477 FreeRangeHeader* head = FreeMemoryList;
478 FreeRangeHeader* iter = head->Next;
480 uintptr_t largest = candidateBlock->BlockSize;
483 while (iter != head) {
484 if (iter->BlockSize > largest) {
485 largest = iter->BlockSize;
486 candidateBlock = iter;
491 largest = largest -
sizeof(MemoryRangeHeader);
495 if (largest < Size || largest <= FreeRangeHeader::getMinBlockSize()) {
496 DEBUG(
dbgs() <<
"JIT: Allocating another slab of memory for function.");
497 candidateBlock = allocateNewCodeSlab((
size_t)Size);
501 CurBlock = candidateBlock;
504 FreeMemoryList = candidateBlock->AllocateBlock();
506 FreeMemoryList = CurBlock->TrimAllocationToSize(FreeMemoryList, Size);
507 uintptr_t unalignedAddr = (uintptr_t)CurBlock +
sizeof(*CurBlock);
512 uint8_t *allocateDataSection(uintptr_t Size,
unsigned Alignment,
513 unsigned SectionID,
StringRef SectionName,
515 return (uint8_t*)DataAllocator.Allocate(Size, Alignment);
518 bool finalizeMemory(std::string *ErrMsg) {
522 uint8_t *getGOTBase()
const {
526 void deallocateBlock(
void *Block) {
528 MemoryRangeHeader *MemRange =
static_cast<MemoryRangeHeader*
>(Block) - 1;
529 assert(MemRange->ThisAllocated &&
"Block isn't allocated!");
533 memset(MemRange+1, 0xCD, MemRange->BlockSize-
sizeof(*MemRange));
537 FreeMemoryList = MemRange->FreeBlock(FreeMemoryList);
542 void deallocateFunctionBody(
void *Body) {
543 if (Body) deallocateBlock(Body);
548 void setMemoryWritable()
550 for (
unsigned i = 0, e = CodeSlabs.size(); i != e; ++i)
555 void setMemoryExecutable()
557 for (
unsigned i = 0, e = CodeSlabs.size(); i != e; ++i)
563 void setPoisonMemory(
bool poison) {
564 PoisonMemory = poison;
569 MemSlab *JITSlabAllocator::Allocate(
size_t Size) {
577 void JITSlabAllocator::Deallocate(
MemSlab *Slab) {
582 DefaultJITMemoryManager::DefaultJITMemoryManager()
590 BumpSlabAllocator(*this),
591 StubAllocator(DefaultSlabSize, DefaultSizeThreshold, BumpSlabAllocator),
592 DataAllocator(DefaultSlabSize, DefaultSizeThreshold, BumpSlabAllocator) {
596 CodeSlabs.push_back(MemBlock);
597 uint8_t *MemBase = (uint8_t*)MemBlock.
base();
611 MemoryRangeHeader *Mem3 = (MemoryRangeHeader*)(MemBase+MemBlock.
size())-1;
612 Mem3->ThisAllocated = 1;
613 Mem3->PrevAllocated = 0;
614 Mem3->BlockSize =
sizeof(MemoryRangeHeader);
617 FreeRangeHeader *Mem2 =
618 (FreeRangeHeader *)(((
char*)Mem3)-FreeRangeHeader::getMinBlockSize());
619 Mem2->ThisAllocated = 0;
620 Mem2->PrevAllocated = 1;
621 Mem2->BlockSize = FreeRangeHeader::getMinBlockSize();
622 Mem2->SetEndOfBlockSizeMarker();
627 MemoryRangeHeader *Mem1 = (MemoryRangeHeader*)Mem2-1;
628 Mem1->ThisAllocated = 1;
629 Mem1->PrevAllocated = 0;
630 Mem1->BlockSize =
sizeof(MemoryRangeHeader);
635 FreeRangeHeader *Mem0 = (FreeRangeHeader*)MemBase;
636 Mem0->ThisAllocated = 0;
637 Mem0->PrevAllocated = 1;
638 Mem0->BlockSize = (
char*)Mem1-(
char*)Mem0;
639 Mem0->SetEndOfBlockSizeMarker();
640 Mem0->AddToFreeList(Mem2);
643 FreeMemoryList = Mem0;
648 void DefaultJITMemoryManager::AllocateGOT() {
649 assert(GOTBase == 0 &&
"Cannot allocate the got multiple times");
650 GOTBase =
new uint8_t[
sizeof(
void*) * 8192];
654 DefaultJITMemoryManager::~DefaultJITMemoryManager() {
655 for (
unsigned i = 0, e = CodeSlabs.size(); i != e; ++i)
668 " JIT\n" +
Twine(ErrMsg));
687 bool DefaultJITMemoryManager::CheckInvariants(std::string &ErrorStr) {
693 FreeRangeHeader* FreeHead = FreeMemoryList;
694 FreeRangeHeader* FreeRange = FreeHead;
699 for (std::vector<sys::MemoryBlock>::iterator
I = CodeSlabs.begin(),
700 E = CodeSlabs.end();
I != E && !Found; ++
I) {
701 char *Start = (
char*)
I->base();
702 char *End = Start +
I->size();
703 Found = (Start <= (
char*)FreeRange && (
char*)FreeRange < End);
706 Err <<
"Corrupt free list; points to " << FreeRange;
710 if (FreeRange->Next->Prev != FreeRange) {
711 Err <<
"Next and Prev pointers do not match.";
716 FreeHdrSet.
insert(FreeRange);
717 FreeRange = FreeRange->Next;
718 }
while (FreeRange != FreeHead);
721 for (std::vector<sys::MemoryBlock>::iterator
I = CodeSlabs.begin(),
722 E = CodeSlabs.end();
I != E; ++
I) {
723 char *Start = (
char*)
I->base();
724 char *End = Start +
I->size();
727 for (MemoryRangeHeader *Hdr = (MemoryRangeHeader*)Start, *LastHdr = NULL;
728 Start <= (
char*)Hdr && (
char*)Hdr < End;
729 Hdr = &Hdr->getBlockAfter()) {
730 if (Hdr->ThisAllocated == 0) {
732 if (!FreeHdrSet.
count(Hdr)) {
733 Err <<
"Found free header at " << Hdr <<
" that is not in free list.";
738 uintptr_t *Marker = ((uintptr_t*)&Hdr->getBlockAfter()) - 1;
739 if (!(Start <= (
char*)Marker && (
char*)Marker < End)) {
740 Err <<
"Block size in header points out of current MemoryBlock.";
743 if (Hdr->BlockSize != *Marker) {
744 Err <<
"End of block size marker (" << *Marker <<
") "
745 <<
"and BlockSize (" << Hdr->BlockSize <<
") don't match.";
750 if (LastHdr && LastHdr->ThisAllocated != Hdr->PrevAllocated) {
751 Err <<
"Hdr->PrevAllocated (" << Hdr->PrevAllocated <<
") != "
752 <<
"LastHdr->ThisAllocated (" << LastHdr->ThisAllocated <<
")";
754 }
else if (!LastHdr && !Hdr->PrevAllocated) {
755 Err <<
"The first header should have PrevAllocated true.";
797 #if defined(__linux__) && defined(__GLIBC__)
820 static StatSymbols initStatSymbols;
846 bool AbortOnFailure) {
861 const char *NameStr = Name.c_str();
863 if (NameStr[0] == 1) ++NameStr;
871 if (NameStr[0] ==
'_') {
879 #if defined(__APPLE__) && defined(__ppc__)
880 if (Name.size() > 9 && Name[Name.size()-9] ==
'$' &&
881 memcmp(&Name[Name.size()-8],
"LDBLStub", 8) == 0) {
884 std::string
Prefix = std::string(Name.begin(), Name.end()-9);
892 if (AbortOnFailure) {
894 "' which could not be resolved!");
902 return new DefaultJITMemoryManager();
906 const size_t DefaultJITMemoryManager::DefaultCodeSlabSize = 512 * 1024;
909 const size_t DefaultJITMemoryManager::DefaultSlabSize = 64 * 1024;
912 const size_t DefaultJITMemoryManager::DefaultSizeThreshold = 16 * 1024;
static void * SearchForAddressOfSymbol(const char *symbolName)
Search through libraries for address of a symbol.
int fstat(int fildes, struct stat *buf);
int fstat64(int filedes, struct stat64 *buf)
static int jit_atexit(void(*Fn)())
int lstat64(const char *path, struct stat64 *buf);
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason, bool gen_crash_diag=true)
static JITMemoryManager * CreateDefaultMemManager()
bool count(PtrType Ptr) const
count - Return true if the specified pointer is in the set.
static bool ReleaseRWX(MemoryBlock &block, std::string *ErrMsg=0)
Release Read/Write/Execute memory.
static bool setExecutable(MemoryBlock &M, std::string *ErrMsg=0)
static std::vector< void(*)()> AtExitHandlers
int memcmp(const void *s1, const void *s2, size_t n);
int lstat(const char *path, struct stat *buf);
static void AddSymbol(StringRef symbolName, void *symbolValue)
Add searchable symbol/value pair.
static void runAtExitHandlers()
int stat(const char *path, struct stat *buf);
int stat64(const char *path, struct stat64 *buf);
static MemoryBlock AllocateRWX(size_t NumBytes, const MemoryBlock *NearBlock, std::string *ErrMsg=0)
Allocate Read/Write/Execute memory.
static void jit_exit(int Status)
Memory block abstraction.
STATISTIC(NumSlabs,"Number of slabs of memory allocated by the JIT")
static bool setWritable(MemoryBlock &M, std::string *ErrMsg=0)
raw_ostream & dbgs()
dbgs - Return a circular-buffered debug stream.
int open64(const char *filename, int flags[, mode_t mode])
uint64_t RoundUpToAlignment(uint64_t Value, uint64_t Align)
virtual ~JITMemoryManager()
void * getPointerToNamedFunction(const char *Name)