mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
Modifying lli to use the SectionMemoryManager.
The functionality of SectionMemoryManager is equivalent to the LLIMCJITMemoryManager being replaced except that it allocates memory as RW and later changes it to RX or R as needed. The page permissions are set in the call to MCJIT::finalizeObject. llvm-svn: 168722
This commit is contained in:
parent
ca8d63b46f
commit
74326c99fd
@ -28,6 +28,7 @@
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
#include "llvm/ExecutionEngine/JITMemoryManager.h"
|
||||
#include "llvm/ExecutionEngine/MCJIT.h"
|
||||
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/IRReader.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
@ -45,16 +46,6 @@
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <cerrno>
|
||||
|
||||
#ifdef __linux__
|
||||
// These includes used by LLIMCJITMemoryManager::getPointerToNamedFunction()
|
||||
// for Glibc trickery. Look comments in this function for more information.
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
#include <cygwin/version.h>
|
||||
#if defined(CYGWIN_VERSION_DLL_MAJOR) && CYGWIN_VERSION_DLL_MAJOR<1007
|
||||
@ -217,214 +208,6 @@ static void do_shutdown() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Memory manager for MCJIT
|
||||
class LLIMCJITMemoryManager : public JITMemoryManager {
|
||||
public:
|
||||
SmallVector<sys::MemoryBlock, 16> AllocatedDataMem;
|
||||
SmallVector<sys::MemoryBlock, 16> AllocatedCodeMem;
|
||||
SmallVector<sys::MemoryBlock, 16> FreeCodeMem;
|
||||
|
||||
LLIMCJITMemoryManager() { }
|
||||
~LLIMCJITMemoryManager();
|
||||
|
||||
virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
|
||||
unsigned SectionID);
|
||||
|
||||
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
|
||||
unsigned SectionID, bool IsReadOnly);
|
||||
|
||||
virtual void *getPointerToNamedFunction(const std::string &Name,
|
||||
bool AbortOnFailure = true);
|
||||
|
||||
virtual bool applyPermissions(std::string *ErrMsg) { return false; }
|
||||
|
||||
// Invalidate instruction cache for code sections. Some platforms with
|
||||
// separate data cache and instruction cache require explicit cache flush,
|
||||
// otherwise JIT code manipulations (like resolved relocations) will get to
|
||||
// the data cache but not to the instruction cache.
|
||||
virtual void invalidateInstructionCache();
|
||||
|
||||
// The RTDyldMemoryManager doesn't use the following functions, so we don't
|
||||
// need implement them.
|
||||
virtual void setMemoryWritable() {
|
||||
llvm_unreachable("Unexpected call!");
|
||||
}
|
||||
virtual void setMemoryExecutable() {
|
||||
llvm_unreachable("Unexpected call!");
|
||||
}
|
||||
virtual void setPoisonMemory(bool poison) {
|
||||
llvm_unreachable("Unexpected call!");
|
||||
}
|
||||
virtual void AllocateGOT() {
|
||||
llvm_unreachable("Unexpected call!");
|
||||
}
|
||||
virtual uint8_t *getGOTBase() const {
|
||||
llvm_unreachable("Unexpected call!");
|
||||
return 0;
|
||||
}
|
||||
virtual uint8_t *startFunctionBody(const Function *F,
|
||||
uintptr_t &ActualSize){
|
||||
llvm_unreachable("Unexpected call!");
|
||||
return 0;
|
||||
}
|
||||
virtual uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
|
||||
unsigned Alignment) {
|
||||
llvm_unreachable("Unexpected call!");
|
||||
return 0;
|
||||
}
|
||||
virtual void endFunctionBody(const Function *F, uint8_t *FunctionStart,
|
||||
uint8_t *FunctionEnd) {
|
||||
llvm_unreachable("Unexpected call!");
|
||||
}
|
||||
virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) {
|
||||
llvm_unreachable("Unexpected call!");
|
||||
return 0;
|
||||
}
|
||||
virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) {
|
||||
llvm_unreachable("Unexpected call!");
|
||||
return 0;
|
||||
}
|
||||
virtual void deallocateFunctionBody(void *Body) {
|
||||
llvm_unreachable("Unexpected call!");
|
||||
}
|
||||
virtual uint8_t* startExceptionTable(const Function* F,
|
||||
uintptr_t &ActualSize) {
|
||||
llvm_unreachable("Unexpected call!");
|
||||
return 0;
|
||||
}
|
||||
virtual void endExceptionTable(const Function *F, uint8_t *TableStart,
|
||||
uint8_t *TableEnd, uint8_t* FrameRegister) {
|
||||
llvm_unreachable("Unexpected call!");
|
||||
}
|
||||
virtual void deallocateExceptionTable(void *ET) {
|
||||
llvm_unreachable("Unexpected call!");
|
||||
}
|
||||
};
|
||||
|
||||
uint8_t *LLIMCJITMemoryManager::allocateDataSection(uintptr_t Size,
|
||||
unsigned Alignment,
|
||||
unsigned SectionID,
|
||||
bool IsReadOnly) {
|
||||
if (!Alignment)
|
||||
Alignment = 16;
|
||||
// Ensure that enough memory is requested to allow aligning.
|
||||
size_t NumElementsAligned = 1 + (Size + Alignment - 1)/Alignment;
|
||||
uint8_t *Addr = (uint8_t*)calloc(NumElementsAligned, Alignment);
|
||||
|
||||
// Honour the alignment requirement.
|
||||
uint8_t *AlignedAddr = (uint8_t*)RoundUpToAlignment((uint64_t)Addr, Alignment);
|
||||
|
||||
// Store the original address from calloc so we can free it later.
|
||||
AllocatedDataMem.push_back(sys::MemoryBlock(Addr, NumElementsAligned*Alignment));
|
||||
return AlignedAddr;
|
||||
}
|
||||
|
||||
uint8_t *LLIMCJITMemoryManager::allocateCodeSection(uintptr_t Size,
|
||||
unsigned Alignment,
|
||||
unsigned SectionID) {
|
||||
if (!Alignment)
|
||||
Alignment = 16;
|
||||
unsigned NeedAllocate = Alignment * ((Size + Alignment - 1)/Alignment + 1);
|
||||
uintptr_t Addr = 0;
|
||||
// Look in the list of free code memory regions and use a block there if one
|
||||
// is available.
|
||||
for (int i = 0, e = FreeCodeMem.size(); i != e; ++i) {
|
||||
sys::MemoryBlock &MB = FreeCodeMem[i];
|
||||
if (MB.size() >= NeedAllocate) {
|
||||
Addr = (uintptr_t)MB.base();
|
||||
uintptr_t EndOfBlock = Addr + MB.size();
|
||||
// Align the address.
|
||||
Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
|
||||
// Store cutted free memory block.
|
||||
FreeCodeMem[i] = sys::MemoryBlock((void*)(Addr + Size),
|
||||
EndOfBlock - Addr - Size);
|
||||
return (uint8_t*)Addr;
|
||||
}
|
||||
}
|
||||
|
||||
// No pre-allocated free block was large enough. Allocate a new memory region.
|
||||
sys::MemoryBlock MB = sys::Memory::AllocateRWX(NeedAllocate, 0, 0);
|
||||
|
||||
AllocatedCodeMem.push_back(MB);
|
||||
Addr = (uintptr_t)MB.base();
|
||||
uintptr_t EndOfBlock = Addr + MB.size();
|
||||
// Align the address.
|
||||
Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
|
||||
// The AllocateRWX may allocate much more memory than we need. In this case,
|
||||
// we store the unused memory as a free memory block.
|
||||
unsigned FreeSize = EndOfBlock-Addr-Size;
|
||||
if (FreeSize > 16)
|
||||
FreeCodeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize));
|
||||
|
||||
// Return aligned address
|
||||
return (uint8_t*)Addr;
|
||||
}
|
||||
|
||||
void LLIMCJITMemoryManager::invalidateInstructionCache() {
|
||||
for (int i = 0, e = AllocatedCodeMem.size(); i != e; ++i)
|
||||
sys::Memory::InvalidateInstructionCache(AllocatedCodeMem[i].base(),
|
||||
AllocatedCodeMem[i].size());
|
||||
}
|
||||
|
||||
static int jit_noop() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *LLIMCJITMemoryManager::getPointerToNamedFunction(const std::string &Name,
|
||||
bool AbortOnFailure) {
|
||||
#if defined(__linux__)
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Function stubs that are invoked instead of certain library calls
|
||||
//
|
||||
// Force the following functions to be linked in to anything that uses the
|
||||
// JIT. This is a hack designed to work around the all-too-clever Glibc
|
||||
// strategy of making these functions work differently when inlined vs. when
|
||||
// not inlined, and hiding their real definitions in a separate archive file
|
||||
// that the dynamic linker can't see. For more info, search for
|
||||
// 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.
|
||||
if (Name == "stat") return (void*)(intptr_t)&stat;
|
||||
if (Name == "fstat") return (void*)(intptr_t)&fstat;
|
||||
if (Name == "lstat") return (void*)(intptr_t)&lstat;
|
||||
if (Name == "stat64") return (void*)(intptr_t)&stat64;
|
||||
if (Name == "fstat64") return (void*)(intptr_t)&fstat64;
|
||||
if (Name == "lstat64") return (void*)(intptr_t)&lstat64;
|
||||
if (Name == "atexit") return (void*)(intptr_t)&atexit;
|
||||
if (Name == "mknod") return (void*)(intptr_t)&mknod;
|
||||
#endif // __linux__
|
||||
|
||||
// We should not invoke parent's ctors/dtors from generated main()!
|
||||
// On Mingw and Cygwin, the symbol __main is resolved to
|
||||
// callee's(eg. tools/lli) one, to invoke wrong duplicated ctors
|
||||
// (and register wrong callee's dtors with atexit(3)).
|
||||
// We expect ExecutionEngine::runStaticConstructorsDestructors()
|
||||
// is called before ExecutionEngine::runFunctionAsMain() is called.
|
||||
if (Name == "__main") return (void*)(intptr_t)&jit_noop;
|
||||
|
||||
const char *NameStr = Name.c_str();
|
||||
void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
|
||||
if (Ptr) return Ptr;
|
||||
|
||||
// If it wasn't found and if it starts with an underscore ('_') character,
|
||||
// try again without the underscore.
|
||||
if (NameStr[0] == '_') {
|
||||
Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
|
||||
if (Ptr) return Ptr;
|
||||
}
|
||||
|
||||
if (AbortOnFailure)
|
||||
report_fatal_error("Program used external function '" + Name +
|
||||
"' which could not be resolved!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LLIMCJITMemoryManager::~LLIMCJITMemoryManager() {
|
||||
for (unsigned i = 0, e = AllocatedCodeMem.size(); i != e; ++i)
|
||||
sys::Memory::ReleaseRWX(AllocatedCodeMem[i]);
|
||||
for (unsigned i = 0, e = AllocatedDataMem.size(); i != e; ++i)
|
||||
free(AllocatedDataMem[i].base());
|
||||
}
|
||||
|
||||
|
||||
void layoutRemoteTargetMemory(RemoteTarget *T, RecordingMemoryManager *JMM) {
|
||||
// Lay out our sections in order, with all the code sections first, then
|
||||
// all the data sections.
|
||||
@ -564,7 +347,7 @@ int main(int argc, char **argv, char * const *envp) {
|
||||
if (RemoteMCJIT)
|
||||
JMM = new RecordingMemoryManager();
|
||||
else
|
||||
JMM = new LLIMCJITMemoryManager();
|
||||
JMM = new SectionMemoryManager();
|
||||
builder.setJITMemoryManager(JMM);
|
||||
} else {
|
||||
if (RemoteMCJIT) {
|
||||
@ -665,8 +448,13 @@ int main(int argc, char **argv, char * const *envp) {
|
||||
// MCJIT itself. FIXME.
|
||||
//
|
||||
// Run static constructors.
|
||||
if (!RemoteMCJIT)
|
||||
EE->runStaticConstructorsDestructors(false);
|
||||
if (!RemoteMCJIT) {
|
||||
if (UseMCJIT && !ForceInterpreter) {
|
||||
// Give MCJIT a chance to apply relocations and set page permissions.
|
||||
EE->finalizeObject();
|
||||
}
|
||||
EE->runStaticConstructorsDestructors(false);
|
||||
}
|
||||
|
||||
if (NoLazyCompilation) {
|
||||
for (Module::iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) {
|
||||
@ -713,7 +501,7 @@ int main(int argc, char **argv, char * const *envp) {
|
||||
(void)EE->getPointerToFunction(EntryFn);
|
||||
// Clear instruction cache before code will be executed.
|
||||
if (JMM)
|
||||
static_cast<LLIMCJITMemoryManager*>(JMM)->invalidateInstructionCache();
|
||||
static_cast<SectionMemoryManager*>(JMM)->invalidateInstructionCache();
|
||||
|
||||
// Run main.
|
||||
Result = EE->runFunctionAsMain(EntryFn, InputArgv, envp);
|
||||
|
Loading…
Reference in New Issue
Block a user