diff --git a/vm/aging_collector.cpp b/vm/aging_collector.cpp index d5b768c827..a7511466bd 100644 --- a/vm/aging_collector.cpp +++ b/vm/aging_collector.cpp @@ -33,13 +33,15 @@ void factor_vm::collect_aging() { if (event) event->reset_timer(); - collector.trace_cards(data->tenured, card_points_to_aging, 0xff); - if (event) - event->ended_card_scan(collector.cards_scanned, collector.decks_scanned); + collector.visitor.visit_cards(data->tenured, card_points_to_aging, 0xff); + if (event) { + event->ended_card_scan(collector.visitor.cards_scanned, + collector.visitor.decks_scanned); + } if (event) event->reset_timer(); - collector.trace_code_heap_roots(&code->points_to_aging); + collector.visitor.visit_code_heap_roots(&code->points_to_aging); if (event) event->ended_code_scan(code->points_to_aging.size()); diff --git a/vm/collector.hpp b/vm/collector.hpp index 08313bf075..32719b5f2c 100644 --- a/vm/collector.hpp +++ b/vm/collector.hpp @@ -63,90 +63,15 @@ template struct collector { data_heap* data; TargetGeneration* target; slot_visitor > visitor; - cell cards_scanned; - cell decks_scanned; cell scan; collector(factor_vm* parent, TargetGeneration* target, Policy policy) : data(parent->data), target(target), - visitor(parent, gc_workhorse(parent, target, policy)), - cards_scanned(0), - decks_scanned(0) { + visitor(parent, gc_workhorse(parent, target, policy)) { scan = target->start + target->occupied_space(); } - void trace_code_heap_roots(std::set* remembered_set) { - FACTOR_FOR_EACH(*remembered_set) { - code_block* compiled = *iter; - visitor.visit_code_block_objects(compiled); - visitor.visit_embedded_literals(compiled); - compiled->flush_icache(); - } - } - - template - cell trace_card(SourceGeneration* gen, cell index, cell start) { - - cell start_addr = data->start + index * card_size; - cell end_addr = start_addr + card_size; - - if (!start || (start + ((object*)start)->size()) < start_addr) { - /* Optimization because finding the objects in a memory range is - expensive. It helps a lot when tracing consecutive cards. */ - cell gen_start_card = (gen->start - data->start) / card_size; - start = gen->starts - .find_object_containing_card(index - gen_start_card); - } - - while (start && start < end_addr) { - visitor.visit_partial_objects(start, start_addr, end_addr); - if ((start + ((object*)start)->size()) >= end_addr) { - /* The object can overlap the card boundary, then the - remainder of it will be handled in the next card - tracing if that card is marked. */ - break; - } - start = gen->next_object_after(start); - } - return start; - } - - template - void trace_cards(SourceGeneration* gen, card mask, card unmask) { - card_deck* decks = data->decks; - card_deck* cards = data->cards; - - cell first_deck = (gen->start - data->start) / deck_size; - cell last_deck = (gen->end - data->start) / deck_size; - - /* Address of last traced object. */ - cell start = 0; - - for (cell di = first_deck; di < last_deck; di++) { - if (decks[di] & mask) { - decks[di] &= ~unmask; - decks_scanned++; - - cell first_card = cards_per_deck * di; - cell last_card = first_card + cards_per_deck; - - for (cell ci = first_card; ci < last_card; ci++) { - if (cards[ci] & mask) { - cards[ci] &= ~unmask; - cards_scanned++; - - start = trace_card(gen, ci, start); - if (!start) { - /* At end of generation, no need to scan more cards. */ - return; - } - } - } - } - } - } - void cheneys_algorithm() { while (scan && scan < this->target->here) { this->visitor.visit_object((object*)scan); diff --git a/vm/nursery_collector.cpp b/vm/nursery_collector.cpp index 9aadb3bb79..2bd5515fbe 100644 --- a/vm/nursery_collector.cpp +++ b/vm/nursery_collector.cpp @@ -29,16 +29,18 @@ void factor_vm::collect_nursery() { if (event) event->reset_timer(); - collector.trace_cards(data->tenured, card_points_to_nursery, - card_points_to_nursery); - collector.trace_cards(data->aging, card_points_to_nursery, 0xff); + collector.visitor.visit_cards(data->tenured, card_points_to_nursery, + card_points_to_nursery); + collector.visitor.visit_cards(data->aging, card_points_to_nursery, 0xff); - if (event) - event->ended_card_scan(collector.cards_scanned, collector.decks_scanned); + if (event) { + event->ended_card_scan(collector.visitor.cards_scanned, + collector.visitor.decks_scanned); + } if (event) event->reset_timer(); - collector.trace_code_heap_roots(&code->points_to_nursery); + collector.visitor.visit_code_heap_roots(&code->points_to_nursery); if (event) event->ended_code_scan(code->points_to_nursery.size()); diff --git a/vm/slot_visitor.hpp b/vm/slot_visitor.hpp index e1c1c7f803..2eb3aad98c 100644 --- a/vm/slot_visitor.hpp +++ b/vm/slot_visitor.hpp @@ -114,15 +114,21 @@ This is used by GC's sweep and compact phases, and the implementation of the modify-code-heap primitive. Iteration is driven by visit_*() methods. Some of them define GC roots: -- visit_context_code_blocks() -- visit_callback_code_blocks() */ + - visit_context_code_blocks() + - visit_callback_code_blocks() +*/ template struct slot_visitor { factor_vm* parent; Fixup fixup; + cell cards_scanned; + cell decks_scanned; slot_visitor(factor_vm* parent, Fixup fixup) - : parent(parent), fixup(fixup) {} + : parent(parent), + fixup(fixup), + cards_scanned(0), + decks_scanned(0) {} cell visit_pointer(cell pointer); void visit_handle(cell* handle); @@ -143,6 +149,14 @@ template struct slot_visitor { void visit_object(object* obj); void visit_mark_stack(std::vector* mark_stack); void visit_instruction_operands(code_block* block, cell rel_base); + + template + cell visit_card(SourceGeneration* gen, cell index, cell start); + + template + void visit_cards(SourceGeneration* gen, card mask, card unmask); + + void visit_code_heap_roots(std::set* remembered_set); }; template @@ -516,4 +530,81 @@ void slot_visitor::visit_instruction_operands(code_block* block, block->each_instruction_operand(visit_func); } +template +template +cell slot_visitor::visit_card(SourceGeneration* gen, + cell index, cell start) { + cell heap_base = parent->data->start; + cell start_addr = heap_base + index * card_size; + cell end_addr = start_addr + card_size; + + /* Forward to the next object whose address is in the card. */ + if (!start || (start + ((object*)start)->size()) < start_addr) { + /* Optimization because finding the objects in a memory range is + expensive. It helps a lot when tracing consecutive cards. */ + cell gen_start_card = (gen->start - heap_base) / card_size; + start = gen->starts + .find_object_containing_card(index - gen_start_card); + } + + while (start && start < end_addr) { + visit_partial_objects(start, start_addr, end_addr); + if ((start + ((object*)start)->size()) >= end_addr) { + /* The object can overlap the card boundary, then the + remainder of it will be handled in the next card + tracing if that card is marked. */ + break; + } + start = gen->next_object_after(start); + } + return start; +} + +template +template +void slot_visitor::visit_cards(SourceGeneration* gen, + card mask, card unmask) { + card_deck* decks = parent->data->decks; + card_deck* cards = parent->data->cards; + cell heap_base = parent->data->start; + + cell first_deck = (gen->start - heap_base) / deck_size; + cell last_deck = (gen->end - heap_base) / deck_size; + + /* Address of last traced object. */ + cell start = 0; + for (cell di = first_deck; di < last_deck; di++) { + if (decks[di] & mask) { + decks[di] &= ~unmask; + decks_scanned++; + + cell first_card = cards_per_deck * di; + cell last_card = first_card + cards_per_deck; + + for (cell ci = first_card; ci < last_card; ci++) { + if (cards[ci] & mask) { + cards[ci] &= ~unmask; + cards_scanned++; + + start = visit_card(gen, ci, start); + if (!start) { + /* At end of generation, no need to scan more cards. */ + return; + } + } + } + } + } +} + +template +void slot_visitor::visit_code_heap_roots(std::set* remembered_set) { + FACTOR_FOR_EACH(*remembered_set) { + code_block* compiled = *iter; + visit_code_block_objects(compiled); + visit_embedded_literals(compiled); + compiled->flush_icache(); + } + } + } diff --git a/vm/to_tenured_collector.cpp b/vm/to_tenured_collector.cpp index b18f9417b8..d4b2b51d65 100644 --- a/vm/to_tenured_collector.cpp +++ b/vm/to_tenured_collector.cpp @@ -5,7 +5,7 @@ namespace factor { void factor_vm::collect_to_tenured() { /* Copy live objects from aging space to tenured space. */ collector collector(this, - this->data->tenured, + data->tenured, to_tenured_policy(this)); mark_stack.clear(); @@ -15,13 +15,15 @@ void factor_vm::collect_to_tenured() { if (event) event->reset_timer(); - collector.trace_cards(data->tenured, card_points_to_aging, 0xff); - if (event) - event->ended_card_scan(collector.cards_scanned, collector.decks_scanned); + collector.visitor.visit_cards(data->tenured, card_points_to_aging, 0xff); + if (event) { + event->ended_card_scan(collector.visitor.cards_scanned, + collector.visitor.decks_scanned); + } if (event) event->reset_timer(); - collector.trace_code_heap_roots(&code->points_to_aging); + collector.visitor.visit_code_heap_roots(&code->points_to_aging); if (event) event->ended_code_scan(code->points_to_aging.size());