vm: number of generations is not configurable anymore, split up begin_gc() and end_gc() into collect_{nursery,aging,aging_again,tenured}()

db4
Slava Pestov 2009-10-06 02:39:12 -05:00
parent d10e27149c
commit b50d3f3fb0
10 changed files with 143 additions and 166 deletions

View File

@ -74,7 +74,7 @@ template<typename Strategy> void factor_vm::trace_card_deck(card_deck *deck, cel
decks_scanned++;
}
/* Copy all newspace objects referenced from marked cards to the destination */
/* Trace all objects referenced from marked cards */
template<typename Strategy> void factor_vm::trace_generation_cards(cell gen, Strategy &strategy)
{
card_deck *first_deck = addr_to_deck(data->generations[gen].start);
@ -95,7 +95,7 @@ template<typename Strategy> void factor_vm::trace_generation_cards(cell gen, Str
unmask = card_points_to_nursery;
/* after the collection, all cards in aging space can be
cleared */
else if(data->have_aging_p() && gen == data->aging())
else if(gen == data->aging())
unmask = card_mark_mask;
else
{
@ -106,7 +106,7 @@ template<typename Strategy> void factor_vm::trace_generation_cards(cell gen, Str
/* if we are collecting aging space into tenured space, we care about
all old->nursery and old->aging pointers. no old->aging pointers can
remain */
else if(data->have_aging_p() && current_gc->collecting_gen == data->aging())
else if(current_gc->collecting_aging_p())
{
if(current_gc->collecting_aging_again)
{
@ -147,7 +147,7 @@ template<typename Strategy> void factor_vm::trace_cards(Strategy &strategy)
u64 start = current_micros();
cell i;
for(i = current_gc->collecting_gen + 1; i < data->gen_count; i++)
for(i = current_gc->collecting_gen + 1; i < gen_count; i++)
trace_generation_cards(i,strategy);
card_scan_time += (current_micros() - start);
@ -284,8 +284,7 @@ template<typename Strategy> void factor_vm::trace_contexts(Strategy &strategy)
}
}
/* Copy all literals referenced from a code block to newspace. Only for
aging and nursery collections */
/* Trace all literals referenced from a code block. Only for aging and nursery collections */
template<typename Strategy> void factor_vm::trace_literal_references(code_block *compiled, Strategy &strategy)
{
if(current_gc->collecting_gen >= compiled->last_scan)
@ -317,8 +316,7 @@ template<typename Strategy> struct literal_reference_tracer {
}
};
/* Copy literals referenced from all code blocks to newspace. Only for
aging and nursery collections */
/* Trace literals referenced from all code blocks. Only for aging and nursery collections */
template<typename Strategy> void factor_vm::trace_code_heap_roots(Strategy &strategy)
{
if(current_gc->collecting_gen >= code->last_code_heap_scan)
@ -379,44 +377,11 @@ void factor_vm::update_dirty_code_blocks()
dirty_code_blocks.clear();
}
/* Prepare to start copying reachable objects into an unused zone */
void factor_vm::begin_gc(cell requested_bytes)
{
if(current_gc->growing_data_heap)
{
assert(current_gc->collecting_tenured_p());
current_gc->old_data_heap = data;
set_data_heap(grow_data_heap(current_gc->old_data_heap,requested_bytes));
current_gc->newspace = &data->generations[data->tenured()];
}
else if(current_gc->collecting_accumulation_gen_p())
{
/* when collecting one of these generations, rotate it
with the semispace */
zone z = data->generations[current_gc->collecting_gen];
data->generations[current_gc->collecting_gen] = data->semispaces[current_gc->collecting_gen];
data->semispaces[current_gc->collecting_gen] = z;
reset_generation(current_gc->collecting_gen);
current_gc->newspace = &data->generations[current_gc->collecting_gen];
clear_cards(current_gc->collecting_gen,current_gc->collecting_gen);
clear_decks(current_gc->collecting_gen,current_gc->collecting_gen);
clear_allot_markers(current_gc->collecting_gen,current_gc->collecting_gen);
}
else
{
/* when collecting a younger generation, we copy
reachable objects to the next oldest generation,
so we set the newspace so the next generation. */
current_gc->newspace = &data->generations[current_gc->collecting_gen + 1];
}
}
template<typename Strategy>
copying_collector<Strategy>::copying_collector(factor_vm *myvm_)
: myvm(myvm_), current_gc(myvm_->current_gc)
copying_collector<Strategy>::copying_collector(factor_vm *myvm_, zone *newspace_)
: myvm(myvm_), current_gc(myvm_->current_gc), newspace(newspace_)
{
scan = current_gc->newspace->here;
scan = newspace->here;
}
template<typename Strategy> Strategy &copying_collector<Strategy>::strategy()
@ -427,10 +392,10 @@ template<typename Strategy> Strategy &copying_collector<Strategy>::strategy()
/* Given a pointer to oldspace, copy it to newspace */
template<typename Strategy> object *copying_collector<Strategy>::copy_untagged_object_impl(object *pointer, cell size)
{
if(current_gc->newspace->here + size >= current_gc->newspace->end)
if(newspace->here + size >= newspace->end)
longjmp(current_gc->gc_unwind,1);
object *newpointer = myvm->allot_zone(current_gc->newspace,size);
object *newpointer = myvm->allot_zone(newspace,size);
gc_stats *s = &myvm->stats[current_gc->collecting_gen];
s->object_count++;
@ -488,7 +453,7 @@ template<typename Strategy> bool copying_collector<Strategy>::should_copy_p(obje
return strategy().should_copy_p(pointer);
}
template<typename Strategy> cell copying_collector<Strategy>::copy_next(cell scan)
template<typename Strategy> cell copying_collector<Strategy>::trace_next(cell scan)
{
cell *obj = (cell *)scan;
cell *end = (cell *)(scan + myvm->binary_payload_start((object *)scan));
@ -506,16 +471,17 @@ template<typename Strategy> cell copying_collector<Strategy>::copy_next(cell sca
template<typename Strategy> void copying_collector<Strategy>::go()
{
strategy().copy_reachable_objects(scan,&current_gc->newspace->here);
strategy().copy_reachable_objects(scan,&newspace->here);
}
struct nursery_collector : copying_collector<nursery_collector>
{
explicit nursery_collector(factor_vm *myvm_) : copying_collector<nursery_collector>(myvm_) {}
explicit nursery_collector(factor_vm *myvm_, zone *newspace_) :
copying_collector<nursery_collector>(myvm_,newspace_) {}
bool should_copy_p(object *untagged)
{
if(myvm->current_gc->newspace->contains_p(untagged))
if(newspace->contains_p(untagged))
return false;
else
return myvm->nursery.contains_p(untagged);
@ -523,29 +489,18 @@ struct nursery_collector : copying_collector<nursery_collector>
void copy_reachable_objects(cell scan, cell *end)
{
while(scan < *end) scan = copy_next(scan);
while(scan < *end) scan = trace_next(scan);
}
};
void factor_vm::collect_nursery()
{
nursery_collector collector(this);
trace_roots(collector);
trace_contexts(collector);
trace_cards(collector);
trace_code_heap_roots(collector);
collector.go();
update_dirty_code_blocks();
}
struct aging_collector : copying_collector<aging_collector>
{
explicit aging_collector(factor_vm *myvm_) : copying_collector<aging_collector>(myvm_) {}
explicit aging_collector(factor_vm *myvm_, zone *newspace_) :
copying_collector<aging_collector>(myvm_,newspace_) {}
bool should_copy_p(object *untagged)
{
if(myvm->current_gc->newspace->contains_p(untagged))
if(newspace->contains_p(untagged))
return false;
else
return !myvm->data->generations[myvm->data->tenured()].contains_p(untagged);
@ -553,29 +508,34 @@ struct aging_collector : copying_collector<aging_collector>
void copy_reachable_objects(cell scan, cell *end)
{
while(scan < *end) scan = copy_next(scan);
while(scan < *end) scan = trace_next(scan);
}
};
void factor_vm::collect_aging()
struct aging_again_collector : copying_collector<aging_again_collector>
{
aging_collector collector(this);
trace_roots(collector);
trace_contexts(collector);
trace_cards(collector);
trace_code_heap_roots(collector);
collector.go();
update_dirty_code_blocks();
}
struct tenured_collector : copying_collector<tenured_collector>
{
explicit tenured_collector(factor_vm *myvm_) : copying_collector<tenured_collector>(myvm_) {}
explicit aging_again_collector(factor_vm *myvm_, zone *newspace_) :
copying_collector<aging_again_collector>(myvm_,newspace_) {}
bool should_copy_p(object *untagged)
{
return !myvm->current_gc->newspace->contains_p(untagged);
return !newspace->contains_p(untagged);
}
void copy_reachable_objects(cell scan, cell *end)
{
while(scan < *end) scan = trace_next(scan);
}
};
struct tenured_collector : copying_collector<tenured_collector>
{
explicit tenured_collector(factor_vm *myvm_, zone *newspace_) :
copying_collector<tenured_collector>(myvm_,newspace_) {}
bool should_copy_p(object *untagged)
{
return !newspace->contains_p(untagged);
}
void copy_reachable_objects(cell scan, cell *end)
@ -583,22 +543,83 @@ struct tenured_collector : copying_collector<tenured_collector>
while(scan < *end)
{
myvm->mark_object_code_block(myvm->untag<object>(scan),*this);
scan = copy_next(scan);
scan = trace_next(scan);
}
}
};
void factor_vm::collect_tenured(bool trace_contexts_)
void factor_vm::collect_nursery()
{
tenured_collector collector(this);
nursery_collector collector(this,&data->generations[data->aging()]);
trace_roots(collector);
trace_contexts(collector);
trace_cards(collector);
trace_code_heap_roots(collector);
collector.go();
update_dirty_code_blocks();
nursery.here = nursery.start;
}
void factor_vm::collect_aging()
{
std::swap(data->generations[data->aging()],data->semispaces[data->aging()]);
reset_generations(data->aging(),data->aging());
aging_collector collector(this,&data->generations[data->aging()]);
trace_roots(collector);
trace_contexts(collector);
trace_cards(collector);
trace_code_heap_roots(collector);
collector.go();
update_dirty_code_blocks();
reset_generations(data->nursery(),data->nursery());
}
void factor_vm::collect_aging_again()
{
aging_again_collector collector(this,&data->generations[data->tenured()]);
trace_roots(collector);
trace_contexts(collector);
trace_cards(collector);
trace_code_heap_roots(collector);
collector.go();
update_dirty_code_blocks();
reset_generations(data->nursery(),data->aging());
}
void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_)
{
if(current_gc->growing_data_heap)
{
current_gc->old_data_heap = data;
set_data_heap(grow_data_heap(current_gc->old_data_heap,requested_bytes));
}
else
{
std::swap(data->generations[data->tenured()],data->semispaces[data->tenured()]);
reset_generations(data->tenured(),data->tenured());
}
tenured_collector collector(this,&data->generations[data->tenured()]);
trace_roots(collector);
if(trace_contexts_) trace_contexts(collector);
collector.go();
free_unmarked_code_blocks();
reset_generations(data->nursery(),data->aging());
if(current_gc->growing_data_heap)
delete current_gc->old_data_heap;
}
void factor_vm::end_gc()
void factor_vm::record_gc_stats()
{
gc_stats *s = &stats[current_gc->collecting_gen];
@ -607,24 +628,6 @@ void factor_vm::end_gc()
s->gc_time += gc_elapsed;
if(s->max_gc_time < gc_elapsed)
s->max_gc_time = gc_elapsed;
if(current_gc->growing_data_heap)
delete current_gc->old_data_heap;
if(current_gc->collecting_nursery_p())
{
nursery.here = nursery.start;
}
else if(current_gc->collecting_accumulation_gen_p())
{
reset_generations(data->nursery(),current_gc->collecting_gen - 1);
}
else
{
/* all generations up to and including the one
collected are now empty */
reset_generations(data->nursery(),current_gc->collecting_gen);
}
}
/* Collect gen and all younger generations.
@ -657,8 +660,7 @@ void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_
}
/* we try collecting aging space twice before going on to
collect tenured */
else if(data->have_aging_p()
&& current_gc->collecting_gen == data->aging()
else if(current_gc->collecting_aging_p()
&& !current_gc->collecting_aging_again)
{
current_gc->collecting_aging_again = true;
@ -670,16 +672,19 @@ void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_
}
}
begin_gc(requested_bytes);
if(current_gc->collecting_nursery_p())
collect_nursery();
else if(current_gc->collecting_aging_p())
collect_aging();
{
if(current_gc->collecting_aging_again)
collect_aging_again();
else
collect_aging();
}
else if(current_gc->collecting_tenured_p())
collect_tenured(trace_contexts_);
collect_tenured(requested_bytes,trace_contexts_);
end_gc();
record_gc_stats();
delete current_gc;
current_gc = NULL;
@ -702,7 +707,7 @@ void factor_vm::primitive_gc_stats()
cell i;
u64 total_gc_time = 0;
for(i = 0; i < max_gen_count; i++)
for(i = 0; i < gen_count; i++)
{
gc_stats *s = &stats[i];
result.add(allot_cell(s->collections));
@ -727,7 +732,7 @@ void factor_vm::primitive_gc_stats()
void factor_vm::clear_gc_stats()
{
for(cell i = 0; i < max_gen_count; i++)
for(cell i = 0; i < gen_count; i++)
memset(&stats[i],0,sizeof(gc_stats));
cards_scanned = 0;

View File

@ -14,9 +14,6 @@ struct gc_state {
/* The data heap we're collecting */
data_heap *data;
/* New objects are copied here */
zone *newspace;
/* sometimes we grow the heap */
bool growing_data_heap;
data_heap *old_data_heap;
@ -46,7 +43,7 @@ struct gc_state {
inline bool collecting_aging_p()
{
return data->have_aging_p() && collecting_gen == data->aging();
return collecting_gen == data->aging();
}
inline bool collecting_tenured_p()
@ -56,22 +53,21 @@ struct gc_state {
inline bool collecting_accumulation_gen_p()
{
return ((data->have_aging_p()
&& collecting_gen == data->aging()
&& !collecting_aging_again)
|| collecting_gen == data->tenured());
return ((collecting_aging_p() && !collecting_aging_again)
|| collecting_tenured_p());
}
};
template<typename Strategy> struct copying_collector {
factor_vm *myvm;
gc_state *current_gc;
zone *newspace;
cell scan;
explicit copying_collector(factor_vm *myvm_);
explicit copying_collector(factor_vm *myvm_, zone *newspace);
Strategy &strategy();
object *copy_untagged_object_impl(object *pointer, cell size);
cell copy_next(cell scan);
cell trace_next(cell scan);
object *copy_object_impl(object *untagged);
object *resolve_forwarding(object *untagged);
cell copy_object(cell pointer);

View File

@ -11,7 +11,7 @@ void factor_vm::init_card_decks()
decks_offset = (cell)data->decks - (start >> deck_bits);
}
data_heap::data_heap(factor_vm *myvm, cell gen_count_, cell young_size_, cell aging_size_, cell tenured_size_)
data_heap::data_heap(factor_vm *myvm, cell young_size_, cell aging_size_, cell tenured_size_)
{
young_size_ = align(young_size_,deck_size);
aging_size_ = align(aging_size_,deck_size);
@ -20,18 +20,8 @@ data_heap::data_heap(factor_vm *myvm, cell gen_count_, cell young_size_, cell ag
young_size = young_size_;
aging_size = aging_size_;
tenured_size = tenured_size_;
gen_count = gen_count_;
cell total_size;
if(gen_count == 2)
total_size = young_size + 2 * tenured_size;
else if(gen_count == 3)
total_size = young_size + 2 * aging_size + 2 * tenured_size;
else
{
total_size = 0;
fatal_error("Invalid number of generations",gen_count);
}
cell total_size = young_size + 2 * aging_size + 2 * tenured_size;
total_size += deck_size;
@ -56,17 +46,11 @@ data_heap::data_heap(factor_vm *myvm, cell gen_count_, cell young_size_, cell ag
alloter = generations[tenured()].init_zone(tenured_size,alloter);
alloter = semispaces[tenured()].init_zone(tenured_size,alloter);
if(gen_count == 3)
{
alloter = generations[aging()].init_zone(aging_size,alloter);
alloter = semispaces[aging()].init_zone(aging_size,alloter);
}
alloter = generations[aging()].init_zone(aging_size,alloter);
alloter = semispaces[aging()].init_zone(aging_size,alloter);
if(gen_count >= 2)
{
alloter = generations[nursery()].init_zone(young_size,alloter);
alloter = semispaces[nursery()].init_zone(0,alloter);
}
alloter = generations[nursery()].init_zone(young_size,alloter);
alloter = semispaces[nursery()].init_zone(0,alloter);
if(seg->end - alloter > deck_size)
myvm->critical_error("Bug in alloc_data_heap",alloter);
@ -77,7 +61,6 @@ data_heap *factor_vm::grow_data_heap(data_heap *data, cell requested_bytes)
cell new_tenured_size = (data->tenured_size * 2) + requested_bytes;
return new data_heap(this,
data->gen_count,
data->young_size,
data->aging_size,
new_tenured_size);
@ -149,9 +132,9 @@ void factor_vm::set_data_heap(data_heap *data_)
clear_allot_markers(data->nursery(),data->tenured());
}
void factor_vm::init_data_heap(cell gens,cell young_size,cell aging_size,cell tenured_size,bool secure_gc_)
void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_size, bool secure_gc_)
{
set_data_heap(new data_heap(this,gens,young_size,aging_size,tenured_size));
set_data_heap(new data_heap(this,young_size,aging_size,tenured_size));
secure_gc = secure_gc_;
init_data_gc();
}
@ -257,7 +240,7 @@ void factor_vm::primitive_data_room()
growable_array a(this);
cell gen;
for(gen = 0; gen < data->gen_count; gen++)
for(gen = 0; gen < gen_count; gen++)
{
zone *z = (gen == data->nursery() ? &nursery : &data->generations[gen]);
a.add(tag_fixnum((z->end - z->here) >> 10));

View File

@ -31,8 +31,6 @@ struct data_heap {
cell aging_size;
cell tenured_size;
cell gen_count;
zone *generations;
zone *semispaces;
@ -49,17 +47,15 @@ struct data_heap {
cell nursery() { return 0; }
/* where objects hang around */
cell aging() { return gen_count - 2; }
cell aging() { return 1; }
/* the oldest generation */
cell tenured() { return gen_count - 1; }
cell tenured() { return 2; }
bool have_aging_p() { return gen_count > 2; }
explicit data_heap(factor_vm *myvm, cell gen_count, cell young_size, cell aging_size, cell tenured_size);
explicit data_heap(factor_vm *myvm, cell young_size, cell aging_size, cell tenured_size);
~data_heap();
};
static const cell max_gen_count = 3;
static const cell gen_count = 3;
}

View File

@ -225,13 +225,13 @@ void factor_vm::dump_generations()
print_string("Nursery: ");
dump_zone(&nursery);
for(i = 1; i < data->gen_count; i++)
for(i = 1; i < gen_count; i++)
{
print_string("Generation "); print_cell(i); print_string(": ");
dump_zone(&data->generations[i]);
}
for(i = 0; i < data->gen_count; i++)
for(i = 0; i < gen_count; i++)
{
print_string("Semispace "); print_cell(i); print_string(": ");
dump_zone(&data->semispaces[i]);

View File

@ -21,7 +21,6 @@ void factor_vm::default_parameters(vm_parameters *p)
p->ds_size = 8 * sizeof(cell);
p->rs_size = 8 * sizeof(cell);
p->gen_count = 2;
p->code_size = 4;
p->young_size = 1;
p->aging_size = 1;
@ -30,7 +29,6 @@ void factor_vm::default_parameters(vm_parameters *p)
p->ds_size = 32 * sizeof(cell);
p->rs_size = 32 * sizeof(cell);
p->gen_count = 3;
p->code_size = 8 * sizeof(cell);
p->young_size = sizeof(cell) / 4;
p->aging_size = sizeof(cell) / 2;
@ -78,7 +76,6 @@ void factor_vm::init_parameters_from_args(vm_parameters *p, int argc, vm_char **
{
if(factor_arg(argv[i],STRING_LITERAL("-datastack=%d"),&p->ds_size));
else if(factor_arg(argv[i],STRING_LITERAL("-retainstack=%d"),&p->rs_size));
else if(factor_arg(argv[i],STRING_LITERAL("-generations=%d"),&p->gen_count));
else if(factor_arg(argv[i],STRING_LITERAL("-young=%d"),&p->young_size));
else if(factor_arg(argv[i],STRING_LITERAL("-aging=%d"),&p->aging_size));
else if(factor_arg(argv[i],STRING_LITERAL("-tenured=%d"),&p->tenured_size));

View File

@ -21,8 +21,7 @@ void factor_vm::load_data_heap(FILE *file, image_header *h, vm_parameters *p)
if(good_size > p->tenured_size)
p->tenured_size = good_size;
init_data_heap(p->gen_count,
p->young_size,
init_data_heap(p->young_size,
p->aging_size,
p->tenured_size,
p->secure_gc);

View File

@ -32,7 +32,7 @@ struct vm_parameters {
const vm_char *image_path;
const vm_char *executable_path;
cell ds_size, rs_size;
cell gen_count, young_size, aging_size, tenured_size;
cell young_size, aging_size, tenured_size;
cell code_size;
bool secure_gc;
bool fep;

View File

@ -24,8 +24,9 @@
#include <time.h>
/* C++ headers */
#include <vector>
#include <algorithm>
#include <set>
#include <vector>
#if __GNUC__ == 4
#include <tr1/unordered_map>

View File

@ -157,7 +157,7 @@ struct factor_vm
void reset_generation(cell i);
void reset_generations(cell from, cell to);
void set_data_heap(data_heap *data_);
void init_data_heap(cell gens,cell young_size,cell aging_size,cell tenured_size,bool secure_gc_);
void init_data_heap(cell young_size, cell aging_size, cell tenured_size, bool secure_gc_);
cell untagged_object_size(object *pointer);
cell unaligned_object_size(object *pointer);
void primitive_size();
@ -231,7 +231,7 @@ struct factor_vm
/* used during garbage collection only */
gc_state *current_gc;
/* statistics */
gc_stats stats[max_gen_count];
gc_stats stats[gen_count];
u64 cards_scanned;
u64 decks_scanned;
u64 card_scan_time;
@ -255,11 +255,11 @@ struct factor_vm
template<typename Strategy> void mark_object_code_block(object *object, Strategy &strategy);
void free_unmarked_code_blocks();
void update_dirty_code_blocks();
void begin_gc(cell requested_bytes);
void collect_nursery();
void collect_aging();
void collect_tenured(bool trace_contexts_);
void end_gc();
void collect_aging_again();
void collect_tenured(cell requested_bytes, bool trace_contexts_);
void record_gc_stats();
void garbage_collection(cell gen, bool growing_data_heap, bool trace_contexts, cell requested_bytes);
void gc();
void primitive_gc();