aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanil Malyshev <dmalyshev@accesssoftek.com>2012-05-16 18:50:11 +0000
committerDanil Malyshev <dmalyshev@accesssoftek.com>2012-05-16 18:50:11 +0000
commit068c65b22d50c265b51886062b2b9c1cb696d67d (patch)
tree291d4c251d82265b2a45db53727414c6dee2abe0
parentab53f8ea6a8aa616b2ae153a5ff941e4a855a07d (diff)
Added LLIMCJITMemoryManager to the lli. This manager will be used for MCJIT instead of DefaultJIMMemoryManager.
It's more flexible for MCJIT tasks, in addition it's provides a invalidation instruction cache for code sections which will be used before JIT code will be executed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@156933 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/ExecutionEngine/MCJIT/MCJITMemoryManager.h4
-rw-r--r--tools/lli/lli.cpp204
-rw-r--r--tools/llvm-rtdyld/llvm-rtdyld.cpp25
3 files changed, 229 insertions, 4 deletions
diff --git a/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.h b/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.h
index a68949aa41..084f9a8ead 100644
--- a/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.h
+++ b/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.h
@@ -34,12 +34,12 @@ public:
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID) {
- return JMM->allocateSpace(Size, Alignment);
+ return JMM->allocateDataSection(Size, Alignment, SectionID);
}
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID) {
- return JMM->allocateSpace(Size, Alignment);
+ return JMM->allocateCodeSection(Size, Alignment, SectionID);
}
virtual void *getPointerToNamedFunction(const std::string &Name,
diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp
index e1759ccede..a1cf92e2c3 100644
--- a/tools/lli/lli.cpp
+++ b/tools/lli/lli.cpp
@@ -35,8 +35,20 @@
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Memory.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
@@ -175,6 +187,191 @@ 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);
+
+ virtual void *getPointerToNamedFunction(const std::string &Name,
+ bool AbortOnFailure = true);
+
+ // 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 MCJITMemoryManager 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) {
+ if (!Alignment)
+ Alignment = 16;
+ uint8_t *Addr = (uint8_t*)calloc((Size + Alignment - 1)/Alignment, Alignment);
+ AllocatedDataMem.push_back(sys::MemoryBlock(Addr, Size));
+ return Addr;
+}
+
+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());
+}
+
+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__
+
+ 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());
+}
+
//===----------------------------------------------------------------------===//
// main Driver function
//
@@ -233,8 +430,11 @@ int main(int argc, char **argv, char * const *envp) {
Mod->setTargetTriple(Triple::normalize(TargetTriple));
// Enable MCJIT if desired.
+ LLIMCJITMemoryManager *JMM = 0;
if (UseMCJIT && !ForceInterpreter) {
builder.setUseMCJIT(true);
+ JMM = new LLIMCJITMemoryManager();
+ builder.setJITMemoryManager(JMM);
}
CodeGenOpt::Level OLvl = CodeGenOpt::Default;
@@ -265,6 +465,10 @@ int main(int argc, char **argv, char * const *envp) {
exit(1);
}
+ // Clear instruction cache before code will be executed.
+ if (JMM)
+ JMM->invalidateInstructionCache();
+
// The following functions have no effect if their respective profiling
// support wasn't enabled in the build configuration.
EE->RegisterJITEventListener(
diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp
index 01a7d15807..95de8d8a4d 100644
--- a/tools/llvm-rtdyld/llvm-rtdyld.cpp
+++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp
@@ -63,18 +63,37 @@ public:
return 0;
}
+ // Invalidate instruction cache for sections with execute permissions.
+ // 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();
};
uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,
unsigned Alignment,
unsigned SectionID) {
- return (uint8_t*)sys::Memory::AllocateRWX(Size, 0, 0).base();
+ sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0);
+ FunctionMemory.push_back(MB);
+ return (uint8_t*)MB.base();
}
uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,
unsigned Alignment,
unsigned SectionID) {
- return (uint8_t*)sys::Memory::AllocateRWX(Size, 0, 0).base();
+ sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0);
+ DataMemory.push_back(MB);
+ return (uint8_t*)MB.base();
+}
+
+void TrivialMemoryManager::invalidateInstructionCache() {
+ for (int i = 0, e = FunctionMemory.size(); i != e; ++i)
+ sys::Memory::InvalidateInstructionCache(FunctionMemory[i].base(),
+ FunctionMemory[i].size());
+
+ for (int i = 0, e = DataMemory.size(); i != e; ++i)
+ sys::Memory::InvalidateInstructionCache(DataMemory[i].base(),
+ DataMemory[i].size());
}
static const char *ProgramName;
@@ -113,6 +132,8 @@ static int executeInput() {
// Resolve all the relocations we can.
Dyld.resolveRelocations();
+ // Clear instruction cache before code will be executed.
+ MemMgr->invalidateInstructionCache();
// FIXME: Error out if there are unresolved relocations.