diff --git a/vm/aging_collector.cpp b/vm/aging_collector.cpp index 49b1c520ec..2972528cb3 100644 --- a/vm/aging_collector.cpp +++ b/vm/aging_collector.cpp @@ -25,7 +25,7 @@ void factor_vm::collect_aging() collector.trace_cards(data->tenured, card_points_to_aging, simple_unmarker(card_mark_mask)); - collector.cheneys_algorithm(); + collector.tenure_reachable_objects(); } { /* If collection fails here, do a to_tenured collection. */ diff --git a/vm/aging_collector.hpp b/vm/aging_collector.hpp index 8f2677c8b6..a04261d826 100644 --- a/vm/aging_collector.hpp +++ b/vm/aging_collector.hpp @@ -15,6 +15,10 @@ struct aging_policy { { return !(aging->contains_p(untagged) || tenured->contains_p(untagged)); } + + void promoted_object(object *obj) {} + + void visited_object(object *obj) {} }; struct aging_collector : copying_collector { diff --git a/vm/aging_space.hpp b/vm/aging_space.hpp index 20e2506539..99efd44de5 100644 --- a/vm/aging_space.hpp +++ b/vm/aging_space.hpp @@ -1,20 +1,29 @@ namespace factor { -struct aging_space : bump_allocator { +struct aging_space : bump_allocator { object_start_map starts; aging_space(cell size, cell start) : - bump_allocator(size,start), starts(size,start) {} + bump_allocator(size,start), starts(size,start) {} object *allot(cell size) { if(here + size > end) return NULL; - object *obj = bump_allocator::allot(size); + object *obj = bump_allocator::allot(size); starts.record_object_start_offset(obj); return obj; } + + cell next_object_after(cell scan) + { + cell size = ((object *)scan)->size(); + if(scan + size < here) + return scan + size; + else + return 0; + } }; } diff --git a/vm/bump_allocator.hpp b/vm/bump_allocator.hpp index 64011e0bb6..b41613b540 100644 --- a/vm/bump_allocator.hpp +++ b/vm/bump_allocator.hpp @@ -1,7 +1,7 @@ namespace factor { -struct bump_allocator { +template struct bump_allocator { /* offset of 'here' and 'end' is hardcoded in compiler backends */ cell here; cell start; @@ -9,27 +9,18 @@ struct bump_allocator { cell size; 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; here = h + align(size,data_alignment); - return (object *)h; - } - - cell next_allocated_block_after(cell scan) - { - cell size = ((object *)scan)->size(); - if(scan + size < here) - return scan + size; - else - return 0; + return (Block *)h; } }; diff --git a/vm/code_heap.cpp b/vm/code_heap.cpp index 2a466857f9..5ae55cb760 100755 --- a/vm/code_heap.cpp +++ b/vm/code_heap.cpp @@ -8,7 +8,7 @@ code_heap::code_heap(cell size) if(size > (1L << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size); seg = new segment(align_page(size),true); if(!seg) fatal_error("Out of memory in heap allocator",size); - allocator = new free_list_allocator(seg->start,size); + allocator = new free_list_allocator(size,seg->start); } code_heap::~code_heap() diff --git a/vm/collector.hpp b/vm/collector.hpp index 9200d95399..bc04ee4de7 100644 --- a/vm/collector.hpp +++ b/vm/collector.hpp @@ -40,7 +40,10 @@ template struct collector { object *untagged = parent->untag(pointer); if(!policy.should_copy_p(untagged)) + { + policy.visited_object(untagged); return; + } object *forwarding = resolve_forwarding(untagged); @@ -49,7 +52,10 @@ template struct collector { else if(policy.should_copy_p(forwarding)) untagged = promote_object(forwarding); else + { untagged = forwarding; + policy.visited_object(untagged); + } *handle = RETAG(untagged,TAG(pointer)); } @@ -79,6 +85,8 @@ template struct collector { stats->object_count++; stats->bytes_copied += size; + policy.promoted_object(newpointer); + return newpointer; } @@ -145,6 +153,141 @@ template struct collector { 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 + 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 *remembered_set) + { + std::set::const_iterator iter = remembered_set->begin(); + std::set::const_iterator end = remembered_set->end(); + + for(; iter != end; iter++) trace_literal_references(*iter); + } }; } diff --git a/vm/copying_collector.hpp b/vm/copying_collector.hpp index ea7faf2423..012aa4ec10 100644 --- a/vm/copying_collector.hpp +++ b/vm/copying_collector.hpp @@ -18,147 +18,12 @@ struct copying_collector : collector { explicit copying_collector(factor_vm *parent_, generation_statistics *stats_, TargetGeneration *target_, Policy policy_) : collector(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 - 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 *remembered_set) - { - std::set::const_iterator iter = remembered_set->begin(); - std::set::const_iterator end = remembered_set->end(); - - for(; iter != end; iter++) trace_literal_references(*iter); - } - void cheneys_algorithm() { while(scan && scan < this->target->here) { this->trace_slots((object *)scan); - scan = this->target->next_allocated_block_after(scan); + scan = this->target->next_object_after(scan); } } }; diff --git a/vm/data_heap.cpp b/vm/data_heap.cpp index 5a8f4d6b36..7c887c7419 100755 --- a/vm/data_heap.cpp +++ b/vm/data_heap.cpp @@ -19,7 +19,7 @@ data_heap::data_heap(cell young_size_, cell aging_size_, cell tenured_size_) aging_size = aging_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; @@ -29,20 +29,21 @@ data_heap::data_heap(cell young_size_, cell aging_size_, cell tenured_size_) cards = new card[cards_size]; cards_end = cards + cards_size; + memset(cards,0,cards_size); cell decks_size = addr_to_deck(total_size); decks = new card_deck[decks_size]; decks_end = decks + decks_size; + memset(decks,0,decks_size); start = align(seg->start,deck_size); 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); - 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); } @@ -54,7 +55,6 @@ data_heap::~data_heap() delete aging; delete aging_semispace; delete tenured; - delete tenured_semispace; delete[] cards; delete[] decks; } @@ -71,8 +71,6 @@ void factor_vm::set_data_heap(data_heap *data_) nursery = *data->nursery; nursery.here = nursery.start; 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) @@ -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->size) >> 10)); - a.add(tag_fixnum((data->tenured->end - data->tenured->here) >> 10)); - a.add(tag_fixnum((data->tenured->size) >> 10)); + //XXX + 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(); dpush(a.elements.value()); @@ -195,7 +196,7 @@ void factor_vm::primitive_data_room() /* Disables GC and activates next-object ( -- obj ) primitive */ void factor_vm::begin_scan() { - heap_scan_ptr = data->tenured->start; + heap_scan_ptr = data->tenured->first_object(); gc_off = true; } @@ -214,12 +215,14 @@ cell factor_vm::next_object() if(!gc_off) 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; - - 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 */ diff --git a/vm/data_heap.hpp b/vm/data_heap.hpp index 526a5eb9ae..fe714b91b0 100755 --- a/vm/data_heap.hpp +++ b/vm/data_heap.hpp @@ -10,11 +10,10 @@ struct data_heap { segment *seg; - bump_allocator *nursery; + nursery_space *nursery; aging_space *aging; aging_space *aging_semispace; tenured_space *tenured; - tenured_space *tenured_semispace; card *cards; card *cards_end; @@ -49,7 +48,6 @@ their allocation pointers and cards reset. */ template void data_heap::reset_generation(Generation *gen) { gen->here = gen->start; - clear_cards(gen); clear_decks(gen); gen->starts.clear_object_start_offsets(); diff --git a/vm/debug.cpp b/vm/debug.cpp index 31164e972b..afc0b43f7a 100755 --- a/vm/debug.cpp +++ b/vm/debug.cpp @@ -209,19 +209,21 @@ void factor_vm::dump_memory(cell from, cell to) dump_cell(from); } -void factor_vm::dump_zone(const char *name, bump_allocator *z) +template +void factor_vm::dump_generation(const char *name, Generation *gen) { print_string(name); print_string(": "); - print_string("Start="); print_cell(z->start); - print_string(", size="); print_cell(z->size); - print_string(", here="); print_cell(z->here - z->start); nl(); + print_string("Start="); print_cell(gen->start); + print_string(", size="); print_cell(gen->size); + print_string(", end="); print_cell(gen->end); + nl(); } void factor_vm::dump_generations() { - dump_zone("Nursery",&nursery); - dump_zone("Aging",data->aging); - dump_zone("Tenured",data->tenured); + dump_generation("Nursery",&nursery); + dump_generation("Aging",data->aging); + dump_generation("Tenured",data->tenured); print_string("Cards: base="); print_cell((cell)data->cards); diff --git a/vm/free_list_allocator.hpp b/vm/free_list_allocator.hpp index da2622bb0b..c8f3bd6f47 100644 --- a/vm/free_list_allocator.hpp +++ b/vm/free_list_allocator.hpp @@ -9,29 +9,17 @@ struct free_list { }; template struct free_list_allocator { - cell start; cell size; + cell start; cell end; free_list free_blocks; mark_bits state; - explicit free_list_allocator(cell start, cell size); - - inline Block *first_block() - { - return (Block *)start; - } - - inline Block *last_block() - { - return (Block *)end; - } - - Block *next_block_after(heap_block *block) - { - return (Block *)((cell)block + block->size()); - } - + explicit free_list_allocator(cell size, cell start); + bool contains_p(Block *block); + Block *first_block(); + Block *last_block(); + Block *next_block_after(Block *block); void clear_free_list(); void add_to_free_list(free_heap_block *block); void build_free_list(cell size); @@ -42,35 +30,42 @@ template struct free_list_allocator { void free(Block *block); void usage(cell *used, cell *total_free, cell *max_free); cell occupied(); - + void sweep(); template void sweep(Iterator &iter); template void compact(Iterator &iter); - - template 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 void iterate(Iterator &iter); }; +template +free_list_allocator::free_list_allocator(cell size_, cell start_) : + size(size_), start(start_), end(start_ + size_), state(mark_bits(size_,start_)) +{ + clear_free_list(); +} + template void free_list_allocator::clear_free_list() { memset(&free_blocks,0,sizeof(free_list)); } -template -free_list_allocator::free_list_allocator(cell start_, cell size_) : - start(start_), size(size_), end(start_ + size_), state(mark_bits(start_,size_)) +template bool free_list_allocator::contains_p(Block *block) { - clear_free_list(); + return ((cell)block - start) < size; +} + +template Block *free_list_allocator::first_block() +{ + return (Block *)start; +} + +template Block *free_list_allocator::last_block() +{ + return (Block *)end; +} + +template Block *free_list_allocator::next_block_after(Block *block) +{ + return (Block *)((cell)block + block->size()); } template void free_list_allocator::add_to_free_list(free_heap_block *block) @@ -234,8 +229,56 @@ template cell free_list_allocator::occupied() return size; } -/* After code GC, all live code blocks are marked, so any -which are not marked can be reclaimed. */ +template +void free_list_allocator::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 template void free_list_allocator::sweep(Iterator &iter) @@ -302,4 +345,20 @@ void free_list_allocator::compact(Iterator &iter) this->build_free_list((cell)compactor.address - this->start); } +template +template +void free_list_allocator::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; + } +} + } diff --git a/vm/full_collector.cpp b/vm/full_collector.cpp index 924cad6777..9191823d75 100644 --- a/vm/full_collector.cpp +++ b/vm/full_collector.cpp @@ -4,7 +4,7 @@ namespace factor { full_collector::full_collector(factor_vm *parent_) : - copying_collector( + collector( parent_, &parent_->gc_stats.full_stats, parent_->data->tenured, @@ -89,18 +89,22 @@ void full_collector::trace_literal_references(code_block *compiled) collections */ void full_collector::mark_code_block(code_block *compiled) { - this->code->set_marked_p(compiled); - trace_literal_references(compiled); + if(!this->code->marked_p(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 *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->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); code->clear_mark_bits(); + data->tenured->clear_mark_bits(); collector.trace_roots(); if(trace_contexts_p) @@ -118,8 +123,9 @@ void factor_vm::collect_full_impl(bool trace_contexts_p) collector.trace_callbacks(); } - collector.cheneys_algorithm(); + collector.mark_reachable_objects(); + data->tenured->sweep(); data->reset_generation(data->aging); 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) { - /* 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); if(compact_code_heap_p) diff --git a/vm/full_collector.hpp b/vm/full_collector.hpp index 5298f56637..9aef352b4b 100644 --- a/vm/full_collector.hpp +++ b/vm/full_collector.hpp @@ -11,9 +11,20 @@ struct full_policy { { 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 { +struct full_collector : collector { bool trace_contexts_p; full_collector(factor_vm *parent_); @@ -22,7 +33,7 @@ struct full_collector : copying_collector { void trace_callbacks(); void trace_literal_references(code_block *compiled); void mark_code_block(code_block *compiled); - void cheneys_algorithm(); + void mark_reachable_objects(); }; } diff --git a/vm/gc.cpp b/vm/gc.cpp index c8ba57b7f2..6cb99b6da0 100755 --- a/vm/gc.cpp +++ b/vm/gc.cpp @@ -235,11 +235,13 @@ object *factor_vm::allot_object(header header, cell size) else { /* 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(); /* 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, size, /* requested size */ diff --git a/vm/image.cpp b/vm/image.cpp index b47fe4e86a..ee0a1064ed 100755 --- a/vm/image.cpp +++ b/vm/image.cpp @@ -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); } - 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) @@ -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); 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.version = image_version; 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_size = code->allocator->occupied(); diff --git a/vm/master.hpp b/vm/master.hpp index 293923ca7b..0282a0597d 100755 --- a/vm/master.hpp +++ b/vm/master.hpp @@ -53,6 +53,7 @@ namespace factor #include "free_list_allocator.hpp" #include "write_barrier.hpp" #include "object_start_map.hpp" +#include "nursery_space.hpp" #include "aging_space.hpp" #include "tenured_space.hpp" #include "data_heap.hpp" diff --git a/vm/nursery_collector.hpp b/vm/nursery_collector.hpp index f9d2172929..778efab138 100644 --- a/vm/nursery_collector.hpp +++ b/vm/nursery_collector.hpp @@ -6,10 +6,14 @@ struct nursery_policy { 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 { diff --git a/vm/nursery_space.hpp b/vm/nursery_space.hpp new file mode 100644 index 0000000000..4425c1612b --- /dev/null +++ b/vm/nursery_space.hpp @@ -0,0 +1,9 @@ +namespace factor +{ + +struct nursery_space : bump_allocator +{ + nursery_space(cell size, cell start) : bump_allocator(size,start) {} +}; + +} diff --git a/vm/tenured_space.hpp b/vm/tenured_space.hpp index 1162bb5fd3..c0c12d3f58 100644 --- a/vm/tenured_space.hpp +++ b/vm/tenured_space.hpp @@ -1,19 +1,65 @@ namespace factor { -struct tenured_space : bump_allocator { +struct tenured_space : free_list_allocator { object_start_map starts; + std::vector mark_stack; tenured_space(cell size, cell start) : - bump_allocator(size,start), starts(size,start) {} + free_list_allocator(size,start), starts(size,start) {} object *allot(cell size) { - if(here + size > end) return NULL; + object *obj = free_list_allocator::allot(size); + if(obj) + { + starts.record_object_start_offset(obj); + return obj; + } + else + return NULL; + } - object *obj = bump_allocator::allot(size); - starts.record_object_start_offset(obj); - return obj; + object *first_allocated_block_after(object *block) + { + 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); } }; diff --git a/vm/to_tenured_collector.cpp b/vm/to_tenured_collector.cpp index 3676324ce2..3150647cd2 100644 --- a/vm/to_tenured_collector.cpp +++ b/vm/to_tenured_collector.cpp @@ -4,12 +4,23 @@ namespace factor { to_tenured_collector::to_tenured_collector(factor_vm *myvm_) : - copying_collector( + collector( myvm_, &myvm_->gc_stats.aging_stats, myvm_->data->tenured, to_tenured_policy(myvm_)) {} +void to_tenured_collector::tenure_reachable_objects() +{ + std::vector *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() { /* Copy live objects from aging space to tenured space. */ @@ -21,7 +32,7 @@ void factor_vm::collect_to_tenured() card_points_to_aging, dummy_unmarker()); 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); nursery.here = nursery.start; diff --git a/vm/to_tenured_collector.hpp b/vm/to_tenured_collector.hpp index 9a4cf3764b..e87ba5ee29 100644 --- a/vm/to_tenured_collector.hpp +++ b/vm/to_tenured_collector.hpp @@ -11,10 +11,18 @@ struct to_tenured_policy { { 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 { +struct to_tenured_collector : collector { to_tenured_collector(factor_vm *myvm_); + void tenure_reachable_objects(); }; } diff --git a/vm/vm.hpp b/vm/vm.hpp index 0509127918..615efe35ed 100755 --- a/vm/vm.hpp +++ b/vm/vm.hpp @@ -11,7 +11,7 @@ struct factor_vm context *ctx; /* New objects are allocated here */ - bump_allocator nursery; + nursery_space nursery; /* Add this to a shifted address to compute write barrier offsets */ cell cards_offset; @@ -308,7 +308,7 @@ struct factor_vm void print_callstack(); void dump_cell(cell x); void dump_memory(cell from, cell to); - void dump_zone(const char *name, bump_allocator *z); + template void dump_generation(const char *name, Generation *gen); void dump_generations(); void dump_objects(cell type); void find_data_references_step(cell *scan);