[llvm-commits] CVS: poolalloc/runtime/PoolAllocator/PoolAllocatorChained.cpp
Chris Lattner
lattner at cs.uiuc.edu
Sun Oct 26 16:22:01 PST 2003
Changes in directory poolalloc/runtime/PoolAllocator:
PoolAllocatorChained.cpp updated: 1.12 -> 1.13
---
Log message:
Continue hard-core C++ification. Now we're pulling PoolSlab specific code
out of the pool library, into the PoolSlab class.
---
Diffs of the changes: (+223 -193)
Index: poolalloc/runtime/PoolAllocator/PoolAllocatorChained.cpp
diff -u poolalloc/runtime/PoolAllocator/PoolAllocatorChained.cpp:1.12 poolalloc/runtime/PoolAllocator/PoolAllocatorChained.cpp:1.13
--- poolalloc/runtime/PoolAllocator/PoolAllocatorChained.cpp:1.12 Sun Oct 26 15:12:42 2003
+++ poolalloc/runtime/PoolAllocator/PoolAllocatorChained.cpp Sun Oct 26 16:21:16 2003
@@ -16,42 +16,45 @@
#include <assert.h>
#include <stdlib.h>
-#undef assert
-#define assert(X)
+//#undef assert
+//#define assert(X)
-// In the current implementation, each slab in the pool has NODES_PER_SLAB nodes
-// unless the isSingleArray flag is set in which case it contains a single array
-// of size ArraySize. Small arrays (size <= NODES_PER_SLAB) are still allocated
-// in the slabs of size NODES_PER_SLAB
+//===----------------------------------------------------------------------===//
//
-static const unsigned NODES_PER_SLAB = 4096;
+// PoolSlab implementation
+//
+//===----------------------------------------------------------------------===//
+
-// PoolSlab Structure - Hold NODES_PER_SLAB objects of the current node type.
-// Invariants: FirstUnused <= UsedEnd
+// PoolSlab Structure - Hold multiple objects of the current node type.
+// Invariants: FirstUnused <= UsedEnd
//
struct PoolSlab {
+ // In the current implementation, each slab in the pool has NodesPerSlab
+ // nodes unless the isSingleArray flag is set in which case it contains a
+ // single array of size ArraySize. Small arrays (size <= NodesPerSlab) are
+ // still allocated in the slabs of size NodesPerSlab
+ //
+ static const unsigned NodesPerSlab = 4096;
+
PoolSlab *Next;
unsigned isSingleArray; // If this slab is used for exactly one array
- unsigned FirstUnused; // First empty node in slab
+ unsigned short FirstUnused; // First empty node in slab
// UsedEnd - 1 past the last allocated node in slab. 0 if slab is empty
- unsigned UsedEnd;
+ unsigned short UsedEnd;
// AllocatedBitVector - One bit is set for every node in this slab which has
// been allocated.
- unsigned char AllocatedBitVector[NODES_PER_SLAB/8];
+ unsigned char AllocatedBitVector[NodesPerSlab/8];
// StartOfAllocation - A bit is set if this is the start of an allocation,
// either a unit allocation or an array.
- unsigned char StartOfAllocation[NODES_PER_SLAB/8];
-
- // The array is allocated from the start to the end of the slab
- unsigned ArraySize; // The size of the array allocated
+ unsigned char StartOfAllocation[NodesPerSlab/8];
char Data[1]; // Buffer to hold data in this slab... VARIABLE SIZED
-
bool isNodeAllocated(unsigned NodeNum) {
return AllocatedBitVector[NodeNum >> 3] & (1 << (NodeNum & 7));
}
@@ -60,23 +63,183 @@
AllocatedBitVector[NodeNum >> 3] |= 1 << (NodeNum & 7);
}
- void markNodeFree(unsigned NodeNum) {
- AllocatedBitVector[NodeNum >> 3] &= ~(1 << (NodeNum & 7));
+ void setStartBit(unsigned NodeNum) {
+ StartOfAllocation[NodeNum >> 3] |= 1 << (NodeNum & 7);
}
+private:
bool isStartOfAllocation(unsigned NodeNum) {
return StartOfAllocation[NodeNum >> 3] & (1 << (NodeNum & 7));
}
- void setStartBit(unsigned NodeNum) {
- StartOfAllocation[NodeNum >> 3] |= 1 << (NodeNum & 7);
+ void markNodeFree(unsigned NodeNum) {
+ AllocatedBitVector[NodeNum >> 3] &= ~(1 << (NodeNum & 7));
}
void clearStartBit(unsigned NodeNum) {
StartOfAllocation[NodeNum >> 3] &= ~(1 << (NodeNum & 7));
}
+
+public:
+ // create - Create a new (empty) slab and add it to the end of the Pools list.
+ static PoolSlab *create(PoolTy *Pool);
+
+ // destroy - Release the memory for the current object.
+ void destroy() {
+ free(this);
+ }
+
+ // isEmpty - This is a quick check to see if this slab is completely empty or
+ // not.
+ bool isEmpty() const { return UsedEnd == 0; }
+
+ // allocateSingle - Allocate a single element from this pool, returning -1 if
+ // there is no space.
+ int allocateSingle();
+
+ // getElementAddress - Return the address of the specified element.
+ void *getElementAddress(unsigned ElementNum, unsigned ElementSize) {
+ return &Data[ElementNum*ElementSize];
+ }
+
+ // containsElement - Return the element number of the specified address in
+ // this slab. If the address is not in slab, return -1.
+ int containsElement(void *Ptr, unsigned ElementSize) const;
+
+ // freeElement - Free the single node, small array, or entire array indicated.
+ void freeElement(unsigned ElementIdx);
};
+
+// create - Create a new (empty) slab and add it to the end of the Pools list.
+PoolSlab *PoolSlab::create(PoolTy *Pool) {
+ PoolSlab *PS = (PoolSlab*)malloc(sizeof(PoolSlab) +
+ Pool->NodeSize*NodesPerSlab-1);
+ assert(PS && "poolalloc: Could not allocate memory!");
+
+ PS->isSingleArray = 0; // Not a single array!
+ PS->FirstUnused = 0; // Nothing allocated.
+ PS->UsedEnd = 0; // Nothing allocated.
+
+ // Add the slab to the list...
+ PS->Next = (PoolSlab*)Pool->Slabs;
+ Pool->Slabs = PS;
+ return PS;
+}
+
+// allocateSingle - Allocate a single element from this pool, returning -1 if
+// there is no space.
+int PoolSlab::allocateSingle() {
+ // If the slab is a single array, go on to the next slab. Don't allocate
+ // single nodes in a SingleArray slab.
+ if (isSingleArray) return -1;
+
+ // Check to see if there are empty entries at the end of the slab...
+ if (UsedEnd < NodesPerSlab) {
+ // Mark the returned entry used
+ markNodeAllocated(UsedEnd);
+ setStartBit(UsedEnd);
+
+ // If we are allocating out the first unused field, bump its index also
+ if (FirstUnused == UsedEnd)
+ FirstUnused++;
+
+ // Return the entry, increment UsedEnd field.
+ return UsedEnd++;
+ }
+
+ // If not, check to see if this node has a declared "FirstUnused" value that
+ // is less than the number of nodes allocated...
+ //
+ if (FirstUnused < NodesPerSlab) {
+ // Successfully allocate out the first unused node
+ unsigned Idx = FirstUnused;
+
+ markNodeAllocated(Idx);
+ setStartBit(Idx);
+
+ // Increment FirstUnused to point to the new first unused value...
+ do {
+ ++FirstUnused;
+ } while (FirstUnused < NodesPerSlab && isNodeAllocated(FirstUnused));
+
+ return Idx;
+ }
+
+ return -1;
+}
+
+// containsElement - Return the element number of the specified address in
+// this slab. If the address is not in slab, return -1.
+int PoolSlab::containsElement(void *Ptr, unsigned ElementSize) const {
+ if (&Data[0] > Ptr || &Data[ElementSize*NodesPerSlab-1] < Ptr)
+ return -1;
+
+ unsigned Index = (char*)Ptr-(char*)&Data[0];
+ assert(Index % ElementSize == 0 &&
+ "Freeing pointer into the middle of an element!");
+ Index /= ElementSize;
+ assert(Index < PoolSlab::NodesPerSlab && "Pool slab searching loop broken!");
+ return Index;
+}
+
+
+// freeElement - Free the single node, small array, or entire array indicated.
+void PoolSlab::freeElement(unsigned ElementIdx) {
+ assert(isNodeAllocated(ElementIdx) &&
+ "poolfree: Attempt to free node that is already freed\n");
+
+ // Mark this element as being free!
+ markNodeFree(ElementIdx);
+
+ // If this slab is a SingleArray, there is nothing else to do.
+ if (isSingleArray) {
+ assert(ElementIdx == 0 &&
+ "poolfree: Attempt to free middle of allocated array\n");
+ return;
+ }
+
+ // If this slab is not a SingleArray
+ assert(isStartOfAllocation(ElementIdx) &&
+ "poolfree: Attempt to free middle of allocated array\n");
+
+ // Free the first cell
+ clearStartBit(ElementIdx);
+ markNodeFree(ElementIdx);
+
+ // Free all nodes if this was a small array allocation.
+ unsigned ElementEndIdx = ElementIdx + 1;
+ while (ElementEndIdx < UsedEnd && !isStartOfAllocation(ElementEndIdx) &&
+ isNodeAllocated(ElementEndIdx)) {
+ markNodeFree(ElementEndIdx);
+ ++ElementEndIdx;
+ }
+
+ // Update the first free field if this node is below the free node line
+ if (ElementIdx < FirstUnused) FirstUnused = ElementIdx;
+
+ // If we are freeing the last element in a slab, shrink the UsedEnd marker
+ // down to the last used node.
+ if (ElementEndIdx == UsedEnd) {
+ UsedEnd = ElementIdx;
+ do {
+ --UsedEnd;
+ // FIXME, this should scan the allocated array an entire byte at a time
+ // for performance when skipping large empty blocks!
+ } while (UsedEnd && !isNodeAllocated(UsedEnd-1));
+
+ assert(FirstUnused <= UsedEnd &&
+ "FirstUnused field was out of date!");
+ }
+}
+
+
+//===----------------------------------------------------------------------===//
+//
+// Pool allocator library implementation
+//
+//===----------------------------------------------------------------------===//
+
// poolinit - Initialize a pool descriptor to empty
//
void poolinit(PoolTy *Pool, unsigned NodeSize) {
@@ -101,179 +264,57 @@
PoolSlab *PS = (PoolSlab*)Pool->Slabs;
while (PS) {
PoolSlab *Next = PS->Next;
- free(PS);
+ PS->destroy();
PS = Next;
}
}
-static void *FindSlabEntry(PoolSlab *PS, unsigned NodeSize) {
-
- // Loop through all of the slabs looking for one with an opening */
- for (; PS; PS = PS->Next) {
- // If the slab is a single array, go on to the next slab. Don't allocate
- // single nodes in a SingleArray slab.
- if (PS->isSingleArray)
- continue;
-
- // Check to see if there are empty entries at the end of the slab...
- if (PS->UsedEnd < NODES_PER_SLAB) {
- // Mark the returned entry used
- PS->markNodeAllocated(PS->UsedEnd);
- PS->setStartBit(PS->UsedEnd);
-
- // If we are allocating out the first unused field, bump its index also
- if (PS->FirstUnused == (unsigned)PS->UsedEnd)
- PS->FirstUnused++;
-
- // Return the entry, increment UsedEnd field.
- return &PS->Data[0] + PS->UsedEnd++ * NodeSize;
- }
-
- // If not, check to see if this node has a declared "FirstUnused" value that
- // is less than the number of nodes allocated...
- //
- if (PS->FirstUnused < NODES_PER_SLAB) {
- // Successfully allocate out the first unused node
- unsigned Idx = PS->FirstUnused;
-
- PS->markNodeAllocated(Idx);
- PS->setStartBit(Idx);
-
- // Increment FirstUnused to point to the new first unused value...
- do {
- ++PS->FirstUnused;
- } while (PS->FirstUnused < NODES_PER_SLAB &&
- PS->isNodeAllocated(PS->FirstUnused));
-
- return &PS->Data[0] + Idx*NodeSize;
- }
- }
-
- // No empty nodes available, must grow # slabs!
- return 0;
-}
-
void *poolalloc(PoolTy *Pool) {
assert(Pool && "Null pool pointer passed in to poolalloc!\n");
unsigned NodeSize = Pool->NodeSize;
- PoolSlab *CurPoolSlab = (PoolSlab*)Pool->Slabs;
+ PoolSlab *PS = (PoolSlab*)Pool->Slabs;
// Fastpath for allocation in the common case.
- if (CurPoolSlab && !CurPoolSlab->isSingleArray &&
- CurPoolSlab->UsedEnd < NODES_PER_SLAB) {
- // Mark the returned entry used
- CurPoolSlab->markNodeAllocated(CurPoolSlab->UsedEnd);
- CurPoolSlab->setStartBit(CurPoolSlab->UsedEnd);
-
- // If we are allocating out the first unused field, bump its index also
- if (CurPoolSlab->FirstUnused == CurPoolSlab->UsedEnd)
- CurPoolSlab->FirstUnused++;
-
- // Return the entry, increment UsedEnd field.
- return &CurPoolSlab->Data[0] + CurPoolSlab->UsedEnd++ * NodeSize;
+ if (PS) {
+ int Element = PS->allocateSingle();
+ if (Element != -1)
+ return PS->getElementAddress(Element, NodeSize);
+ PS = PS->Next;
}
- if (void *Result = FindSlabEntry(CurPoolSlab, NodeSize))
- return Result;
+ // Loop through all of the slabs looking for one with an opening
+ for (; PS; PS = PS->Next) {
+ int Element = PS->allocateSingle();
+ if (Element != -1)
+ return PS->getElementAddress(Element, NodeSize);
+ }
// Otherwise we must allocate a new slab and add it to the list
- PoolSlab *PS = (PoolSlab*)malloc(sizeof(PoolSlab)+NodeSize*NODES_PER_SLAB-1);
- assert(PS && "poolalloc: Could not allocate memory!");
-
- // Initialize the slab to indicate that the first element is allocated
- PS->FirstUnused = 1;
- PS->UsedEnd = 1;
-
- // This is not a single array
- PS->isSingleArray = 0;
- PS->ArraySize = 0;
-
- PS->markNodeAllocated(0);
- PS->setStartBit(0);
-
- // Add the slab to the list...
- PS->Next = CurPoolSlab;
- Pool->Slabs = PS;
- return &PS->Data[0];
+ PoolSlab *New = PoolSlab::create(Pool);
+ int Idx = New->allocateSingle();
+ assert(Idx == 0 && "New allocation didn't return zero'th node?");
+ return New->getElementAddress(0, 0);
}
-void poolfree(PoolTy *Pool, char *Node) {
+void poolfree(PoolTy *Pool, void *Node) {
assert(Pool && "Null pool pointer passed in to poolfree!\n");
-
- // Return if this pool has size 0
unsigned NodeSize = Pool->NodeSize;
- if (NodeSize == 0)
- return;
PoolSlab *PS = (PoolSlab*)Pool->Slabs;
PoolSlab **PPS = (PoolSlab**)&Pool->Slabs;
// Search for the slab that contains this node...
- while (&PS->Data[0] > Node || &PS->Data[NodeSize*NODES_PER_SLAB-1] < Node) {
+ int Idx = PS->containsElement(Node, NodeSize);
+ for (; Idx == -1; PPS = &PS->Next, PS = PS->Next) {
assert(PS && "poolfree: node being free'd not found in allocation "
" pool specified!\n");
-
- PPS = &PS->Next;
- PS = PS->Next;
+ Idx = PS->containsElement(Node, NodeSize);
}
- // PS now points to the slab where Node is
- unsigned Idx = (Node-&PS->Data[0])/NodeSize;
- assert(Idx < NODES_PER_SLAB && "Pool slab searching loop broken!");
-
- if (PS->isSingleArray) {
-
- // If this slab is a SingleArray
- assert(Idx == 0 && "poolfree: Attempt to free middle of allocated array\n");
- assert(PS->isNodeAllocated(0) &&
- "poolfree: Attempt to free node that is already freed\n");
-
- // Mark this SingleArray slab as being free by just marking the first
- // entry as free
- PS->markNodeFree(0);
- } else {
-
- // If this slab is not a SingleArray
- assert(PS->isStartOfAllocation(Idx) &&
- "poolfree: Attempt to free middle of allocated array\n");
-
- // Free the first node
- assert(PS->isNodeAllocated(Idx) &&
- "poolfree: Attempt to free node that is already freed\n");
+ // Free the actual element now!
+ PS->freeElement(Idx);
- PS->clearStartBit(Idx);
- PS->markNodeFree(Idx);
-
- // Free all nodes
- unsigned idxiter = Idx + 1;
- while (idxiter < NODES_PER_SLAB && (!PS->isStartOfAllocation(idxiter)) &&
- (PS->isNodeAllocated(idxiter))) {
- PS->markNodeFree(idxiter);
- ++idxiter;
- }
-
- // Update the first free field if this node is below the free node line
- if (Idx < PS->FirstUnused) PS->FirstUnused = Idx;
-
- // If we are not freeing the last element in a slab...
- if (idxiter != PS->UsedEnd)
- return;
-
- // Otherwise we are freeing the last element in a slab... shrink the
- // UsedEnd marker down to last used node.
- PS->UsedEnd = Idx+1;
- do {
- --PS->UsedEnd;
- // FIXME, this should scan the allocated array an entire byte at a time
- // for performance!
- //
- } while (PS->UsedEnd && !PS->isNodeAllocated(PS->UsedEnd-1));
-
- assert(PS->FirstUnused <= PS->UsedEnd &&
- "FirstUnused field was out of date!");
- }
-
// Ok, if this slab is empty, we unlink it from the of slabs and either move
// it to the head of the list, or free it, depending on whether or not there
// is already an empty slab at the head of the list.
@@ -282,31 +323,31 @@
if (PS->isSingleArray) {
// If it is a SingleArray, just free it
*PPS = PS->Next;
- free(PS);
- } else if (PS->UsedEnd == 0) { // Empty slab?
+ PS->destroy();
+ } else if (PS->isEmpty()) { // Empty slab?
PoolSlab *HeadSlab;
*PPS = PS->Next; // Unlink from the list of slabs...
HeadSlab = (PoolSlab*)Pool->Slabs;
- if (HeadSlab && HeadSlab->UsedEnd == 0) {// List already has empty slab?
- free(PS); // Free memory for slab
+ if (HeadSlab && HeadSlab->isEmpty()) { // List already has empty slab?
+ PS->destroy(); // Free memory for slab
} else {
- PS->Next = HeadSlab; // No empty slab yet, add this
- Pool->Slabs = PS; // one to the head of the list
+ PS->Next = HeadSlab; // No empty slab yet, add this
+ Pool->Slabs = PS; // one to the head of the list
}
}
} else {
// Pool is not freeable for safety reasons
// Leave it in the list of PoolSlabs as an empty PoolSlab
if (!PS->isSingleArray)
- if (PS->UsedEnd == 0) {
+ if (PS->isEmpty()) {
PS->FirstUnused = 0;
// Do not free the pool, but move it to the head of the list if there is
// no empty slab there already
PoolSlab *HeadSlab;
HeadSlab = (PoolSlab*)Pool->Slabs;
- if (HeadSlab && HeadSlab->UsedEnd != 0) {
+ if (HeadSlab && !HeadSlab->isEmpty()) {
PS->Next = HeadSlab;
Pool->Slabs = PS;
}
@@ -316,25 +357,16 @@
// The poolallocarray version of FindSlabEntry
static void *FindSlabEntryArray(PoolSlab *PS, unsigned NodeSize, unsigned Size){
+ if (Size > PoolSlab::NodesPerSlab) return 0;
+
// Loop through all of the slabs looking for one with an opening
for (; PS; PS = PS->Next) {
-
- // For large array allocation
- if (Size > NODES_PER_SLAB) {
- // If this slab is a SingleArray that is free with size > Size, use it
- if (PS->isSingleArray && !PS->isNodeAllocated(0) &&PS->ArraySize >= Size){
- // Allocate the array in this slab
- // In a single array, only the first node needs to be marked
- PS->markNodeAllocated(0);
- return &PS->Data[0];
- } else
- continue;
- } else if (PS->isSingleArray)
+ if (PS->isSingleArray)
continue; // Do not allocate small arrays in SingleArray slabs
// For small array allocation, check to see if there are empty entries at
// the end of the slab...
- if (PS->UsedEnd-1 < NODES_PER_SLAB-Size) {
+ if (PS->UsedEnd-1 < PoolSlab::NodesPerSlab-Size) {
// Mark the returned entry used and set the start bit
PS->setStartBit(PS->UsedEnd);
for (unsigned i = PS->UsedEnd; i < PS->UsedEnd + Size; ++i)
@@ -354,7 +386,7 @@
// If not, check to see if this node has a declared "FirstUnused" value
// starting which Size nodes can be allocated
//
- if (PS->FirstUnused < NODES_PER_SLAB - Size + 1 &&
+ if (PS->FirstUnused < PoolSlab::NodesPerSlab - Size + 1 &&
(PS->UsedEnd < PS->FirstUnused+1 ||
PS->UsedEnd - PS->FirstUnused >= Size+1)) {
unsigned Idx = PS->FirstUnused, foundArray;
@@ -372,7 +404,7 @@
PS->markNodeAllocated(i);
PS->FirstUnused += Size;
- while (PS->FirstUnused < NODES_PER_SLAB &&
+ while (PS->FirstUnused < PoolSlab::NodesPerSlab &&
PS->isNodeAllocated(PS->FirstUnused)) {
++PS->FirstUnused;
}
@@ -400,15 +432,14 @@
return Result;
// Otherwise we must allocate a new slab and add it to the list
- if (Size > NODES_PER_SLAB) {
+ if (Size > PoolSlab::NodesPerSlab) {
// Allocate a new slab of size Size
PS = (PoolSlab*)malloc(sizeof(PoolSlab)+NodeSize*Size-1);
assert(PS && "poolallocarray: Could not allocate memory!\n");
PS->isSingleArray = 1;
- PS->ArraySize = Size;
PS->markNodeAllocated(0);
} else {
- PS = (PoolSlab*)malloc(sizeof(PoolSlab)+NodeSize*NODES_PER_SLAB-1);
+ PS = (PoolSlab*)malloc(sizeof(PoolSlab)+NodeSize*PoolSlab::NodesPerSlab-1);
assert(PS && "poolallocarray: Could not allocate memory!\n");
// Initialize the slab to indicate that the first element is allocated
@@ -416,7 +447,6 @@
PS->UsedEnd = Size;
PS->isSingleArray = 0;
- PS->ArraySize = 0;
PS->setStartBit(0);
for (unsigned i = 0; i != Size; ++i)
More information about the llvm-commits
mailing list