mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-31 08:16:47 +00:00 
			
		
		
		
	git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@5429 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			167 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <assert.h>
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #undef assert
 | |
| #define assert(X)
 | |
| 
 | |
| 
 | |
| #define NODES_PER_SLAB 512
 | |
| 
 | |
| typedef struct PoolTy {
 | |
|   void    *Data;
 | |
|   unsigned NodeSize;
 | |
| } PoolTy;
 | |
| 
 | |
| /* PoolSlab Structure - Hold NODES_PER_SLAB objects of the current node type.
 | |
|  *   Invariants: FirstUnused <= LastUsed+1
 | |
|  */
 | |
| typedef struct PoolSlab {
 | |
|   unsigned FirstUnused;     /* First empty node in slab    */
 | |
|   int LastUsed;             /* Last allocated node in slab */
 | |
|   struct PoolSlab *Next;
 | |
|   unsigned char AllocatedBitVector[NODES_PER_SLAB/8];
 | |
|   char Data[1];   /* Buffer to hold data in this slab... variable sized */
 | |
| } PoolSlab;
 | |
| 
 | |
| #define NODE_ALLOCATED(POOLSLAB, NODENUM) \
 | |
|    ((POOLSLAB)->AllocatedBitVector[(NODENUM) >> 3] & (1 << ((NODENUM) & 7)))
 | |
| #define MARK_NODE_ALLOCATED(POOLSLAB, NODENUM) \
 | |
|    (POOLSLAB)->AllocatedBitVector[(NODENUM) >> 3] |= 1 << ((NODENUM) & 7)
 | |
| #define MARK_NODE_FREE(POOLSLAB, NODENUM) \
 | |
|    (POOLSLAB)->AllocatedBitVector[(NODENUM) >> 3] &= ~(1 << ((NODENUM) & 7))
 | |
| 
 | |
| 
 | |
| /* poolinit - Initialize a pool descriptor to empty
 | |
|  */
 | |
| void poolinit(PoolTy *Pool, unsigned Size) {
 | |
|   assert(Pool && "Null pool pointer passed in!");
 | |
| 
 | |
|   Pool->NodeSize = Size;
 | |
|   Pool->Data = 0;
 | |
| }
 | |
| 
 | |
| /* pooldestroy - Release all memory allocated for a pool
 | |
|  */
 | |
| void pooldestroy(PoolTy *Pool) {
 | |
|   PoolSlab *PS = (PoolSlab*)Pool->Data;
 | |
|   while (PS) {
 | |
|     PoolSlab *Next = PS->Next;
 | |
|     free(PS);
 | |
|     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) {
 | |
|     /* Check to see if there are empty entries at the end of the slab... */
 | |
|     if (PS->LastUsed < NODES_PER_SLAB-1) {
 | |
|       /* Mark the returned entry used */
 | |
|       MARK_NODE_ALLOCATED(PS, PS->LastUsed+1);
 | |
| 
 | |
|       /* If we are allocating out the first unused field, bump its index also */
 | |
|       if (PS->FirstUnused == PS->LastUsed+1)
 | |
|         PS->FirstUnused++;
 | |
| 
 | |
|       /* Return the entry, increment LastUsed field. */
 | |
|       return &PS->Data[0] + ++PS->LastUsed * 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;
 | |
|       
 | |
|       /* Increment FirstUnused to point to the new first unused value... */
 | |
|       do {
 | |
|         ++PS->FirstUnused;
 | |
|       } while (PS->FirstUnused < NODES_PER_SLAB &&
 | |
|                NODE_ALLOCATED(PS, PS->FirstUnused));
 | |
| 
 | |
|       return &PS->Data[0] + Idx*NodeSize;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /* No empty nodes available, must grow # slabs! */
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| char *poolalloc(PoolTy *Pool) {
 | |
|   unsigned NodeSize = Pool->NodeSize;
 | |
|   PoolSlab *PS = (PoolSlab*)Pool->Data;
 | |
|   void *Result;
 | |
| 
 | |
|   if ((Result = FindSlabEntry(PS, NodeSize)))
 | |
|     return Result;
 | |
| 
 | |
|   /* Otherwise we must allocate a new slab and add it to the list */
 | |
|   PS = (PoolSlab*)malloc(sizeof(PoolSlab)+NodeSize*NODES_PER_SLAB-1);
 | |
| 
 | |
|   /* Initialize the slab to indicate that the first element is allocated */
 | |
|   PS->FirstUnused = 1;
 | |
|   PS->LastUsed = 0;
 | |
|   PS->AllocatedBitVector[0] = 1;
 | |
| 
 | |
|   /* Add the slab to the list... */
 | |
|   PS->Next = (PoolSlab*)Pool->Data;
 | |
|   Pool->Data = PS;
 | |
|   return &PS->Data[0];
 | |
| }
 | |
| 
 | |
| void poolfree(PoolTy *Pool, char *Node) {
 | |
|   unsigned NodeSize = Pool->NodeSize, Idx;
 | |
|   PoolSlab *PS = (PoolSlab*)Pool->Data;
 | |
|   PoolSlab **PPS = (PoolSlab**)&Pool->Data;
 | |
| 
 | |
|   /* Seach for the slab that contains this node... */
 | |
|   while (&PS->Data[0] > Node || &PS->Data[NodeSize*NODES_PER_SLAB] < Node) {
 | |
|     assert(PS && "free'd node not found in allocation pool specified!");
 | |
|     PPS = &PS->Next;
 | |
|     PS = PS->Next;
 | |
|   }
 | |
| 
 | |
|   Idx = (Node-&PS->Data[0])/NodeSize;
 | |
|   assert(Idx < NODES_PER_SLAB && "Pool slab searching loop broken!");
 | |
| 
 | |
|   /* 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 (Idx != PS->LastUsed) {
 | |
|     MARK_NODE_FREE(PS, Idx);
 | |
|     return;
 | |
|   } 
 | |
| 
 | |
|   /* Otherwise we are freeing the last element in a slab... shrink the
 | |
|    * LastUsed marker down to last used node.
 | |
|    */
 | |
|   do {
 | |
|     --PS->LastUsed;
 | |
|     /* Fixme, this should scan the allocated array an entire byte at a time for
 | |
|      * performance!
 | |
|      */
 | |
|   } while (PS->LastUsed >= 0 && (!NODE_ALLOCATED(PS, PS->LastUsed)));
 | |
|   
 | |
|   assert(PS->FirstUnused <= PS->LastUsed+1 &&
 | |
|          "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.
 | |
|    */
 | |
|   if (PS->LastUsed == -1) {   /* Empty slab? */
 | |
|     PoolSlab *HeadSlab;
 | |
|     *PPS = PS->Next;   /* Unlink from the list of slabs... */
 | |
| 
 | |
|     HeadSlab = (PoolSlab*)Pool->Data;
 | |
|     if (HeadSlab && HeadSlab->LastUsed == -1){/* List already has empty slab? */
 | |
|       free(PS);                               /* Free memory for slab */
 | |
|     } else {
 | |
|       PS->Next = HeadSlab;                    /* No empty slab yet, add this */
 | |
|       Pool->Data = PS;                        /* one to the head of the list */
 | |
|     }
 | |
|   }
 | |
| }
 |