namespace factor { static const cell free_list_count = 32; static const cell allocation_page_size = 1024; struct free_heap_block { cell header; bool free_p() const { return (header & 1) == 1; } cell size() const { cell size = header & ~7; FACTOR_ASSERT(size > 0); return size; } void make_free(cell size) { FACTOR_ASSERT(size > 0); header = size | 1; } }; struct block_size_compare { bool operator()(free_heap_block* a, free_heap_block* b) const { return a->size() < b->size(); } }; typedef std::multiset large_block_set; struct free_list { std::vector small_blocks[free_list_count]; large_block_set large_blocks; cell free_block_count; cell free_space; void clear_free_list(); void initial_free_list(cell start, cell end, cell occupied); void add_to_free_list(free_heap_block* block); free_heap_block* find_free_block(cell size); free_heap_block* split_free_block(free_heap_block* block, cell size); bool can_allot_p(cell size); cell largest_free_block(); }; struct allocator_room { cell size; cell occupied_space; cell total_free; cell contiguous_free; cell free_block_count; }; template struct free_list_allocator { cell size; cell start; cell end; free_list free_blocks; mark_bits state; free_list_allocator(cell size, cell start); void initial_free_list(cell occupied); bool contains_p(Block* block); bool can_allot_p(cell size); Block* allot(cell size); void free(Block* block); cell occupied_space(); cell free_space(); cell largest_free_block(); cell free_block_count(); void sweep(); template void sweep(Iterator& iter); template void compact(Iterator& iter, Fixup fixup, const Block** finger); template void iterate(Iterator& iter, Fixup fixup); template void iterate(Iterator& iter); allocator_room as_allocator_room(); }; template free_list_allocator::free_list_allocator(cell size, cell start) : size(size), start(start), end(start + size), state(mark_bits(size, start)) { initial_free_list(0); } template void free_list_allocator::initial_free_list(cell occupied) { free_blocks.initial_free_list(start, end, occupied); } template bool free_list_allocator::contains_p(Block* block) { return ((cell)block - start) < size; } template bool free_list_allocator::can_allot_p(cell size) { return free_blocks.can_allot_p(size); } template Block* free_list_allocator::allot(cell size) { size = align(size, data_alignment); free_heap_block* block = free_blocks.find_free_block(size); if (block) { block = free_blocks.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->make_free(block->size()); free_blocks.add_to_free_list(free_block); } template cell free_list_allocator::free_space() { return free_blocks.free_space; } template cell free_list_allocator::occupied_space() { return size - free_blocks.free_space; } template cell free_list_allocator::largest_free_block() { return free_blocks.largest_free_block(); } template cell free_list_allocator::free_block_count() { return free_blocks.free_block_count; } template template void free_list_allocator::sweep(Iterator& iter) { free_blocks.clear_free_list(); cell start = this->start; cell end = this->end; while (start != end) { /* find next unmarked block */ start = state.next_unmarked_block_after(start); if (start != end) { /* find size */ cell size = state.unmarked_block_size(start); FACTOR_ASSERT(size > 0); free_heap_block* free_block = (free_heap_block*)start; free_block->make_free(size); free_blocks.add_to_free_list(free_block); iter((Block*)start, size); start = start + size; } } } template void free_list_allocator::sweep() { auto null_sweep = [](Block* free_block, cell size) { }; sweep(null_sweep); } /* The forwarding map must be computed first by calling state.compute_forwarding(). */ template template void free_list_allocator::compact(Iterator& iter, Fixup fixup, const Block** finger) { cell dest_addr = start; auto compact_block_func = [&](Block* block, cell size) { cell block_addr = (cell)block; if (!state.marked_p(block_addr)) return; *finger = (Block*)(block_addr + size); memmove((Block*)dest_addr, block, size); iter(block, (Block*)dest_addr, size); dest_addr += size; }; iterate(compact_block_func, fixup); /* Now update the free list; there will be a single free block at the end */ free_blocks.initial_free_list(start, end, dest_addr - start); } /* During compaction we have to be careful and measure object sizes differently */ template template void free_list_allocator::iterate(Iterator& iter, Fixup fixup) { cell scan = this->start; while (scan != this->end) { Block* block = (Block*)scan; cell size = fixup.size(block); if (!block->free_p()) iter(block, size); scan += size; } } template template void free_list_allocator::iterate(Iterator& iter) { iterate(iter, no_fixup()); } template allocator_room free_list_allocator::as_allocator_room() { allocator_room room; room.size = size; room.occupied_space = occupied_space(); room.total_free = free_space(); room.contiguous_free = largest_free_block(); room.free_block_count = free_block_count(); return room; } }