Add an option to allocate JITed global data separately from code. By

default, this option is not enabled to support clients who rely on
this behavior.

Fixes http://llvm.org/PR4483

A patch to allocate additional memory for globals after we run out is
forthcoming.

Patch by Reid Kleckner!


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@75059 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jeffrey Yasskin
2009-07-08 21:59:57 +00:00
parent e41dec60fa
commit 489393d7b9
12 changed files with 291 additions and 72 deletions

View File

@@ -251,6 +251,8 @@ namespace {
/// middle of emitting a function, and we don't know how large the function we
/// are emitting is.
class VISIBILITY_HIDDEN DefaultJITMemoryManager : public JITMemoryManager {
bool PoisonMemory; // Whether to poison freed memory.
std::vector<sys::MemoryBlock> Blocks; // Memory blocks allocated by the JIT
FreeRangeHeader *FreeMemoryList; // Circular list of free blocks.
@@ -258,6 +260,7 @@ namespace {
MemoryRangeHeader *CurBlock;
uint8_t *CurStubPtr, *StubBase;
uint8_t *CurGlobalPtr, *GlobalEnd;
uint8_t *GOTBase; // Target Specific reserved memory
void *DlsymTable; // Stub external symbol information
@@ -324,7 +327,7 @@ namespace {
CurBlock = FreeMemoryList;
FreeMemoryList = FreeMemoryList->AllocateBlock();
uint8_t *result = (uint8_t *)CurBlock+1;
uint8_t *result = (uint8_t *)(CurBlock + 1);
if (Alignment == 0) Alignment = 1;
result = (uint8_t*)(((intptr_t)result+Alignment-1) &
@@ -336,6 +339,30 @@ namespace {
return result;
}
/// allocateGlobal - Allocate memory for a global. Unlike allocateSpace,
/// this method does not touch the current block and can be called at any
/// time.
uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) {
uint8_t *Result = CurGlobalPtr;
// Align the pointer.
if (Alignment == 0) Alignment = 1;
Result = (uint8_t*)(((uintptr_t)Result + Alignment-1) &
~(uintptr_t)(Alignment-1));
// Move the current global pointer forward.
CurGlobalPtr += Result - CurGlobalPtr + Size;
// Check for overflow.
if (CurGlobalPtr > GlobalEnd) {
// FIXME: Allocate more memory.
fprintf(stderr, "JIT ran out of memory for globals!\n");
abort();
}
return Result;
}
/// startExceptionTable - Use startFunctionBody to allocate memory for the
/// function's exception table.
uint8_t* startExceptionTable(const Function* F, uintptr_t &ActualSize) {
@@ -375,12 +402,12 @@ namespace {
// Find the block that is allocated for this function.
MemoryRangeHeader *MemRange = I->second;
assert(MemRange->ThisAllocated && "Block isn't allocated!");
// Fill the buffer with garbage!
#ifndef NDEBUG
memset(MemRange+1, 0xCD, MemRange->BlockSize-sizeof(*MemRange));
#endif
if (PoisonMemory) {
memset(MemRange+1, 0xCD, MemRange->BlockSize-sizeof(*MemRange));
}
// Free the memory.
FreeMemoryList = MemRange->FreeBlock(FreeMemoryList);
@@ -393,12 +420,12 @@ namespace {
// Find the block that is allocated for this function.
MemRange = I->second;
assert(MemRange->ThisAllocated && "Block isn't allocated!");
// Fill the buffer with garbage!
#ifndef NDEBUG
memset(MemRange+1, 0xCD, MemRange->BlockSize-sizeof(*MemRange));
#endif
if (PoisonMemory) {
memset(MemRange+1, 0xCD, MemRange->BlockSize-sizeof(*MemRange));
}
// Free the memory.
FreeMemoryList = MemRange->FreeBlock(FreeMemoryList);
@@ -420,10 +447,22 @@ namespace {
for (unsigned i = 0, e = Blocks.size(); i != e; ++i)
sys::Memory::setExecutable(Blocks[i]);
}
/// setPoisonMemory - Controls whether we write garbage over freed memory.
///
void setPoisonMemory(bool poison) {
PoisonMemory = poison;
}
};
}
DefaultJITMemoryManager::DefaultJITMemoryManager() {
#ifdef NDEBUG
PoisonMemory = true;
#else
PoisonMemory = false;
#endif
// Allocate a 16M block of memory for functions.
#if defined(__APPLE__) && defined(__arm__)
sys::MemoryBlock MemBlock = getNewMemoryBlock(4 << 20);
@@ -433,11 +472,13 @@ DefaultJITMemoryManager::DefaultJITMemoryManager() {
uint8_t *MemBase = static_cast<uint8_t*>(MemBlock.base());
// Allocate stubs backwards from the base, allocate functions forward
// from the base.
// Allocate stubs backwards to the base, globals forward from the stubs, and
// functions forward after globals.
StubBase = MemBase;
CurStubPtr = MemBase + 512*1024; // Use 512k for stubs, working backwards.
CurGlobalPtr = CurStubPtr; // Use 2M for globals, working forwards.
GlobalEnd = CurGlobalPtr + 2*1024*1024;
// We set up the memory chunk with 4 mem regions, like this:
// [ START
// [ Free #0 ] -> Large space to allocate functions from.
@@ -474,7 +515,7 @@ DefaultJITMemoryManager::DefaultJITMemoryManager() {
// Add a FreeRangeHeader to the start of the function body region, indicating
// that the space is free. Mark the previous block allocated so we never look
// at it.
FreeRangeHeader *Mem0 = (FreeRangeHeader*)CurStubPtr;
FreeRangeHeader *Mem0 = (FreeRangeHeader*)GlobalEnd;
Mem0->ThisAllocated = 0;
Mem0->PrevAllocated = 1;
Mem0->BlockSize = (char*)Mem1-(char*)Mem0;
@@ -522,7 +563,7 @@ uint8_t *DefaultJITMemoryManager::allocateStub(const GlobalValue* F,
sys::MemoryBlock DefaultJITMemoryManager::getNewMemoryBlock(unsigned size) {
// Allocate a new block close to the last one.
const sys::MemoryBlock *BOld = Blocks.empty() ? 0 : &Blocks.front();
const sys::MemoryBlock *BOld = Blocks.empty() ? 0 : &Blocks.back();
std::string ErrMsg;
sys::MemoryBlock B = sys::Memory::AllocateRWX(size, BOld, &ErrMsg);
if (B.base() == 0) {