[llvm-commits] [llvm] r76838 - in /llvm/trunk: include/llvm/ExecutionEngine/JITMemoryManager.h include/llvm/Support/Allocator.h include/llvm/System/Memory.h lib/ExecutionEngine/JIT/JITEmitter.cpp lib/ExecutionEngine/JIT/JITMemoryManager.cpp lib/Support/Allocator.cpp lib/System/Unix/Memory.inc lib/System/Win32/Memory.inc tools/lli/lli.cpp unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp unittests/Support/AllocatorTest.cpp

Reid Kleckner reid at kleckner.net
Wed Jul 22 18:40:55 PDT 2009


Author: rnk
Date: Wed Jul 22 20:40:54 2009
New Revision: 76838

URL: http://llvm.org/viewvc/llvm-project?rev=76838&view=rev
Log:
Reverting r76825 and r76828, since they caused clang runtime errors and some build failure involving memset.

Modified:
    llvm/trunk/include/llvm/ExecutionEngine/JITMemoryManager.h
    llvm/trunk/include/llvm/Support/Allocator.h
    llvm/trunk/include/llvm/System/Memory.h
    llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp
    llvm/trunk/lib/ExecutionEngine/JIT/JITMemoryManager.cpp
    llvm/trunk/lib/Support/Allocator.cpp
    llvm/trunk/lib/System/Unix/Memory.inc
    llvm/trunk/lib/System/Win32/Memory.inc
    llvm/trunk/tools/lli/lli.cpp
    llvm/trunk/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp
    llvm/trunk/unittests/Support/AllocatorTest.cpp

Modified: llvm/trunk/include/llvm/ExecutionEngine/JITMemoryManager.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/JITMemoryManager.h?rev=76838&r1=76837&r2=76838&view=diff

==============================================================================
--- llvm/trunk/include/llvm/ExecutionEngine/JITMemoryManager.h (original)
+++ llvm/trunk/include/llvm/ExecutionEngine/JITMemoryManager.h Wed Jul 22 20:40:54 2009
@@ -15,12 +15,9 @@
 #define LLVM_EXECUTION_ENGINE_JIT_MEMMANAGER_H
 
 #include "llvm/Support/DataTypes.h"
-#include <string>
 
 namespace llvm {
-
   class Function;
-  class GlobalValue;
 
 /// JITMemoryManager - This interface is used by the JIT to allocate and manage
 /// memory for the code generated by the JIT.  This can be reimplemented by
@@ -91,19 +88,16 @@
   //===--------------------------------------------------------------------===//
   // Main Allocation Functions
   //===--------------------------------------------------------------------===//
-
-  /// startFunctionBody - When we start JITing a function, the JIT calls this
+  
+  /// startFunctionBody - When we start JITing a function, the JIT calls this 
   /// method to allocate a block of free RWX memory, which returns a pointer to
-  /// it.  If the JIT wants to request a block of memory of at least a certain
-  /// size, it passes that value as ActualSize, and this method returns a block
-  /// with at least that much space.  If the JIT doesn't know ahead of time how
-  /// much space it will need to emit the function, it passes 0 for the
-  /// ActualSize.  In either case, this method is required to pass back the size
-  /// of the allocated block through ActualSize.  The JIT will be careful to
-  /// not write more than the returned ActualSize bytes of memory.
-  virtual uint8_t *startFunctionBody(const Function *F,
+  /// it.  The JIT doesn't know ahead of time how much space it will need to
+  /// emit the function, so it doesn't pass in the size.  Instead, this method
+  /// is required to pass back a "valid size".  The JIT will be careful to not
+  /// write more than the returned ActualSize bytes of memory. 
+  virtual uint8_t *startFunctionBody(const Function *F, 
                                      uintptr_t &ActualSize) = 0;
-
+  
   /// allocateStub - This method is called by the JIT to allocate space for a
   /// function stub (used to handle limited branch displacements) while it is
   /// JIT compiling a function.  For example, if foo calls bar, and if bar
@@ -124,12 +118,10 @@
   virtual void endFunctionBody(const Function *F, uint8_t *FunctionStart,
                                uint8_t *FunctionEnd) = 0;
 
-  /// allocateSpace - Allocate a memory block of the given size.  This method
-  /// cannot be called between calls to startFunctionBody and endFunctionBody.
+  /// allocateSpace - Allocate a memory block of the given size.
   virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) = 0;
 
   /// allocateGlobal - Allocate memory for a global.
-  ///
   virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) = 0;
 
   /// deallocateMemForFunction - Free JIT memory for the specified function.
@@ -145,49 +137,6 @@
   /// the exception table.
   virtual void endExceptionTable(const Function *F, uint8_t *TableStart,
                                  uint8_t *TableEnd, uint8_t* FrameRegister) = 0;
-
-  /// CheckInvariants - For testing only.  Return true if all internal
-  /// invariants are preserved, or return false and set ErrorStr to a helpful
-  /// error message.
-  virtual bool CheckInvariants(std::string &ErrorStr) {
-    return true;
-  }
-
-  /// GetDefaultCodeSlabSize - For testing only.  Returns DefaultCodeSlabSize
-  /// from DefaultJITMemoryManager.
-  virtual size_t GetDefaultCodeSlabSize() {
-    return 0;
-  }
-
-  /// GetDefaultDataSlabSize - For testing only.  Returns DefaultCodeSlabSize
-  /// from DefaultJITMemoryManager.
-  virtual size_t GetDefaultDataSlabSize() {
-    return 0;
-  }
-
-  /// GetDefaultStubSlabSize - For testing only.  Returns DefaultCodeSlabSize
-  /// from DefaultJITMemoryManager.
-  virtual size_t GetDefaultStubSlabSize() {
-    return 0;
-  }
-
-  /// GetNumCodeSlabs - For testing only.  Returns the number of MemoryBlocks
-  /// allocated for code.
-  virtual unsigned GetNumCodeSlabs() {
-    return 0;
-  }
-
-  /// GetNumDataSlabs - For testing only.  Returns the number of MemoryBlocks
-  /// allocated for data.
-  virtual unsigned GetNumDataSlabs() {
-    return 0;
-  }
-
-  /// GetNumStubSlabs - For testing only.  Returns the number of MemoryBlocks
-  /// allocated for function stubs.
-  virtual unsigned GetNumStubSlabs() {
-    return 0;
-  }
 };
 
 } // end namespace llvm.

Modified: llvm/trunk/include/llvm/Support/Allocator.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Allocator.h?rev=76838&r1=76837&r2=76838&view=diff

==============================================================================
--- llvm/trunk/include/llvm/Support/Allocator.h (original)
+++ llvm/trunk/include/llvm/Support/Allocator.h Wed Jul 22 20:40:54 2009
@@ -15,8 +15,6 @@
 #define LLVM_SUPPORT_ALLOCATOR_H
 
 #include "llvm/Support/AlignOf.h"
-#include "llvm/Support/DataTypes.h"
-#include <cassert>
 #include <cstdlib>
 
 namespace llvm {
@@ -43,104 +41,21 @@
   void PrintStats() const {}
 };
 
-/// MemSlab - This structure lives at the beginning of every slab allocated by
-/// the bump allocator.
-class MemSlab {
-public:
-  size_t Size;
-  MemSlab *NextPtr;
-};
-
-/// SlabAllocator - This class can be used to parameterize the underlying
-/// allocation strategy for the bump allocator.  In particular, this is used
-/// by the JIT to allocate contiguous swathes of executable memory.  The
-/// interface uses MemSlab's instead of void *'s so that the allocator
-/// doesn't have to remember the size of the pointer it allocated.
-class SlabAllocator {
-public:
-  virtual ~SlabAllocator();
-  virtual MemSlab *Allocate(size_t Size) = 0;
-  virtual void Deallocate(MemSlab *Slab) = 0;
-};
-
-/// MallocSlabAllocator - The default slab allocator for the bump allocator
-/// is an adapter class for MallocAllocator that just forwards the method
-/// calls and translates the arguments.
-class MallocSlabAllocator : public SlabAllocator {
-  /// Allocator - The underlying allocator that we forward to.
-  ///
-  MallocAllocator Allocator;
-
-public:
-  MallocSlabAllocator() : Allocator() { }
-  virtual ~MallocSlabAllocator();
-  virtual MemSlab *Allocate(size_t Size);
-  virtual void Deallocate(MemSlab *Slab);
-};
-
-/// BumpPtrAllocator - This allocator is useful for containers that need
-/// very simple memory allocation strategies.  In particular, this just keeps
+/// BumpPtrAllocator - This allocator is useful for containers that need very
+/// simple memory allocation strategies.  In particular, this just keeps
 /// allocating memory, and never deletes it until the entire block is dead. This
 /// makes allocation speedy, but must only be used when the trade-off is ok.
 class BumpPtrAllocator {
   BumpPtrAllocator(const BumpPtrAllocator &); // do not implement
   void operator=(const BumpPtrAllocator &);   // do not implement
 
-  /// SlabSize - Allocate data into slabs of this size unless we get an
-  /// allocation above SizeThreshold.
-  size_t SlabSize;
-
-  /// SizeThreshold - For any allocation larger than this threshold, we should
-  /// allocate a separate slab.
-  size_t SizeThreshold;
-
-  /// Allocator - The underlying allocator we use to get slabs of memory.  This
-  /// defaults to MallocSlabAllocator, which wraps malloc, but it could be
-  /// changed to use a custom allocator.
-  SlabAllocator &Allocator;
-
-  /// CurSlab - The slab that we are currently allocating into.
-  ///
-  MemSlab *CurSlab;
-
-  /// CurPtr - The current pointer into the current slab.  This points to the
-  /// next free byte in the slab.
-  char *CurPtr;
-
-  /// End - The end of the current slab.
-  ///
-  char *End;
-
-  /// BytesAllocated - This field tracks how many bytes we've allocated, so
-  /// that we can compute how much space was wasted.
-  size_t BytesAllocated;
-
-  /// AlignPtr - Align Ptr to Alignment bytes, rounding up.  Alignment should
-  /// be a power of two.  This method rounds up, so AlignPtr(7, 4) == 8 and
-  /// AlignPtr(8, 4) == 8.
-  static char *AlignPtr(char *Ptr, size_t Alignment);
-
-  /// StartNewSlab - Allocate a new slab and move the bump pointers over into
-  /// the new slab.  Modifies CurPtr and End.
-  void StartNewSlab();
-
-  /// DeallocateSlabs - Deallocate all memory slabs after and including this
-  /// one.
-  void DeallocateSlabs(MemSlab *Slab);
-
-  static MallocSlabAllocator DefaultSlabAllocator;
-
+  void *TheMemory;
 public:
-  BumpPtrAllocator(size_t size = 4096, size_t threshold = 4096,
-                   SlabAllocator &allocator = DefaultSlabAllocator);
+  BumpPtrAllocator();
   ~BumpPtrAllocator();
 
-  /// Reset - Deallocate all but the current slab and reset the current pointer
-  /// to the beginning of it, freeing all memory allocated so far.
   void Reset();
 
-  /// Allocate - Allocate space at the specified alignment.
-  ///
   void *Allocate(size_t Size, size_t Alignment);
 
   /// Allocate space, but do not construct, one object.
@@ -168,11 +83,9 @@
 
   void Deallocate(const void * /*Ptr*/) {}
 
-  unsigned GetNumSlabs() const;
-
   void PrintStats() const;
 };
 
 }  // end namespace llvm
 
-#endif // LLVM_SUPPORT_ALLOCATOR_H
+#endif

Modified: llvm/trunk/include/llvm/System/Memory.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/System/Memory.h?rev=76838&r1=76837&r2=76838&view=diff

==============================================================================
--- llvm/trunk/include/llvm/System/Memory.h (original)
+++ llvm/trunk/include/llvm/System/Memory.h Wed Jul 22 20:40:54 2009
@@ -14,7 +14,6 @@
 #ifndef LLVM_SYSTEM_MEMORY_H
 #define LLVM_SYSTEM_MEMORY_H
 
-#include "llvm/Support/DataTypes.h"
 #include <string>
 
 namespace llvm {
@@ -27,13 +26,11 @@
   /// @brief Memory block abstraction.
   class MemoryBlock {
   public:
-    MemoryBlock() { }
-    MemoryBlock(void *addr, size_t size) : Address(addr), Size(size) { }
     void *base() const { return Address; }
-    size_t size() const { return Size; }
+    unsigned size() const { return Size; }
   private:
     void *Address;    ///< Address of first byte of memory area
-    size_t Size;      ///< Size, in bytes of the memory area
+    unsigned Size;    ///< Size, in bytes of the memory area
     friend class Memory;
   };
 
@@ -53,7 +50,7 @@
     /// a null memory block and fills in *ErrMsg.
     /// 
     /// @brief Allocate Read/Write/Execute memory.
-    static MemoryBlock AllocateRWX(size_t NumBytes,
+    static MemoryBlock AllocateRWX(unsigned NumBytes,
                                    const MemoryBlock *NearBlock,
                                    std::string *ErrMsg = 0);
 

Modified: llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp?rev=76838&r1=76837&r2=76838&view=diff

==============================================================================
--- llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp (original)
+++ llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp Wed Jul 22 20:40:54 2009
@@ -51,7 +51,6 @@
 
 STATISTIC(NumBytes, "Number of bytes of machine code compiled");
 STATISTIC(NumRelos, "Number of relocations applied");
-STATISTIC(NumRetries, "Number of retries with more memory");
 static JIT *TheJIT = 0;
 
 
@@ -426,12 +425,6 @@
     // save BufferBegin/BufferEnd/CurBufferPtr here.
     uint8_t *SavedBufferBegin, *SavedBufferEnd, *SavedCurBufferPtr;
 
-    // When reattempting to JIT a function after running out of space, we store
-    // the estimated size of the function we're trying to JIT here, so we can
-    // ask the memory manager for at least this much space.  When we
-    // successfully emit the function, we reset this back to zero.
-    uintptr_t SizeEstimate;
-
     /// Relocations - These are the relocations that the function needs, as
     /// emitted.
     std::vector<MachineRelocation> Relocations;
@@ -503,8 +496,7 @@
     DebugLocTuple PrevDLT;
 
   public:
-    JITEmitter(JIT &jit, JITMemoryManager *JMM)
-        : SizeEstimate(0), Resolver(jit), CurFn(0) {
+    JITEmitter(JIT &jit, JITMemoryManager *JMM) : Resolver(jit), CurFn(0) {
       MemMgr = JMM ? JMM : JITMemoryManager::CreateDefaultMemManager();
       if (jit.getJITInfo().needsGOT()) {
         MemMgr->AllocateGOT();
@@ -569,14 +561,9 @@
       return MBBLocations[MBB->getNumber()];
     }
 
-    /// retryWithMoreMemory - Log a retry and deallocate all memory for the
-    /// given function.  Increase the minimum allocation size so that we get
-    /// more memory next time.
-    void retryWithMoreMemory(MachineFunction &F);
-
     /// deallocateMemForFunction - Deallocate all memory for the specified
     /// function body.
-    void deallocateMemForFunction(const Function *F);
+    void deallocateMemForFunction(Function *F);
 
     /// AddStubToCurrentFunction - Mark the current function being JIT'd as
     /// using the stub at the specified address. Allows
@@ -938,9 +925,6 @@
     // previously allocated.
     ActualSize += GetSizeOfGlobalsInBytes(F);
     DOUT << "JIT: ActualSize after globals " << ActualSize << "\n";
-  } else if (SizeEstimate > 0) {
-    // SizeEstimate will be non-zero on reallocation attempts.
-    ActualSize = SizeEstimate;
   }
 
   BufferBegin = CurBufferPtr = MemMgr->startFunctionBody(F.getFunction(),
@@ -965,15 +949,12 @@
 
 bool JITEmitter::finishFunction(MachineFunction &F) {
   if (CurBufferPtr == BufferEnd) {
-    // We must call endFunctionBody before retrying, because
-    // deallocateMemForFunction requires it.
-    MemMgr->endFunctionBody(F.getFunction(), BufferBegin, CurBufferPtr);
-    retryWithMoreMemory(F);
-    return true;
+    // FIXME: Allocate more space, then try again.
+    llvm_report_error("JIT: Ran out of space for generated machine code!");
   }
-
+  
   emitJumpTableInfo(F.getJumpTableInfo());
-
+  
   // FnStart is the start of the text, not the start of the constant pool and
   // other per-function data.
   uint8_t *FnStart =
@@ -1064,12 +1045,8 @@
   MemMgr->endFunctionBody(F.getFunction(), BufferBegin, CurBufferPtr);
 
   if (CurBufferPtr == BufferEnd) {
-    retryWithMoreMemory(F);
-    return true;
-  } else {
-    // Now that we've succeeded in emitting the function, reset the
-    // SizeEstimate back down to zero.
-    SizeEstimate = 0;
+    // FIXME: Allocate more space, then try again.
+    llvm_report_error("JIT: Ran out of space for generated machine code!");
   }
 
   BufferBegin = CurBufferPtr = 0;
@@ -1154,19 +1131,9 @@
   return false;
 }
 
-void JITEmitter::retryWithMoreMemory(MachineFunction &F) {
-  DOUT << "JIT: Ran out of space for native code.  Reattempting.\n";
-  Relocations.clear();  // Clear the old relocations or we'll reapply them.
-  ConstPoolAddresses.clear();
-  ++NumRetries;
-  deallocateMemForFunction(F.getFunction());
-  // Try again with at least twice as much free space.
-  SizeEstimate = (uintptr_t)(2 * (BufferEnd - BufferBegin));
-}
-
 /// deallocateMemForFunction - Deallocate all memory for the specified
 /// function body.  Also drop any references the function has to stubs.
-void JITEmitter::deallocateMemForFunction(const Function *F) {
+void JITEmitter::deallocateMemForFunction(Function *F) {
   MemMgr->deallocateMemForFunction(F);
 
   // If the function did not reference any stubs, return.

Modified: llvm/trunk/lib/ExecutionEngine/JIT/JITMemoryManager.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/JIT/JITMemoryManager.cpp?rev=76838&r1=76837&r2=76838&view=diff

==============================================================================
--- llvm/trunk/lib/ExecutionEngine/JIT/JITMemoryManager.cpp (original)
+++ llvm/trunk/lib/ExecutionEngine/JIT/JITMemoryManager.cpp Wed Jul 22 20:40:54 2009
@@ -11,16 +11,10 @@
 //
 //===----------------------------------------------------------------------===//
 
-#define DEBUG_TYPE "jit"
-#include "llvm/ExecutionEngine/JITMemoryManager.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/Statistic.h"
 #include "llvm/GlobalValue.h"
-#include "llvm/Support/Allocator.h"
+#include "llvm/ExecutionEngine/JITMemoryManager.h"
 #include "llvm/Support/Compiler.h"
-#include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
 #include "llvm/System/Memory.h"
 #include <map>
 #include <vector>
@@ -31,7 +25,6 @@
 #include <cstring>
 using namespace llvm;
 
-STATISTIC(NumSlabs, "Number of slabs of memory allocated by the JIT");
 
 JITMemoryManager::~JITMemoryManager() {}
 
@@ -148,7 +141,7 @@
 /// FreeRangeHeader to allocate from.
 FreeRangeHeader *MemoryRangeHeader::FreeBlock(FreeRangeHeader *FreeList) {
   MemoryRangeHeader *FollowingBlock = &getBlockAfter();
-  assert(ThisAllocated && "This block is already free!");
+  assert(ThisAllocated && "This block is already allocated!");
   assert(FollowingBlock->PrevAllocated && "Flags out of sync!");
   
   FreeRangeHeader *FreeListToReturn = FreeList;
@@ -251,157 +244,70 @@
 // Memory Block Implementation.
 //===----------------------------------------------------------------------===//
 
-namespace {
-
-  class DefaultJITMemoryManager;
-
-  class JITSlabAllocator : public SlabAllocator {
-    DefaultJITMemoryManager &JMM;
-  public:
-    JITSlabAllocator(DefaultJITMemoryManager &jmm) : JMM(jmm) { }
-    virtual ~JITSlabAllocator() { }
-    virtual MemSlab *Allocate(size_t Size);
-    virtual void Deallocate(MemSlab *Slab);
-  };
-
+namespace {  
   /// DefaultJITMemoryManager - Manage memory for the JIT code generation.
   /// This splits a large block of MAP_NORESERVE'd memory into two
   /// sections, one for function stubs, one for the functions themselves.  We
   /// have to do this because we may need to emit a function stub while in the
   /// middle of emitting a function, and we don't know how large the function we
   /// are emitting is.
-  class DefaultJITMemoryManager : public JITMemoryManager {
-
-    // Whether to poison freed memory.
-    bool PoisonMemory;
-
-    /// LastSlab - This points to the last slab allocated and is used as the
-    /// NearBlock parameter to AllocateRWX so that we can attempt to lay out all
-    /// stubs, data, and code contiguously in memory.  In general, however, this
-    /// is not possible because the NearBlock parameter is ignored on Windows
-    /// platforms and even on Unix it works on a best-effort pasis.
-    sys::MemoryBlock LastSlab;
-
-    // Memory slabs allocated by the JIT.  We refer to them as slabs so we don't
-    // confuse them with the blocks of memory descibed above.
-    std::vector<sys::MemoryBlock> CodeSlabs;
-    JITSlabAllocator BumpSlabAllocator;
-    BumpPtrAllocator StubAllocator;
-    BumpPtrAllocator DataAllocator;
-
-    // Circular list of free blocks.
-    FreeRangeHeader *FreeMemoryList;
+  class VISIBILITY_HIDDEN DefaultJITMemoryManager : public JITMemoryManager {
+    bool PoisonMemory;  // Whether to poison freed memory.
 
+    std::vector<sys::MemoryBlock> Blocks; // Memory blocks allocated by the JIT
+    FreeRangeHeader *FreeMemoryList;      // Circular list of free blocks.
+    
     // When emitting code into a memory block, this is the block.
     MemoryRangeHeader *CurBlock;
-
+    
+    uint8_t *CurStubPtr, *StubBase;
+    uint8_t *CurGlobalPtr, *GlobalEnd;
     uint8_t *GOTBase;     // Target Specific reserved memory
     void *DlsymTable;     // Stub external symbol information
 
+    // Centralize memory block allocation.
+    sys::MemoryBlock getNewMemoryBlock(unsigned size);
+    
     std::map<const Function*, MemoryRangeHeader*> FunctionBlocks;
     std::map<const Function*, MemoryRangeHeader*> TableBlocks;
   public:
     DefaultJITMemoryManager();
     ~DefaultJITMemoryManager();
 
-    /// allocateNewSlab - Allocates a new MemoryBlock and remembers it as the
-    /// last slab it allocated, so that subsequent allocations follow it.
-    sys::MemoryBlock allocateNewSlab(size_t size);
-
-    /// DefaultCodeSlabSize - When we have to go map more memory, we allocate at
-    /// least this much unless more is requested.
-    static const size_t DefaultCodeSlabSize;
-
-    /// DefaultSlabSize - Allocate data into slabs of this size unless we get
-    /// an allocation above SizeThreshold.
-    static const size_t DefaultSlabSize;
-
-    /// DefaultSizeThreshold - For any allocation larger than this threshold, we
-    /// should allocate a separate slab.
-    static const size_t DefaultSizeThreshold;
-
     void AllocateGOT();
     void SetDlsymTable(void *);
-
-    // Testing methods.
-    virtual bool CheckInvariants(std::string &ErrorStr);
-    size_t GetDefaultCodeSlabSize() { return DefaultCodeSlabSize; }
-    size_t GetDefaultDataSlabSize() { return DefaultSlabSize; }
-    size_t GetDefaultStubSlabSize() { return DefaultSlabSize; }
-    unsigned GetNumCodeSlabs() { return CodeSlabs.size(); }
-    unsigned GetNumDataSlabs() { return DataAllocator.GetNumSlabs(); }
-    unsigned GetNumStubSlabs() { return StubAllocator.GetNumSlabs(); }
-
+    
+    uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
+                          unsigned Alignment);
+    
     /// startFunctionBody - When a function starts, allocate a block of free
     /// executable memory, returning a pointer to it and its actual size.
     uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize) {
-
+      
       FreeRangeHeader* candidateBlock = FreeMemoryList;
       FreeRangeHeader* head = FreeMemoryList;
       FreeRangeHeader* iter = head->Next;
 
       uintptr_t largest = candidateBlock->BlockSize;
-
+      
       // Search for the largest free block
       while (iter != head) {
-        if (iter->BlockSize > largest) {
-          largest = iter->BlockSize;
-          candidateBlock = iter;
-        }
-        iter = iter->Next;
+          if (iter->BlockSize > largest) {
+              largest = iter->BlockSize;
+              candidateBlock = iter;
+          }
+          iter = iter->Next;
       }
-
-      // If this block isn't big enough for the allocation desired, allocate
-      // another block of memory and add it to the free list.
-      if (largest - sizeof(MemoryRangeHeader) < ActualSize) {
-        DOUT << "JIT: Allocating another slab of memory for function.";
-        candidateBlock = allocateNewCodeSlab((size_t)ActualSize);
-      }
-
+      
       // Select this candidate block for allocation
       CurBlock = candidateBlock;
 
       // Allocate the entire memory block.
       FreeMemoryList = candidateBlock->AllocateBlock();
-      ActualSize = CurBlock->BlockSize - sizeof(MemoryRangeHeader);
-      return (uint8_t *)(CurBlock + 1);
+      ActualSize = CurBlock->BlockSize-sizeof(MemoryRangeHeader);
+      return (uint8_t *)(CurBlock+1);
     }
-
-    /// allocateNewCodeSlab - Helper method to allocate a new slab of code
-    /// memory from the OS and add it to the free list.  Returns the new
-    /// FreeRangeHeader at the base of the slab.
-    FreeRangeHeader *allocateNewCodeSlab(size_t MinSize) {
-      // If the user needs at least MinSize free memory, then we account for
-      // two MemoryRangeHeaders: the one in the user's block, and the one at the
-      // end of the slab.
-      size_t PaddedMin = MinSize + 2 * sizeof(MemoryRangeHeader);
-      size_t SlabSize = std::max(DefaultCodeSlabSize, PaddedMin);
-      sys::MemoryBlock B = allocateNewSlab(SlabSize);
-      CodeSlabs.push_back(B);
-      char *MemBase = (char*)(B.base());
-
-      // Put a tiny allocated block at the end of the memory chunk, so when
-      // FreeBlock calls getBlockAfter it doesn't fall off the end.
-      MemoryRangeHeader *EndBlock =
-          (MemoryRangeHeader*)(MemBase + B.size()) - 1;
-      EndBlock->ThisAllocated = 1;
-      EndBlock->PrevAllocated = 0;
-      EndBlock->BlockSize = sizeof(MemoryRangeHeader);
-
-      // Start out with a vast new block of free memory.
-      FreeRangeHeader *NewBlock = (FreeRangeHeader*)MemBase;
-      NewBlock->ThisAllocated = 0;
-      // Make sure getFreeBlockBefore doesn't look into unmapped memory.
-      NewBlock->PrevAllocated = 1;
-      NewBlock->BlockSize = (uintptr_t)EndBlock - (uintptr_t)NewBlock;
-      NewBlock->SetEndOfBlockSizeMarker();
-      NewBlock->AddToFreeList(FreeMemoryList);
-
-      assert(NewBlock->BlockSize - sizeof(MemoryRangeHeader) >= MinSize &&
-             "The block was too small!");
-      return NewBlock;
-    }
-
+    
     /// endFunctionBody - The function F is now allocated, and takes the memory
     /// in the range [FunctionStart,FunctionEnd).
     void endFunctionBody(const Function *F, uint8_t *FunctionStart,
@@ -417,8 +323,7 @@
       FreeMemoryList =CurBlock->TrimAllocationToSize(FreeMemoryList, BlockSize);
     }
 
-    /// allocateSpace - Allocate a memory block of the given size.  This method
-    /// cannot be called between calls to startFunctionBody and endFunctionBody.
+    /// allocateSpace - Allocate a memory block of the given size.
     uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) {
       CurBlock = FreeMemoryList;
       FreeMemoryList = FreeMemoryList->AllocateBlock();
@@ -435,15 +340,27 @@
       return result;
     }
 
-    /// allocateStub - Allocate memory for a function stub.
-    uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
-                          unsigned Alignment) {
-      return (uint8_t*)StubAllocator.Allocate(StubSize, Alignment);
-    }
-
-    /// allocateGlobal - Allocate memory for a global.
+    /// allocateGlobal - Allocate memory for a global.  Unlike allocateSpace,
+    /// this method does not touch the current block and can be called at any
+    /// time.
     uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) {
-      return (uint8_t*)DataAllocator.Allocate(Size, Alignment);
+      uint8_t *Result = CurGlobalPtr;
+
+      // Align the pointer.
+      if (Alignment == 0) Alignment = 1;
+      Result = (uint8_t*)(((uintptr_t)Result + Alignment-1) &
+                          ~(uintptr_t)(Alignment-1));
+
+      // Move the current global pointer forward.
+      CurGlobalPtr += Result - CurGlobalPtr + Size;
+
+      // Check for overflow.
+      if (CurGlobalPtr > GlobalEnd) {
+        // FIXME: Allocate more memory.
+        llvm_report_error("JIT ran out of memory for globals!");
+      }
+
+      return Result;
     }
 
     /// startExceptionTable - Use startFunctionBody to allocate memory for the 
@@ -520,15 +437,15 @@
     /// the code pages may need permissions changed.
     void setMemoryWritable(void)
     {
-      for (unsigned i = 0, e = CodeSlabs.size(); i != e; ++i)
-        sys::Memory::setWritable(CodeSlabs[i]);
+      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 = CodeSlabs.size(); i != e; ++i)
-        sys::Memory::setExecutable(CodeSlabs[i]);
+      for (unsigned i = 0, e = Blocks.size(); i != e; ++i)
+        sys::Memory::setExecutable(Blocks[i]);
     }
 
     /// setPoisonMemory - Controls whether we write garbage over freed memory.
@@ -539,35 +456,28 @@
   };
 }
 
-MemSlab *JITSlabAllocator::Allocate(size_t Size) {
-  sys::MemoryBlock B = JMM.allocateNewSlab(Size);
-  MemSlab *Slab = (MemSlab*)B.base();
-  Slab->Size = B.size();
-  Slab->NextPtr = 0;
-  return Slab;
-}
-
-void JITSlabAllocator::Deallocate(MemSlab *Slab) {
-  sys::MemoryBlock B(Slab, Slab->Size);
-  sys::Memory::ReleaseRWX(B);
-}
-
-DefaultJITMemoryManager::DefaultJITMemoryManager()
-  : LastSlab(0, 0),
-    BumpSlabAllocator(*this),
-    StubAllocator(DefaultSlabSize, DefaultSizeThreshold, BumpSlabAllocator),
-    DataAllocator(DefaultSlabSize, DefaultSizeThreshold, BumpSlabAllocator) {
-
+DefaultJITMemoryManager::DefaultJITMemoryManager() {
 #ifdef NDEBUG
+  PoisonMemory = true;
+#else
   PoisonMemory = false;
+#endif
+
+  // Allocate a 16M block of memory for functions.
+#if defined(__APPLE__) && defined(__arm__)
+  sys::MemoryBlock MemBlock = getNewMemoryBlock(4 << 20);
 #else
-  PoisonMemory = true;
+  sys::MemoryBlock MemBlock = getNewMemoryBlock(16 << 20);
 #endif
 
-  // Allocate space for code.
-  sys::MemoryBlock MemBlock = allocateNewSlab(DefaultCodeSlabSize);
-  CodeSlabs.push_back(MemBlock);
-  uint8_t *MemBase = (uint8_t*)MemBlock.base();
+  uint8_t *MemBase = static_cast<uint8_t*>(MemBlock.base());
+
+  // Allocate stubs backwards to the base, globals forward from the stubs, and
+  // functions forward after globals.
+  StubBase   = MemBase;
+  CurStubPtr = MemBase + 512*1024; // Use 512k for stubs, working backwards.
+  CurGlobalPtr = CurStubPtr;       // Use 2M for globals, working forwards.
+  GlobalEnd = CurGlobalPtr + 2*1024*1024;
 
   // We set up the memory chunk with 4 mem regions, like this:
   //  [ START
@@ -584,7 +494,7 @@
   MemoryRangeHeader *Mem3 = (MemoryRangeHeader*)(MemBase+MemBlock.size())-1;
   Mem3->ThisAllocated = 1;
   Mem3->PrevAllocated = 0;
-  Mem3->BlockSize     = sizeof(MemoryRangeHeader);
+  Mem3->BlockSize     = 0;
   
   /// Add a tiny free region so that the free list always has one entry.
   FreeRangeHeader *Mem2 = 
@@ -600,12 +510,12 @@
   MemoryRangeHeader *Mem1 = (MemoryRangeHeader*)Mem2-1;
   Mem1->ThisAllocated = 1;
   Mem1->PrevAllocated = 0;
-  Mem1->BlockSize     = sizeof(MemoryRangeHeader);
+  Mem1->BlockSize     = (char*)Mem2 - (char*)Mem1;
   
   // Add a FreeRangeHeader to the start of the function body region, indicating
   // that the space is free.  Mark the previous block allocated so we never look
   // at it.
-  FreeRangeHeader *Mem0 = (FreeRangeHeader*)MemBase;
+  FreeRangeHeader *Mem0 = (FreeRangeHeader*)GlobalEnd;
   Mem0->ThisAllocated = 0;
   Mem0->PrevAllocated = 1;
   Mem0->BlockSize = (char*)Mem1-(char*)Mem0;
@@ -630,124 +540,40 @@
 }
 
 DefaultJITMemoryManager::~DefaultJITMemoryManager() {
-  for (unsigned i = 0, e = CodeSlabs.size(); i != e; ++i)
-    sys::Memory::ReleaseRWX(CodeSlabs[i]);
-
+  for (unsigned i = 0, e = Blocks.size(); i != e; ++i)
+    sys::Memory::ReleaseRWX(Blocks[i]);
+  
   delete[] GOTBase;
+  Blocks.clear();
+}
+
+uint8_t *DefaultJITMemoryManager::allocateStub(const GlobalValue* F,
+                                                     unsigned StubSize,
+                                                     unsigned Alignment) {
+  CurStubPtr -= StubSize;
+  CurStubPtr = (uint8_t*)(((intptr_t)CurStubPtr) &
+                          ~(intptr_t)(Alignment-1));
+  if (CurStubPtr < StubBase) {
+    // FIXME: allocate a new block
+    llvm_report_error("JIT ran out of memory for function stubs!");
+  }
+  return CurStubPtr;
 }
 
-sys::MemoryBlock DefaultJITMemoryManager::allocateNewSlab(size_t size) {
+sys::MemoryBlock DefaultJITMemoryManager::getNewMemoryBlock(unsigned size) {
   // Allocate a new block close to the last one.
+  const sys::MemoryBlock *BOld = Blocks.empty() ? 0 : &Blocks.back();
   std::string ErrMsg;
-  sys::MemoryBlock *LastSlabPtr = LastSlab.base() ? &LastSlab : 0;
-  sys::MemoryBlock B = sys::Memory::AllocateRWX(size, LastSlabPtr, &ErrMsg);
+  sys::MemoryBlock B = sys::Memory::AllocateRWX(size, BOld, &ErrMsg);
   if (B.base() == 0) {
     llvm_report_error("Allocation failed when allocating new memory in the"
                       " JIT\n" + ErrMsg);
   }
-  LastSlab = B;
-  ++NumSlabs;
+  Blocks.push_back(B);
   return B;
 }
 
-/// CheckInvariants - For testing only.  Return "" if all internal invariants
-/// are preserved, and a helpful error message otherwise.  For free and
-/// allocated blocks, make sure that adding BlockSize gives a valid block.
-/// For free blocks, make sure they're in the free list and that their end of
-/// block size marker is correct.  This function should return an error before
-/// accessing bad memory.  This function is defined here instead of in
-/// JITMemoryManagerTest.cpp so that we don't have to expose all of the
-/// implementation details of DefaultJITMemoryManager.
-bool DefaultJITMemoryManager::CheckInvariants(std::string &ErrorStr) {
-  raw_string_ostream Err(ErrorStr);
-
-  // Construct a the set of FreeRangeHeader pointers so we can query it
-  // efficiently.
-  llvm::SmallPtrSet<MemoryRangeHeader*, 16> FreeHdrSet;
-  FreeRangeHeader* FreeHead = FreeMemoryList;
-  FreeRangeHeader* FreeRange = FreeHead;
-
-  do {
-    // Check that the free range pointer is in the blocks we've allocated.
-    bool Found = false;
-    for (std::vector<sys::MemoryBlock>::iterator I = CodeSlabs.begin(),
-         E = CodeSlabs.end(); I != E && !Found; ++I) {
-      char *Start = (char*)I->base();
-      char *End = Start + I->size();
-      Found = (Start <= (char*)FreeRange && (char*)FreeRange < End);
-    }
-    if (!Found) {
-      Err << "Corrupt free list; points to " << FreeRange;
-      return false;
-    }
-
-    if (FreeRange->Next->Prev != FreeRange) {
-      Err << "Next and Prev pointers do not match.";
-      return false;
-    }
-
-    // Otherwise, add it to the set.
-    FreeHdrSet.insert(FreeRange);
-    FreeRange = FreeRange->Next;
-  } while (FreeRange != FreeHead);
-
-  // Go over each block, and look at each MemoryRangeHeader.
-  for (std::vector<sys::MemoryBlock>::iterator I = CodeSlabs.begin(),
-       E = CodeSlabs.end(); I != E; ++I) {
-    char *Start = (char*)I->base();
-    char *End = Start + I->size();
-
-    // Check each memory range.
-    for (MemoryRangeHeader *Hdr = (MemoryRangeHeader*)Start, *LastHdr = NULL;
-         Start <= (char*)Hdr && (char*)Hdr < End;
-         Hdr = &Hdr->getBlockAfter()) {
-      if (Hdr->ThisAllocated == 0) {
-        // Check that this range is in the free list.
-        if (!FreeHdrSet.count(Hdr)) {
-          Err << "Found free header at " << Hdr << " that is not in free list.";
-          return false;
-        }
-
-        // Now make sure the size marker at the end of the block is correct.
-        uintptr_t *Marker = ((uintptr_t*)&Hdr->getBlockAfter()) - 1;
-        if (!(Start <= (char*)Marker && (char*)Marker < End)) {
-          Err << "Block size in header points out of current MemoryBlock.";
-          return false;
-        }
-        if (Hdr->BlockSize != *Marker) {
-          Err << "End of block size marker (" << *Marker << ") "
-              << "and BlockSize (" << Hdr->BlockSize << ") don't match.";
-          return false;
-        }
-      }
-
-      if (LastHdr && LastHdr->ThisAllocated != Hdr->PrevAllocated) {
-        Err << "Hdr->PrevAllocated (" << Hdr->PrevAllocated << ") != "
-            << "LastHdr->ThisAllocated (" << LastHdr->ThisAllocated << ")";
-        return false;
-      } else if (!LastHdr && !Hdr->PrevAllocated) {
-        Err << "The first header should have PrevAllocated true.";
-        return false;
-      }
-
-      // Remember the last header.
-      LastHdr = Hdr;
-    }
-  }
-
-  // All invariants are preserved.
-  return true;
-}
 
 JITMemoryManager *JITMemoryManager::CreateDefaultMemManager() {
   return new DefaultJITMemoryManager();
 }
-
-// Allocate memory for code in 512K slabs.
-const size_t DefaultJITMemoryManager::DefaultCodeSlabSize = 512 * 1024;
-
-// Allocate globals and stubs in slabs of 64K.  (probably 16 pages)
-const size_t DefaultJITMemoryManager::DefaultSlabSize = 64 * 1024;
-
-// Waste at most 16K at the end of each bump slab.  (probably 4 pages)
-const size_t DefaultJITMemoryManager::DefaultSizeThreshold = 16 * 1024;

Modified: llvm/trunk/lib/Support/Allocator.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Allocator.cpp?rev=76838&r1=76837&r2=76838&view=diff

==============================================================================
--- llvm/trunk/lib/Support/Allocator.cpp (original)
+++ llvm/trunk/lib/Support/Allocator.cpp Wed Jul 22 20:40:54 2009
@@ -15,155 +15,127 @@
 #include "llvm/Support/Recycler.h"
 #include "llvm/Support/DataTypes.h"
 #include "llvm/Support/Streams.h"
-#include <cstring>
+#include <ostream>
+using namespace llvm;
 
-namespace llvm {
-
-BumpPtrAllocator::BumpPtrAllocator(size_t size, size_t threshold,
-                                   SlabAllocator &allocator)
-    : SlabSize(size), SizeThreshold(threshold), Allocator(allocator),
-      CurSlab(0), BytesAllocated(0) {
-  StartNewSlab();
-}
-
-BumpPtrAllocator::~BumpPtrAllocator() {
-  DeallocateSlabs(CurSlab);
-}
-
-/// AlignPtr - Align Ptr to Alignment bytes, rounding up.  Alignment should
-/// be a power of two.  This method rounds up, so AlignPtr(7, 4) == 8 and
-/// AlignPtr(8, 4) == 8.
-char *BumpPtrAllocator::AlignPtr(char *Ptr, size_t Alignment) {
-  assert(Alignment && (Alignment & (Alignment - 1)) == 0 &&
-         "Alignment is not a power of two!");
-
-  // Do the alignment.
-  return (char*)(((uintptr_t)Ptr + Alignment - 1) &
-                 ~(uintptr_t)(Alignment - 1));
-}
-
-/// StartNewSlab - Allocate a new slab and move the bump pointers over into
-/// the new slab.  Modifies CurPtr and End.
-void BumpPtrAllocator::StartNewSlab() {
-  MemSlab *NewSlab = Allocator.Allocate(SlabSize);
-  NewSlab->NextPtr = CurSlab;
-  CurSlab = NewSlab;
-  CurPtr = (char*)(CurSlab + 1);
-  End = CurPtr + CurSlab->Size;
-}
-
-/// DeallocateSlabs - Deallocate all memory slabs after and including this
-/// one.
-void BumpPtrAllocator::DeallocateSlabs(MemSlab *Slab) {
-  while (Slab) {
-    MemSlab *NextSlab = Slab->NextPtr;
-#ifndef NDEBUG
-    // Poison the memory so stale pointers crash sooner.  Note we must
-    // preserve the Size and NextPtr fields at the beginning.
-    memset(Slab + 1, 0xCD, Slab->Size - sizeof(MemSlab));
-#endif
-    Allocator.Deallocate(Slab);
-    Slab = NextSlab;
+//===----------------------------------------------------------------------===//
+// MemRegion class implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+/// MemRegion - This is one chunk of the BumpPtrAllocator.
+class MemRegion {
+  unsigned RegionSize;
+  MemRegion *Next;
+  char *NextPtr;
+public:
+  void Init(unsigned size, unsigned Alignment, MemRegion *next) {
+    RegionSize = size;
+    Next = next;
+    NextPtr = (char*)(this+1);
+    
+    // Align NextPtr.
+    NextPtr = (char*)((intptr_t)(NextPtr+Alignment-1) &
+                      ~(intptr_t)(Alignment-1));
   }
-}
-
-/// Reset - Deallocate all but the current slab and reset the current pointer
-/// to the beginning of it, freeing all memory allocated so far.
-void BumpPtrAllocator::Reset() {
-  DeallocateSlabs(CurSlab->NextPtr);
-  CurSlab->NextPtr = 0;
-  CurPtr = (char*)(CurSlab + 1);
-  End = CurPtr + CurSlab->Size;
-}
-
-/// Allocate - Allocate space at the specified alignment.
-///
-void *BumpPtrAllocator::Allocate(size_t Size, size_t Alignment) {
-  // Keep track of how many bytes we've allocated.
-  BytesAllocated += Size;
-
-  // 0-byte alignment means 1-byte alignment.
-  if (Alignment == 0) Alignment = 1;
-
-  // Allocate the aligned space, going forwards from CurPtr.
-  char *Ptr = AlignPtr(CurPtr, Alignment);
-
-  // Check if we can hold it.
-  if (Ptr + Size < End) {
-    CurPtr = Ptr + Size;
-    return Ptr;
+  
+  const MemRegion *getNext() const { return Next; }
+  unsigned getNumBytesAllocated() const {
+    return NextPtr-(const char*)this;
   }
-
-  // If Size is really big, allocate a separate slab for it.
-  if (Size > SizeThreshold) {
-    size_t PaddedSize = Size + sizeof(MemSlab) + Alignment - 1;
-    MemSlab *NewSlab = Allocator.Allocate(PaddedSize);
-
-    // Put the new slab after the current slab, since we are not allocating
-    // into it.
-    NewSlab->NextPtr = CurSlab->NextPtr;
-    CurSlab->NextPtr = NewSlab;
-
-    Ptr = AlignPtr((char*)(NewSlab + 1), Alignment);
-    assert((uintptr_t)Ptr + Size < (uintptr_t)NewSlab + NewSlab->Size);
-    return Ptr;
+  
+  /// Allocate - Allocate and return at least the specified number of bytes.
+  ///
+  void *Allocate(size_t AllocSize, size_t Alignment, MemRegion **RegPtr) {
+    
+    char* Result = (char*) (((uintptr_t) (NextPtr+Alignment-1)) 
+                            & ~((uintptr_t) Alignment-1));
+
+    // Speculate the new value of NextPtr.
+    char* NextPtrTmp = Result + AllocSize;
+    
+    // If we are still within the current region, return Result.
+    if (unsigned (NextPtrTmp - (char*) this) <= RegionSize) {
+      NextPtr = NextPtrTmp;
+      return Result;
+    }
+    
+    // Otherwise, we have to allocate a new chunk.  Create one twice as big as
+    // this one.
+    MemRegion *NewRegion = (MemRegion *)malloc(RegionSize*2);
+    NewRegion->Init(RegionSize*2, Alignment, this);
+
+    // Update the current "first region" pointer  to point to the new region.
+    *RegPtr = NewRegion;
+    
+    // Try allocating from it now.
+    return NewRegion->Allocate(AllocSize, Alignment, RegPtr);
   }
-
-  // Otherwise, start a new slab and try again.
-  StartNewSlab();
-  Ptr = AlignPtr(CurPtr, Alignment);
-  CurPtr = Ptr + Size;
-  assert(CurPtr < End && "Unable to allocate memory!");
-  return Ptr;
-}
-
-unsigned BumpPtrAllocator::GetNumSlabs() const {
-  unsigned NumSlabs = 0;
-  for (MemSlab *Slab = CurSlab; Slab != 0; Slab = Slab->NextPtr) {
-    ++NumSlabs;
+  
+  /// Deallocate - Recursively release all memory for this and its next regions
+  /// to the system.
+  void Deallocate() {
+    MemRegion *next = Next;
+    free(this);
+    if (next)
+      next->Deallocate();
   }
-  return NumSlabs;
-}
 
-void BumpPtrAllocator::PrintStats() const {
-  unsigned NumSlabs = 0;
-  size_t TotalMemory = 0;
-  for (MemSlab *Slab = CurSlab; Slab != 0; Slab = Slab->NextPtr) {
-    TotalMemory += Slab->Size;
-    ++NumSlabs;
+  /// DeallocateAllButLast - Recursively release all memory for this and its
+  /// next regions to the system stopping at the last region in the list.
+  /// Returns the pointer to the last region.
+  MemRegion *DeallocateAllButLast() {
+    MemRegion *next = Next;
+    if (!next)
+      return this;
+    free(this);
+    return next->DeallocateAllButLast();
   }
-
-  cerr << "\nNumber of memory regions: " << NumSlabs << '\n'
-       << "Bytes used: " << BytesAllocated << '\n'
-       << "Bytes allocated: " << TotalMemory << '\n'
-       << "Bytes wasted: " << (TotalMemory - BytesAllocated)
-       << " (includes alignment, etc)\n";
+};
 }
 
-MallocSlabAllocator BumpPtrAllocator::DefaultSlabAllocator =
-  MallocSlabAllocator();
-
-SlabAllocator::~SlabAllocator() { }
+//===----------------------------------------------------------------------===//
+// BumpPtrAllocator class implementation
+//===----------------------------------------------------------------------===//
 
-MallocSlabAllocator::~MallocSlabAllocator() { }
+BumpPtrAllocator::BumpPtrAllocator() {
+  TheMemory = malloc(4096);
+  ((MemRegion*)TheMemory)->Init(4096, 1, 0);
+}
 
-MemSlab *MallocSlabAllocator::Allocate(size_t Size) {
-  MemSlab *Slab = (MemSlab*)Allocator.Allocate(Size, 0);
-  Slab->Size = Size;
-  Slab->NextPtr = 0;
-  return Slab;
+BumpPtrAllocator::~BumpPtrAllocator() {
+  ((MemRegion*)TheMemory)->Deallocate();
 }
 
-void MallocSlabAllocator::Deallocate(MemSlab *Slab) {
-  Allocator.Deallocate(Slab);
+void BumpPtrAllocator::Reset() {
+  MemRegion *MRP = (MemRegion*)TheMemory;
+  MRP = MRP->DeallocateAllButLast();
+  MRP->Init(4096, 1, 0);
+  TheMemory = MRP;
 }
 
-void PrintRecyclerStats(size_t Size,
-                        size_t Align,
-                        size_t FreeListSize) {
-  cerr << "Recycler element size: " << Size << '\n'
-       << "Recycler element alignment: " << Align << '\n'
-       << "Number of elements free for recycling: " << FreeListSize << '\n';
+void *BumpPtrAllocator::Allocate(size_t Size, size_t Align) {
+  MemRegion *MRP = (MemRegion*)TheMemory;
+  void *Ptr = MRP->Allocate(Size, Align, &MRP);
+  TheMemory = MRP;
+  return Ptr;
 }
 
+void BumpPtrAllocator::PrintStats() const {
+  unsigned BytesUsed = 0;
+  unsigned NumRegions = 0;
+  const MemRegion *R = (MemRegion*)TheMemory;
+  for (; R; R = R->getNext(), ++NumRegions)
+    BytesUsed += R->getNumBytesAllocated();
+
+  cerr << "\nNumber of memory regions: " << NumRegions << "\n";
+  cerr << "Bytes allocated: " << BytesUsed << "\n";
+}
+
+void llvm::PrintRecyclerStats(size_t Size,
+                              size_t Align,
+                              size_t FreeListSize) {
+  cerr << "Recycler element size: " << Size << '\n';
+  cerr << "Recycler element alignment: " << Align << '\n';
+  cerr << "Number of elements free for recycling: " << FreeListSize << '\n';
 }

Modified: llvm/trunk/lib/System/Unix/Memory.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/System/Unix/Memory.inc?rev=76838&r1=76837&r2=76838&view=diff

==============================================================================
--- llvm/trunk/lib/System/Unix/Memory.inc (original)
+++ llvm/trunk/lib/System/Unix/Memory.inc Wed Jul 22 20:40:54 2009
@@ -12,7 +12,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "Unix.h"
-#include "llvm/Support/DataTypes.h"
 #include "llvm/System/Process.h"
 
 #ifdef HAVE_SYS_MMAN_H
@@ -29,12 +28,12 @@
 /// is very OS specific.
 ///
 llvm::sys::MemoryBlock 
-llvm::sys::Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock,
+llvm::sys::Memory::AllocateRWX(unsigned NumBytes, const MemoryBlock* NearBlock,
                                std::string *ErrMsg) {
   if (NumBytes == 0) return MemoryBlock();
 
-  size_t pageSize = Process::GetPageSize();
-  size_t NumPages = (NumBytes+pageSize-1)/pageSize;
+  unsigned pageSize = Process::GetPageSize();
+  unsigned NumPages = (NumBytes+pageSize-1)/pageSize;
 
   int fd = -1;
 #ifdef NEED_DEV_ZERO_FOR_MMAP

Modified: llvm/trunk/lib/System/Win32/Memory.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/System/Win32/Memory.inc?rev=76838&r1=76837&r2=76838&view=diff

==============================================================================
--- llvm/trunk/lib/System/Win32/Memory.inc (original)
+++ llvm/trunk/lib/System/Win32/Memory.inc Wed Jul 22 20:40:54 2009
@@ -13,7 +13,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "Win32.h"
-#include "llvm/Support/DataTypes.h"
 #include "llvm/System/Process.h"
 
 namespace llvm {
@@ -24,13 +23,13 @@
 //===          and must not be UNIX code
 //===----------------------------------------------------------------------===//
 
-MemoryBlock Memory::AllocateRWX(size_t NumBytes,
+MemoryBlock Memory::AllocateRWX(unsigned NumBytes,
                                 const MemoryBlock *NearBlock,
                                 std::string *ErrMsg) {
   if (NumBytes == 0) return MemoryBlock();
 
-  static const size_t pageSize = Process::GetPageSize();
-  size_t NumPages = (NumBytes+pageSize-1)/pageSize;
+  static const long pageSize = Process::GetPageSize();
+  unsigned NumPages = (NumBytes+pageSize-1)/pageSize;
 
   //FIXME: support NearBlock if ever needed on Win64.
 

Modified: llvm/trunk/tools/lli/lli.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/lli.cpp?rev=76838&r1=76837&r2=76838&view=diff

==============================================================================
--- llvm/trunk/tools/lli/lli.cpp (original)
+++ llvm/trunk/tools/lli/lli.cpp Wed Jul 22 20:40:54 2009
@@ -136,6 +136,9 @@
   builder.setEngineKind(ForceInterpreter
                         ? EngineKind::Interpreter
                         : EngineKind::JIT);
+  // FIXME: Don't allocate GVs with code once the JIT because smarter about
+  // memory management.
+  builder.setAllocateGVsWithCode(true);
 
   // If we are supposed to override the target triple, do so now.
   if (!TargetTriple.empty())

Modified: llvm/trunk/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp?rev=76838&r1=76837&r2=76838&view=diff

==============================================================================
--- llvm/trunk/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp (original)
+++ llvm/trunk/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp Wed Jul 22 20:40:54 2009
@@ -1,276 +0,0 @@
-//===- JITMemoryManagerTest.cpp - Unit tests for the JIT memory manager ---===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ExecutionEngine/JITMemoryManager.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Function.h"
-#include "llvm/GlobalValue.h"
-
-using namespace llvm;
-
-namespace {
-
-Function *makeFakeFunction() {
-  std::vector<const Type*> params;
-  const FunctionType *FTy = FunctionType::get(Type::VoidTy, params, false);
-  return Function::Create(FTy, GlobalValue::ExternalLinkage);
-}
-
-// Allocate three simple functions that fit in the initial slab.  This exercises
-// the code in the case that we don't have to allocate more memory to store the
-// function bodies.
-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);
-  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);
-  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);
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-
-  // Deallocate them out of order, in case that matters.
-  MemMgr->deallocateMemForFunction(F2.get());
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F1.get());
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F3.get());
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-}
-
-// Make three large functions that take up most of the space in the slab.  Then
-// try allocating three smaller functions that don't require additional slabs.
-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.
-  const uintptr_t smallFuncSize = 1024;
-  const uintptr_t bigFuncSize = (MemMgr->GetDefaultCodeSlabSize() -
-                                 smallFuncSize * 2);
-
-  // Allocate big functions
-  OwningPtr<Function> F1(makeFakeFunction());
-  size = bigFuncSize;
-  start = MemMgr->startFunctionBody(F1.get(), size);
-  ASSERT_LE(bigFuncSize, size);
-  memset(start, 0xFF, bigFuncSize);
-  MemMgr->endFunctionBody(F1.get(), start, start + bigFuncSize);
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-
-  OwningPtr<Function> F2(makeFakeFunction());
-  size = bigFuncSize;
-  start = MemMgr->startFunctionBody(F2.get(), size);
-  ASSERT_LE(bigFuncSize, size);
-  memset(start, 0xFF, bigFuncSize);
-  MemMgr->endFunctionBody(F2.get(), start, start + bigFuncSize);
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-
-  OwningPtr<Function> F3(makeFakeFunction());
-  size = bigFuncSize;
-  start = MemMgr->startFunctionBody(F3.get(), size);
-  ASSERT_LE(bigFuncSize, size);
-  memset(start, 0xFF, bigFuncSize);
-  MemMgr->endFunctionBody(F3.get(), start, start + bigFuncSize);
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-
-  // Check that each large function took it's own slab.
-  EXPECT_EQ(3U, MemMgr->GetNumCodeSlabs());
-
-  // Allocate small functions
-  OwningPtr<Function> F4(makeFakeFunction());
-  size = smallFuncSize;
-  start = MemMgr->startFunctionBody(F4.get(), size);
-  ASSERT_LE(smallFuncSize, size);
-  memset(start, 0xFF, smallFuncSize);
-  MemMgr->endFunctionBody(F4.get(), start, start + smallFuncSize);
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-
-  OwningPtr<Function> F5(makeFakeFunction());
-  size = smallFuncSize;
-  start = MemMgr->startFunctionBody(F5.get(), size);
-  ASSERT_LE(smallFuncSize, size);
-  memset(start, 0xFF, smallFuncSize);
-  MemMgr->endFunctionBody(F5.get(), start, start + smallFuncSize);
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-
-  OwningPtr<Function> F6(makeFakeFunction());
-  size = smallFuncSize;
-  start = MemMgr->startFunctionBody(F6.get(), size);
-  ASSERT_LE(smallFuncSize, size);
-  memset(start, 0xFF, smallFuncSize);
-  MemMgr->endFunctionBody(F6.get(), start, start + 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());
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F1.get());
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F4.get());
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F3.get());
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F5.get());
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-  MemMgr->deallocateMemForFunction(F6.get());
-  EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
-}
-
-// Allocate five global ints of varying widths and alignment, and check their
-// alignment and overlap.
-TEST(JITMemoryManagerTest, TestSmallGlobalInts) {
-  OwningPtr<JITMemoryManager> MemMgr(
-      JITMemoryManager::CreateDefaultMemManager());
-  uint8_t  *a = (uint8_t *)MemMgr->allocateGlobal(8,  0);
-  uint16_t *b = (uint16_t*)MemMgr->allocateGlobal(16, 2);
-  uint32_t *c = (uint32_t*)MemMgr->allocateGlobal(32, 4);
-  uint64_t *d = (uint64_t*)MemMgr->allocateGlobal(64, 8);
-
-  // Check the alignment.
-  EXPECT_EQ(0U, ((uintptr_t)b) & 0x1);
-  EXPECT_EQ(0U, ((uintptr_t)c) & 0x3);
-  EXPECT_EQ(0U, ((uintptr_t)d) & 0x7);
-
-  // Initialize them each one at a time and make sure they don't overlap.
-  *a = 0xff;
-  *b = 0U;
-  *c = 0U;
-  *d = 0U;
-  EXPECT_EQ(0xffU, *a);
-  EXPECT_EQ(0U, *b);
-  EXPECT_EQ(0U, *c);
-  EXPECT_EQ(0U, *d);
-  *a = 0U;
-  *b = 0xffffU;
-  EXPECT_EQ(0U, *a);
-  EXPECT_EQ(0xffffU, *b);
-  EXPECT_EQ(0U, *c);
-  EXPECT_EQ(0U, *d);
-  *b = 0U;
-  *c = 0xffffffffU;
-  EXPECT_EQ(0U, *a);
-  EXPECT_EQ(0U, *b);
-  EXPECT_EQ(0xffffffffU, *c);
-  EXPECT_EQ(0U, *d);
-  *c = 0U;
-  *d = 0xffffffffffffffffU;
-  EXPECT_EQ(0U, *a);
-  EXPECT_EQ(0U, *b);
-  EXPECT_EQ(0U, *c);
-  EXPECT_EQ(0xffffffffffffffffU, *d);
-
-  // Make sure we didn't allocate any extra slabs for this tiny amount of data.
-  EXPECT_EQ(1U, MemMgr->GetNumDataSlabs());
-}
-
-// Allocate a small global, a big global, and a third global, and make sure we
-// only use two slabs for that.
-TEST(JITMemoryManagerTest, TestLargeGlobalArray) {
-  OwningPtr<JITMemoryManager> MemMgr(
-      JITMemoryManager::CreateDefaultMemManager());
-  size_t Size = 4 * MemMgr->GetDefaultDataSlabSize();
-  uint64_t *a = (uint64_t*)MemMgr->allocateGlobal(64, 8);
-  uint8_t *g = MemMgr->allocateGlobal(Size, 8);
-  uint64_t *b = (uint64_t*)MemMgr->allocateGlobal(64, 8);
-
-  // Check the alignment.
-  EXPECT_EQ(0U, ((uintptr_t)a) & 0x7);
-  EXPECT_EQ(0U, ((uintptr_t)g) & 0x7);
-  EXPECT_EQ(0U, ((uintptr_t)b) & 0x7);
-
-  // Initialize them to make sure we don't segfault and make sure they don't
-  // overlap.
-  memset(a, 0x1, 8);
-  memset(g, 0x2, Size);
-  memset(b, 0x3, 8);
-  EXPECT_EQ(0x0101010101010101U, *a);
-  // Just check the edges.
-  EXPECT_EQ(0x02U, g[0]);
-  EXPECT_EQ(0x02U, g[Size - 1]);
-  EXPECT_EQ(0x0303030303030303U, *b);
-
-  // Check the number of slabs.
-  EXPECT_EQ(2U, MemMgr->GetNumDataSlabs());
-}
-
-// Allocate lots of medium globals so that we can test moving the bump allocator
-// to a new slab.
-TEST(JITMemoryManagerTest, TestManyGlobals) {
-  OwningPtr<JITMemoryManager> MemMgr(
-      JITMemoryManager::CreateDefaultMemManager());
-  size_t SlabSize = MemMgr->GetDefaultDataSlabSize();
-  size_t Size = 128;
-  int Iters = (SlabSize / Size) + 1;
-
-  // We should start with one slab.
-  EXPECT_EQ(1U, MemMgr->GetNumDataSlabs());
-
-  // After allocating a bunch of globals, we should have two.
-  for (int I = 0; I < Iters; ++I)
-    MemMgr->allocateGlobal(Size, 8);
-  EXPECT_EQ(2U, MemMgr->GetNumDataSlabs());
-
-  // And after much more, we should have three.
-  for (int I = 0; I < Iters; ++I)
-    MemMgr->allocateGlobal(Size, 8);
-  EXPECT_EQ(3U, MemMgr->GetNumDataSlabs());
-}
-
-// Allocate lots of function stubs so that we can test moving the stub bump
-// allocator to a new slab.
-TEST(JITMemoryManagerTest, TestManyStubs) {
-  OwningPtr<JITMemoryManager> MemMgr(
-      JITMemoryManager::CreateDefaultMemManager());
-  size_t SlabSize = MemMgr->GetDefaultStubSlabSize();
-  size_t Size = 128;
-  int Iters = (SlabSize / Size) + 1;
-
-  // We should start with one slab.
-  EXPECT_EQ(1U, MemMgr->GetNumStubSlabs());
-
-  // After allocating a bunch of stubs, we should have two.
-  for (int I = 0; I < Iters; ++I)
-    MemMgr->allocateStub(NULL, Size, 8);
-  EXPECT_EQ(2U, MemMgr->GetNumStubSlabs());
-
-  // And after much more, we should have three.
-  for (int I = 0; I < Iters; ++I)
-    MemMgr->allocateStub(NULL, Size, 8);
-  EXPECT_EQ(3U, MemMgr->GetNumStubSlabs());
-}
-
-}

Modified: llvm/trunk/unittests/Support/AllocatorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/AllocatorTest.cpp?rev=76838&r1=76837&r2=76838&view=diff

==============================================================================
--- llvm/trunk/unittests/Support/AllocatorTest.cpp (original)
+++ llvm/trunk/unittests/Support/AllocatorTest.cpp Wed Jul 22 20:40:54 2009
@@ -1,61 +0,0 @@
-//===- llvm/unittest/Support/AllocatorTest.cpp - BumpPtrAllocator tests ---===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Support/Allocator.h"
-
-#include "gtest/gtest.h"
-
-using namespace llvm;
-
-namespace {
-
-TEST(AllocatorTest, Basics) {
-  BumpPtrAllocator Alloc;
-  int *a = (int*)Alloc.Allocate(sizeof(int), 0);
-  int *b = (int*)Alloc.Allocate(sizeof(int) * 10, 0);
-  int *c = (int*)Alloc.Allocate(sizeof(int), 0);
-  *a = 1;
-  b[0] = 2;
-  b[9] = 2;
-  *c = 3;
-  EXPECT_EQ(1, *a);
-  EXPECT_EQ(2, b[0]);
-  EXPECT_EQ(2, b[9]);
-  EXPECT_EQ(3, *c);
-  EXPECT_EQ(1U, Alloc.GetNumSlabs());
-}
-
-// Allocate enough bytes to create three slabs.
-TEST(AllocatorTest, ThreeSlabs) {
-  BumpPtrAllocator Alloc(4096, 4096);
-  Alloc.Allocate(3000, 0);
-  EXPECT_EQ(1U, Alloc.GetNumSlabs());
-  Alloc.Allocate(3000, 0);
-  EXPECT_EQ(2U, Alloc.GetNumSlabs());
-  Alloc.Allocate(3000, 0);
-  EXPECT_EQ(3U, Alloc.GetNumSlabs());
-}
-
-// Allocate enough bytes to create two slabs, reset the allocator, and do it
-// again.
-TEST(AllocatorTest, TestReset) {
-  BumpPtrAllocator Alloc(4096, 4096);
-  Alloc.Allocate(3000, 0);
-  EXPECT_EQ(1U, Alloc.GetNumSlabs());
-  Alloc.Allocate(3000, 0);
-  EXPECT_EQ(2U, Alloc.GetNumSlabs());
-  Alloc.Reset();
-  EXPECT_EQ(1U, Alloc.GetNumSlabs());
-  Alloc.Allocate(3000, 0);
-  EXPECT_EQ(1U, Alloc.GetNumSlabs());
-  Alloc.Allocate(3000, 0);
-  EXPECT_EQ(2U, Alloc.GetNumSlabs());
-}
-
-}  // anonymous namespace





More information about the llvm-commits mailing list