mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-29 22:50:47 +00:00
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:
parent
422f3d58a8
commit
a00269bc3e
@ -43,9 +43,11 @@ namespace sys {
|
||||
/// This method allocates a block of Read/Write/Execute memory that is
|
||||
/// suitable for executing dynamically generated code (e.g. JIT). An
|
||||
/// 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.
|
||||
/// @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
|
||||
/// allocated with the AllocateRWX method. It should not be used to
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/System/Memory.h"
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
@ -47,12 +49,15 @@ namespace {
|
||||
/// are emitting is. This never bothers to release the memory, because when
|
||||
/// we are ready to destroy the JIT, the program exits.
|
||||
class JITMemoryManager {
|
||||
sys::MemoryBlock MemBlock; // Virtual memory block allocated RWX
|
||||
unsigned char *MemBase; // Base of block of memory, start of stub mem
|
||||
std::list<sys::MemoryBlock> Blocks; // List of blocks allocated by the JIT
|
||||
unsigned char *FunctionBase; // Start of the function body area
|
||||
unsigned char *ConstantPool; // Memory allocated for constant pools
|
||||
unsigned char *CurStubPtr, *CurFunctionPtr, *CurConstantPtr;
|
||||
unsigned char *GlobalBase; // Start of the Global area
|
||||
unsigned char *ConstantBase; // Memory allocated for constant pools
|
||||
unsigned char *CurStubPtr, *CurFunctionPtr, *CurConstantPtr, *CurGlobalPtr;
|
||||
unsigned char *GOTBase; //Target Specific reserved memory
|
||||
|
||||
// centralize memory block allocation
|
||||
sys::MemoryBlock getNewMemoryBlock(unsigned size);
|
||||
public:
|
||||
JITMemoryManager(bool useGOT);
|
||||
~JITMemoryManager();
|
||||
@ -71,32 +76,45 @@ namespace {
|
||||
}
|
||||
|
||||
JITMemoryManager::JITMemoryManager(bool useGOT) {
|
||||
// Allocate a 16M block of memory...
|
||||
MemBlock = sys::Memory::AllocateRWX((16 << 20));
|
||||
MemBase = reinterpret_cast<unsigned char*>(MemBlock.base());
|
||||
ConstantPool = MemBase;
|
||||
GOTBase = ConstantPool + 512*1024; //512 for constants
|
||||
//8k number of entries in the GOT
|
||||
FunctionBase = GOTBase + 8192 * sizeof(void*) + 512*1024; // Use 512k for stubs
|
||||
// Allocate a 16M block of memory for functions
|
||||
sys::MemoryBlock FunBlock = getNewMemoryBlock(16 << 20);
|
||||
// Allocate a 1M block of memory for Constants
|
||||
sys::MemoryBlock ConstBlock = getNewMemoryBlock(1 << 20);
|
||||
// Allocate a 1M Block of memory for Globals
|
||||
sys::MemoryBlock GVBlock = getNewMemoryBlock(1 << 20);
|
||||
|
||||
//make it easier to tell if we are managing the GOT
|
||||
if (!useGOT)
|
||||
GOTBase = NULL;
|
||||
Blocks.push_front(FunBlock);
|
||||
Blocks.push_front(ConstBlock);
|
||||
Blocks.push_front(GVBlock);
|
||||
|
||||
// Allocate stubs backwards from the function base, allocate functions forward
|
||||
// from the function base.
|
||||
CurStubPtr = CurFunctionPtr = FunctionBase;
|
||||
FunctionBase = reinterpret_cast<unsigned char*>(FunBlock.base());
|
||||
ConstantBase = reinterpret_cast<unsigned char*>(ConstBlock.base());
|
||||
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() {
|
||||
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) {
|
||||
CurStubPtr -= StubSize;
|
||||
if (CurStubPtr < MemBase) {
|
||||
if (CurStubPtr < FunctionBase) {
|
||||
//FIXME: allocate a new block
|
||||
std::cerr << "JIT ran out of memory for function stubs!\n";
|
||||
abort();
|
||||
}
|
||||
@ -110,26 +128,31 @@ unsigned char *JITMemoryManager::allocateConstant(unsigned ConstantSize,
|
||||
CurConstantPtr =
|
||||
(unsigned char *)((intptr_t)CurConstantPtr & ~((intptr_t)Alignment - 1));
|
||||
|
||||
if (CurConstantPtr < ConstantPool) {
|
||||
std::cerr << "JIT ran out of memory for constant pools!\n";
|
||||
abort();
|
||||
if (CurConstantPtr < ConstantBase) {
|
||||
//Either allocate another MB or 2xConstantSize
|
||||
sys::MemoryBlock ConstBlock = getNewMemoryBlock(2 * ConstantSize);
|
||||
ConstantBase = reinterpret_cast<unsigned char*>(ConstBlock.base());
|
||||
CurConstantPtr = ConstantBase + ConstBlock.size();
|
||||
return allocateConstant(ConstantSize, Alignment);
|
||||
}
|
||||
return CurConstantPtr;
|
||||
}
|
||||
|
||||
unsigned char *JITMemoryManager::allocateGlobal(unsigned Size,
|
||||
unsigned Alignment) {
|
||||
// For now, intersperse them with Constants
|
||||
// Reserve space and align pointer.
|
||||
CurConstantPtr -= Size;
|
||||
CurConstantPtr =
|
||||
(unsigned char *)((intptr_t)CurConstantPtr & ~((intptr_t)Alignment - 1));
|
||||
// Reserve space and align pointer.
|
||||
CurGlobalPtr -= Size;
|
||||
CurGlobalPtr =
|
||||
(unsigned char *)((intptr_t)CurGlobalPtr & ~((intptr_t)Alignment - 1));
|
||||
|
||||
if (CurConstantPtr < ConstantPool) {
|
||||
std::cerr << "JIT ran out of memory for Globals!\n";
|
||||
abort();
|
||||
if (CurGlobalPtr < GlobalBase) {
|
||||
//Either allocate another MB or 2xSize
|
||||
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() {
|
||||
@ -151,6 +174,23 @@ bool JITMemoryManager::isManagingGOT() const {
|
||||
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.
|
||||
//
|
||||
|
@ -25,7 +25,7 @@ namespace llvm {
|
||||
/// to emit code to the memory then jump to it. Getting this type of memory
|
||||
/// is very OS specific.
|
||||
///
|
||||
MemoryBlock Memory::AllocateRWX(unsigned NumBytes) {
|
||||
MemoryBlock Memory::AllocateRWX(unsigned NumBytes, const MemoryBlock* NearBlock) {
|
||||
if (NumBytes == 0) return MemoryBlock();
|
||||
|
||||
long pageSize = Process::GetPageSize();
|
||||
@ -47,10 +47,16 @@ MemoryBlock Memory::AllocateRWX(unsigned NumBytes) {
|
||||
MAP_ANON
|
||||
#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);
|
||||
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;
|
||||
result.Address = pa;
|
||||
|
@ -23,12 +23,14 @@ using namespace sys;
|
||||
//=== and must not be UNIX code
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
MemoryBlock Memory::AllocateRWX(unsigned NumBytes) {
|
||||
MemoryBlock Memory::AllocateRWX(unsigned NumBytes, const MemoryBlock* NearBlock) {
|
||||
if (NumBytes == 0) return MemoryBlock();
|
||||
|
||||
static const long pageSize = Process::GetPageSize();
|
||||
unsigned NumPages = (NumBytes+pageSize-1)/pageSize;
|
||||
|
||||
//FIXME: support NearBlock if ever needed on Win64.
|
||||
|
||||
void *pa = VirtualAlloc(NULL, NumPages*pageSize, MEM_COMMIT,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
if (pa == NULL) {
|
||||
|
Loading…
Reference in New Issue
Block a user