support near allocations for the JIT

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22554 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Andrew Lenharth
2005-07-29 23:40:16 +00:00
parent 422f3d58a8
commit a00269bc3e
4 changed files with 87 additions and 37 deletions

View File

@@ -43,9 +43,11 @@ namespace sys {
/// This method allocates a block of Read/Write/Execute memory that is /// This method allocates a block of Read/Write/Execute memory that is
/// suitable for executing dynamically generated code (e.g. JIT). An /// suitable for executing dynamically generated code (e.g. JIT). An
/// attempt to allocate \p NumBytes bytes of virtual memory is made. /// attempt to allocate \p NumBytes bytes of virtual memory is made.
/// \p NearBlock may point to an existing allocation in which case
/// an attempt is made to allocate more memory near the existing block.
/// @throws std::string if an error occurred. /// @throws std::string if an error occurred.
/// @brief Allocate Read/Write/Execute memory. /// @brief Allocate Read/Write/Execute memory.
static MemoryBlock AllocateRWX(unsigned NumBytes); static MemoryBlock AllocateRWX(unsigned NumBytes, const MemoryBlock* NearBlock);
/// This method releases a block of Read/Write/Execute memory that was /// This method releases a block of Read/Write/Execute memory that was
/// allocated with the AllocateRWX method. It should not be used to /// allocated with the AllocateRWX method. It should not be used to

View File

@@ -26,6 +26,8 @@
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h" #include "llvm/ADT/Statistic.h"
#include "llvm/System/Memory.h" #include "llvm/System/Memory.h"
#include <list>
#include <algorithm>
using namespace llvm; using namespace llvm;
namespace { namespace {
@@ -47,12 +49,15 @@ namespace {
/// are emitting is. This never bothers to release the memory, because when /// are emitting is. This never bothers to release the memory, because when
/// we are ready to destroy the JIT, the program exits. /// we are ready to destroy the JIT, the program exits.
class JITMemoryManager { class JITMemoryManager {
sys::MemoryBlock MemBlock; // Virtual memory block allocated RWX std::list<sys::MemoryBlock> Blocks; // List of blocks allocated by the JIT
unsigned char *MemBase; // Base of block of memory, start of stub mem
unsigned char *FunctionBase; // Start of the function body area unsigned char *FunctionBase; // Start of the function body area
unsigned char *ConstantPool; // Memory allocated for constant pools unsigned char *GlobalBase; // Start of the Global area
unsigned char *CurStubPtr, *CurFunctionPtr, *CurConstantPtr; unsigned char *ConstantBase; // Memory allocated for constant pools
unsigned char *CurStubPtr, *CurFunctionPtr, *CurConstantPtr, *CurGlobalPtr;
unsigned char *GOTBase; //Target Specific reserved memory unsigned char *GOTBase; //Target Specific reserved memory
// centralize memory block allocation
sys::MemoryBlock getNewMemoryBlock(unsigned size);
public: public:
JITMemoryManager(bool useGOT); JITMemoryManager(bool useGOT);
~JITMemoryManager(); ~JITMemoryManager();
@@ -71,32 +76,45 @@ namespace {
} }
JITMemoryManager::JITMemoryManager(bool useGOT) { JITMemoryManager::JITMemoryManager(bool useGOT) {
// Allocate a 16M block of memory... // Allocate a 16M block of memory for functions
MemBlock = sys::Memory::AllocateRWX((16 << 20)); sys::MemoryBlock FunBlock = getNewMemoryBlock(16 << 20);
MemBase = reinterpret_cast<unsigned char*>(MemBlock.base()); // Allocate a 1M block of memory for Constants
ConstantPool = MemBase; sys::MemoryBlock ConstBlock = getNewMemoryBlock(1 << 20);
GOTBase = ConstantPool + 512*1024; //512 for constants // Allocate a 1M Block of memory for Globals
//8k number of entries in the GOT sys::MemoryBlock GVBlock = getNewMemoryBlock(1 << 20);
FunctionBase = GOTBase + 8192 * sizeof(void*) + 512*1024; // Use 512k for stubs
//make it easier to tell if we are managing the GOT Blocks.push_front(FunBlock);
if (!useGOT) Blocks.push_front(ConstBlock);
GOTBase = NULL; Blocks.push_front(GVBlock);
// Allocate stubs backwards from the function base, allocate functions forward FunctionBase = reinterpret_cast<unsigned char*>(FunBlock.base());
// from the function base. ConstantBase = reinterpret_cast<unsigned char*>(ConstBlock.base());
CurStubPtr = CurFunctionPtr = FunctionBase; GlobalBase = reinterpret_cast<unsigned char*>(GVBlock.base());
CurConstantPtr = ConstantPool + 512*1024; //Allocate the GOT just like a global array
GOTBase = NULL;
if (useGOT)
GOTBase = allocateGlobal(sizeof(void*) * 8192, 8);
// Allocate stubs backwards from the base, allocate functions forward
// from the base.
CurStubPtr = CurFunctionPtr = FunctionBase + 512*1024;// Use 512k for stubs
CurConstantPtr = ConstantBase + ConstBlock.size();
CurGlobalPtr = GlobalBase + GVBlock.size();
} }
JITMemoryManager::~JITMemoryManager() { JITMemoryManager::~JITMemoryManager() {
sys::Memory::ReleaseRWX(MemBlock); for (std::list<sys::MemoryBlock>::iterator ib = Blocks.begin(), ie = Blocks.end();
ib != ie; ++ib)
sys::Memory::ReleaseRWX(*ib);
Blocks.clear();
} }
unsigned char *JITMemoryManager::allocateStub(unsigned StubSize) { unsigned char *JITMemoryManager::allocateStub(unsigned StubSize) {
CurStubPtr -= StubSize; CurStubPtr -= StubSize;
if (CurStubPtr < MemBase) { if (CurStubPtr < FunctionBase) {
//FIXME: allocate a new block
std::cerr << "JIT ran out of memory for function stubs!\n"; std::cerr << "JIT ran out of memory for function stubs!\n";
abort(); abort();
} }
@@ -110,26 +128,31 @@ unsigned char *JITMemoryManager::allocateConstant(unsigned ConstantSize,
CurConstantPtr = CurConstantPtr =
(unsigned char *)((intptr_t)CurConstantPtr & ~((intptr_t)Alignment - 1)); (unsigned char *)((intptr_t)CurConstantPtr & ~((intptr_t)Alignment - 1));
if (CurConstantPtr < ConstantPool) { if (CurConstantPtr < ConstantBase) {
std::cerr << "JIT ran out of memory for constant pools!\n"; //Either allocate another MB or 2xConstantSize
abort(); sys::MemoryBlock ConstBlock = getNewMemoryBlock(2 * ConstantSize);
ConstantBase = reinterpret_cast<unsigned char*>(ConstBlock.base());
CurConstantPtr = ConstantBase + ConstBlock.size();
return allocateConstant(ConstantSize, Alignment);
} }
return CurConstantPtr; return CurConstantPtr;
} }
unsigned char *JITMemoryManager::allocateGlobal(unsigned Size, unsigned char *JITMemoryManager::allocateGlobal(unsigned Size,
unsigned Alignment) { unsigned Alignment) {
// For now, intersperse them with Constants // Reserve space and align pointer.
// Reserve space and align pointer. CurGlobalPtr -= Size;
CurConstantPtr -= Size; CurGlobalPtr =
CurConstantPtr = (unsigned char *)((intptr_t)CurGlobalPtr & ~((intptr_t)Alignment - 1));
(unsigned char *)((intptr_t)CurConstantPtr & ~((intptr_t)Alignment - 1));
if (CurConstantPtr < ConstantPool) { if (CurGlobalPtr < GlobalBase) {
std::cerr << "JIT ran out of memory for Globals!\n"; //Either allocate another MB or 2xSize
abort(); sys::MemoryBlock GVBlock = getNewMemoryBlock(2 * Size);
GlobalBase = reinterpret_cast<unsigned char*>(GVBlock.base());
CurGlobalPtr = GlobalBase + GVBlock.size();
return allocateGlobal(Size, Alignment);
} }
return CurConstantPtr; return CurGlobalPtr;
} }
unsigned char *JITMemoryManager::startFunctionBody() { unsigned char *JITMemoryManager::startFunctionBody() {
@@ -151,6 +174,23 @@ bool JITMemoryManager::isManagingGOT() const {
return GOTBase != NULL; return GOTBase != NULL;
} }
sys::MemoryBlock JITMemoryManager::getNewMemoryBlock(unsigned size) {
const sys::MemoryBlock* BOld = 0;
if (Blocks.size())
BOld = &Blocks.front();
//never allocate less than 1 MB
sys::MemoryBlock B;
try {
B = sys::Memory::AllocateRWX(std::max(((unsigned)1 << 20), size), BOld);
} catch (std::string& err) {
std::cerr << "Allocation failed when allocating new memory in the JIT\n";
std::cerr << err << "\n";
abort();
}
Blocks.push_front(B);
return B;
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// JIT lazy compilation code. // JIT lazy compilation code.
// //

View File

@@ -25,7 +25,7 @@ namespace llvm {
/// to emit code to the memory then jump to it. Getting this type of memory /// to emit code to the memory then jump to it. Getting this type of memory
/// is very OS specific. /// is very OS specific.
/// ///
MemoryBlock Memory::AllocateRWX(unsigned NumBytes) { MemoryBlock Memory::AllocateRWX(unsigned NumBytes, const MemoryBlock* NearBlock) {
if (NumBytes == 0) return MemoryBlock(); if (NumBytes == 0) return MemoryBlock();
long pageSize = Process::GetPageSize(); long pageSize = Process::GetPageSize();
@@ -47,10 +47,16 @@ MemoryBlock Memory::AllocateRWX(unsigned NumBytes) {
MAP_ANON MAP_ANON
#endif #endif
; ;
void *pa = ::mmap(0, pageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC,
void* start = NearBlock ? (unsigned char*) NearBlock->base() + NearBlock->size() : 0;
void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC,
flags, fd, 0); flags, fd, 0);
if (pa == MAP_FAILED) { if (pa == MAP_FAILED) {
ThrowErrno("Can't allocate RWX Memory"); if (NearBlock) //Try again without a near hint
return AllocateRWX(NumBytes, 0);
else
ThrowErrno("Can't allocate RWX Memory");
} }
MemoryBlock result; MemoryBlock result;
result.Address = pa; result.Address = pa;

View File

@@ -23,12 +23,14 @@ using namespace sys;
//=== and must not be UNIX code //=== and must not be UNIX code
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
MemoryBlock Memory::AllocateRWX(unsigned NumBytes) { MemoryBlock Memory::AllocateRWX(unsigned NumBytes, const MemoryBlock* NearBlock) {
if (NumBytes == 0) return MemoryBlock(); if (NumBytes == 0) return MemoryBlock();
static const long pageSize = Process::GetPageSize(); static const long pageSize = Process::GetPageSize();
unsigned NumPages = (NumBytes+pageSize-1)/pageSize; unsigned NumPages = (NumBytes+pageSize-1)/pageSize;
//FIXME: support NearBlock if ever needed on Win64.
void *pa = VirtualAlloc(NULL, NumPages*pageSize, MEM_COMMIT, void *pa = VirtualAlloc(NULL, NumPages*pageSize, MEM_COMMIT,
PAGE_EXECUTE_READWRITE); PAGE_EXECUTE_READWRITE);
if (pa == NULL) { if (pa == NULL) {