Move the Function*->allocated blocks map from the JITMemoryManager to the
authorJeffrey Yasskin <jyasskin@google.com>
Tue, 20 Oct 2009 18:13:21 +0000 (18:13 +0000)
committerJeffrey Yasskin <jyasskin@google.com>
Tue, 20 Oct 2009 18:13:21 +0000 (18:13 +0000)
JITEmitter.

I'm gradually making Functions auto-remove themselves from the JIT when they're
destroyed. In this case, the Function needs to be removed from the JITEmitter,
but the map recording which Functions need to be removed lived behind the
JITMemoryManager interface, which made things difficult.

This patch replaces the deallocateMemForFunction(Function*) method with a pair
of methods deallocateFunctionBody(void *) and deallocateExceptionTable(void *)
corresponding to the two startFoo/endFoo pairs.

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

include/llvm/ExecutionEngine/JITMemoryManager.h
lib/ExecutionEngine/JIT/JITEmitter.cpp
lib/ExecutionEngine/JIT/JITMemoryManager.cpp
unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp

index 9f6fb63fbe56122884879f5883108817a8e071cf..568518898c31e0eea1fb6e66a26ea1c762a1d6ac 100644 (file)
@@ -132,9 +132,11 @@ public:
   ///
   virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) = 0;
 
-  /// deallocateMemForFunction - Free JIT memory for the specified function.
-  /// This is never called when the JIT is currently emitting a function.
-  virtual void deallocateMemForFunction(const Function *F) = 0;
+  /// deallocateFunctionBody - Free the specified function body.  The argument
+  /// must be the return value from a call to startFunctionBody() that hasn't
+  /// been deallocated yet.  This is never called when the JIT is currently
+  /// emitting a function.
+  virtual void deallocateFunctionBody(void *Body) = 0;
   
   /// startExceptionTable - When we finished JITing the function, if exception
   /// handling is set, we emit the exception table.
@@ -146,6 +148,12 @@ public:
   virtual void endExceptionTable(const Function *F, uint8_t *TableStart,
                                  uint8_t *TableEnd, uint8_t* FrameRegister) = 0;
 
+  /// deallocateExceptionTable - Free the specified exception table's memory.
+  /// The argument must be the return value from a call to startExceptionTable()
+  /// that hasn't been deallocated yet.  This is never called when the JIT is
+  /// currently emitting an exception table.
+  virtual void deallocateExceptionTable(void *ET) = 0;
+
   /// CheckInvariants - For testing only.  Return true if all internal
   /// invariants are preserved, or return false and set ErrorStr to a helpful
   /// error message.
index 5066447cd982c1e18dc7faf040091425d81b71af..073d6fbbde6a2fc7a1766ec11912403a2d1e7b22 100644 (file)
@@ -42,6 +42,7 @@
 #include "llvm/System/Disassembler.h"
 #include "llvm/System/Memory.h"
 #include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Statistic.h"
@@ -548,6 +549,13 @@ namespace {
     /// finishFunction.
     JITEvent_EmittedFunctionDetails EmissionDetails;
 
+    struct EmittedCode {
+      void *FunctionBody;
+      void *ExceptionTable;
+      EmittedCode() : FunctionBody(0), ExceptionTable(0) {}
+    };
+    DenseMap<const Function *, EmittedCode> EmittedFunctions;
+
     // CurFnStubUses - For a given Function, a vector of stubs that it
     // references.  This facilitates the JIT detecting that a stub is no
     // longer used, so that it may be deallocated.
@@ -1011,7 +1019,8 @@ void JITEmitter::startFunction(MachineFunction &F) {
   BufferBegin = CurBufferPtr = MemMgr->startFunctionBody(F.getFunction(),
                                                          ActualSize);
   BufferEnd = BufferBegin+ActualSize;
-  
+  EmittedFunctions[F.getFunction()].FunctionBody = BufferBegin;
+
   // Ensure the constant pool/jump table info is at least 4-byte aligned.
   emitAlignment(16);
 
@@ -1201,6 +1210,7 @@ bool JITEmitter::finishFunction(MachineFunction &F) {
     BufferBegin = CurBufferPtr = MemMgr->startExceptionTable(F.getFunction(),
                                                              ActualSize);
     BufferEnd = BufferBegin+ActualSize;
+    EmittedFunctions[F.getFunction()].ExceptionTable = BufferBegin;
     uint8_t *EhStart;
     uint8_t *FrameRegister = DE->EmitDwarfTable(F, *this, FnStart, FnEnd,
                                                 EhStart);
@@ -1244,7 +1254,13 @@ void JITEmitter::retryWithMoreMemory(MachineFunction &F) {
 /// deallocateMemForFunction - Deallocate all memory for the specified
 /// function body.  Also drop any references the function has to stubs.
 void JITEmitter::deallocateMemForFunction(const Function *F) {
-  MemMgr->deallocateMemForFunction(F);
+  DenseMap<const Function *, EmittedCode>::iterator Emitted =
+    EmittedFunctions.find(F);
+  if (Emitted != EmittedFunctions.end()) {
+    MemMgr->deallocateFunctionBody(Emitted->second.FunctionBody);
+    MemMgr->deallocateExceptionTable(Emitted->second.ExceptionTable);
+    EmittedFunctions.erase(Emitted);
+  }
 
   // TODO: Do we need to unregister exception handling information from libgcc
   // here?
index 474843f06624725f740485b19559ab46ffdc167e..ea9d09fffc7e26987965a608750166b5aeb3a2e3 100644 (file)
@@ -297,9 +297,6 @@ namespace {
 
     uint8_t *GOTBase;     // Target Specific reserved memory
     void *DlsymTable;     // Stub external symbol information
-
-    std::map<const Function*, MemoryRangeHeader*> FunctionBlocks;
-    std::map<const Function*, MemoryRangeHeader*> TableBlocks;
   public:
     DefaultJITMemoryManager();
     ~DefaultJITMemoryManager();
@@ -414,7 +411,6 @@ namespace {
              "Mismatched function start/end!");
 
       uintptr_t BlockSize = FunctionEnd - (uint8_t *)CurBlock;
-      FunctionBlocks[F] = CurBlock;
 
       // Release the memory at the end of this block that isn't needed.
       FreeMemoryList =CurBlock->TrimAllocationToSize(FreeMemoryList, BlockSize);
@@ -464,7 +460,6 @@ namespace {
              "Mismatched table start/end!");
       
       uintptr_t BlockSize = TableEnd - (uint8_t *)CurBlock;
-      TableBlocks[F] = CurBlock;
 
       // Release the memory at the end of this block that isn't needed.
       FreeMemoryList =CurBlock->TrimAllocationToSize(FreeMemoryList, BlockSize);
@@ -478,15 +473,9 @@ namespace {
       return DlsymTable;
     }
     
-    /// deallocateMemForFunction - Deallocate all memory for the specified
-    /// function body.
-    void deallocateMemForFunction(const Function *F) {
-      std::map<const Function*, MemoryRangeHeader*>::iterator
-        I = FunctionBlocks.find(F);
-      if (I == FunctionBlocks.end()) return;
-      
+    void deallocateBlock(void *Block) {
       // Find the block that is allocated for this function.
-      MemoryRangeHeader *MemRange = I->second;
+      MemoryRangeHeader *MemRange = static_cast<MemoryRangeHeader*>(Block) - 1;
       assert(MemRange->ThisAllocated && "Block isn't allocated!");
 
       // Fill the buffer with garbage!
@@ -496,27 +485,18 @@ namespace {
 
       // Free the memory.
       FreeMemoryList = MemRange->FreeBlock(FreeMemoryList);
-      
-      // Finally, remove this entry from FunctionBlocks.
-      FunctionBlocks.erase(I);
-      
-      I = TableBlocks.find(F);
-      if (I == TableBlocks.end()) return;
-      
-      // Find the block that is allocated for this function.
-      MemRange = I->second;
-      assert(MemRange->ThisAllocated && "Block isn't allocated!");
+    }
 
-      // Fill the buffer with garbage!
-      if (PoisonMemory) {
-        memset(MemRange+1, 0xCD, MemRange->BlockSize-sizeof(*MemRange));
-      }
+    /// deallocateFunctionBody - Deallocate all memory for the specified
+    /// function body.
+    void deallocateFunctionBody(void *Body) {
+      deallocateBlock(Body);
+    }
 
-      // Free the memory.
-      FreeMemoryList = MemRange->FreeBlock(FreeMemoryList);
-      
-      // Finally, remove this entry from TableBlocks.
-      TableBlocks.erase(I);
+    /// deallocateExceptionTable - Deallocate memory for the specified
+    /// exception table.
+    void deallocateExceptionTable(void *ET) {
+      deallocateBlock(ET);
     }
 
     /// setMemoryWritable - When code generation is in progress,
index 89a4be70be20e6fd90df2f7ef9b223c3dd28edb9..f0c491fba5b38ba671554d0418dcb3e23ee442ae 100644 (file)
@@ -32,37 +32,36 @@ TEST(JITMemoryManagerTest, NoAllocations) {
   OwningPtr<JITMemoryManager> MemMgr(
       JITMemoryManager::CreateDefaultMemManager());
   uintptr_t size;
-  uint8_t *start;
   std::string Error;
 
   // Allocate the functions.
   OwningPtr<Function> F1(makeFakeFunction());
   size = 1024;
-  start = MemMgr->startFunctionBody(F1.get(), size);
-  memset(start, 0xFF, 1024);
-  MemMgr->endFunctionBody(F1.get(), start, start + 1024);
+  uint8_t *FunctionBody1 = MemMgr->startFunctionBody(F1.get(), size);
+  memset(FunctionBody1, 0xFF, 1024);
+  MemMgr->endFunctionBody(F1.get(), FunctionBody1, FunctionBody1 + 1024);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
 
   OwningPtr<Function> F2(makeFakeFunction());
   size = 1024;
-  start = MemMgr->startFunctionBody(F2.get(), size);
-  memset(start, 0xFF, 1024);
-  MemMgr->endFunctionBody(F2.get(), start, start + 1024);
+  uint8_t *FunctionBody2 = MemMgr->startFunctionBody(F2.get(), size);
+  memset(FunctionBody2, 0xFF, 1024);
+  MemMgr->endFunctionBody(F2.get(), FunctionBody2, FunctionBody2 + 1024);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
 
   OwningPtr<Function> F3(makeFakeFunction());
   size = 1024;
-  start = MemMgr->startFunctionBody(F3.get(), size);
-  memset(start, 0xFF, 1024);
-  MemMgr->endFunctionBody(F3.get(), start, start + 1024);
+  uint8_t *FunctionBody3 = MemMgr->startFunctionBody(F3.get(), size);
+  memset(FunctionBody3, 0xFF, 1024);
+  MemMgr->endFunctionBody(F3.get(), FunctionBody3, FunctionBody3 + 1024);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
 
   // Deallocate them out of order, in case that matters.
-  MemMgr->deallocateMemForFunction(F2.get());
+  MemMgr->deallocateFunctionBody(FunctionBody2);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F1.get());
+  MemMgr->deallocateFunctionBody(FunctionBody1);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F3.get());
+  MemMgr->deallocateFunctionBody(FunctionBody3);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
 }
 
@@ -72,7 +71,6 @@ TEST(JITMemoryManagerTest, TestCodeAllocation) {
   OwningPtr<JITMemoryManager> MemMgr(
       JITMemoryManager::CreateDefaultMemManager());
   uintptr_t size;
-  uint8_t *start;
   std::string Error;
 
   // Big functions are a little less than the largest block size.
@@ -83,26 +81,26 @@ TEST(JITMemoryManagerTest, TestCodeAllocation) {
   // Allocate big functions
   OwningPtr<Function> F1(makeFakeFunction());
   size = bigFuncSize;
-  start = MemMgr->startFunctionBody(F1.get(), size);
+  uint8_t *FunctionBody1 = MemMgr->startFunctionBody(F1.get(), size);
   ASSERT_LE(bigFuncSize, size);
-  memset(start, 0xFF, bigFuncSize);
-  MemMgr->endFunctionBody(F1.get(), start, start + bigFuncSize);
+  memset(FunctionBody1, 0xFF, bigFuncSize);
+  MemMgr->endFunctionBody(F1.get(), FunctionBody1, FunctionBody1 + bigFuncSize);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
 
   OwningPtr<Function> F2(makeFakeFunction());
   size = bigFuncSize;
-  start = MemMgr->startFunctionBody(F2.get(), size);
+  uint8_t *FunctionBody2 = MemMgr->startFunctionBody(F2.get(), size);
   ASSERT_LE(bigFuncSize, size);
-  memset(start, 0xFF, bigFuncSize);
-  MemMgr->endFunctionBody(F2.get(), start, start + bigFuncSize);
+  memset(FunctionBody2, 0xFF, bigFuncSize);
+  MemMgr->endFunctionBody(F2.get(), FunctionBody2, FunctionBody2 + bigFuncSize);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
 
   OwningPtr<Function> F3(makeFakeFunction());
   size = bigFuncSize;
-  start = MemMgr->startFunctionBody(F3.get(), size);
+  uint8_t *FunctionBody3 = MemMgr->startFunctionBody(F3.get(), size);
   ASSERT_LE(bigFuncSize, size);
-  memset(start, 0xFF, bigFuncSize);
-  MemMgr->endFunctionBody(F3.get(), start, start + bigFuncSize);
+  memset(FunctionBody3, 0xFF, bigFuncSize);
+  MemMgr->endFunctionBody(F3.get(), FunctionBody3, FunctionBody3 + bigFuncSize);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
 
   // Check that each large function took it's own slab.
@@ -111,43 +109,46 @@ TEST(JITMemoryManagerTest, TestCodeAllocation) {
   // Allocate small functions
   OwningPtr<Function> F4(makeFakeFunction());
   size = smallFuncSize;
-  start = MemMgr->startFunctionBody(F4.get(), size);
+  uint8_t *FunctionBody4 = MemMgr->startFunctionBody(F4.get(), size);
   ASSERT_LE(smallFuncSize, size);
-  memset(start, 0xFF, smallFuncSize);
-  MemMgr->endFunctionBody(F4.get(), start, start + smallFuncSize);
+  memset(FunctionBody4, 0xFF, smallFuncSize);
+  MemMgr->endFunctionBody(F4.get(), FunctionBody4,
+                          FunctionBody4 + smallFuncSize);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
 
   OwningPtr<Function> F5(makeFakeFunction());
   size = smallFuncSize;
-  start = MemMgr->startFunctionBody(F5.get(), size);
+  uint8_t *FunctionBody5 = MemMgr->startFunctionBody(F5.get(), size);
   ASSERT_LE(smallFuncSize, size);
-  memset(start, 0xFF, smallFuncSize);
-  MemMgr->endFunctionBody(F5.get(), start, start + smallFuncSize);
+  memset(FunctionBody5, 0xFF, smallFuncSize);
+  MemMgr->endFunctionBody(F5.get(), FunctionBody5,
+                          FunctionBody5 + smallFuncSize);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
 
   OwningPtr<Function> F6(makeFakeFunction());
   size = smallFuncSize;
-  start = MemMgr->startFunctionBody(F6.get(), size);
+  uint8_t *FunctionBody6 = MemMgr->startFunctionBody(F6.get(), size);
   ASSERT_LE(smallFuncSize, size);
-  memset(start, 0xFF, smallFuncSize);
-  MemMgr->endFunctionBody(F6.get(), start, start + smallFuncSize);
+  memset(FunctionBody6, 0xFF, smallFuncSize);
+  MemMgr->endFunctionBody(F6.get(), FunctionBody6,
+                          FunctionBody6 + smallFuncSize);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
 
   // Check that the small functions didn't allocate any new slabs.
   EXPECT_EQ(3U, MemMgr->GetNumCodeSlabs());
 
   // Deallocate them out of order, in case that matters.
-  MemMgr->deallocateMemForFunction(F2.get());
+  MemMgr->deallocateFunctionBody(FunctionBody2);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F1.get());
+  MemMgr->deallocateFunctionBody(FunctionBody1);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F4.get());
+  MemMgr->deallocateFunctionBody(FunctionBody4);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F3.get());
+  MemMgr->deallocateFunctionBody(FunctionBody3);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F5.get());
+  MemMgr->deallocateFunctionBody(FunctionBody5);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F6.get());
+  MemMgr->deallocateFunctionBody(FunctionBody6);
   EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
 }