| //===- PoolAllocatorBitMask.cpp - Implementation of poolallocator runtime -===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file was developed by the LLVM research group and is distributed under |
| // the University of Illinois Open Source License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file is one possible implementation of the LLVM pool allocator runtime |
| // library. |
| // |
| // This uses the 'Ptr1' field to maintain a linked list of slabs that are either |
| // empty or are partially allocated from. The 'Ptr2' field of the PoolTy is |
| // used to track a linked list of slabs which are full, ie, all elements have |
| // been allocated from them. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "PoolAllocator.h" |
| #include "PageManager.h" |
| #include <assert.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| |
| //===----------------------------------------------------------------------===// |
| // |
| // PoolSlab implementation |
| // |
| //===----------------------------------------------------------------------===// |
| |
| |
| // PoolSlab Structure - Hold multiple objects of the current node type. |
| // Invariants: FirstUnused <= UsedEnd |
| // |
| struct PoolSlab { |
| PoolSlab **PrevPtr, *Next; |
| bool isSingleArray; // If this slab is used for exactly one array |
| |
| private: |
| // FirstUnused - First empty node in slab |
| unsigned short FirstUnused; |
| |
| // UsedBegin - The first node in the slab that is used. |
| unsigned short UsedBegin; |
| |
| // UsedEnd - 1 past the last allocated node in slab. 0 if slab is empty |
| unsigned short UsedEnd; |
| |
| // NumNodesInSlab - This contains the number of nodes in this slab, which |
| // effects the size of the NodeFlags vector, and indicates the number of nodes |
| // which are in the slab. |
| unsigned short NumNodesInSlab; |
| |
| // NodeFlagsVector - This array contains two bits for each node in this pool |
| // slab. The first (low address) bit indicates whether this node has been |
| // allocated, and the second (next higher) bit indicates whether this is the |
| // start of an allocation. |
| // |
| // This is a variable sized array, which has 2*NumNodesInSlab bits (rounded up |
| // to 4 bytes). |
| unsigned NodeFlagsVector[]; |
| |
| bool isNodeAllocated(unsigned NodeNum) { |
| return NodeFlagsVector[NodeNum/16] & (1 << (NodeNum & 15)); |
| } |
| |
| void markNodeAllocated(unsigned NodeNum) { |
| NodeFlagsVector[NodeNum/16] |= 1 << (NodeNum & 15); |
| } |
| |
| void markNodeFree(unsigned NodeNum) { |
| NodeFlagsVector[NodeNum/16] &= ~(1 << (NodeNum & 15)); |
| } |
| |
| void setStartBit(unsigned NodeNum) { |
| NodeFlagsVector[NodeNum/16] |= 1 << ((NodeNum & 15)+16); |
| } |
| |
| bool isStartOfAllocation(unsigned NodeNum) { |
| return NodeFlagsVector[NodeNum/16] & (1 << ((NodeNum & 15)+16)); |
| } |
| |
| void clearStartBit(unsigned NodeNum) { |
| NodeFlagsVector[NodeNum/16] &= ~(1 << ((NodeNum & 15)+16)); |
| } |
| |
| public: |
| // create - Create a new (empty) slab and add it to the end of the Pools list. |
| static PoolSlab *create(PoolTy *Pool); |
| |
| // createSingleArray - Create a slab for a large singlearray with NumNodes |
| // entries in it, returning the pointer into the pool directly. |
| static void *createSingleArray(PoolTy *Pool, unsigned NumNodes); |
| |
| // getSlabSize - Return the number of nodes that each slab should contain. |
| static unsigned getSlabSize(PoolTy *Pool) { |
| // We need space for the header... |
| unsigned NumNodes = PageSize-sizeof(PoolSlab); |
| |
| // We need space for the NodeFlags... |
| unsigned NodeFlagsBytes = NumNodes/Pool->NodeSize * 2 / 8; |
| NumNodes -= (NodeFlagsBytes+3) & ~3; // Round up to int boundaries. |
| |
| // Divide the remainder among the nodes! |
| return NumNodes / Pool->NodeSize; |
| } |
| |
| void addToList(PoolSlab **PrevPtrPtr) { |
| PoolSlab *InsertBefore = *PrevPtrPtr; |
| *PrevPtrPtr = this; |
| PrevPtr = PrevPtrPtr; |
| Next = InsertBefore; |
| if (InsertBefore) InsertBefore->PrevPtr = &Next; |
| } |
| |
| void unlinkFromList() { |
| *PrevPtr = Next; |
| if (Next) Next->PrevPtr = PrevPtr; |
| } |
| |
| unsigned getSlabSize() const { |
| return NumNodesInSlab; |
| } |
| |
| // destroy - Release the memory for the current object. |
| void destroy(); |
| |
| // isEmpty - This is a quick check to see if this slab is completely empty or |
| // not. |
| bool isEmpty() const { return UsedEnd == 0; } |
| |
| // isFull - This is a quick check to see if the slab is completely allocated. |
| // |
| bool isFull() const { return isSingleArray || FirstUnused == getSlabSize(); } |
| |
| // allocateSingle - Allocate a single element from this pool, returning -1 if |
| // there is no space. |
| int allocateSingle(); |
| |
| // allocateMultiple - Allocate multiple contiguous elements from this pool, |
| // returning -1 if there is no space. |
| int allocateMultiple(unsigned Num); |
| |
| // getElementAddress - Return the address of the specified element. |
| void *getElementAddress(unsigned ElementNum, unsigned ElementSize) { |
| char *Data = (char*)&NodeFlagsVector[((unsigned)NumNodesInSlab+15)/16]; |
| return &Data[ElementNum*ElementSize]; |
| } |
| const void *getElementAddress(unsigned ElementNum, unsigned ElementSize)const{ |
| const char *Data = |
| (const char *)&NodeFlagsVector[(unsigned)(NumNodesInSlab+15)/16]; |
| 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 short ElementIdx); |
| |
| // lastNodeAllocated - Return one past the last node in the pool which is |
| // before ScanIdx, that is allocated. If there are no allocated nodes in this |
| // slab before ScanIdx, return 0. |
| unsigned lastNodeAllocated(unsigned ScanIdx); |
| }; |
| |
| // create - Create a new (empty) slab and add it to the end of the Pools list. |
| PoolSlab *PoolSlab::create(PoolTy *Pool) { |
| unsigned NodesPerSlab = getSlabSize(Pool); |
| |
| unsigned Size = sizeof(PoolSlab) + 4*((NodesPerSlab+15)/16) + |
| Pool->NodeSize*getSlabSize(Pool); |
| assert(Size <= PageSize && "Trying to allocate a slab larger than a page!"); |
| PoolSlab *PS = (PoolSlab*)AllocatePage(); |
| |
| PS->NumNodesInSlab = NodesPerSlab; |
| PS->isSingleArray = 0; // Not a single array! |
| PS->FirstUnused = 0; // Nothing allocated. |
| PS->UsedBegin = 0; // Nothing allocated. |
| PS->UsedEnd = 0; // Nothing allocated. |
| |
| // Add the slab to the list... |
| PS->addToList((PoolSlab**)&Pool->Ptr1); |
| return PS; |
| } |
| |
| void *PoolSlab::createSingleArray(PoolTy *Pool, unsigned NumNodes) { |
| // FIXME: This wastes memory by allocating space for the NodeFlagsVector |
| unsigned NodesPerSlab = getSlabSize(Pool); |
| assert(NumNodes > NodesPerSlab && "No need to create a single array!"); |
| |
| unsigned NumPages = (NumNodes+NodesPerSlab-1)/NodesPerSlab; |
| PoolSlab *PS = (PoolSlab*)AllocateNPages(NumPages); |
| assert(PS && "poolalloc: Could not allocate memory!"); |
| |
| PS->addToList((PoolSlab**)&Pool->Ptr2); |
| |
| PS->isSingleArray = 1; // Not a single array! |
| *(unsigned*)&PS->FirstUnused = NumPages; |
| return PS->getElementAddress(0, 0); |
| } |
| |
| void PoolSlab::destroy() { |
| if (isSingleArray) |
| for (unsigned NumPages = *(unsigned*)&FirstUnused; NumPages != 1;--NumPages) |
| FreePage((char*)this + (NumPages-1)*PageSize); |
| |
| FreePage(this); |
| } |
| |
| // 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; |
| |
| unsigned SlabSize = getSlabSize(); |
| |
| // Check to see if there are empty entries at the end of the slab... |
| if (UsedEnd < SlabSize) { |
| // Mark the returned entry used |
| unsigned short UE = UsedEnd; |
| markNodeAllocated(UE); |
| setStartBit(UE); |
| |
| // If we are allocating out the first unused field, bump its index also |
| if (FirstUnused == UE) |
| 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 < SlabSize) { |
| // Successfully allocate out the first unused node |
| unsigned Idx = FirstUnused; |
| markNodeAllocated(Idx); |
| setStartBit(Idx); |
| |
| // Increment FirstUnused to point to the new first unused value... |
| // FIXME: this should be optimized |
| unsigned short FU = FirstUnused; |
| do { |
| ++FU; |
| } while (FU != SlabSize && isNodeAllocated(FU)); |
| FirstUnused = FU; |
| |
| return Idx; |
| } |
| |
| return -1; |
| } |
| |
| // allocateMultiple - Allocate multiple contiguous elements from this pool, |
| // returning -1 if there is no space. |
| int PoolSlab::allocateMultiple(unsigned Size) { |
| // Do not allocate small arrays in SingleArray slabs |
| if (isSingleArray) return -1; |
| |
| // For small array allocation, check to see if there are empty entries at the |
| // end of the slab... |
| if (UsedEnd+Size <= getSlabSize()) { |
| // Mark the returned entry used and set the start bit |
| unsigned UE = UsedEnd; |
| setStartBit(UE); |
| for (unsigned i = UE; i != UE+Size; ++i) |
| markNodeAllocated(i); |
| |
| // If we are allocating out the first unused field, bump its index also |
| if (FirstUnused == UE) |
| FirstUnused += Size; |
| |
| // Increment UsedEnd |
| UsedEnd += Size; |
| |
| // Return the entry |
| return UE; |
| } |
| |
| // If not, check to see if this node has a declared "FirstUnused" value |
| // starting which Size nodes can be allocated |
| // |
| unsigned Idx = FirstUnused; |
| while (Idx+Size <= getSlabSize()) { |
| assert(!isNodeAllocated(Idx) && "FirstUsed is not accurate!"); |
| |
| // Check if there is a continuous array of Size nodes starting FirstUnused |
| unsigned LastUnused = Idx+1; |
| for (; LastUnused != Idx+Size && !isNodeAllocated(LastUnused); ++LastUnused) |
| /*empty*/; |
| |
| // If we found an unused section of this pool which is large enough, USE IT! |
| if (LastUnused == Idx+Size) { |
| setStartBit(Idx); |
| // FIXME: this loop can be made more efficient! |
| for (unsigned i = Idx; i != Idx + Size; ++i) |
| markNodeAllocated(i); |
| |
| // This should not be allocating on the end of the pool, so we don't need |
| // to bump the UsedEnd pointer. |
| assert(Idx != UsedEnd && "Shouldn't allocate at end of pool!"); |
| |
| // If we are allocating out the first unused field, bump its index also. |
| if (Idx == FirstUnused) |
| FirstUnused += Size; |
| |
| // Return the entry |
| return Idx; |
| } |
| |
| // Otherwise, try later in the pool. Find the next unused entry. |
| Idx = LastUnused; |
| while (Idx+Size <= getSlabSize() && isNodeAllocated(Idx)) |
| ++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 { |
| const void *FirstElement = getElementAddress(0, 0); |
| if (FirstElement <= Ptr) { |
| unsigned Delta = (char*)Ptr-(char*)FirstElement; |
| unsigned Index = Delta/ElementSize; |
| if (Index < getSlabSize()) { |
| assert(Delta % ElementSize == 0 && |
| "Freeing pointer into the middle of an element!"); |
| return Index; |
| } |
| } |
| return -1; |
| } |
| |
| |
| // freeElement - Free the single node, small array, or entire array indicated. |
| void PoolSlab::freeElement(unsigned short ElementIdx) { |
| assert(isNodeAllocated(ElementIdx) && |
| "poolfree: Attempt to free node that is already freed\n"); |
| assert(!isSingleArray && "Cannot free an element from a single array!"); |
| |
| // Mark this element as being free! |
| markNodeFree(ElementIdx); |
| |
| // 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 short ElementEndIdx = ElementIdx + 1; |
| |
| // FIXME: This should use manual strength reduction to produce decent code. |
| unsigned short UE = UsedEnd; |
| while (ElementEndIdx != UE && |
| !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; |
| |
| // Update the first used field if this node was the first used. |
| if (ElementIdx == UsedBegin) UsedBegin = ElementEndIdx; |
| |
| // If we are freeing the last element in a slab, shrink the UsedEnd marker |
| // down to the last used node. |
| if (ElementEndIdx == UE) { |
| #if 0 |
| printf("FU: %d, UB: %d, UE: %d FREED: [%d-%d)", |
| FirstUnused, UsedBegin, UsedEnd, ElementIdx, ElementEndIdx); |
| #endif |
| |
| // If the user is freeing the slab entirely in-order, it's quite possible |
| // that all nodes are free in the slab. If this is the case, simply reset |
| // our pointers. |
| if (UsedBegin == UE) { |
| //printf(": SLAB EMPTY\n"); |
| FirstUnused = 0; |
| UsedBegin = 0; |
| UsedEnd = 0; |
| } else if (FirstUnused == ElementIdx) { |
| // Freed the last node(s) in this slab. |
| FirstUnused = ElementIdx; |
| UsedEnd = ElementIdx; |
| } else { |
| UsedEnd = lastNodeAllocated(ElementIdx); |
| assert(FirstUnused <= UsedEnd && |
| "FirstUnused field was out of date!"); |
| } |
| } |
| } |
| |
| unsigned PoolSlab::lastNodeAllocated(unsigned ScanIdx) { |
| // Check the last few nodes in the current word of flags... |
| unsigned CurWord = ScanIdx/16; |
| unsigned short Flags = NodeFlagsVector[CurWord] & 0xFFFF; |
| if (Flags) { |
| // Mask off nodes above this one |
| Flags &= (1 << ((ScanIdx & 15)+1))-1; |
| if (Flags) { |
| // If there is still something in the flags vector, then there is a node |
| // allocated in this part. The goto is a hack to get the uncommonly |
| // executed code away from the common code path. |
| //printf("A: "); |
| goto ContainsAllocatedNode; |
| } |
| } |
| |
| // Ok, the top word doesn't contain anything, scan the whole flag words now. |
| --CurWord; |
| while (CurWord != ~0U) { |
| Flags = NodeFlagsVector[CurWord] & 0xFFFF; |
| if (Flags) { |
| // There must be a node allocated in this word! |
| //printf("B: "); |
| goto ContainsAllocatedNode; |
| } |
| CurWord--; |
| } |
| return 0; |
| |
| ContainsAllocatedNode: |
| // Figure out exactly which node is allocated in this word now. The node |
| // allocated is the one with the highest bit set in 'Flags'. |
| // |
| // This should use __builtin_clz to get the value, but this builtin is only |
| // available with GCC 3.4 and above. :( |
| assert(Flags && "Should have allocated node!"); |
| |
| unsigned short MSB; |
| #if GCC3_4_EVENTUALLY |
| MSB = 16 - ::__builtin_clz(Flags); |
| #else |
| for (MSB = 15; (Flags & (1U << MSB)) == 0; --MSB) |
| /*empty*/; |
| #endif |
| |
| assert((1U << MSB) & Flags); // The bit should be set |
| assert((~(1U << MSB) & Flags) < Flags);// Removing it should make flag smaller |
| ScanIdx = CurWord*16 + MSB; |
| assert(isNodeAllocated(ScanIdx)); |
| return ScanIdx; |
| } |
| |
| |
| //===----------------------------------------------------------------------===// |
| // |
| // Pool allocator library implementation |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // poolinit - Initialize a pool descriptor to empty |
| // |
| void poolinit(PoolTy *Pool, unsigned NodeSize) { |
| assert(Pool && "Null pool pointer passed into poolinit!\n"); |
| |
| // Ensure the page manager is initialized |
| InitializePageManager(); |
| |
| // We must alway return unique pointers, even if they asked for 0 bytes |
| Pool->NodeSize = NodeSize ? NodeSize : 1; |
| Pool->Ptr1 = Pool->Ptr2 = 0; |
| Pool->FreeablePool = 1; |
| } |
| |
| void poolmakeunfreeable(PoolTy *Pool) { |
| assert(Pool && "Null pool pointer passed in to poolmakeunfreeable!\n"); |
| Pool->FreeablePool = 0; |
| } |
| |
| // pooldestroy - Release all memory allocated for a pool |
| // |
| void pooldestroy(PoolTy *Pool) { |
| assert(Pool && "Null pool pointer passed in to pooldestroy!\n"); |
| |
| // Free any partially allocated slabs |
| PoolSlab *PS = (PoolSlab*)Pool->Ptr1; |
| while (PS) { |
| PoolSlab *Next = PS->Next; |
| PS->destroy(); |
| PS = Next; |
| } |
| |
| // Free the completely allocated slabs |
| PS = (PoolSlab*)Pool->Ptr2; |
| while (PS) { |
| PoolSlab *Next = PS->Next; |
| PS->destroy(); |
| PS = Next; |
| } |
| } |
| |
| |
| // poolallocarray - a helper function used to implement poolalloc, when the |
| // number of nodes to allocate is not 1. |
| static void *poolallocarray(PoolTy* Pool, unsigned Size) { |
| assert(Pool && "Null pool pointer passed into poolallocarray!\n"); |
| if (Size > PoolSlab::getSlabSize(Pool)) |
| return PoolSlab::createSingleArray(Pool, Size); |
| |
| PoolSlab *PS = (PoolSlab*)Pool->Ptr1; |
| |
| // Loop through all of the slabs looking for one with an opening |
| for (; PS; PS = PS->Next) { |
| int Element = PS->allocateMultiple(Size); |
| if (Element != -1) { |
| // We allocated an element. Check to see if this slab has been completely |
| // filled up. If so, move it to the Ptr2 list. |
| if (PS->isFull()) { |
| PS->unlinkFromList(); |
| PS->addToList((PoolSlab**)&Pool->Ptr2); |
| } |
| return PS->getElementAddress(Element, Pool->NodeSize); |
| } |
| } |
| |
| PoolSlab *New = PoolSlab::create(Pool); |
| int Idx = New->allocateMultiple(Size); |
| assert(Idx == 0 && "New allocation didn't return zero'th node?"); |
| return New->getElementAddress(0, 0); |
| } |
| |
| void *poolalloc(PoolTy *Pool, unsigned NumBytes) { |
| assert(Pool && "Null pool pointer passed in to poolalloc!\n"); |
| |
| unsigned NodeSize = Pool->NodeSize; |
| unsigned NodesToAllocate = (NumBytes+NodeSize-1)/NodeSize; |
| if (NodesToAllocate > 1) |
| return poolallocarray(Pool, NodesToAllocate); |
| |
| // Special case the most common situation, where a single node is being |
| // allocated. |
| PoolSlab *PS = (PoolSlab*)Pool->Ptr1; |
| |
| if (__builtin_expect(PS != 0, 1)) { |
| int Element = PS->allocateSingle(); |
| if (__builtin_expect(Element != -1, 1)) { |
| // We allocated an element. Check to see if this slab has been |
| // completely filled up. If so, move it to the Ptr2 list. |
| if (__builtin_expect(PS->isFull(), false)) { |
| PS->unlinkFromList(); |
| PS->addToList((PoolSlab**)&Pool->Ptr2); |
| } |
| |
| return PS->getElementAddress(Element, NodeSize); |
| } |
| |
| // Loop through all of the slabs looking for one with an opening |
| for (PS = PS->Next; PS; PS = PS->Next) { |
| int Element = PS->allocateSingle(); |
| if (Element != -1) { |
| // We allocated an element. Check to see if this slab has been |
| // completely filled up. If so, move it to the Ptr2 list. |
| if (PS->isFull()) { |
| PS->unlinkFromList(); |
| PS->addToList((PoolSlab**)&Pool->Ptr2); |
| } |
| |
| return PS->getElementAddress(Element, NodeSize); |
| } |
| } |
| } |
| |
| // Otherwise we must allocate a new slab and add it to the list |
| 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); |
| } |
| |
| |
| |
| // SearchForContainingSlab - Do a brute force search through the list of |
| // allocated slabs for the node in question. |
| // |
| static PoolSlab *SearchForContainingSlab(PoolTy *Pool, void *Node, |
| unsigned &TheIndex) { |
| PoolSlab *PS = (PoolSlab*)Pool->Ptr1; |
| unsigned NodeSize = Pool->NodeSize; |
| |
| // Search the partially allocated slab list for the slab that contains this |
| // node. |
| int Idx = -1; |
| if (PS) { // Pool->Ptr1 could be null if Ptr2 isn't |
| for (; PS; PS = PS->Next) { |
| Idx = PS->containsElement(Node, NodeSize); |
| if (Idx != -1) break; |
| } |
| } |
| |
| // If the partially allocated slab list doesn't contain it, maybe the |
| // completely allocated list does. |
| if (PS == 0) { |
| PS = (PoolSlab*)Pool->Ptr2; |
| assert(Idx == -1 && "Found node but don't have PS?"); |
| |
| while (1) { |
| assert(PS && "poolfree: node being free'd not found in allocation " |
| " pool specified!\n"); |
| Idx = PS->containsElement(Node, NodeSize); |
| if (Idx != -1) break; |
| PS = PS->Next; |
| } |
| } |
| TheIndex = Idx; |
| return PS; |
| } |
| |
| // same as above, but this is the actual run time check called from the |
| // code to check if the node belongs to the pool or not, so will be |
| // like crazy, (use a hash table ?) |
| // FIXME cannot call this for pointers in the middle of the node yet, |
| // asserts out if we do |
| void poolcheck(PoolTy *Pool, void *Node) { |
| PoolSlab *PS = (PoolSlab*)Pool->Ptr1; |
| unsigned NodeSize = Pool->NodeSize; |
| |
| // Search the partially allocated slab list for the slab that contains this |
| // node. |
| int Idx = -1; |
| if (PS) { // Pool->Ptr1 could be null if Ptr2 isn't |
| for (; PS; PS = PS->Next) { |
| Idx = PS->containsElement(Node, NodeSize); |
| if (Idx != -1) break; |
| } |
| } |
| |
| // If the partially allocated slab list doesn't contain it, maybe the |
| // completely allocated list does. |
| if (PS == 0) { |
| PS = (PoolSlab*)Pool->Ptr2; |
| while (1) { |
| assert(PS && "poolfree: node being free'd not found in allocation " |
| " pool specified!\n"); |
| Idx = PS->containsElement(Node, NodeSize); |
| if (Idx != -1) break; |
| PS = PS->Next; |
| } |
| } |
| } |
| |
| void poolfree(PoolTy *Pool, void *Node) { |
| assert(Pool && "Null pool pointer passed in to poolfree!\n"); |
| PoolSlab *PS; |
| unsigned Idx; |
| if (0) { // THIS SHOULD BE SET FOR SAFECODE! |
| unsigned TheIndex; |
| PS = SearchForContainingSlab(Pool, Node, TheIndex); |
| Idx = TheIndex; |
| } else { |
| // Since it is undefined behavior to free a node which has not been |
| // allocated, we know that the pointer coming in has to be a valid node |
| // pointer in the pool. Mask off some bits of the address to find the base |
| // of the pool. |
| assert((PageSize & PageSize-1) == 0 && "Page size is not a power of 2??"); |
| PS = (PoolSlab*)((long)Node & ~(PageSize-1)); |
| |
| if (PS->isSingleArray) { |
| PS->unlinkFromList(); |
| PS->destroy(); |
| return; |
| } |
| |
| Idx = PS->containsElement(Node, Pool->NodeSize); |
| assert((int)Idx != -1 && "Node not contained in slab??"); |
| } |
| |
| // If PS was full, it must have been in list #2. Unlink it and move it to |
| // list #1. |
| if (PS->isFull()) { |
| // Now that we found the node, we are about to free an element from it. |
| // This will make the slab no longer completely full, so we must move it to |
| // the other list! |
| PS->unlinkFromList(); // Remove it from the Ptr2 list. |
| |
| PoolSlab **InsertPosPtr = (PoolSlab**)&Pool->Ptr1; |
| |
| // If the partially full list has an empty node sitting at the front of the |
| // list, insert right after it. |
| if ((*InsertPosPtr)->isEmpty()) |
| InsertPosPtr = &(*InsertPosPtr)->Next; |
| |
| PS->addToList(InsertPosPtr); // Insert it now in the Ptr1 list. |
| } |
| |
| // Free the actual element now! |
| PS->freeElement(Idx); |
| |
| // 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. |
| // |
| if (PS->isEmpty()) { |
| PS->unlinkFromList(); // Unlink from the list of slabs... |
| |
| // If we can free this pool, check to see if there are any empty slabs at |
| // the start of this list. If so, delete the FirstSlab! |
| PoolSlab *FirstSlab = (PoolSlab*)Pool->Ptr1; |
| if (Pool->FreeablePool && FirstSlab && FirstSlab->isEmpty()) { |
| // Here we choose to delete FirstSlab instead of the pool we just freed |
| // from because the pool we just freed from is more likely to be in the |
| // processor cache. |
| FirstSlab->unlinkFromList(); |
| FirstSlab->destroy(); |
| } |
| |
| // Link our slab onto the head of the list so that allocations will find it |
| // efficiently. |
| PS->addToList((PoolSlab**)&Pool->Ptr1); |
| } |
| } |