VM: merge of the free_list and free_list_allocator classes
Seem simpler to have all the free list stuff in one class rather than split it over two classes.char-rename
parent
f0eec26f3c
commit
c2f4fdb172
|
@ -43,7 +43,6 @@ ifdef CONFIG
|
|||
vm/entry_points.o \
|
||||
vm/errors.o \
|
||||
vm/factor.o \
|
||||
vm/free_list.o \
|
||||
vm/full_collector.o \
|
||||
vm/gc.o \
|
||||
vm/image.o \
|
||||
|
|
|
@ -67,7 +67,6 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \
|
|||
vm\entry_points.obj \
|
||||
vm\errors.obj \
|
||||
vm\factor.obj \
|
||||
vm\free_list.obj \
|
||||
vm\full_collector.obj \
|
||||
vm\gc.obj \
|
||||
vm\image.obj \
|
||||
|
|
|
@ -301,7 +301,7 @@ code_block* factor_vm::allot_code_block(cell size, code_block_type type) {
|
|||
if (block == NULL) {
|
||||
std::cout << "Code heap used: " << code->allocator->occupied_space()
|
||||
<< "\n";
|
||||
std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
|
||||
std::cout << "Code heap free: " << code->allocator->free_space << "\n";
|
||||
fatal_error("Out of memory in add-compiled-block", 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ bool data_heap::high_fragmentation_p() {
|
|||
}
|
||||
|
||||
bool data_heap::low_memory_p() {
|
||||
return tenured->free_space() <= high_water_mark();
|
||||
return tenured->free_space <= high_water_mark();
|
||||
}
|
||||
|
||||
void data_heap::mark_all_cards() {
|
||||
|
@ -123,9 +123,9 @@ data_heap_room factor_vm::data_room() {
|
|||
room.aging_free = data->aging->free_space();
|
||||
room.tenured_size = data->tenured->size;
|
||||
room.tenured_occupied = data->tenured->occupied_space();
|
||||
room.tenured_total_free = data->tenured->free_space();
|
||||
room.tenured_total_free = data->tenured->free_space;
|
||||
room.tenured_contiguous_free = data->tenured->largest_free_block();
|
||||
room.tenured_free_block_count = data->tenured->free_block_count();
|
||||
room.tenured_free_block_count = data->tenured->free_block_count;
|
||||
room.cards = data->cards_end - data->cards;
|
||||
room.decks = data->decks_end - data->decks;
|
||||
room.mark_stack = mark_stack.capacity() * sizeof(cell);
|
||||
|
|
118
vm/free_list.cpp
118
vm/free_list.cpp
|
@ -1,118 +0,0 @@
|
|||
#include "master.hpp"
|
||||
|
||||
namespace factor {
|
||||
|
||||
void free_list::clear_free_list() {
|
||||
for (cell i = 0; i < free_list_count; i++)
|
||||
small_blocks[i].clear();
|
||||
large_blocks.clear();
|
||||
free_block_count = 0;
|
||||
free_space = 0;
|
||||
}
|
||||
|
||||
void free_list::initial_free_list(cell start, cell end, cell occupied) {
|
||||
clear_free_list();
|
||||
if (occupied != end - start) {
|
||||
free_heap_block* last_block = (free_heap_block*)(start + occupied);
|
||||
last_block->make_free(end - (cell)last_block);
|
||||
add_to_free_list(last_block);
|
||||
}
|
||||
}
|
||||
|
||||
void free_list::add_to_free_list(free_heap_block* block) {
|
||||
cell size = block->size();
|
||||
|
||||
free_block_count++;
|
||||
free_space += size;
|
||||
|
||||
if (size < free_list_count * data_alignment)
|
||||
small_blocks[size / data_alignment].push_back(block);
|
||||
else
|
||||
large_blocks.insert(block);
|
||||
}
|
||||
|
||||
free_heap_block* free_list::find_free_block(cell size) {
|
||||
// Check small free lists
|
||||
cell bucket = size / data_alignment;
|
||||
if (bucket < free_list_count) {
|
||||
std::vector<free_heap_block*>& blocks = small_blocks[bucket];
|
||||
if (blocks.size() == 0) {
|
||||
// Round up to a multiple of 'size'
|
||||
cell large_block_size = ((allocation_page_size + size - 1) / size) * size;
|
||||
|
||||
// Allocate a block this big
|
||||
free_heap_block* large_block = find_free_block(large_block_size);
|
||||
if (!large_block)
|
||||
return NULL;
|
||||
|
||||
large_block = split_free_block(large_block, large_block_size);
|
||||
|
||||
// Split it up into pieces and add each piece back to the free list
|
||||
for (cell offset = 0; offset < large_block_size; offset += size) {
|
||||
free_heap_block* small_block = large_block;
|
||||
large_block = (free_heap_block*)((cell)large_block + size);
|
||||
small_block->make_free(size);
|
||||
add_to_free_list(small_block);
|
||||
}
|
||||
}
|
||||
|
||||
free_heap_block* block = blocks.back();
|
||||
blocks.pop_back();
|
||||
|
||||
free_block_count--;
|
||||
free_space -= block->size();
|
||||
|
||||
return block;
|
||||
} else {
|
||||
// Check large free list
|
||||
free_heap_block key;
|
||||
key.make_free(size);
|
||||
large_block_set::iterator iter = large_blocks.lower_bound(&key);
|
||||
large_block_set::iterator end = large_blocks.end();
|
||||
|
||||
if (iter != end) {
|
||||
free_heap_block* block = *iter;
|
||||
large_blocks.erase(iter);
|
||||
|
||||
free_block_count--;
|
||||
free_space -= block->size();
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free_heap_block* free_list::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->make_free(block->size() - size);
|
||||
block->make_free(size);
|
||||
add_to_free_list(split);
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
bool free_list::can_allot_p(cell size) {
|
||||
return largest_free_block() >= std::max(size, allocation_page_size);
|
||||
}
|
||||
|
||||
cell free_list::largest_free_block() {
|
||||
if (large_blocks.size()) {
|
||||
large_block_set::reverse_iterator last = large_blocks.rbegin();
|
||||
return (*last)->size();
|
||||
} else {
|
||||
for (int i = free_list_count - 1; i >= 0; i--) {
|
||||
if (small_blocks[i].size())
|
||||
return small_blocks[i].back()->size();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
207
vm/free_list.hpp
207
vm/free_list.hpp
|
@ -26,23 +26,6 @@ struct block_size_compare {
|
|||
}
|
||||
};
|
||||
|
||||
typedef std::multiset<free_heap_block*, block_size_compare> large_block_set;
|
||||
|
||||
struct free_list {
|
||||
std::vector<free_heap_block*> 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;
|
||||
|
@ -52,44 +35,86 @@ struct allocator_room {
|
|||
};
|
||||
|
||||
template <typename Block> struct free_list_allocator {
|
||||
cell size;
|
||||
// Region of memory managed by this free list allocator.
|
||||
cell start;
|
||||
cell end;
|
||||
free_list free_blocks;
|
||||
cell size;
|
||||
|
||||
// Stores the free blocks
|
||||
std::vector<free_heap_block*> small_blocks[free_list_count];
|
||||
std::multiset<free_heap_block*, block_size_compare> large_blocks;
|
||||
cell free_block_count;
|
||||
cell free_space;
|
||||
|
||||
mark_bits state;
|
||||
|
||||
// Initializing & freeing
|
||||
free_list_allocator(cell size, cell start);
|
||||
void initial_free_list(cell occupied);
|
||||
void clear_free_list();
|
||||
void add_to_free_list(free_heap_block* block);
|
||||
void free(Block* block);
|
||||
|
||||
// Allocating
|
||||
free_heap_block* find_free_block(cell size);
|
||||
free_heap_block* split_free_block(free_heap_block* block, cell size);
|
||||
Block* allot(cell size);
|
||||
|
||||
// Data
|
||||
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();
|
||||
allocator_room as_allocator_room();
|
||||
|
||||
// Iteration
|
||||
void sweep();
|
||||
template <typename Iterator> void sweep(Iterator& iter);
|
||||
template <typename Iterator, typename Fixup>
|
||||
void compact(Iterator& iter, Fixup fixup, const Block** finger);
|
||||
template <typename Iterator, typename Fixup>
|
||||
void iterate(Iterator& iter, Fixup fixup);
|
||||
template <typename Iterator> void iterate(Iterator& iter);
|
||||
allocator_room as_allocator_room();
|
||||
};
|
||||
|
||||
template <typename Block>
|
||||
free_list_allocator<Block>::free_list_allocator(cell size, cell start)
|
||||
: size(size),
|
||||
start(start),
|
||||
end(start + size),
|
||||
state(mark_bits(size, start)) {
|
||||
initial_free_list(0);
|
||||
void free_list_allocator<Block>::clear_free_list() {
|
||||
for (cell i = 0; i < free_list_count; i++)
|
||||
small_blocks[i].clear();
|
||||
large_blocks.clear();
|
||||
free_block_count = 0;
|
||||
free_space = 0;
|
||||
}
|
||||
|
||||
template <typename Block>
|
||||
void free_list_allocator<Block>::add_to_free_list(free_heap_block* block) {
|
||||
cell size = block->size();
|
||||
|
||||
free_block_count++;
|
||||
free_space += size;
|
||||
|
||||
if (size < free_list_count * data_alignment)
|
||||
small_blocks[size / data_alignment].push_back(block);
|
||||
else
|
||||
large_blocks.insert(block);
|
||||
}
|
||||
|
||||
template <typename Block>
|
||||
void free_list_allocator<Block>::initial_free_list(cell occupied) {
|
||||
free_blocks.initial_free_list(start, end, occupied);
|
||||
clear_free_list();
|
||||
if (occupied != end - start) {
|
||||
free_heap_block* last_block = (free_heap_block*)(start + occupied);
|
||||
last_block->make_free(end - (cell)last_block);
|
||||
add_to_free_list(last_block);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Block>
|
||||
free_list_allocator<Block>::free_list_allocator(cell size, cell start)
|
||||
: start(start),
|
||||
end(start + size),
|
||||
size(size),
|
||||
state(mark_bits(size, start)) {
|
||||
initial_free_list(0);
|
||||
}
|
||||
|
||||
template <typename Block>
|
||||
|
@ -99,47 +124,121 @@ bool free_list_allocator<Block>::contains_p(Block* block) {
|
|||
|
||||
template <typename Block>
|
||||
bool free_list_allocator<Block>::can_allot_p(cell size) {
|
||||
return free_blocks.can_allot_p(size);
|
||||
return largest_free_block() >= std::max(size, allocation_page_size);
|
||||
}
|
||||
|
||||
template <typename Block> Block* free_list_allocator<Block>::allot(cell size) {
|
||||
template <typename Block>
|
||||
free_heap_block* free_list_allocator<Block>::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->make_free(block->size() - size);
|
||||
block->make_free(size);
|
||||
add_to_free_list(split);
|
||||
}
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
template <typename Block>
|
||||
free_heap_block* free_list_allocator<Block>::find_free_block(cell size) {
|
||||
// Check small free lists
|
||||
cell bucket = size / data_alignment;
|
||||
if (bucket < free_list_count) {
|
||||
std::vector<free_heap_block*>& blocks = small_blocks[bucket];
|
||||
if (blocks.size() == 0) {
|
||||
// Round up to a multiple of 'size'
|
||||
cell large_block_size = ((allocation_page_size + size - 1) / size) * size;
|
||||
|
||||
// Allocate a block this big
|
||||
free_heap_block* large_block = find_free_block(large_block_size);
|
||||
if (!large_block)
|
||||
return NULL;
|
||||
|
||||
large_block = split_free_block(large_block, large_block_size);
|
||||
|
||||
// Split it up into pieces and add each piece back to the free list
|
||||
for (cell offset = 0; offset < large_block_size; offset += size) {
|
||||
free_heap_block* small_block = large_block;
|
||||
large_block = (free_heap_block*)((cell)large_block + size);
|
||||
small_block->make_free(size);
|
||||
add_to_free_list(small_block);
|
||||
}
|
||||
}
|
||||
|
||||
free_heap_block* block = blocks.back();
|
||||
blocks.pop_back();
|
||||
|
||||
free_block_count--;
|
||||
free_space -= block->size();
|
||||
|
||||
return block;
|
||||
} else {
|
||||
// Check large free list
|
||||
free_heap_block key;
|
||||
key.make_free(size);
|
||||
auto iter = large_blocks.lower_bound(&key);
|
||||
auto end = large_blocks.end();
|
||||
|
||||
if (iter != end) {
|
||||
free_heap_block* block = *iter;
|
||||
large_blocks.erase(iter);
|
||||
|
||||
free_block_count--;
|
||||
free_space -= block->size();
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename Block>
|
||||
Block* free_list_allocator<Block>::allot(cell size) {
|
||||
size = align(size, data_alignment);
|
||||
|
||||
free_heap_block* block = free_blocks.find_free_block(size);
|
||||
free_heap_block* block = find_free_block(size);
|
||||
if (block) {
|
||||
block = free_blocks.split_free_block(block, size);
|
||||
block = split_free_block(block, size);
|
||||
return (Block*)block;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename Block> void free_list_allocator<Block>::free(Block* block) {
|
||||
template <typename Block>
|
||||
void free_list_allocator<Block>::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);
|
||||
add_to_free_list(free_block);
|
||||
}
|
||||
|
||||
template <typename Block> cell free_list_allocator<Block>::free_space() {
|
||||
return free_blocks.free_space;
|
||||
}
|
||||
|
||||
template <typename Block> cell free_list_allocator<Block>::occupied_space() {
|
||||
return size - free_blocks.free_space;
|
||||
template <typename Block>
|
||||
cell free_list_allocator<Block>::occupied_space() {
|
||||
return size - free_space;
|
||||
}
|
||||
|
||||
template <typename Block>
|
||||
cell free_list_allocator<Block>::largest_free_block() {
|
||||
return free_blocks.largest_free_block();
|
||||
}
|
||||
|
||||
template <typename Block> cell free_list_allocator<Block>::free_block_count() {
|
||||
return free_blocks.free_block_count;
|
||||
if (large_blocks.size()) {
|
||||
auto last = large_blocks.rbegin();
|
||||
return (*last)->size();
|
||||
} else {
|
||||
for (int i = free_list_count - 1; i >= 0; i--) {
|
||||
if (small_blocks[i].size())
|
||||
return small_blocks[i].back()->size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Block>
|
||||
template <typename Iterator>
|
||||
void free_list_allocator<Block>::sweep(Iterator& iter) {
|
||||
free_blocks.clear_free_list();
|
||||
clear_free_list();
|
||||
|
||||
cell start = this->start;
|
||||
cell end = this->end;
|
||||
|
@ -155,7 +254,7 @@ void free_list_allocator<Block>::sweep(Iterator& iter) {
|
|||
|
||||
free_heap_block* free_block = (free_heap_block*)start;
|
||||
free_block->make_free(size);
|
||||
free_blocks.add_to_free_list(free_block);
|
||||
add_to_free_list(free_block);
|
||||
iter((Block*)start, size);
|
||||
|
||||
start = start + size;
|
||||
|
@ -188,7 +287,7 @@ void free_list_allocator<Block>::compact(Iterator& iter, Fixup 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);
|
||||
initial_free_list(dest_addr - start);
|
||||
}
|
||||
|
||||
// During compaction we have to be careful and measure object sizes
|
||||
|
@ -211,9 +310,9 @@ allocator_room free_list_allocator<Block>::as_allocator_room() {
|
|||
allocator_room room;
|
||||
room.size = size;
|
||||
room.occupied_space = occupied_space();
|
||||
room.total_free = free_space();
|
||||
room.total_free = free_space;
|
||||
room.contiguous_free = largest_free_block();
|
||||
room.free_block_count = free_block_count();
|
||||
room.free_block_count = free_block_count;
|
||||
return room;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue