From b50d3f3fb0e61246ab09d4929f204418581e9a29 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 6 Oct 2009 02:39:12 -0500 Subject: [PATCH] vm: number of generations is not configurable anymore, split up begin_gc() and end_gc() into collect_{nursery,aging,aging_again,tenured}() --- vm/data_gc.cpp | 221 ++++++++++++++++++++++++----------------------- vm/data_gc.hpp | 16 ++-- vm/data_heap.cpp | 35 ++------ vm/data_heap.hpp | 12 +-- vm/debug.cpp | 4 +- vm/factor.cpp | 3 - vm/image.cpp | 3 +- vm/image.hpp | 2 +- vm/master.hpp | 3 +- vm/vm.hpp | 10 +-- 10 files changed, 143 insertions(+), 166 deletions(-) diff --git a/vm/data_gc.cpp b/vm/data_gc.cpp index 291c5094d7..19a740ac70 100755 --- a/vm/data_gc.cpp +++ b/vm/data_gc.cpp @@ -74,7 +74,7 @@ template 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 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 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 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 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 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 void factor_vm::trace_literal_references(code_block *compiled, Strategy &strategy) { if(current_gc->collecting_gen >= compiled->last_scan) @@ -317,8 +316,7 @@ template 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 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 -copying_collector::copying_collector(factor_vm *myvm_) -: myvm(myvm_), current_gc(myvm_->current_gc) +copying_collector::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 Strategy ©ing_collector::strategy() @@ -427,10 +392,10 @@ template Strategy ©ing_collector::strategy() /* Given a pointer to oldspace, copy it to newspace */ template object *copying_collector::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 bool copying_collector::should_copy_p(obje return strategy().should_copy_p(pointer); } -template cell copying_collector::copy_next(cell scan) +template cell copying_collector::trace_next(cell scan) { cell *obj = (cell *)scan; cell *end = (cell *)(scan + myvm->binary_payload_start((object *)scan)); @@ -506,16 +471,17 @@ template cell copying_collector::copy_next(cell sca template void copying_collector::go() { - strategy().copy_reachable_objects(scan,¤t_gc->newspace->here); + strategy().copy_reachable_objects(scan,&newspace->here); } struct nursery_collector : copying_collector { - explicit nursery_collector(factor_vm *myvm_) : copying_collector(myvm_) {} + explicit nursery_collector(factor_vm *myvm_, zone *newspace_) : + copying_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 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 { - explicit aging_collector(factor_vm *myvm_) : copying_collector(myvm_) {} + explicit aging_collector(factor_vm *myvm_, zone *newspace_) : + copying_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 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_collector collector(this); + explicit aging_again_collector(factor_vm *myvm_, zone *newspace_) : + copying_collector(myvm_,newspace_) {} - trace_roots(collector); - trace_contexts(collector); - trace_cards(collector); - trace_code_heap_roots(collector); - collector.go(); - update_dirty_code_blocks(); -} + bool should_copy_p(object *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 { - explicit tenured_collector(factor_vm *myvm_) : copying_collector(myvm_) {} + explicit tenured_collector(factor_vm *myvm_, zone *newspace_) : + copying_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) @@ -583,22 +543,83 @@ struct tenured_collector : copying_collector while(scan < *end) { myvm->mark_object_code_block(myvm->untag(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; diff --git a/vm/data_gc.hpp b/vm/data_gc.hpp index 95c7249823..80c7cd9a01 100755 --- a/vm/data_gc.hpp +++ b/vm/data_gc.hpp @@ -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 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); diff --git a/vm/data_heap.cpp b/vm/data_heap.cpp index 20952736d2..d43d70e963 100755 --- a/vm/data_heap.cpp +++ b/vm/data_heap.cpp @@ -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)); diff --git a/vm/data_heap.hpp b/vm/data_heap.hpp index 59dbb0cb66..af7035b7d5 100755 --- a/vm/data_heap.hpp +++ b/vm/data_heap.hpp @@ -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; } diff --git a/vm/debug.cpp b/vm/debug.cpp index 117b35af18..70d5b27766 100755 --- a/vm/debug.cpp +++ b/vm/debug.cpp @@ -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]); diff --git a/vm/factor.cpp b/vm/factor.cpp index 77c2e67148..9ade30318c 100755 --- a/vm/factor.cpp +++ b/vm/factor.cpp @@ -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)); diff --git a/vm/image.cpp b/vm/image.cpp index bf50b30d4b..1e10bd2886 100755 --- a/vm/image.cpp +++ b/vm/image.cpp @@ -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); diff --git a/vm/image.hpp b/vm/image.hpp index a964d3eb13..5b1bcaf74a 100755 --- a/vm/image.hpp +++ b/vm/image.hpp @@ -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; diff --git a/vm/master.hpp b/vm/master.hpp index 0e34144099..2c4358f704 100755 --- a/vm/master.hpp +++ b/vm/master.hpp @@ -24,8 +24,9 @@ #include /* C++ headers */ -#include +#include #include +#include #if __GNUC__ == 4 #include diff --git a/vm/vm.hpp b/vm/vm.hpp index ce45a6122d..70283cdcea 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -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 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();