OSDN Git Service

On Darwin ARM, memory needs special handling to do JIT. This patch expands
authorJim Grosbach <grosbach@apple.com>
Fri, 3 Oct 2008 16:17:20 +0000 (16:17 +0000)
committerJim Grosbach <grosbach@apple.com>
Fri, 3 Oct 2008 16:17:20 +0000 (16:17 +0000)
this handling to work properly for modifying stub functions, relocations
back to entry points after JIT compilation, etc..

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@57013 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ExecutionEngine/JITMemoryManager.h
include/llvm/System/Memory.h
lib/ExecutionEngine/JIT/JITEmitter.cpp
lib/ExecutionEngine/JIT/JITMemoryManager.cpp
lib/System/Memory.cpp
lib/System/Unix/Memory.inc

index e1f2763..0d79d14 100644 (file)
@@ -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
   //===--------------------------------------------------------------------===//
index 86895e2..4d0828b 100644 (file)
@@ -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);
   };
 }
 }
index ffaeb1c..a90a6a5 100644 (file)
@@ -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;
index 804e88d..0ffc779 100644 (file)
@@ -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]);
+    }
   };
 }
 
index 2fc6a23..3660bcb 100644 (file)
@@ -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
-}
index cf0157d..646311d 100644 (file)
@@ -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
+}
+