vm: mark sweep gc for tenured space work in progress

db4
Slava Pestov 2009-10-20 22:20:49 -05:00
parent f0816d72f1
commit 814f6371d6
22 changed files with 420 additions and 251 deletions

View File

@ -25,7 +25,7 @@ void factor_vm::collect_aging()
collector.trace_cards(data->tenured, collector.trace_cards(data->tenured,
card_points_to_aging, card_points_to_aging,
simple_unmarker(card_mark_mask)); simple_unmarker(card_mark_mask));
collector.cheneys_algorithm(); collector.tenure_reachable_objects();
} }
{ {
/* If collection fails here, do a to_tenured collection. */ /* If collection fails here, do a to_tenured collection. */

View File

@ -15,6 +15,10 @@ struct aging_policy {
{ {
return !(aging->contains_p(untagged) || tenured->contains_p(untagged)); return !(aging->contains_p(untagged) || tenured->contains_p(untagged));
} }
void promoted_object(object *obj) {}
void visited_object(object *obj) {}
}; };
struct aging_collector : copying_collector<aging_space,aging_policy> { struct aging_collector : copying_collector<aging_space,aging_policy> {

View File

@ -1,20 +1,29 @@
namespace factor namespace factor
{ {
struct aging_space : bump_allocator { struct aging_space : bump_allocator<object> {
object_start_map starts; object_start_map starts;
aging_space(cell size, cell start) : aging_space(cell size, cell start) :
bump_allocator(size,start), starts(size,start) {} bump_allocator<object>(size,start), starts(size,start) {}
object *allot(cell size) object *allot(cell size)
{ {
if(here + size > end) return NULL; if(here + size > end) return NULL;
object *obj = bump_allocator::allot(size); object *obj = bump_allocator<object>::allot(size);
starts.record_object_start_offset(obj); starts.record_object_start_offset(obj);
return obj; return obj;
} }
cell next_object_after(cell scan)
{
cell size = ((object *)scan)->size();
if(scan + size < here)
return scan + size;
else
return 0;
}
}; };
} }

View File

@ -1,7 +1,7 @@
namespace factor namespace factor
{ {
struct bump_allocator { template<typename Block> struct bump_allocator {
/* offset of 'here' and 'end' is hardcoded in compiler backends */ /* offset of 'here' and 'end' is hardcoded in compiler backends */
cell here; cell here;
cell start; cell start;
@ -9,27 +9,18 @@ struct bump_allocator {
cell size; cell size;
bump_allocator(cell size_, cell start_) : bump_allocator(cell size_, cell start_) :
here(0), start(start_), end(start_ + size_), size(size_) {} here(start_), start(start_), end(start_ + size_), size(size_) {}
inline bool contains_p(object *pointer) inline bool contains_p(Block *block)
{ {
return ((cell)pointer - start) < size; return ((cell)block - start) < size;
} }
inline object *allot(cell size) inline Block *allot(cell size)
{ {
cell h = here; cell h = here;
here = h + align(size,data_alignment); here = h + align(size,data_alignment);
return (object *)h; return (Block *)h;
}
cell next_allocated_block_after(cell scan)
{
cell size = ((object *)scan)->size();
if(scan + size < here)
return scan + size;
else
return 0;
} }
}; };

View File

@ -8,7 +8,7 @@ code_heap::code_heap(cell size)
if(size > (1L << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size); if(size > (1L << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size);
seg = new segment(align_page(size),true); seg = new segment(align_page(size),true);
if(!seg) fatal_error("Out of memory in heap allocator",size); if(!seg) fatal_error("Out of memory in heap allocator",size);
allocator = new free_list_allocator<heap_block>(seg->start,size); allocator = new free_list_allocator<heap_block>(size,seg->start);
} }
code_heap::~code_heap() code_heap::~code_heap()

View File

@ -40,7 +40,10 @@ template<typename TargetGeneration, typename Policy> struct collector {
object *untagged = parent->untag<object>(pointer); object *untagged = parent->untag<object>(pointer);
if(!policy.should_copy_p(untagged)) if(!policy.should_copy_p(untagged))
{
policy.visited_object(untagged);
return; return;
}
object *forwarding = resolve_forwarding(untagged); object *forwarding = resolve_forwarding(untagged);
@ -49,7 +52,10 @@ template<typename TargetGeneration, typename Policy> struct collector {
else if(policy.should_copy_p(forwarding)) else if(policy.should_copy_p(forwarding))
untagged = promote_object(forwarding); untagged = promote_object(forwarding);
else else
{
untagged = forwarding; untagged = forwarding;
policy.visited_object(untagged);
}
*handle = RETAG(untagged,TAG(pointer)); *handle = RETAG(untagged,TAG(pointer));
} }
@ -79,6 +85,8 @@ template<typename TargetGeneration, typename Policy> struct collector {
stats->object_count++; stats->object_count++;
stats->bytes_copied += size; stats->bytes_copied += size;
policy.promoted_object(newpointer);
return newpointer; return newpointer;
} }
@ -145,6 +153,141 @@ template<typename TargetGeneration, typename Policy> struct collector {
ctx = ctx->next; ctx = ctx->next;
} }
} }
inline cell first_card_in_deck(cell deck)
{
return deck << (deck_bits - card_bits);
}
inline cell last_card_in_deck(cell deck)
{
return first_card_in_deck(deck + 1);
}
inline cell card_deck_for_address(cell a)
{
return addr_to_deck(a - this->data->start);
}
inline cell card_start_address(cell card)
{
return (card << card_bits) + this->data->start;
}
inline cell card_end_address(cell card)
{
return ((card + 1) << card_bits) + this->data->start;
}
void trace_partial_objects(cell start, cell end, cell card_start, cell card_end)
{
if(card_start < end)
{
start += sizeof(cell);
if(start < card_start) start = card_start;
if(end > card_end) end = card_end;
cell *slot_ptr = (cell *)start;
cell *end_ptr = (cell *)end;
if(slot_ptr != end_ptr)
{
for(; slot_ptr < end_ptr; slot_ptr++)
this->trace_handle(slot_ptr);
}
}
}
template<typename SourceGeneration, typename Unmarker>
void trace_cards(SourceGeneration *gen, card mask, Unmarker unmarker)
{
u64 start_time = current_micros();
card_deck *decks = this->data->decks;
card_deck *cards = this->data->cards;
cell gen_start_card = addr_to_card(gen->start - this->data->start);
cell first_deck = card_deck_for_address(gen->start);
cell last_deck = card_deck_for_address(gen->end);
cell start = 0, binary_start = 0, end = 0;
for(cell deck_index = first_deck; deck_index < last_deck; deck_index++)
{
if(decks[deck_index] & mask)
{
this->parent->gc_stats.decks_scanned++;
cell first_card = first_card_in_deck(deck_index);
cell last_card = last_card_in_deck(deck_index);
for(cell card_index = first_card; card_index < last_card; card_index++)
{
if(cards[card_index] & mask)
{
this->parent->gc_stats.cards_scanned++;
if(end < card_start_address(card_index))
{
start = gen->starts.find_object_containing_card(card_index - gen_start_card);
binary_start = start + this->parent->binary_payload_start((object *)start);
end = start + ((object *)start)->size();
}
#ifdef FACTOR_DEBUG
assert(addr_to_card(start - this->data->start) <= card_index);
assert(start < card_end_address(card_index));
#endif
scan_next_object: {
trace_partial_objects(
start,
binary_start,
card_start_address(card_index),
card_end_address(card_index));
if(end < card_end_address(card_index))
{
start = gen->next_object_after(start);
if(start)
{
binary_start = start + this->parent->binary_payload_start((object *)start);
end = start + ((object *)start)->size();
goto scan_next_object;
}
}
}
unmarker(&cards[card_index]);
if(!start) goto end;
}
}
unmarker(&decks[deck_index]);
}
}
end: this->parent->gc_stats.card_scan_time += (current_micros() - start_time);
}
/* Trace all literals referenced from a code block. Only for aging and nursery collections */
void trace_literal_references(code_block *compiled)
{
this->trace_handle(&compiled->owner);
this->trace_handle(&compiled->literals);
this->trace_handle(&compiled->relocation);
this->parent->gc_stats.code_blocks_scanned++;
}
void trace_code_heap_roots(std::set<code_block *> *remembered_set)
{
std::set<code_block *>::const_iterator iter = remembered_set->begin();
std::set<code_block *>::const_iterator end = remembered_set->end();
for(; iter != end; iter++) trace_literal_references(*iter);
}
}; };
} }

View File

@ -18,147 +18,12 @@ struct copying_collector : collector<TargetGeneration,Policy> {
explicit copying_collector(factor_vm *parent_, generation_statistics *stats_, TargetGeneration *target_, Policy policy_) : explicit copying_collector(factor_vm *parent_, generation_statistics *stats_, TargetGeneration *target_, Policy policy_) :
collector<TargetGeneration,Policy>(parent_,stats_,target_,policy_), scan(target_->here) {} collector<TargetGeneration,Policy>(parent_,stats_,target_,policy_), scan(target_->here) {}
inline cell first_card_in_deck(cell deck)
{
return deck << (deck_bits - card_bits);
}
inline cell last_card_in_deck(cell deck)
{
return first_card_in_deck(deck + 1);
}
inline cell card_deck_for_address(cell a)
{
return addr_to_deck(a - this->data->start);
}
inline cell card_start_address(cell card)
{
return (card << card_bits) + this->data->start;
}
inline cell card_end_address(cell card)
{
return ((card + 1) << card_bits) + this->data->start;
}
void trace_partial_objects(cell start, cell end, cell card_start, cell card_end)
{
if(card_start < end)
{
start += sizeof(cell);
if(start < card_start) start = card_start;
if(end > card_end) end = card_end;
cell *slot_ptr = (cell *)start;
cell *end_ptr = (cell *)end;
if(slot_ptr != end_ptr)
{
for(; slot_ptr < end_ptr; slot_ptr++)
this->trace_handle(slot_ptr);
}
}
}
template<typename SourceGeneration, typename Unmarker>
void trace_cards(SourceGeneration *gen, card mask, Unmarker unmarker)
{
u64 start_time = current_micros();
card_deck *decks = this->data->decks;
card_deck *cards = this->data->cards;
cell gen_start_card = addr_to_card(gen->start - this->data->start);
cell first_deck = card_deck_for_address(gen->start);
cell last_deck = card_deck_for_address(gen->end);
cell start = 0, binary_start = 0, end = 0;
for(cell deck_index = first_deck; deck_index < last_deck; deck_index++)
{
if(decks[deck_index] & mask)
{
this->parent->gc_stats.decks_scanned++;
cell first_card = first_card_in_deck(deck_index);
cell last_card = last_card_in_deck(deck_index);
for(cell card_index = first_card; card_index < last_card; card_index++)
{
if(cards[card_index] & mask)
{
this->parent->gc_stats.cards_scanned++;
if(end < card_start_address(card_index))
{
start = gen->starts.find_object_containing_card(card_index - gen_start_card);
binary_start = start + this->parent->binary_payload_start((object *)start);
end = start + ((object *)start)->size();
}
#ifdef FACTOR_DEBUG
assert(addr_to_card(start - this->data->start) <= card_index);
assert(start < card_end_address(card_index));
#endif
scan_next_object: {
trace_partial_objects(
start,
binary_start,
card_start_address(card_index),
card_end_address(card_index));
if(end < card_end_address(card_index))
{
start = gen->next_allocated_block_after(start);
if(start)
{
binary_start = start + this->parent->binary_payload_start((object *)start);
end = start + ((object *)start)->size();
goto scan_next_object;
}
}
}
unmarker(&cards[card_index]);
if(!start) goto end;
}
}
unmarker(&decks[deck_index]);
}
}
end: this->parent->gc_stats.card_scan_time += (current_micros() - start_time);
}
/* Trace all literals referenced from a code block. Only for aging and nursery collections */
void trace_literal_references(code_block *compiled)
{
this->trace_handle(&compiled->owner);
this->trace_handle(&compiled->literals);
this->trace_handle(&compiled->relocation);
this->parent->gc_stats.code_blocks_scanned++;
}
void trace_code_heap_roots(std::set<code_block *> *remembered_set)
{
std::set<code_block *>::const_iterator iter = remembered_set->begin();
std::set<code_block *>::const_iterator end = remembered_set->end();
for(; iter != end; iter++) trace_literal_references(*iter);
}
void cheneys_algorithm() void cheneys_algorithm()
{ {
while(scan && scan < this->target->here) while(scan && scan < this->target->here)
{ {
this->trace_slots((object *)scan); this->trace_slots((object *)scan);
scan = this->target->next_allocated_block_after(scan); scan = this->target->next_object_after(scan);
} }
} }
}; };

View File

@ -19,7 +19,7 @@ data_heap::data_heap(cell young_size_, cell aging_size_, cell tenured_size_)
aging_size = aging_size_; aging_size = aging_size_;
tenured_size = tenured_size_; tenured_size = tenured_size_;
cell total_size = young_size + 2 * aging_size + 2 * tenured_size; cell total_size = young_size + 2 * aging_size + tenured_size;
total_size += deck_size; total_size += deck_size;
@ -29,20 +29,21 @@ data_heap::data_heap(cell young_size_, cell aging_size_, cell tenured_size_)
cards = new card[cards_size]; cards = new card[cards_size];
cards_end = cards + cards_size; cards_end = cards + cards_size;
memset(cards,0,cards_size);
cell decks_size = addr_to_deck(total_size); cell decks_size = addr_to_deck(total_size);
decks = new card_deck[decks_size]; decks = new card_deck[decks_size];
decks_end = decks + decks_size; decks_end = decks + decks_size;
memset(decks,0,decks_size);
start = align(seg->start,deck_size); start = align(seg->start,deck_size);
tenured = new tenured_space(tenured_size,start); tenured = new tenured_space(tenured_size,start);
tenured_semispace = new tenured_space(tenured_size,tenured->end);
aging = new aging_space(aging_size,tenured_semispace->end); aging = new aging_space(aging_size,tenured->end);
aging_semispace = new aging_space(aging_size,aging->end); aging_semispace = new aging_space(aging_size,aging->end);
nursery = new bump_allocator(young_size,aging_semispace->end); nursery = new nursery_space(young_size,aging_semispace->end);
assert(seg->end - nursery->end <= deck_size); assert(seg->end - nursery->end <= deck_size);
} }
@ -54,7 +55,6 @@ data_heap::~data_heap()
delete aging; delete aging;
delete aging_semispace; delete aging_semispace;
delete tenured; delete tenured;
delete tenured_semispace;
delete[] cards; delete[] cards;
delete[] decks; delete[] decks;
} }
@ -71,8 +71,6 @@ void factor_vm::set_data_heap(data_heap *data_)
nursery = *data->nursery; nursery = *data->nursery;
nursery.here = nursery.start; nursery.here = nursery.start;
init_card_decks(); init_card_decks();
data->reset_generation(data->aging);
data->reset_generation(data->tenured);
} }
void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_size) void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_size)
@ -185,8 +183,11 @@ void factor_vm::primitive_data_room()
a.add(tag_fixnum((data->aging->end - data->aging->here) >> 10)); a.add(tag_fixnum((data->aging->end - data->aging->here) >> 10));
a.add(tag_fixnum((data->aging->size) >> 10)); a.add(tag_fixnum((data->aging->size) >> 10));
a.add(tag_fixnum((data->tenured->end - data->tenured->here) >> 10)); //XXX
a.add(tag_fixnum((data->tenured->size) >> 10)); cell used, total_free, max_free;
data->tenured->usage(&used,&total_free,&max_free);
a.add(tag_fixnum(total_free >> 10));
a.add(tag_fixnum(used >> 10));
a.trim(); a.trim();
dpush(a.elements.value()); dpush(a.elements.value());
@ -195,7 +196,7 @@ void factor_vm::primitive_data_room()
/* Disables GC and activates next-object ( -- obj ) primitive */ /* Disables GC and activates next-object ( -- obj ) primitive */
void factor_vm::begin_scan() void factor_vm::begin_scan()
{ {
heap_scan_ptr = data->tenured->start; heap_scan_ptr = data->tenured->first_object();
gc_off = true; gc_off = true;
} }
@ -214,12 +215,14 @@ cell factor_vm::next_object()
if(!gc_off) if(!gc_off)
general_error(ERROR_HEAP_SCAN,false_object,false_object,NULL); general_error(ERROR_HEAP_SCAN,false_object,false_object,NULL);
if(heap_scan_ptr >= data->tenured->here) if(heap_scan_ptr)
{
cell current = heap_scan_ptr;
heap_scan_ptr = data->tenured->next_object_after(heap_scan_ptr);
return tag_dynamic((object *)current);
}
else
return false_object; return false_object;
object *obj = (object *)heap_scan_ptr;
heap_scan_ptr += obj->size();
return tag_dynamic(obj);
} }
/* Push object at heap scan cursor and advance; pushes f when done */ /* Push object at heap scan cursor and advance; pushes f when done */

View File

@ -10,11 +10,10 @@ struct data_heap {
segment *seg; segment *seg;
bump_allocator *nursery; nursery_space *nursery;
aging_space *aging; aging_space *aging;
aging_space *aging_semispace; aging_space *aging_semispace;
tenured_space *tenured; tenured_space *tenured;
tenured_space *tenured_semispace;
card *cards; card *cards;
card *cards_end; card *cards_end;
@ -49,7 +48,6 @@ their allocation pointers and cards reset. */
template<typename Generation> void data_heap::reset_generation(Generation *gen) template<typename Generation> void data_heap::reset_generation(Generation *gen)
{ {
gen->here = gen->start; gen->here = gen->start;
clear_cards(gen); clear_cards(gen);
clear_decks(gen); clear_decks(gen);
gen->starts.clear_object_start_offsets(); gen->starts.clear_object_start_offsets();

View File

@ -209,19 +209,21 @@ void factor_vm::dump_memory(cell from, cell to)
dump_cell(from); dump_cell(from);
} }
void factor_vm::dump_zone(const char *name, bump_allocator *z) template<typename Generation>
void factor_vm::dump_generation(const char *name, Generation *gen)
{ {
print_string(name); print_string(": "); print_string(name); print_string(": ");
print_string("Start="); print_cell(z->start); print_string("Start="); print_cell(gen->start);
print_string(", size="); print_cell(z->size); print_string(", size="); print_cell(gen->size);
print_string(", here="); print_cell(z->here - z->start); nl(); print_string(", end="); print_cell(gen->end);
nl();
} }
void factor_vm::dump_generations() void factor_vm::dump_generations()
{ {
dump_zone("Nursery",&nursery); dump_generation("Nursery",&nursery);
dump_zone("Aging",data->aging); dump_generation("Aging",data->aging);
dump_zone("Tenured",data->tenured); dump_generation("Tenured",data->tenured);
print_string("Cards: base="); print_string("Cards: base=");
print_cell((cell)data->cards); print_cell((cell)data->cards);

View File

@ -9,29 +9,17 @@ struct free_list {
}; };
template<typename Block> struct free_list_allocator { template<typename Block> struct free_list_allocator {
cell start;
cell size; cell size;
cell start;
cell end; cell end;
free_list free_blocks; free_list free_blocks;
mark_bits<Block> state; mark_bits<Block> state;
explicit free_list_allocator(cell start, cell size); explicit free_list_allocator(cell size, cell start);
bool contains_p(Block *block);
inline Block *first_block() Block *first_block();
{ Block *last_block();
return (Block *)start; Block *next_block_after(Block *block);
}
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 clear_free_list();
void add_to_free_list(free_heap_block *block); void add_to_free_list(free_heap_block *block);
void build_free_list(cell size); void build_free_list(cell size);
@ -42,35 +30,42 @@ template<typename Block> struct free_list_allocator {
void free(Block *block); void free(Block *block);
void usage(cell *used, cell *total_free, cell *max_free); void usage(cell *used, cell *total_free, cell *max_free);
cell occupied(); cell occupied();
void sweep();
template<typename Iterator> void sweep(Iterator &iter); template<typename Iterator> void sweep(Iterator &iter);
template<typename Iterator> void compact(Iterator &iter); template<typename Iterator> void compact(Iterator &iter);
template<typename Iterator> void iterate(Iterator &iter);
template<typename Iterator> 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<typename Block>
free_list_allocator<Block>::free_list_allocator(cell size_, cell start_) :
size(size_), start(start_), end(start_ + size_), state(mark_bits<Block>(size_,start_))
{
clear_free_list();
}
template<typename Block> void free_list_allocator<Block>::clear_free_list() template<typename Block> void free_list_allocator<Block>::clear_free_list()
{ {
memset(&free_blocks,0,sizeof(free_list)); memset(&free_blocks,0,sizeof(free_list));
} }
template<typename Block> template<typename Block> bool free_list_allocator<Block>::contains_p(Block *block)
free_list_allocator<Block>::free_list_allocator(cell start_, cell size_) :
start(start_), size(size_), end(start_ + size_), state(mark_bits<Block>(start_,size_))
{ {
clear_free_list(); return ((cell)block - start) < size;
}
template<typename Block> Block *free_list_allocator<Block>::first_block()
{
return (Block *)start;
}
template<typename Block> Block *free_list_allocator<Block>::last_block()
{
return (Block *)end;
}
template<typename Block> Block *free_list_allocator<Block>::next_block_after(Block *block)
{
return (Block *)((cell)block + block->size());
} }
template<typename Block> void free_list_allocator<Block>::add_to_free_list(free_heap_block *block) template<typename Block> void free_list_allocator<Block>::add_to_free_list(free_heap_block *block)
@ -234,8 +229,56 @@ template<typename Block> cell free_list_allocator<Block>::occupied()
return size; return size;
} }
/* After code GC, all live code blocks are marked, so any template<typename Block>
which are not marked can be reclaimed. */ void free_list_allocator<Block>::sweep()
{
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;
}
else
{
if(prev && prev->free_p())
{
free_heap_block *free_prev = (free_heap_block *)prev;
free_prev->set_size(free_prev->size() + size);
}
else
{
((free_heap_block *)scan)->set_free();
prev = scan;
}
}
scan = (Block *)((cell)scan + size);
}
if(prev && prev->free_p())
this->add_to_free_list((free_heap_block *)prev);
}
template<typename Block> template<typename Block>
template<typename Iterator> template<typename Iterator>
void free_list_allocator<Block>::sweep(Iterator &iter) void free_list_allocator<Block>::sweep(Iterator &iter)
@ -302,4 +345,20 @@ void free_list_allocator<Block>::compact(Iterator &iter)
this->build_free_list((cell)compactor.address - this->start); this->build_free_list((cell)compactor.address - this->start);
} }
template<typename Block>
template<typename Iterator>
void free_list_allocator<Block>::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;
}
}
} }

View File

@ -4,7 +4,7 @@ namespace factor
{ {
full_collector::full_collector(factor_vm *parent_) : full_collector::full_collector(factor_vm *parent_) :
copying_collector<tenured_space,full_policy>( collector<tenured_space,full_policy>(
parent_, parent_,
&parent_->gc_stats.full_stats, &parent_->gc_stats.full_stats,
parent_->data->tenured, parent_->data->tenured,
@ -89,18 +89,22 @@ void full_collector::trace_literal_references(code_block *compiled)
collections */ collections */
void full_collector::mark_code_block(code_block *compiled) void full_collector::mark_code_block(code_block *compiled)
{ {
this->code->set_marked_p(compiled); if(!this->code->marked_p(compiled))
trace_literal_references(compiled); {
this->code->set_marked_p(compiled);
trace_literal_references(compiled);
}
} }
void full_collector::cheneys_algorithm() void full_collector::mark_reachable_objects()
{ {
while(scan && scan < target->here) std::vector<object *> *mark_stack = &this->target->mark_stack;
while(!mark_stack->empty())
{ {
object *obj = (object *)scan; object *obj = mark_stack->back();
mark_stack->pop_back();
this->trace_slots(obj); this->trace_slots(obj);
this->mark_object_code_block(obj); this->mark_object_code_block(obj);
scan = target->next_allocated_block_after(scan);
} }
} }
@ -109,6 +113,7 @@ void factor_vm::collect_full_impl(bool trace_contexts_p)
full_collector collector(this); full_collector collector(this);
code->clear_mark_bits(); code->clear_mark_bits();
data->tenured->clear_mark_bits();
collector.trace_roots(); collector.trace_roots();
if(trace_contexts_p) if(trace_contexts_p)
@ -118,8 +123,9 @@ void factor_vm::collect_full_impl(bool trace_contexts_p)
collector.trace_callbacks(); collector.trace_callbacks();
} }
collector.cheneys_algorithm(); collector.mark_reachable_objects();
data->tenured->sweep();
data->reset_generation(data->aging); data->reset_generation(data->aging);
nursery.here = nursery.start; nursery.here = nursery.start;
} }
@ -144,9 +150,6 @@ void factor_vm::collect_growing_heap(cell requested_bytes,
void factor_vm::collect_full(bool trace_contexts_p, bool compact_code_heap_p) void factor_vm::collect_full(bool trace_contexts_p, bool compact_code_heap_p)
{ {
/* Copy all live objects to the tenured semispace. */
std::swap(data->tenured,data->tenured_semispace);
data->reset_generation(data->tenured);
collect_full_impl(trace_contexts_p); collect_full_impl(trace_contexts_p);
if(compact_code_heap_p) if(compact_code_heap_p)

View File

@ -11,9 +11,20 @@ struct full_policy {
{ {
return !tenured->contains_p(untagged); return !tenured->contains_p(untagged);
} }
void promoted_object(object *obj)
{
tenured->mark_and_push(obj);
}
void visited_object(object *obj)
{
if(!tenured->marked_p(obj))
tenured->mark_and_push(obj);
}
}; };
struct full_collector : copying_collector<tenured_space,full_policy> { struct full_collector : collector<tenured_space,full_policy> {
bool trace_contexts_p; bool trace_contexts_p;
full_collector(factor_vm *parent_); full_collector(factor_vm *parent_);
@ -22,7 +33,7 @@ struct full_collector : copying_collector<tenured_space,full_policy> {
void trace_callbacks(); void trace_callbacks();
void trace_literal_references(code_block *compiled); void trace_literal_references(code_block *compiled);
void mark_code_block(code_block *compiled); void mark_code_block(code_block *compiled);
void cheneys_algorithm(); void mark_reachable_objects();
}; };
} }

View File

@ -235,11 +235,13 @@ object *factor_vm::allot_object(header header, cell size)
else else
{ {
/* If tenured space does not have enough room, collect */ /* If tenured space does not have enough room, collect */
if(data->tenured->here + size > data->tenured->end) //XXX
//if(data->tenured->here + size > data->tenured->end)
primitive_full_gc(); primitive_full_gc();
/* If it still won't fit, grow the heap */ /* If it still won't fit, grow the heap */
if(data->tenured->here + size > data->tenured->end) //XXX
//if(data->tenured->here + size > data->tenured->end)
{ {
gc(collect_growing_heap_op, gc(collect_growing_heap_op,
size, /* requested size */ size, /* requested size */

View File

@ -39,7 +39,7 @@ void factor_vm::load_data_heap(FILE *file, image_header *h, vm_parameters *p)
fatal_error("load_data_heap failed",0); fatal_error("load_data_heap failed",0);
} }
data->tenured->here = data->tenured->start + h->data_size; data->tenured->build_free_list(h->data_size);
} }
void factor_vm::load_code_heap(FILE *file, image_header *h, vm_parameters *p) void factor_vm::load_code_heap(FILE *file, image_header *h, vm_parameters *p)
@ -203,7 +203,7 @@ void factor_vm::relocate_data(cell data_relocation_base, cell code_relocation_ba
{ {
relocate_object((object *)obj,data_relocation_base,code_relocation_base); relocate_object((object *)obj,data_relocation_base,code_relocation_base);
data->tenured->starts.record_object_start_offset((object *)obj); data->tenured->starts.record_object_start_offset((object *)obj);
obj = data->tenured->next_allocated_block_after(obj); obj = data->tenured->next_object_after(obj);
} }
} }
@ -289,7 +289,7 @@ bool factor_vm::save_image(const vm_char *filename)
h.magic = image_magic; h.magic = image_magic;
h.version = image_version; h.version = image_version;
h.data_relocation_base = data->tenured->start; h.data_relocation_base = data->tenured->start;
h.data_size = data->tenured->here - data->tenured->start; h.data_size = data->tenured->occupied();
h.code_relocation_base = code->seg->start; h.code_relocation_base = code->seg->start;
h.code_size = code->allocator->occupied(); h.code_size = code->allocator->occupied();

View File

@ -53,6 +53,7 @@ namespace factor
#include "free_list_allocator.hpp" #include "free_list_allocator.hpp"
#include "write_barrier.hpp" #include "write_barrier.hpp"
#include "object_start_map.hpp" #include "object_start_map.hpp"
#include "nursery_space.hpp"
#include "aging_space.hpp" #include "aging_space.hpp"
#include "tenured_space.hpp" #include "tenured_space.hpp"
#include "data_heap.hpp" #include "data_heap.hpp"

View File

@ -6,10 +6,14 @@ struct nursery_policy {
nursery_policy(factor_vm *parent_) : parent(parent_) {} nursery_policy(factor_vm *parent_) : parent(parent_) {}
bool should_copy_p(object *untagged) bool should_copy_p(object *obj)
{ {
return parent->nursery.contains_p(untagged); return parent->nursery.contains_p(obj);
} }
void promoted_object(object *obj) {}
void visited_object(object *obj) {}
}; };
struct nursery_collector : copying_collector<aging_space,nursery_policy> { struct nursery_collector : copying_collector<aging_space,nursery_policy> {

9
vm/nursery_space.hpp Normal file
View File

@ -0,0 +1,9 @@
namespace factor
{
struct nursery_space : bump_allocator<object>
{
nursery_space(cell size, cell start) : bump_allocator<object>(size,start) {}
};
}

View File

@ -1,19 +1,65 @@
namespace factor namespace factor
{ {
struct tenured_space : bump_allocator { struct tenured_space : free_list_allocator<object> {
object_start_map starts; object_start_map starts;
std::vector<object *> mark_stack;
tenured_space(cell size, cell start) : tenured_space(cell size, cell start) :
bump_allocator(size,start), starts(size,start) {} free_list_allocator<object>(size,start), starts(size,start) {}
object *allot(cell size) object *allot(cell size)
{ {
if(here + size > end) return NULL; object *obj = free_list_allocator<object>::allot(size);
if(obj)
{
starts.record_object_start_offset(obj);
return obj;
}
else
return NULL;
}
object *obj = bump_allocator::allot(size); object *first_allocated_block_after(object *block)
starts.record_object_start_offset(obj); {
return obj; while(block != this->last_block() && block->free_p())
{
free_heap_block *free_block = (free_heap_block *)block;
block = (object *)((cell)free_block + free_block->size());
}
if(block == this->last_block())
return NULL;
else
return block;
}
cell first_object()
{
return (cell)first_allocated_block_after(this->first_block());
}
cell next_object_after(cell scan)
{
cell size = ((object *)scan)->size();
object *next = (object *)(scan + size);
return (cell)first_allocated_block_after(next);
}
void clear_mark_bits()
{
state.clear_mark_bits();
}
bool marked_p(object *obj)
{
return this->state.marked_p(obj);
}
void mark_and_push(object *obj)
{
this->state.set_marked_p(obj);
this->mark_stack.push_back(obj);
} }
}; };

View File

@ -4,12 +4,23 @@ namespace factor
{ {
to_tenured_collector::to_tenured_collector(factor_vm *myvm_) : to_tenured_collector::to_tenured_collector(factor_vm *myvm_) :
copying_collector<tenured_space,to_tenured_policy>( collector<tenured_space,to_tenured_policy>(
myvm_, myvm_,
&myvm_->gc_stats.aging_stats, &myvm_->gc_stats.aging_stats,
myvm_->data->tenured, myvm_->data->tenured,
to_tenured_policy(myvm_)) {} to_tenured_policy(myvm_)) {}
void to_tenured_collector::tenure_reachable_objects()
{
std::vector<object *> *mark_stack = &this->target->mark_stack;
while(!mark_stack->empty())
{
object *obj = mark_stack->back();
mark_stack->pop_back();
this->trace_slots(obj);
}
}
void factor_vm::collect_to_tenured() void factor_vm::collect_to_tenured()
{ {
/* Copy live objects from aging space to tenured space. */ /* Copy live objects from aging space to tenured space. */
@ -21,7 +32,7 @@ void factor_vm::collect_to_tenured()
card_points_to_aging, card_points_to_aging,
dummy_unmarker()); dummy_unmarker());
collector.trace_code_heap_roots(&code->points_to_aging); collector.trace_code_heap_roots(&code->points_to_aging);
collector.cheneys_algorithm(); collector.tenure_reachable_objects();
update_code_heap_for_minor_gc(&code->points_to_aging); update_code_heap_for_minor_gc(&code->points_to_aging);
nursery.here = nursery.start; nursery.here = nursery.start;

View File

@ -11,10 +11,18 @@ struct to_tenured_policy {
{ {
return !tenured->contains_p(untagged); return !tenured->contains_p(untagged);
} }
void promoted_object(object *obj)
{
tenured->mark_stack.push_back(obj);
}
void visited_object(object *obj) {}
}; };
struct to_tenured_collector : copying_collector<tenured_space,to_tenured_policy> { struct to_tenured_collector : collector<tenured_space,to_tenured_policy> {
to_tenured_collector(factor_vm *myvm_); to_tenured_collector(factor_vm *myvm_);
void tenure_reachable_objects();
}; };
} }

View File

@ -11,7 +11,7 @@ struct factor_vm
context *ctx; context *ctx;
/* New objects are allocated here */ /* New objects are allocated here */
bump_allocator nursery; nursery_space nursery;
/* Add this to a shifted address to compute write barrier offsets */ /* Add this to a shifted address to compute write barrier offsets */
cell cards_offset; cell cards_offset;
@ -308,7 +308,7 @@ struct factor_vm
void print_callstack(); void print_callstack();
void dump_cell(cell x); void dump_cell(cell x);
void dump_memory(cell from, cell to); void dump_memory(cell from, cell to);
void dump_zone(const char *name, bump_allocator *z); template<typename Generation> void dump_generation(const char *name, Generation *gen);
void dump_generations(); void dump_generations();
void dump_objects(cell type); void dump_objects(cell type);
void find_data_references_step(cell *scan); void find_data_references_step(cell *scan);