2011-05-01 02:50:00 -04:00
|
|
|
/* picoc heap memory allocation. This is a complete (but small) memory
|
|
|
|
* allocator for embedded systems which have no memory allocator. Alternatively
|
|
|
|
* you can define USE_MALLOC_HEAP to use your system's own malloc() allocator */
|
|
|
|
|
2009-02-23 21:14:07 -05:00
|
|
|
/* stack grows up from the bottom and heap grows down from the top of heap space */
|
2011-02-17 02:11:20 -05:00
|
|
|
#include "interpreter.h"
|
2009-02-23 21:14:07 -05:00
|
|
|
|
|
|
|
#define FREELIST_BUCKETS 8 /* freelists for 4, 8, 12 ... 32 byte allocs */
|
|
|
|
#define SPLIT_MEM_THRESHOLD 16 /* don't split memory which is close in size */
|
|
|
|
|
2010-07-27 10:03:06 -04:00
|
|
|
#ifdef USE_MALLOC_STACK
|
|
|
|
static unsigned char *HeapMemory = NULL; /* stack memory since our heap is malloc()ed */
|
|
|
|
static void *HeapBottom = NULL; /* the bottom of the (downward-growing) heap */
|
|
|
|
static void *StackFrame = NULL; /* the current stack frame */
|
|
|
|
void *HeapStackTop = NULL; /* the top of the stack */
|
|
|
|
#else
|
|
|
|
# ifdef SURVEYOR_HOST
|
2009-02-28 14:32:38 -05:00
|
|
|
static unsigned char *HeapMemory = (unsigned char *)C_HEAPSTART; /* all memory - stack and heap */
|
2009-03-01 16:09:42 -05:00
|
|
|
static void *HeapBottom = (void *)C_HEAPSTART + HEAP_SIZE; /* the bottom of the (downward-growing) heap */
|
2009-04-15 06:47:51 -04:00
|
|
|
static void *StackFrame = (void *)C_HEAPSTART; /* the current stack frame */
|
2009-04-18 21:15:01 -04:00
|
|
|
void *HeapStackTop = (void *)C_HEAPSTART; /* the top of the stack */
|
2009-05-05 20:25:09 -04:00
|
|
|
void *HeapMemStart = (void *)C_HEAPSTART;
|
2010-07-27 10:03:06 -04:00
|
|
|
# else
|
2009-02-23 21:14:07 -05:00
|
|
|
static unsigned char HeapMemory[HEAP_SIZE]; /* all memory - stack and heap */
|
|
|
|
static void *HeapBottom = &HeapMemory[HEAP_SIZE]; /* the bottom of the (downward-growing) heap */
|
2009-02-28 14:26:48 -05:00
|
|
|
static void *StackFrame = &HeapMemory[0]; /* the current stack frame */
|
2009-04-15 06:47:51 -04:00
|
|
|
void *HeapStackTop = &HeapMemory[0]; /* the top of the stack */
|
2010-07-27 10:03:06 -04:00
|
|
|
# endif
|
2009-03-01 16:09:42 -05:00
|
|
|
#endif
|
2009-02-28 14:26:48 -05:00
|
|
|
|
2009-02-23 21:14:07 -05:00
|
|
|
static struct AllocNode *FreeListBucket[FREELIST_BUCKETS]; /* we keep a pool of freelist buckets to reduce fragmentation */
|
|
|
|
static struct AllocNode *FreeListBig; /* free memory which doesn't fit in a bucket */
|
|
|
|
|
2009-04-10 05:35:10 -04:00
|
|
|
#ifdef DEBUG_HEAP
|
|
|
|
void ShowBigList()
|
|
|
|
{
|
|
|
|
struct AllocNode *LPos;
|
|
|
|
|
|
|
|
printf("Heap: bottom=0x%lx 0x%lx-0x%lx, big freelist=", (long)HeapBottom, (long)&HeapMemory[0], (long)&HeapMemory[HEAP_SIZE]);
|
|
|
|
for (LPos = FreeListBig; LPos != NULL; LPos = LPos->NextFree)
|
|
|
|
printf("0x%lx:%d ", (long)LPos, LPos->Size);
|
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-02-23 21:14:07 -05:00
|
|
|
/* initialise the stack and heap storage */
|
2010-07-27 10:03:06 -04:00
|
|
|
void HeapInit(int StackOrHeapSize)
|
2009-02-23 21:14:07 -05:00
|
|
|
{
|
|
|
|
int Count;
|
2009-11-07 12:47:25 -05:00
|
|
|
int AlignOffset = 0;
|
2009-02-23 21:14:07 -05:00
|
|
|
|
2010-07-27 10:03:06 -04:00
|
|
|
#ifdef USE_MALLOC_STACK
|
|
|
|
HeapMemory = malloc(StackOrHeapSize);
|
|
|
|
#endif
|
|
|
|
|
2009-11-07 13:39:35 -05:00
|
|
|
while (((unsigned long)&HeapMemory[AlignOffset] & (sizeof(ALIGN_TYPE)-1)) != 0)
|
2009-11-07 12:47:25 -05:00
|
|
|
AlignOffset++;
|
|
|
|
|
|
|
|
StackFrame = &HeapMemory[AlignOffset];
|
|
|
|
HeapStackTop = &HeapMemory[AlignOffset];
|
2009-02-23 21:14:07 -05:00
|
|
|
*(void **)StackFrame = NULL;
|
2010-07-27 10:03:06 -04:00
|
|
|
HeapBottom = &HeapMemory[StackOrHeapSize-sizeof(ALIGN_TYPE)+AlignOffset];
|
2009-02-23 21:14:07 -05:00
|
|
|
FreeListBig = NULL;
|
|
|
|
for (Count = 0; Count < FREELIST_BUCKETS; Count++)
|
|
|
|
FreeListBucket[Count] = NULL;
|
|
|
|
}
|
|
|
|
|
2010-07-27 10:03:06 -04:00
|
|
|
void HeapCleanup()
|
|
|
|
{
|
|
|
|
#ifdef USE_MALLOC_STACK
|
|
|
|
free(HeapMemory);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2009-02-23 21:14:07 -05:00
|
|
|
/* allocate some space on the stack, in the current stack frame
|
|
|
|
* clears memory. can return NULL if out of stack space */
|
|
|
|
void *HeapAllocStack(int Size)
|
|
|
|
{
|
2009-06-02 03:50:46 -04:00
|
|
|
char *NewMem = HeapStackTop;
|
|
|
|
char *NewTop = (char *)HeapStackTop + MEM_ALIGN(Size);
|
2009-06-02 01:51:51 -04:00
|
|
|
#ifdef DEBUG_HEAP
|
2009-11-06 13:17:36 -05:00
|
|
|
printf("HeapAllocStack(%ld) at 0x%lx\n", (unsigned long)MEM_ALIGN(Size), (unsigned long)HeapStackTop);
|
2009-06-02 01:51:51 -04:00
|
|
|
#endif
|
2009-06-02 03:50:46 -04:00
|
|
|
if (NewTop > (char *)HeapBottom)
|
2009-02-23 21:14:07 -05:00
|
|
|
return NULL;
|
|
|
|
|
2009-06-02 03:50:46 -04:00
|
|
|
HeapStackTop = (void *)NewTop;
|
2009-11-08 14:23:50 -05:00
|
|
|
memset((void *)NewMem, '\0', Size);
|
2009-02-23 21:14:07 -05:00
|
|
|
return NewMem;
|
2009-01-26 03:57:32 -05:00
|
|
|
}
|
|
|
|
|
2009-06-02 01:51:51 -04:00
|
|
|
/* allocate some space on the stack, in the current stack frame */
|
|
|
|
void HeapUnpopStack(int Size)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG_HEAP
|
2009-11-06 13:17:36 -05:00
|
|
|
printf("HeapUnpopStack(%ld) at 0x%lx\n", (unsigned long)MEM_ALIGN(Size), (unsigned long)HeapStackTop);
|
2009-06-02 01:51:51 -04:00
|
|
|
#endif
|
2009-06-02 03:50:46 -04:00
|
|
|
HeapStackTop = (void *)((char *)HeapStackTop + MEM_ALIGN(Size));
|
2009-06-02 01:51:51 -04:00
|
|
|
}
|
|
|
|
|
2009-01-26 03:57:32 -05:00
|
|
|
/* free some space at the top of the stack */
|
|
|
|
int HeapPopStack(void *Addr, int Size)
|
|
|
|
{
|
|
|
|
int ToLose = MEM_ALIGN(Size);
|
2009-06-02 03:50:46 -04:00
|
|
|
if (ToLose > ((char *)HeapStackTop - (char *)&HeapMemory[0]))
|
2009-01-26 03:57:32 -05:00
|
|
|
return FALSE;
|
|
|
|
|
2009-06-02 01:51:51 -04:00
|
|
|
#ifdef DEBUG_HEAP
|
2009-11-06 13:17:36 -05:00
|
|
|
printf("HeapPopStack(0x%lx, %ld) back to 0x%lx\n", (unsigned long)Addr, (unsigned long)MEM_ALIGN(Size), (unsigned long)HeapStackTop - ToLose);
|
2009-06-02 01:51:51 -04:00
|
|
|
#endif
|
2009-06-02 03:50:46 -04:00
|
|
|
HeapStackTop = (void *)((char *)HeapStackTop - ToLose);
|
2009-11-06 17:16:12 -05:00
|
|
|
assert(Addr == NULL || HeapStackTop == Addr);
|
2009-01-26 03:57:32 -05:00
|
|
|
|
|
|
|
return TRUE;
|
2009-02-23 21:14:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* push a new stack frame on to the stack */
|
|
|
|
void HeapPushStackFrame()
|
|
|
|
{
|
|
|
|
#ifdef DEBUG_HEAP
|
2009-04-15 06:47:51 -04:00
|
|
|
printf("Adding stack frame at 0x%lx\n", (unsigned long)HeapStackTop);
|
2009-02-23 21:14:07 -05:00
|
|
|
#endif
|
2009-04-15 06:47:51 -04:00
|
|
|
*(void **)HeapStackTop = StackFrame;
|
|
|
|
StackFrame = HeapStackTop;
|
2009-11-06 17:34:12 -05:00
|
|
|
HeapStackTop = (void *)((char *)HeapStackTop + MEM_ALIGN(sizeof(ALIGN_TYPE)));
|
2009-02-23 21:14:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* pop the current stack frame, freeing all memory in the frame. can return NULL */
|
|
|
|
int HeapPopStackFrame()
|
|
|
|
{
|
|
|
|
if (*(void **)StackFrame != NULL)
|
|
|
|
{
|
2009-04-15 06:47:51 -04:00
|
|
|
HeapStackTop = StackFrame;
|
2009-02-23 21:14:07 -05:00
|
|
|
StackFrame = *(void **)StackFrame;
|
|
|
|
#ifdef DEBUG_HEAP
|
2009-04-15 06:47:51 -04:00
|
|
|
printf("Popping stack frame back to 0x%lx\n", (unsigned long)HeapStackTop);
|
2009-02-23 21:14:07 -05:00
|
|
|
#endif
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate some dynamically allocated memory. memory is cleared. can return NULL if out of memory */
|
2009-06-02 04:00:02 -04:00
|
|
|
void *HeapAllocMem(int Size)
|
2009-02-23 21:14:07 -05:00
|
|
|
{
|
2009-03-10 22:19:18 -04:00
|
|
|
#ifdef USE_MALLOC_HEAP
|
|
|
|
return calloc(Size, 1);
|
|
|
|
#else
|
2009-02-23 21:14:07 -05:00
|
|
|
struct AllocNode *NewMem = NULL;
|
|
|
|
struct AllocNode **FreeNode;
|
2009-11-06 13:08:11 -05:00
|
|
|
int AllocSize = MEM_ALIGN(Size) + MEM_ALIGN(sizeof(NewMem->Size));
|
2009-03-10 21:59:22 -04:00
|
|
|
int Bucket;
|
2009-11-06 13:15:59 -05:00
|
|
|
void *ReturnMem;
|
2009-02-01 06:31:18 -05:00
|
|
|
|
|
|
|
if (Size == 0)
|
2009-02-23 21:14:07 -05:00
|
|
|
return NULL;
|
|
|
|
|
2009-03-09 22:01:12 -04:00
|
|
|
assert(Size > 0);
|
|
|
|
|
2009-03-10 21:59:22 -04:00
|
|
|
/* make sure we have enough space for an AllocNode */
|
|
|
|
if (AllocSize < sizeof(struct AllocNode))
|
|
|
|
AllocSize = sizeof(struct AllocNode);
|
|
|
|
|
|
|
|
Bucket = AllocSize >> 2;
|
2009-02-23 21:14:07 -05:00
|
|
|
if (Bucket < FREELIST_BUCKETS && FreeListBucket[Bucket] != NULL)
|
2009-11-06 13:08:11 -05:00
|
|
|
{
|
|
|
|
/* try to allocate from a freelist bucket first */
|
2009-02-23 21:14:07 -05:00
|
|
|
#ifdef DEBUG_HEAP
|
2009-02-03 01:27:34 -05:00
|
|
|
printf("allocating %d(%d) from bucket", Size, AllocSize);
|
2009-02-03 05:39:48 -05:00
|
|
|
#endif
|
2009-02-23 21:14:07 -05:00
|
|
|
NewMem = FreeListBucket[Bucket];
|
2009-02-28 14:26:48 -05:00
|
|
|
assert((unsigned long)NewMem >= (unsigned long)&HeapMemory[0] && (unsigned char *)NewMem - &HeapMemory[0] < HEAP_SIZE);
|
2009-02-23 21:14:07 -05:00
|
|
|
FreeListBucket[Bucket] = *(struct AllocNode **)NewMem;
|
2009-02-28 14:26:48 -05:00
|
|
|
assert(FreeListBucket[Bucket] == NULL || ((unsigned long)FreeListBucket[Bucket] >= (unsigned long)&HeapMemory[0] && (unsigned char *)FreeListBucket[Bucket] - &HeapMemory[0] < HEAP_SIZE));
|
2009-02-23 21:14:07 -05:00
|
|
|
NewMem->Size = AllocSize;
|
|
|
|
}
|
|
|
|
else if (FreeListBig != NULL)
|
2009-11-06 13:08:11 -05:00
|
|
|
{
|
|
|
|
/* grab the first item from the "big" freelist we can fit in */
|
2009-02-23 21:14:07 -05:00
|
|
|
for (FreeNode = &FreeListBig; *FreeNode != NULL && (*FreeNode)->Size < AllocSize; FreeNode = &(*FreeNode)->NextFree)
|
|
|
|
{}
|
|
|
|
|
|
|
|
if (*FreeNode != NULL)
|
|
|
|
{
|
2009-02-28 14:26:48 -05:00
|
|
|
assert((unsigned long)*FreeNode >= (unsigned long)&HeapMemory[0] && (unsigned char *)*FreeNode - &HeapMemory[0] < HEAP_SIZE);
|
2009-02-03 01:27:34 -05:00
|
|
|
assert((*FreeNode)->Size < HEAP_SIZE && (*FreeNode)->Size > 0);
|
2009-11-06 13:08:11 -05:00
|
|
|
if ((*FreeNode)->Size < AllocSize + SPLIT_MEM_THRESHOLD)
|
|
|
|
{
|
|
|
|
/* close in size - reduce fragmentation by not splitting */
|
2009-02-03 05:39:48 -05:00
|
|
|
#ifdef DEBUG_HEAP
|
|
|
|
printf("allocating %d(%d) from freelist, no split (%d)", Size, AllocSize, (*FreeNode)->Size);
|
|
|
|
#endif
|
2009-02-23 21:14:07 -05:00
|
|
|
NewMem = *FreeNode;
|
2009-02-28 14:26:48 -05:00
|
|
|
assert((unsigned long)NewMem >= (unsigned long)&HeapMemory[0] && (unsigned char *)NewMem - &HeapMemory[0] < HEAP_SIZE);
|
2009-02-23 21:14:07 -05:00
|
|
|
*FreeNode = NewMem->NextFree;
|
|
|
|
}
|
|
|
|
else
|
2009-11-06 13:08:11 -05:00
|
|
|
{
|
|
|
|
/* split this big memory chunk */
|
2009-02-03 05:39:48 -05:00
|
|
|
#ifdef DEBUG_HEAP
|
2009-02-03 01:27:34 -05:00
|
|
|
printf("allocating %d(%d) from freelist, split chunk (%d)", Size, AllocSize, (*FreeNode)->Size);
|
2009-02-03 05:39:48 -05:00
|
|
|
#endif
|
2009-06-02 03:50:46 -04:00
|
|
|
NewMem = (void *)((char *)*FreeNode + (*FreeNode)->Size - AllocSize);
|
2009-02-28 14:26:48 -05:00
|
|
|
assert((unsigned long)NewMem >= (unsigned long)&HeapMemory[0] && (unsigned char *)NewMem - &HeapMemory[0] < HEAP_SIZE);
|
2009-02-23 21:14:07 -05:00
|
|
|
(*FreeNode)->Size -= AllocSize;
|
|
|
|
NewMem->Size = AllocSize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NewMem == NULL)
|
2009-11-06 13:08:11 -05:00
|
|
|
{
|
|
|
|
/* couldn't allocate from a freelist - try to increase the size of the heap area */
|
2009-02-03 05:39:48 -05:00
|
|
|
#ifdef DEBUG_HEAP
|
2009-11-06 13:17:36 -05:00
|
|
|
printf("allocating %d(%d) at bottom of heap (0x%lx-0x%lx)", Size, AllocSize, (long)((char *)HeapBottom - AllocSize), (long)HeapBottom);
|
2009-02-03 05:39:48 -05:00
|
|
|
#endif
|
2009-06-02 03:50:46 -04:00
|
|
|
if ((char *)HeapBottom - AllocSize < (char *)HeapStackTop)
|
2009-02-23 21:14:07 -05:00
|
|
|
return NULL;
|
|
|
|
|
2009-06-02 03:50:46 -04:00
|
|
|
HeapBottom = (void *)((char *)HeapBottom - AllocSize);
|
2009-02-23 21:14:07 -05:00
|
|
|
NewMem = HeapBottom;
|
|
|
|
NewMem->Size = AllocSize;
|
|
|
|
}
|
|
|
|
|
2009-11-06 13:15:59 -05:00
|
|
|
ReturnMem = (void *)((char *)NewMem + MEM_ALIGN(sizeof(NewMem->Size)));
|
|
|
|
memset(ReturnMem, '\0', AllocSize - MEM_ALIGN(sizeof(NewMem->Size)));
|
2009-02-03 05:39:48 -05:00
|
|
|
#ifdef DEBUG_HEAP
|
2009-11-06 13:15:59 -05:00
|
|
|
printf(" = %lx\n", (unsigned long)ReturnMem);
|
2009-02-03 05:39:48 -05:00
|
|
|
#endif
|
2009-11-06 13:15:59 -05:00
|
|
|
return ReturnMem;
|
2009-03-10 22:19:18 -04:00
|
|
|
#endif
|
2009-02-23 21:14:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* free some dynamically allocated memory */
|
2009-06-02 04:00:02 -04:00
|
|
|
void HeapFreeMem(void *Mem)
|
2009-02-23 21:14:07 -05:00
|
|
|
{
|
2009-03-10 22:19:18 -04:00
|
|
|
#ifdef USE_MALLOC_HEAP
|
2010-06-13 07:31:19 -04:00
|
|
|
free(Mem);
|
2009-03-10 22:19:18 -04:00
|
|
|
#else
|
2009-11-06 13:15:59 -05:00
|
|
|
struct AllocNode *MemNode = (struct AllocNode *)((char *)Mem - MEM_ALIGN(sizeof(MemNode->Size)));
|
2009-02-23 21:14:07 -05:00
|
|
|
int Bucket = MemNode->Size >> 2;
|
|
|
|
|
2009-11-06 13:17:36 -05:00
|
|
|
#ifdef DEBUG_HEAP
|
2009-11-06 17:16:12 -05:00
|
|
|
printf("HeapFreeMem(0x%lx)\n", (unsigned long)Mem);
|
2009-11-06 13:17:36 -05:00
|
|
|
#endif
|
2009-02-28 14:26:48 -05:00
|
|
|
assert((unsigned long)Mem >= (unsigned long)&HeapMemory[0] && (unsigned char *)Mem - &HeapMemory[0] < HEAP_SIZE);
|
2009-02-03 01:27:34 -05:00
|
|
|
assert(MemNode->Size < HEAP_SIZE && MemNode->Size > 0);
|
2009-02-01 06:31:18 -05:00
|
|
|
if (Mem == NULL)
|
|
|
|
return;
|
|
|
|
|
2009-01-31 22:39:16 -05:00
|
|
|
if ((void *)MemNode == HeapBottom)
|
2009-11-06 13:08:11 -05:00
|
|
|
{
|
|
|
|
/* pop it off the bottom of the heap, reducing the heap size */
|
2009-02-03 05:39:48 -05:00
|
|
|
#ifdef DEBUG_HEAP
|
2009-02-03 01:27:34 -05:00
|
|
|
printf("freeing %d from bottom of heap\n", MemNode->Size);
|
2009-02-03 05:39:48 -05:00
|
|
|
#endif
|
2009-06-02 03:50:46 -04:00
|
|
|
HeapBottom = (void *)((char *)HeapBottom + MemNode->Size);
|
2009-04-10 05:35:10 -04:00
|
|
|
#ifdef DEBUG_HEAP
|
|
|
|
ShowBigList();
|
|
|
|
#endif
|
2009-01-31 22:39:16 -05:00
|
|
|
}
|
2009-02-23 21:14:07 -05:00
|
|
|
else if (Bucket < FREELIST_BUCKETS)
|
2009-11-06 13:08:11 -05:00
|
|
|
{
|
|
|
|
/* we can fit it in a bucket */
|
2009-02-03 05:39:48 -05:00
|
|
|
#ifdef DEBUG_HEAP
|
2009-02-03 01:27:34 -05:00
|
|
|
printf("freeing %d to bucket\n", MemNode->Size);
|
2009-02-03 05:39:48 -05:00
|
|
|
#endif
|
2009-02-28 14:26:48 -05:00
|
|
|
assert(FreeListBucket[Bucket] == NULL || ((unsigned long)FreeListBucket[Bucket] >= (unsigned long)&HeapMemory[0] && (unsigned char *)FreeListBucket[Bucket] - &HeapMemory[0] < HEAP_SIZE));
|
2009-02-23 21:14:07 -05:00
|
|
|
*(struct AllocNode **)MemNode = FreeListBucket[Bucket];
|
|
|
|
FreeListBucket[Bucket] = (struct AllocNode *)MemNode;
|
|
|
|
}
|
|
|
|
else
|
2009-11-06 13:08:11 -05:00
|
|
|
{
|
|
|
|
/* put it in the big memory freelist */
|
2009-02-03 05:39:48 -05:00
|
|
|
#ifdef DEBUG_HEAP
|
2009-02-03 01:27:34 -05:00
|
|
|
printf("freeing %lx:%d to freelist\n", (unsigned long)Mem, MemNode->Size);
|
2009-02-03 05:39:48 -05:00
|
|
|
#endif
|
2009-02-28 14:26:48 -05:00
|
|
|
assert(FreeListBig == NULL || ((unsigned long)FreeListBig >= (unsigned long)&HeapMemory[0] && (unsigned char *)FreeListBig - &HeapMemory[0] < HEAP_SIZE));
|
2009-02-23 21:14:07 -05:00
|
|
|
MemNode->NextFree = FreeListBig;
|
|
|
|
FreeListBig = MemNode;
|
2009-04-10 05:35:10 -04:00
|
|
|
#ifdef DEBUG_HEAP
|
|
|
|
ShowBigList();
|
|
|
|
#endif
|
2009-02-23 21:14:07 -05:00
|
|
|
}
|
2009-03-10 22:19:18 -04:00
|
|
|
#endif
|
2009-01-23 06:34:12 -05:00
|
|
|
}
|
2009-11-06 13:08:11 -05:00
|
|
|
|