[llvm-commits] CVS: poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp Makefile PoolAllocator.h
Chris Lattner
lattner at cs.uiuc.edu
Thu Dec 25 13:47:01 PST 2003
Changes in directory poolalloc/runtime/FL2Allocator:
FreeListAllocator.cpp added (r1.1)
Makefile added (r1.1)
PoolAllocator.h added (r1.1)
---
Log message:
initial checkin of fl2allocator for sumant
---
Diffs of the changes: (+301 -0)
Index: poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp
diff -c /dev/null poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp:1.1
*** /dev/null Thu Dec 25 13:46:30 2003
--- poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp Thu Dec 25 13:46:20 2003
***************
*** 0 ****
--- 1,218 ----
+ //===- FreeListAllocator.cpp - Simple linked-list based pool allocator ----===//
+ //
+ // 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.
+ //
+ //
+ //===----------------------------------------------------------------------===//
+
+ #include "PoolAllocator.h"
+ #include <assert.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+
+ //===----------------------------------------------------------------------===//
+ //
+ // PoolSlab implementation
+ //
+ //===----------------------------------------------------------------------===//
+
+ #define PageSize (18U*1024U)
+
+ // PoolSlab Structure - Hold multiple objects of the current node type.
+ // Invariants: FirstUnused <= UsedEnd
+ //
+ struct PoolSlab {
+ // Next - This link is used when we need to traverse the list of slabs in a
+ // pool, for example, to destroy them all.
+ PoolSlab *Next;
+
+ public:
+ static void create(PoolTy *Pool);
+ void destroy();
+
+ PoolSlab *getNext() const { return Next; }
+ };
+
+ // create - Create a new (empty) slab and add it to the end of the Pools list.
+ void PoolSlab::create(PoolTy *Pool) {
+ PoolSlab *PS = (PoolSlab*)malloc(PageSize);
+
+ // Add the body of the slab to the free list...
+ FreedNodeHeader *SlabBody = (FreedNodeHeader*)(PS+1);
+ SlabBody->Size = PageSize-sizeof(PoolSlab)-sizeof(FreedNodeHeader);
+ SlabBody->NormalHeader.Next = Pool->FreeNodeList;
+ Pool->FreeNodeList = SlabBody;
+
+ // Add the slab to the list...
+ PS->Next = Pool->Slabs;
+ Pool->Slabs = PS;
+ }
+
+ void PoolSlab::destroy() {
+ free(this);
+ }
+
+
+ //===----------------------------------------------------------------------===//
+ //
+ // Pool allocator library implementation
+ //
+ //===----------------------------------------------------------------------===//
+
+ // poolinit - Initialize a pool descriptor to empty
+ //
+ void poolinit(PoolTy *Pool) {
+ assert(Pool && "Null pool pointer passed into poolinit!\n");
+ Pool->Slabs = 0;
+ Pool->FreeNodeList = 0;
+ Pool->LargeArrays = 0;
+ }
+
+ // pooldestroy - Release all memory allocated for a pool
+ //
+ void pooldestroy(PoolTy *Pool) {
+ assert(Pool && "Null pool pointer passed in to pooldestroy!\n");
+
+ // Free all allocated slabs.
+ PoolSlab *PS = Pool->Slabs;
+ while (PS) {
+ PoolSlab *Next = PS->getNext();
+ PS->destroy();
+ PS = Next;
+ }
+
+ // Free all of the large arrays.
+ LargeArrayHeader *LAH = Pool->LargeArrays;
+ while (LAH) {
+ LargeArrayHeader *Next = LAH->Next;
+ free(LAH);
+ LAH = Next;
+ }
+ }
+
+
+ void *poolalloc(PoolTy *Pool, unsigned NumBytes) {
+ assert(Pool && "Null pool pointer passed in to poolalloc!\n");
+ if (NumBytes == 0)
+ NumBytes = 4;
+ else
+ NumBytes = (NumBytes+3) & ~3; // Round up to 4 bytes...
+
+ // Fast path. In the common case, we can allocate a portion of the node at
+ // the front of the free list.
+ if (Pool->FreeNodeList) {
+ FreedNodeHeader *FirstNode = Pool->FreeNodeList;
+ unsigned FirstNodeSize = FirstNode->Size;
+ if (FirstNodeSize > 2*NumBytes+sizeof(NodeHeader)) {
+ // Put the remainder back on the list...
+ FreedNodeHeader *NextNodes =
+ (FreedNodeHeader*)((char*)FirstNode + sizeof(NodeHeader) + NumBytes);
+ NextNodes->Size = FirstNodeSize-NumBytes-sizeof(NodeHeader);
+ NextNodes->NormalHeader.Next = FirstNode->NormalHeader.Next;
+ Pool->FreeNodeList = NextNodes;
+ FirstNode->NormalHeader.ObjectSize = NumBytes;
+ return &FirstNode->NormalHeader+1;
+ } else if (FirstNodeSize > NumBytes) {
+ Pool->FreeNodeList = FirstNode->NormalHeader.Next; // Unlink
+ FirstNode->NormalHeader.ObjectSize = FirstNodeSize;
+ return &FirstNode->NormalHeader+1;
+ }
+ }
+
+ // Perform a search of the free list, taking the front of the first free chunk
+ // that is big enough.
+ if (NumBytes <= PageSize-sizeof(PoolSlab)-sizeof(NodeHeader)) {
+ do {
+ FreedNodeHeader **FN = &Pool->FreeNodeList;
+ FreedNodeHeader *FNN = *FN;
+
+ // Search the list for the first-fit
+ while (FNN && FNN->Size < NumBytes)
+ FN = &FNN->NormalHeader.Next, FNN = *FN;
+
+ if (FNN) {
+ // We found a slab big enough. If it's a perfect fit, just unlink from
+ // the free list, otherwise, slice a little bit off and adjust the free
+ // list.
+ if (FNN->Size > 2*NumBytes+sizeof(NodeHeader)) {
+ // Put the remainder back on the list...
+ FreedNodeHeader *NextNodes =
+ (FreedNodeHeader*)((char*)FNN + sizeof(NodeHeader) + NumBytes);
+ NextNodes->Size = FNN->Size-NumBytes-sizeof(NodeHeader);
+ NextNodes->NormalHeader.Next = FNN->NormalHeader.Next;
+ *FN = NextNodes;
+ FNN->NormalHeader.ObjectSize = NumBytes;
+ return &FNN->NormalHeader+1;
+ } else {
+ *FN = FNN->NormalHeader.Next; // Unlink
+ FNN->NormalHeader.ObjectSize = FNN->Size;
+ return &FNN->NormalHeader+1;
+ }
+ }
+
+ // Oops, we didn't find anything on the free list big enough! Allocate
+ // another slab and try again.
+ PoolSlab::create(Pool);
+ } while (1);
+ }
+
+ // Otherwise, the allocation is a large array. Since we're not going to be
+ // able to help much for this allocation, simply pass it on to malloc.
+ LargeArrayHeader *LAH = (LargeArrayHeader*)malloc(sizeof(LargeArrayHeader) +
+ NumBytes);
+ LAH->Next = Pool->LargeArrays;
+ Pool->LargeArrays = LAH;
+ LAH->Prev = &Pool->LargeArrays;
+ LAH->Marker = ~0U;
+ return LAH+1;
+ }
+
+
+ void poolfree(PoolTy *Pool, void *Node) {
+ assert(Pool && "Null pool pointer passed in to poolfree!\n");
+
+ // Check to see how many elements were allocated to this node...
+ FreedNodeHeader *FNH = (FreedNodeHeader*)((char*)Node-sizeof(NodeHeader));
+ unsigned Size = FNH->NormalHeader.ObjectSize;
+ if (Size == ~0U) {
+ // Must unlink from list.
+ fprintf(stderr, "CANNOT FREE LARGE ARRAY YET!\n");
+ return;
+ }
+
+ // If there are already nodes on the freelist, see if this blocks should be
+ // coallesced into one of the early blocks on the front of the list. This is
+ // a simple check that prevents many horrible forms of fragmentation.
+ //
+ if (FreedNodeHeader *CurFrontNode = Pool->FreeNodeList) {
+ if ((char*)FNH + sizeof(NodeHeader) + Size == (char*)CurFrontNode) {
+ // This node immediately preceeds the node on the front of the
+ // free-list. Remove the current front of the free list, replacing it
+ // with the current block.
+ FNH->Size = Size + CurFrontNode->Size+sizeof(NodeHeader);
+ FNH->NormalHeader.Next = CurFrontNode->NormalHeader.Next;
+ Pool->FreeNodeList = FNH;
+ return;
+ }
+
+ if ((char*)CurFrontNode + sizeof(NodeHeader) + CurFrontNode->Size ==
+ (char*)FNH) {
+ // This node immediately follows the node on the front of the free-list.
+ // No list manipulation is required.
+ CurFrontNode->Size += Size+sizeof(NodeHeader);
+ return;
+ }
+ }
+
+ FNH->Size = Size;
+ FNH->NormalHeader.Next = Pool->FreeNodeList;
+ Pool->FreeNodeList = FNH;
+ }
Index: poolalloc/runtime/FL2Allocator/Makefile
diff -c /dev/null poolalloc/runtime/FL2Allocator/Makefile:1.1
*** /dev/null Thu Dec 25 13:46:30 2003
--- poolalloc/runtime/FL2Allocator/Makefile Thu Dec 25 13:46:20 2003
***************
*** 0 ****
--- 1,9 ----
+ LEVEL = ../..
+ BYTECODE_LIBRARY=1
+ SHARED_LIBRARY=1
+ LIBRARYNAME=poolalloc_rt
+
+ include $(LEVEL)/Makefile.common
+
+ # Always build optimized and debug versions
+ all:: $(LIBNAME_OBJO) $(LIBNAME_OBJG)
Index: poolalloc/runtime/FL2Allocator/PoolAllocator.h
diff -c /dev/null poolalloc/runtime/FL2Allocator/PoolAllocator.h:1.1
*** /dev/null Thu Dec 25 13:46:30 2003
--- poolalloc/runtime/FL2Allocator/PoolAllocator.h Thu Dec 25 13:46:20 2003
***************
*** 0 ****
--- 1,74 ----
+ //===- PoolAllocator.h - Pool allocator runtime interface file --*- C++ -*-===//
+ //
+ // 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 defines the interface which is implemented by the LLVM pool
+ // allocator runtime library.
+ //
+ //===----------------------------------------------------------------------===//
+
+ #ifndef POOLALLOCATOR_RUNTIME_H
+ #define POOLALLOCATOR_RUNTIME_H
+
+ struct PoolSlab;
+ struct FreedNodeHeader;
+
+ // NodeHeader - Each block of memory is preceeded in the the pool by one of
+ // these headers. If the node is allocated, the ObjectSize value is used, if
+ // the object is free, the 'Next' value is used.
+ union NodeHeader {
+ FreedNodeHeader *Next;
+ unsigned ObjectSize;
+ };
+
+
+ // When objects are on the free list, we pretend they have this header.
+ struct FreedNodeHeader {
+ // NormalHeader - This is the normal node header that is on allocated or free
+ // blocks.
+ NodeHeader NormalHeader;
+
+ // Size - This is stored in the actual data area, indicating how many bytes
+ // there are in the region.
+ unsigned Size;
+ };
+
+
+ // Large Arrays are passed on to directly malloc, and are not necessarily page
+ // aligned. These arrays are marked by setting the object size preheader to ~0.
+ // LargeArrays are on their own list to allow for efficient deletion.
+ struct LargeArrayHeader {
+ LargeArrayHeader **Prev, *Next;
+
+ // Marker: this is the ObjectSize marker which MUST BE THE LAST ELEMENT of
+ // this header!
+ unsigned Marker;
+ };
+
+
+ struct PoolTy {
+ // Lists - the list of slabs in this pool.
+ PoolSlab *Slabs;
+
+ // LargeArrays - A doubly linked list of large array chunks, dynamically
+ // allocated with malloc.
+ LargeArrayHeader *LargeArrays;
+
+ // The list of free'd nodes.
+ FreedNodeHeader *FreeNodeList;
+ };
+
+ extern "C" {
+ void poolinit(PoolTy *Pool);
+ void poolmakeunfreeable(PoolTy *Pool);
+ void pooldestroy(PoolTy *Pool);
+ void *poolalloc(PoolTy *Pool, unsigned NumBytes);
+ void poolfree(PoolTy *Pool, void *Node);
+ }
+
+ #endif
More information about the llvm-commits
mailing list