2009-10-07 16:48:09 -04:00
|
|
|
namespace factor
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
template<typename TargetGeneration, typename Policy> struct collector {
|
2009-10-18 21:31:59 -04:00
|
|
|
factor_vm *parent;
|
2009-10-07 16:48:09 -04:00
|
|
|
data_heap *data;
|
2009-10-09 00:10:32 -04:00
|
|
|
code_heap *code;
|
2009-10-07 16:48:09 -04:00
|
|
|
gc_state *current_gc;
|
2009-10-15 06:51:11 -04:00
|
|
|
generation_statistics *stats;
|
2009-10-07 16:48:09 -04:00
|
|
|
TargetGeneration *target;
|
|
|
|
|
Policy policy;
|
|
|
|
|
|
2009-10-18 21:31:59 -04:00
|
|
|
explicit collector(factor_vm *parent_, generation_statistics *stats_, TargetGeneration *target_, Policy policy_) :
|
|
|
|
|
parent(parent_),
|
|
|
|
|
data(parent_->data),
|
|
|
|
|
code(parent_->code),
|
|
|
|
|
current_gc(parent_->current_gc),
|
2009-10-15 06:51:11 -04:00
|
|
|
stats(stats_),
|
2009-10-07 16:48:09 -04:00
|
|
|
target(target_),
|
|
|
|
|
policy(policy_) {}
|
|
|
|
|
|
|
|
|
|
object *resolve_forwarding(object *untagged)
|
|
|
|
|
{
|
2009-10-18 21:31:59 -04:00
|
|
|
parent->check_data_pointer(untagged);
|
2009-10-07 16:48:09 -04:00
|
|
|
|
|
|
|
|
/* is there another forwarding pointer? */
|
|
|
|
|
while(untagged->h.forwarding_pointer_p())
|
|
|
|
|
untagged = untagged->h.forwarding_pointer();
|
|
|
|
|
|
|
|
|
|
/* we've found the destination */
|
|
|
|
|
untagged->h.check_header();
|
|
|
|
|
return untagged;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-14 07:03:52 -04:00
|
|
|
void trace_handle(cell *handle)
|
2009-10-07 16:48:09 -04:00
|
|
|
{
|
|
|
|
|
cell pointer = *handle;
|
|
|
|
|
|
2009-10-14 07:03:52 -04:00
|
|
|
if(immediate_p(pointer)) return;
|
2009-10-07 16:48:09 -04:00
|
|
|
|
2009-10-21 21:12:57 -04:00
|
|
|
object *untagged = untag<object>(pointer);
|
2009-10-07 16:48:09 -04:00
|
|
|
if(!policy.should_copy_p(untagged))
|
2009-10-20 23:20:49 -04:00
|
|
|
{
|
|
|
|
|
policy.visited_object(untagged);
|
2009-10-14 07:03:52 -04:00
|
|
|
return;
|
2009-10-20 23:20:49 -04:00
|
|
|
}
|
2009-10-07 16:48:09 -04:00
|
|
|
|
|
|
|
|
object *forwarding = resolve_forwarding(untagged);
|
|
|
|
|
|
|
|
|
|
if(forwarding == untagged)
|
|
|
|
|
untagged = promote_object(untagged);
|
|
|
|
|
else if(policy.should_copy_p(forwarding))
|
|
|
|
|
untagged = promote_object(forwarding);
|
|
|
|
|
else
|
2009-10-20 23:20:49 -04:00
|
|
|
{
|
2009-10-07 16:48:09 -04:00
|
|
|
untagged = forwarding;
|
2009-10-20 23:20:49 -04:00
|
|
|
policy.visited_object(untagged);
|
|
|
|
|
}
|
2009-10-07 16:48:09 -04:00
|
|
|
|
|
|
|
|
*handle = RETAG(untagged,TAG(pointer));
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-14 07:03:52 -04:00
|
|
|
void trace_slots(object *ptr)
|
2009-10-07 16:48:09 -04:00
|
|
|
{
|
|
|
|
|
cell *slot = (cell *)ptr;
|
2009-10-18 21:31:59 -04:00
|
|
|
cell *end = (cell *)((cell)ptr + parent->binary_payload_start(ptr));
|
2009-10-07 16:48:09 -04:00
|
|
|
|
|
|
|
|
if(slot != end)
|
|
|
|
|
{
|
|
|
|
|
slot++;
|
2009-10-14 07:03:52 -04:00
|
|
|
for(; slot < end; slot++) trace_handle(slot);
|
2009-10-07 16:48:09 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object *promote_object(object *untagged)
|
|
|
|
|
{
|
2009-10-20 14:13:39 -04:00
|
|
|
cell size = untagged->size();
|
2009-10-07 16:48:09 -04:00
|
|
|
object *newpointer = target->allot(size);
|
|
|
|
|
/* XXX not exception-safe */
|
|
|
|
|
if(!newpointer) longjmp(current_gc->gc_unwind,1);
|
|
|
|
|
|
|
|
|
|
memcpy(newpointer,untagged,size);
|
|
|
|
|
untagged->h.forward_to(newpointer);
|
|
|
|
|
|
2009-10-09 04:20:06 -04:00
|
|
|
stats->object_count++;
|
|
|
|
|
stats->bytes_copied += size;
|
|
|
|
|
|
2009-10-20 23:20:49 -04:00
|
|
|
policy.promoted_object(newpointer);
|
|
|
|
|
|
2009-10-07 16:48:09 -04:00
|
|
|
return newpointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void trace_stack_elements(segment *region, cell *top)
|
|
|
|
|
{
|
|
|
|
|
for(cell *ptr = (cell *)region->start; ptr <= top; ptr++)
|
|
|
|
|
trace_handle(ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void trace_registered_locals()
|
|
|
|
|
{
|
2009-10-18 21:31:59 -04:00
|
|
|
std::vector<cell>::const_iterator iter = parent->gc_locals.begin();
|
|
|
|
|
std::vector<cell>::const_iterator end = parent->gc_locals.end();
|
2009-10-07 16:48:09 -04:00
|
|
|
|
|
|
|
|
for(; iter < end; iter++)
|
|
|
|
|
trace_handle((cell *)(*iter));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void trace_registered_bignums()
|
|
|
|
|
{
|
2009-10-18 21:31:59 -04:00
|
|
|
std::vector<cell>::const_iterator iter = parent->gc_bignums.begin();
|
|
|
|
|
std::vector<cell>::const_iterator end = parent->gc_bignums.end();
|
2009-10-07 16:48:09 -04:00
|
|
|
|
|
|
|
|
for(; iter < end; iter++)
|
|
|
|
|
{
|
|
|
|
|
cell *handle = (cell *)(*iter);
|
|
|
|
|
|
|
|
|
|
if(*handle)
|
|
|
|
|
{
|
|
|
|
|
*handle |= BIGNUM_TYPE;
|
|
|
|
|
trace_handle(handle);
|
|
|
|
|
*handle &= ~BIGNUM_TYPE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Copy roots over at the start of GC, namely various constants, stacks,
|
|
|
|
|
the user environment and extra roots registered by local_roots.hpp */
|
|
|
|
|
void trace_roots()
|
|
|
|
|
{
|
2009-10-18 21:31:59 -04:00
|
|
|
trace_handle(&parent->true_object);
|
|
|
|
|
trace_handle(&parent->bignum_zero);
|
|
|
|
|
trace_handle(&parent->bignum_pos_one);
|
|
|
|
|
trace_handle(&parent->bignum_neg_one);
|
2009-10-07 16:48:09 -04:00
|
|
|
|
|
|
|
|
trace_registered_locals();
|
|
|
|
|
trace_registered_bignums();
|
|
|
|
|
|
2009-10-18 21:31:59 -04:00
|
|
|
for(int i = 0; i < USER_ENV; i++) trace_handle(&parent->userenv[i]);
|
2009-10-07 16:48:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void trace_contexts()
|
|
|
|
|
{
|
2009-10-18 21:31:59 -04:00
|
|
|
context *ctx = parent->ctx;
|
2009-10-07 16:48:09 -04:00
|
|
|
|
2009-10-16 05:33:35 -04:00
|
|
|
while(ctx)
|
2009-10-07 16:48:09 -04:00
|
|
|
{
|
2009-10-16 05:33:35 -04:00
|
|
|
trace_stack_elements(ctx->datastack_region,(cell *)ctx->datastack);
|
|
|
|
|
trace_stack_elements(ctx->retainstack_region,(cell *)ctx->retainstack);
|
2009-10-07 16:48:09 -04:00
|
|
|
|
2009-10-16 05:33:35 -04:00
|
|
|
trace_handle(&ctx->catchstack_save);
|
|
|
|
|
trace_handle(&ctx->current_callback_save);
|
2009-10-07 16:48:09 -04:00
|
|
|
|
2009-10-16 05:33:35 -04:00
|
|
|
ctx = ctx->next;
|
2009-10-07 16:48:09 -04:00
|
|
|
}
|
|
|
|
|
}
|
2009-10-20 23:20:49 -04:00
|
|
|
|
|
|
|
|
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<typename SourceGeneration, typename Unmarker>
|
|
|
|
|
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<code_block *> *remembered_set)
|
|
|
|
|
{
|
|
|
|
|
std::set<code_block *>::const_iterator iter = remembered_set->begin();
|
|
|
|
|
std::set<code_block *>::const_iterator end = remembered_set->end();
|
|
|
|
|
|
|
|
|
|
for(; iter != end; iter++) trace_literal_references(*iter);
|
|
|
|
|
}
|
2009-10-07 16:48:09 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|