mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-15 06:29:05 +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:
@@ -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
|
||||||
|
@@ -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.
|
||||||
//
|
//
|
||||||
|
@@ -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;
|
||||||
|
@@ -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) {
|
||||||
|
Reference in New Issue
Block a user