VM: moving collector methods to slot_visitor methods
collector::trace_cards moved to slot_visitor::visit_cards and collector::trace_code_heap_roots moved to slot_visitor::visit_code_heap_roots. Both those methods are pointer visitorslocals-and-roots
parent
b79490b063
commit
f629a95b03
|
@ -33,13 +33,15 @@ void factor_vm::collect_aging() {
|
||||||
|
|
||||||
if (event)
|
if (event)
|
||||||
event->reset_timer();
|
event->reset_timer();
|
||||||
collector.trace_cards(data->tenured, card_points_to_aging, 0xff);
|
collector.visitor.visit_cards(data->tenured, card_points_to_aging, 0xff);
|
||||||
if (event)
|
if (event) {
|
||||||
event->ended_card_scan(collector.cards_scanned, collector.decks_scanned);
|
event->ended_card_scan(collector.visitor.cards_scanned,
|
||||||
|
collector.visitor.decks_scanned);
|
||||||
|
}
|
||||||
|
|
||||||
if (event)
|
if (event)
|
||||||
event->reset_timer();
|
event->reset_timer();
|
||||||
collector.trace_code_heap_roots(&code->points_to_aging);
|
collector.visitor.visit_code_heap_roots(&code->points_to_aging);
|
||||||
if (event)
|
if (event)
|
||||||
event->ended_code_scan(code->points_to_aging.size());
|
event->ended_code_scan(code->points_to_aging.size());
|
||||||
|
|
||||||
|
|
|
@ -63,90 +63,15 @@ template <typename TargetGeneration, typename Policy> struct collector {
|
||||||
data_heap* data;
|
data_heap* data;
|
||||||
TargetGeneration* target;
|
TargetGeneration* target;
|
||||||
slot_visitor<gc_workhorse<TargetGeneration, Policy> > visitor;
|
slot_visitor<gc_workhorse<TargetGeneration, Policy> > visitor;
|
||||||
cell cards_scanned;
|
|
||||||
cell decks_scanned;
|
|
||||||
cell scan;
|
cell scan;
|
||||||
|
|
||||||
collector(factor_vm* parent, TargetGeneration* target, Policy policy)
|
collector(factor_vm* parent, TargetGeneration* target, Policy policy)
|
||||||
: data(parent->data),
|
: data(parent->data),
|
||||||
target(target),
|
target(target),
|
||||||
visitor(parent, gc_workhorse<TargetGeneration, Policy>(parent, target, policy)),
|
visitor(parent, gc_workhorse<TargetGeneration, Policy>(parent, target, policy)) {
|
||||||
cards_scanned(0),
|
|
||||||
decks_scanned(0) {
|
|
||||||
scan = target->start + target->occupied_space();
|
scan = target->start + target->occupied_space();
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_code_heap_roots(std::set<code_block*>* 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 <typename SourceGeneration>
|
|
||||||
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 <typename SourceGeneration>
|
|
||||||
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() {
|
void cheneys_algorithm() {
|
||||||
while (scan && scan < this->target->here) {
|
while (scan && scan < this->target->here) {
|
||||||
this->visitor.visit_object((object*)scan);
|
this->visitor.visit_object((object*)scan);
|
||||||
|
|
|
@ -29,16 +29,18 @@ void factor_vm::collect_nursery() {
|
||||||
|
|
||||||
if (event)
|
if (event)
|
||||||
event->reset_timer();
|
event->reset_timer();
|
||||||
collector.trace_cards(data->tenured, card_points_to_nursery,
|
collector.visitor.visit_cards(data->tenured, card_points_to_nursery,
|
||||||
card_points_to_nursery);
|
card_points_to_nursery);
|
||||||
collector.trace_cards(data->aging, card_points_to_nursery, 0xff);
|
collector.visitor.visit_cards(data->aging, card_points_to_nursery, 0xff);
|
||||||
|
|
||||||
if (event)
|
if (event) {
|
||||||
event->ended_card_scan(collector.cards_scanned, collector.decks_scanned);
|
event->ended_card_scan(collector.visitor.cards_scanned,
|
||||||
|
collector.visitor.decks_scanned);
|
||||||
|
}
|
||||||
|
|
||||||
if (event)
|
if (event)
|
||||||
event->reset_timer();
|
event->reset_timer();
|
||||||
collector.trace_code_heap_roots(&code->points_to_nursery);
|
collector.visitor.visit_code_heap_roots(&code->points_to_nursery);
|
||||||
if (event)
|
if (event)
|
||||||
event->ended_code_scan(code->points_to_nursery.size());
|
event->ended_code_scan(code->points_to_nursery.size());
|
||||||
|
|
||||||
|
|
|
@ -115,14 +115,20 @@ modify-code-heap primitive.
|
||||||
|
|
||||||
Iteration is driven by visit_*() methods. Some of them define GC roots:
|
Iteration is driven by visit_*() methods. Some of them define GC roots:
|
||||||
- visit_context_code_blocks()
|
- visit_context_code_blocks()
|
||||||
- visit_callback_code_blocks() */
|
- visit_callback_code_blocks()
|
||||||
|
*/
|
||||||
|
|
||||||
template <typename Fixup> struct slot_visitor {
|
template <typename Fixup> struct slot_visitor {
|
||||||
factor_vm* parent;
|
factor_vm* parent;
|
||||||
Fixup fixup;
|
Fixup fixup;
|
||||||
|
cell cards_scanned;
|
||||||
|
cell decks_scanned;
|
||||||
|
|
||||||
slot_visitor<Fixup>(factor_vm* parent, Fixup fixup)
|
slot_visitor<Fixup>(factor_vm* parent, Fixup fixup)
|
||||||
: parent(parent), fixup(fixup) {}
|
: parent(parent),
|
||||||
|
fixup(fixup),
|
||||||
|
cards_scanned(0),
|
||||||
|
decks_scanned(0) {}
|
||||||
|
|
||||||
cell visit_pointer(cell pointer);
|
cell visit_pointer(cell pointer);
|
||||||
void visit_handle(cell* handle);
|
void visit_handle(cell* handle);
|
||||||
|
@ -143,6 +149,14 @@ template <typename Fixup> struct slot_visitor {
|
||||||
void visit_object(object* obj);
|
void visit_object(object* obj);
|
||||||
void visit_mark_stack(std::vector<cell>* mark_stack);
|
void visit_mark_stack(std::vector<cell>* mark_stack);
|
||||||
void visit_instruction_operands(code_block* block, cell rel_base);
|
void visit_instruction_operands(code_block* block, cell rel_base);
|
||||||
|
|
||||||
|
template <typename SourceGeneration>
|
||||||
|
cell visit_card(SourceGeneration* gen, cell index, cell start);
|
||||||
|
|
||||||
|
template <typename SourceGeneration>
|
||||||
|
void visit_cards(SourceGeneration* gen, card mask, card unmask);
|
||||||
|
|
||||||
|
void visit_code_heap_roots(std::set<code_block*>* remembered_set);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Fixup>
|
template <typename Fixup>
|
||||||
|
@ -516,4 +530,81 @@ void slot_visitor<Fixup>::visit_instruction_operands(code_block* block,
|
||||||
block->each_instruction_operand(visit_func);
|
block->each_instruction_operand(visit_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Fixup>
|
||||||
|
template <typename SourceGeneration>
|
||||||
|
cell slot_visitor<Fixup>::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 <typename Fixup>
|
||||||
|
template <typename SourceGeneration>
|
||||||
|
void slot_visitor<Fixup>::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 <typename Fixup>
|
||||||
|
void slot_visitor<Fixup>::visit_code_heap_roots(std::set<code_block*>* remembered_set) {
|
||||||
|
FACTOR_FOR_EACH(*remembered_set) {
|
||||||
|
code_block* compiled = *iter;
|
||||||
|
visit_code_block_objects(compiled);
|
||||||
|
visit_embedded_literals(compiled);
|
||||||
|
compiled->flush_icache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace factor {
|
||||||
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. */
|
||||||
collector<tenured_space, to_tenured_policy> collector(this,
|
collector<tenured_space, to_tenured_policy> collector(this,
|
||||||
this->data->tenured,
|
data->tenured,
|
||||||
to_tenured_policy(this));
|
to_tenured_policy(this));
|
||||||
|
|
||||||
mark_stack.clear();
|
mark_stack.clear();
|
||||||
|
@ -15,13 +15,15 @@ void factor_vm::collect_to_tenured() {
|
||||||
|
|
||||||
if (event)
|
if (event)
|
||||||
event->reset_timer();
|
event->reset_timer();
|
||||||
collector.trace_cards(data->tenured, card_points_to_aging, 0xff);
|
collector.visitor.visit_cards(data->tenured, card_points_to_aging, 0xff);
|
||||||
if (event)
|
if (event) {
|
||||||
event->ended_card_scan(collector.cards_scanned, collector.decks_scanned);
|
event->ended_card_scan(collector.visitor.cards_scanned,
|
||||||
|
collector.visitor.decks_scanned);
|
||||||
|
}
|
||||||
|
|
||||||
if (event)
|
if (event)
|
||||||
event->reset_timer();
|
event->reset_timer();
|
||||||
collector.trace_code_heap_roots(&code->points_to_aging);
|
collector.visitor.visit_code_heap_roots(&code->points_to_aging);
|
||||||
if (event)
|
if (event)
|
||||||
event->ended_code_scan(code->points_to_aging.size());
|
event->ended_code_scan(code->points_to_aging.size());
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue