summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Grosbach <grosbach@apple.com>2008-10-03 16:17:20 +0000
committerJim Grosbach <grosbach@apple.com>2008-10-03 16:17:20 +0000
commitb22ef71d46f0f583dc1401f20df809d1da8d1831 (patch)
treecdb15da7dd03d15b3bc71aeaad0572c8c16e68a0
parent332ad5e01630e1d8c1b976dd7bf1a5a893df8e94 (diff)
downloadbcm5719-llvm-b22ef71d46f0f583dc1401f20df809d1da8d1831.tar.gz
bcm5719-llvm-b22ef71d46f0f583dc1401f20df809d1da8d1831.zip
On Darwin ARM, memory needs special handling to do JIT. This patch expands
this handling to work properly for modifying stub functions, relocations back to entry points after JIT compilation, etc.. llvm-svn: 57013
-rw-r--r--llvm/include/llvm/ExecutionEngine/JITMemoryManager.h8
-rw-r--r--llvm/include/llvm/System/Memory.h9
-rw-r--r--llvm/lib/ExecutionEngine/JIT/JITEmitter.cpp12
-rw-r--r--llvm/lib/ExecutionEngine/JIT/JITMemoryManager.cpp15
-rw-r--r--llvm/lib/System/Memory.cpp11
-rw-r--r--llvm/lib/System/Unix/Memory.inc26
6 files changed, 66 insertions, 15 deletions
diff --git a/llvm/include/llvm/ExecutionEngine/JITMemoryManager.h b/llvm/include/llvm/ExecutionEngine/JITMemoryManager.h
index e1f2763e1db..0d79d14d71f 100644
--- a/llvm/include/llvm/ExecutionEngine/JITMemoryManager.h
+++ b/llvm/include/llvm/ExecutionEngine/JITMemoryManager.h
@@ -35,6 +35,14 @@ public:
/// JIT Memory Manager if the client does not provide one to the JIT.
static JITMemoryManager *CreateDefaultMemManager();
+ /// setMemoryWritable - When code generation is in progress,
+ /// the code pages may need permissions changed.
+ virtual void setMemoryWritable(void) = 0;
+
+ /// setMemoryExecutable - When code generation is done and we're ready to
+ /// start execution, the code pages may need permissions changed.
+ virtual void setMemoryExecutable(void) = 0;
+
//===--------------------------------------------------------------------===//
// Global Offset Table Management
//===--------------------------------------------------------------------===//
diff --git a/llvm/include/llvm/System/Memory.h b/llvm/include/llvm/System/Memory.h
index 86895e2317d..4d0828b575b 100644
--- a/llvm/include/llvm/System/Memory.h
+++ b/llvm/include/llvm/System/Memory.h
@@ -70,10 +70,15 @@ namespace sys {
/// platforms.
static void InvalidateInstructionCache(const void *Addr, size_t Len);
- /// SetRXPrivilege - Before the JIT can run a block of code, it has to be
+ /// setExecutable - Before the JIT can run a block of code, it has to be
/// given read and executable privilege. Return true if it is already r-x
/// or the system is able to change its previlege.
- static bool SetRXPrivilege(const void *Addr, size_t Size);
+ static bool setExecutable (MemoryBlock &M, std::string *ErrMsg = 0);
+
+ /// setWritable - When adding to a block of code, the JIT may need
+ /// to mark a block of code as RW since the protections are on page
+ /// boundaries, and the JIT internal allocations are not page aligned.
+ static bool setWritable (MemoryBlock &M, std::string *ErrMsg = 0);
};
}
}
diff --git a/llvm/lib/ExecutionEngine/JIT/JITEmitter.cpp b/llvm/lib/ExecutionEngine/JIT/JITEmitter.cpp
index ffaeb1c4ea9..a90a6a52fa9 100644
--- a/llvm/lib/ExecutionEngine/JIT/JITEmitter.cpp
+++ b/llvm/lib/ExecutionEngine/JIT/JITEmitter.cpp
@@ -560,6 +560,10 @@ namespace {
if (ExceptionHandling) DE->setModuleInfo(Info);
}
+ void setMemoryExecutable(void) {
+ MemMgr->setMemoryExecutable();
+ }
+
private:
void *getPointerToGlobal(GlobalValue *GV, void *Reference, bool NoNeedStub);
void *getPointerToGVLazyPtr(GlobalValue *V, void *Reference,
@@ -791,6 +795,8 @@ unsigned JITEmitter::GetSizeOfGlobalsInBytes(MachineFunction &MF) {
void JITEmitter::startFunction(MachineFunction &F) {
uintptr_t ActualSize = 0;
+ // Set the memory writable, if it's not already
+ MemMgr->setMemoryWritable();
if (MemMgr->NeedsExactSize()) {
DOUT << "ExactSize\n";
const TargetInstrInfo* TII = F.getTarget().getInstrInfo();
@@ -938,7 +944,7 @@ bool JITEmitter::finishFunction(MachineFunction &F) {
Relocations.clear();
// Mark code region readable and executable if it's not so already.
- sys::Memory::SetRXPrivilege(FnStart, FnEnd-FnStart);
+ MemMgr->setMemoryExecutable();
#ifndef NDEBUG
{
@@ -1086,6 +1092,10 @@ void JITEmitter::startFunctionStub(const GlobalValue* F, unsigned StubSize,
void *JITEmitter::finishFunctionStub(const GlobalValue* F) {
NumBytes += getCurrentPCOffset();
+
+ // Invalidate the icache if necessary.
+ sys::Memory::InvalidateInstructionCache(BufferBegin, NumBytes);
+
std::swap(SavedBufferBegin, BufferBegin);
BufferEnd = SavedBufferEnd;
CurBufferPtr = SavedCurBufferPtr;
diff --git a/llvm/lib/ExecutionEngine/JIT/JITMemoryManager.cpp b/llvm/lib/ExecutionEngine/JIT/JITMemoryManager.cpp
index 804e88df4ca..0ffc7799013 100644
--- a/llvm/lib/ExecutionEngine/JIT/JITMemoryManager.cpp
+++ b/llvm/lib/ExecutionEngine/JIT/JITMemoryManager.cpp
@@ -365,6 +365,21 @@ namespace {
// Finally, remove this entry from TableBlocks.
TableBlocks.erase(I);
}
+
+ /// setMemoryWritable - When code generation is in progress,
+ /// the code pages may need permissions changed.
+ void setMemoryWritable(void)
+ {
+ for (unsigned i = 0, e = Blocks.size(); i != e; ++i)
+ sys::Memory::setWritable(Blocks[i]);
+ }
+ /// setMemoryExecutable - When code generation is done and we're ready to
+ /// start execution, the code pages may need permissions changed.
+ void setMemoryExecutable(void)
+ {
+ for (unsigned i = 0, e = Blocks.size(); i != e; ++i)
+ sys::Memory::setExecutable(Blocks[i]);
+ }
};
}
diff --git a/llvm/lib/System/Memory.cpp b/llvm/lib/System/Memory.cpp
index 2fc6a23a3af..3660bcb1a4a 100644
--- a/llvm/lib/System/Memory.cpp
+++ b/llvm/lib/System/Memory.cpp
@@ -58,14 +58,3 @@ void llvm::sys::Memory::InvalidateInstructionCache(const void *Addr,
#endif // end PPC
}
-
-bool llvm::sys::Memory::SetRXPrivilege(const void *Addr, size_t Size) {
-#if defined(__APPLE__) && defined(__arm__)
- kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr,
- (vm_size_t)Size, 0,
- VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY);
- return KERN_SUCCESS == kr;
-#else
- return true;
-#endif
-}
diff --git a/llvm/lib/System/Unix/Memory.inc b/llvm/lib/System/Unix/Memory.inc
index cf0157d5778..646311d8cd6 100644
--- a/llvm/lib/System/Unix/Memory.inc
+++ b/llvm/lib/System/Unix/Memory.inc
@@ -76,7 +76,7 @@ llvm::sys::Memory::AllocateRWX(unsigned NumBytes, const MemoryBlock* NearBlock,
(vm_size_t)(pageSize*NumPages), 0,
VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY);
if (KERN_SUCCESS != kr) {
- MakeErrMsg(ErrMsg, "vm_protect max RWX failed\n");
+ MakeErrMsg(ErrMsg, "vm_protect max RX failed\n");
return sys::MemoryBlock();
}
@@ -103,3 +103,27 @@ bool llvm::sys::Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) {
return false;
}
+bool llvm::sys::Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) {
+#if defined(__APPLE__) && defined(__arm__)
+ if (M.Address == 0 || M.Size == 0) return false;
+ sys::Memory::InvalidateInstructionCache(M.Address, M.Size);
+ kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address,
+ (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_WRITE);
+ return KERN_SUCCESS == kr;
+#else
+ return true;
+#endif
+}
+
+bool llvm::sys::Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) {
+#if defined(__APPLE__) && defined(__arm__)
+ if (M.Address == 0 || M.Size == 0) return false;
+ sys::Memory::InvalidateInstructionCache(M.Address, M.Size);
+ kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address,
+ (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY);
+ return KERN_SUCCESS == kr;
+#else
+ return false;
+#endif
+}
+
OpenPOWER on IntegriCloud