factor/vm/heap.c

159 lines
2.9 KiB
C
Raw Normal View History

2006-09-24 22:29:52 -04:00
#include "factor.h"
void new_heap(HEAP *heap, CELL size)
{
heap->base = (CELL)(alloc_bounded_block(size)->start);
if(heap->base == 0)
fatal_error("Cannot allocate code heap",size);
heap->limit = heap->base + size;
heap->free_list = NULL;
}
INLINE void update_free_list(HEAP *heap, F_BLOCK *prev, F_BLOCK *next_free)
{
if(prev)
prev->next_free = next_free;
else
heap->free_list = next_free;
}
/* called after reading the code heap from the image file. we must build the
free list, and add a large free block from compiling.base + size to
compiling.limit. */
void build_free_list(HEAP *heap, CELL size)
{
F_BLOCK *prev = NULL;
F_BLOCK *scan = (F_BLOCK *)heap->base;
F_BLOCK *end = (F_BLOCK *)(heap->base + size);
2006-09-25 02:47:56 -04:00
while(scan && scan < end)
2006-09-24 22:29:52 -04:00
{
if(scan->status == B_FREE)
{
update_free_list(heap,prev,scan);
prev = scan;
}
2006-09-25 02:47:56 -04:00
scan = next_block(heap,scan);
2006-09-24 22:29:52 -04:00
}
if((CELL)(end + 1) <= heap->limit)
{
end->status = B_FREE;
end->next_free = NULL;
2006-09-25 02:47:56 -04:00
end->size = heap->limit - (CELL)end;
2006-09-24 22:29:52 -04:00
}
else
2006-09-25 02:47:56 -04:00
{
end = NULL;
if(prev)
prev->size = heap->limit - (CELL)prev;
}
update_free_list(heap,prev,end);
2006-09-24 22:29:52 -04:00
}
CELL heap_allot(HEAP *heap, CELL size)
{
F_BLOCK *prev = NULL;
F_BLOCK *scan = heap->free_list;
while(scan)
{
2006-09-25 02:47:56 -04:00
CELL this_size = scan->size - sizeof(F_BLOCK);
2006-09-24 22:29:52 -04:00
2006-09-25 02:47:56 -04:00
if(this_size < size)
{
prev = scan;
scan = scan->next_free;
continue;
}
2006-09-24 22:29:52 -04:00
2006-09-25 02:47:56 -04:00
/* we found a candidate block */
F_BLOCK *next_free;
2006-09-24 22:29:52 -04:00
2006-09-25 02:47:56 -04:00
if(this_size - size <= sizeof(F_BLOCK))
{
/* too small to be split */
next_free = scan->next_free;
2006-09-24 22:29:52 -04:00
}
2006-09-25 02:47:56 -04:00
else
{
/* split the block in two */
CELL new_size = size + sizeof(F_BLOCK);
F_BLOCK *split = (F_BLOCK *)((CELL)scan + new_size);
split->status = B_FREE;
split->size = scan->size - new_size;
split->next_free = scan->next_free;
scan->size = new_size;
next_free = split;
}
/* update the free list */
update_free_list(heap,prev,next_free);
/* this is our new block */
scan->status = B_ALLOCATED;
2006-09-24 22:29:52 -04:00
2006-09-25 02:47:56 -04:00
return (CELL)(scan + 1);
2006-09-24 22:29:52 -04:00
}
if(heap->base == 0)
critical_error("Code heap is full",size);
return 0; /* can't happen */
}
/* free blocks which are allocated and not marked */
void free_unmarked(HEAP *heap)
{
F_BLOCK *prev = NULL;
F_BLOCK *scan = (F_BLOCK *)heap->base;
while(scan)
{
if(scan->status == B_ALLOCATED)
{
/* merge blocks? */
2006-09-25 02:47:56 -04:00
if(next_block(heap,prev) == scan)
prev->size += scan->size;
2006-09-24 22:29:52 -04:00
else
{
scan->status = B_FREE;
update_free_list(heap,prev,scan);
prev = scan;
}
}
2006-09-25 02:47:56 -04:00
scan = next_block(heap,scan);
2006-09-24 22:29:52 -04:00
}
if(prev)
prev->next_free = NULL;
}
2006-09-26 01:08:05 -04:00
CELL heap_free_space(HEAP *heap)
{
CELL size = 0;
F_BLOCK *scan = (F_BLOCK *)heap->base;
while(scan)
{
if(scan->status == B_FREE)
size += scan->size;
scan = next_block(heap,scan);
}
return size;
}
CELL heap_size(HEAP *heap)
{
CELL start = heap->base;
F_BLOCK *scan = (F_BLOCK *)start;
while(next_block(heap,scan))
scan = next_block(heap,scan);
return (CELL)scan - (CELL)start;
}