namespace factor { static const cell free_list_count = 32; struct free_list { free_heap_block *small_blocks[free_list_count]; free_heap_block *large_blocks; }; template struct free_list_allocator { cell start; cell size; cell end; free_list free_blocks; mark_bits state; explicit free_list_allocator(cell start, cell size); inline Block *first_block() { return (Block *)start; } inline Block *last_block() { return (Block *)end; } Block *next_block_after(heap_block *block) { return (Block *)((cell)block + block->size()); } void clear_free_list(); void add_to_free_list(free_heap_block *block); void build_free_list(cell size); void assert_free_block(free_heap_block *block); free_heap_block *find_free_block(cell size); free_heap_block *split_free_block(free_heap_block *block, cell size); Block *allot(cell size); void free(Block *block); void usage(cell *used, cell *total_free, cell *max_free); cell occupied(); template void sweep(Iterator &iter); template void compact(Iterator &iter); template void iterate(Iterator &iter) { Block *scan = first_block(); Block *end = last_block(); while(scan != end) { cell size = scan->size(); Block *next = (Block *)((cell)scan + size); if(!scan->free_p()) iter(scan,size); scan = next; } } }; template void free_list_allocator::clear_free_list() { memset(&free_blocks,0,sizeof(free_list)); } template free_list_allocator::free_list_allocator(cell start_, cell size_) : start(start_), size(size_), end(start_ + size_), state(mark_bits(start_,size_)) { clear_free_list(); } template void free_list_allocator::add_to_free_list(free_heap_block *block) { if(block->size() < free_list_count * block_granularity) { int index = block->size() / block_granularity; block->next_free = free_blocks.small_blocks[index]; free_blocks.small_blocks[index] = block; } else { block->next_free = free_blocks.large_blocks; free_blocks.large_blocks = block; } } /* Called after reading the heap from the image file, and after heap compaction. Makes a free list consisting of one free block, at the very end. */ template void free_list_allocator::build_free_list(cell size) { clear_free_list(); free_heap_block *last_block = (free_heap_block *)(start + size); last_block->set_free(); last_block->set_size(end - (cell)last_block); add_to_free_list(last_block); } template void free_list_allocator::assert_free_block(free_heap_block *block) { #ifdef FACTOR_DEBUG assert(block->free_p()); #endif } template free_heap_block *free_list_allocator::find_free_block(cell size) { cell attempt = size; while(attempt < free_list_count * block_granularity) { int index = attempt / block_granularity; free_heap_block *block = free_blocks.small_blocks[index]; if(block) { assert_free_block(block); free_blocks.small_blocks[index] = block->next_free; return block; } attempt *= 2; } free_heap_block *prev = NULL; free_heap_block *block = free_blocks.large_blocks; while(block) { assert_free_block(block); if(block->size() >= size) { if(prev) prev->next_free = block->next_free; else free_blocks.large_blocks = block->next_free; return block; } prev = block; block = block->next_free; } return NULL; } template free_heap_block *free_list_allocator::split_free_block(free_heap_block *block, cell size) { if(block->size() != size) { /* split the block in two */ free_heap_block *split = (free_heap_block *)((cell)block + size); split->set_free(); split->set_size(block->size() - size); split->next_free = block->next_free; block->set_size(size); add_to_free_list(split); } return block; } template Block *free_list_allocator::allot(cell size) { size = align(size,block_granularity); free_heap_block *block = find_free_block(size); if(block) { block = split_free_block(block,size); return (Block *)block; } else return NULL; } template void free_list_allocator::free(Block *block) { free_heap_block *free_block = (free_heap_block *)block; free_block->set_free(); add_to_free_list(free_block); } /* Compute total sum of sizes of free blocks, and size of largest free block */ template void free_list_allocator::usage(cell *used, cell *total_free, cell *max_free) { *used = 0; *total_free = 0; *max_free = 0; Block *scan = first_block(); Block *end = last_block(); while(scan != end) { cell size = scan->size(); if(scan->free_p()) { *total_free += size; if(size > *max_free) *max_free = size; } else *used += size; scan = next_block_after(scan); } } /* The size of the heap after compaction */ template cell free_list_allocator::occupied() { Block *scan = first_block(); Block *last = last_block(); while(scan != last) { if(scan->free_p()) break; else scan = next_block_after(scan); } if(scan != last) { free_heap_block *free_block = (free_heap_block *)scan; assert(free_block->free_p()); assert((cell)scan + free_block->size() == end); return (cell)scan - (cell)first_block(); } else return size; } /* After code GC, all live code blocks are marked, so any which are not marked can be reclaimed. */ template template void free_list_allocator::sweep(Iterator &iter) { this->clear_free_list(); Block *prev = NULL; Block *scan = this->first_block(); Block *end = this->last_block(); while(scan != end) { cell size = scan->size(); if(scan->free_p()) { if(prev && prev->free_p()) { free_heap_block *free_prev = (free_heap_block *)prev; free_prev->set_size(free_prev->size() + size); } else prev = scan; } else if(this->state.marked_p(scan)) { if(prev && prev->free_p()) this->add_to_free_list((free_heap_block *)prev); prev = scan; iter(scan,size); } else { if(prev && prev->free_p()) { free_heap_block *free_prev = (free_heap_block *)prev; free_prev->set_size(free_prev->size() + size); } else { scan->set_free(); prev = scan; } } scan = (Block *)((cell)scan + size); } if(prev && prev->free_p()) this->add_to_free_list((free_heap_block *)prev); } /* The forwarding map must be computed first by calling state.compute_forwarding(). */ template template void free_list_allocator::compact(Iterator &iter) { heap_compactor compactor(&state,first_block(),iter); this->iterate(compactor); /* Now update the free list; there will be a single free block at the end */ this->build_free_list((cell)compactor.address - this->start); } }