vm: factor out code that visits object slots and code heap blocks into slot_visitor and code_block_visitor
parent
9abe29bebc
commit
fd1e992e7d
|
@ -0,0 +1,79 @@
|
||||||
|
namespace factor
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename Visitor> struct call_frame_code_block_visitor {
|
||||||
|
Visitor visitor;
|
||||||
|
|
||||||
|
explicit call_frame_code_block_visitor(Visitor visitor_) : visitor(visitor_) {}
|
||||||
|
|
||||||
|
void operator()(stack_frame *frame)
|
||||||
|
{
|
||||||
|
cell offset = (cell)FRAME_RETURN_ADDRESS(frame,parent) - (cell)frame->xt;
|
||||||
|
|
||||||
|
code_block *new_block = visitor.visit_code_block(parent->frame_code(frame));
|
||||||
|
frame->xt = new_block->xt();
|
||||||
|
|
||||||
|
FRAME_RETURN_ADDRESS(frame,parent) = (void *)((cell)frame->xt + offset);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Visitor> void factor_vm::visit_object_code_block(object *obj, Visitor visitor)
|
||||||
|
{
|
||||||
|
switch(obj->h.hi_tag())
|
||||||
|
{
|
||||||
|
case WORD_TYPE:
|
||||||
|
{
|
||||||
|
word *w = (word *)obj;
|
||||||
|
if(w->code)
|
||||||
|
w->code = visitor.visit_code_block(w->code);
|
||||||
|
if(w->profiling)
|
||||||
|
w->code = visitor.visit_code_block(w->profiling);
|
||||||
|
|
||||||
|
update_word_xt(obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QUOTATION_TYPE:
|
||||||
|
{
|
||||||
|
quotation *q = (quotation *)obj;
|
||||||
|
if(q->code)
|
||||||
|
set_quot_xt(visitor.visit_code_block(q->code));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CALLSTACK_TYPE:
|
||||||
|
{
|
||||||
|
callstack *stack = (callstack *)obj;
|
||||||
|
call_frame_code_block_visitor<Visitor> call_frame_visitor(visitor);
|
||||||
|
iterate_callstack_object(stack,call_frame_visitor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Visitor> void factor_vm::visit_context_code_blocks(Visitor visitor)
|
||||||
|
{
|
||||||
|
callstack *stack = (callstack *)obj;
|
||||||
|
call_frame_code_block_visitor<Visitor> call_frame_visitor(visitor);
|
||||||
|
iterate_active_frames(call_frame_visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Visitor> struct callback_code_block_visitor {
|
||||||
|
callback_heap *callbacks;
|
||||||
|
Visitor visitor;
|
||||||
|
|
||||||
|
explicit callback_code_block_visitor(callback_heap *callbacks_, Visitor visitor_) :
|
||||||
|
callbacks(callbacks_), visitor(visitor_) {}
|
||||||
|
|
||||||
|
void operator()(callback *stub)
|
||||||
|
{
|
||||||
|
stub->compiled = visitor.visit_code_block(stub->compiled);
|
||||||
|
callbacks->update(stub);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Visitor> void factor_vm::visit_callback_code_blocks(Visitor visitor)
|
||||||
|
{
|
||||||
|
callback_code_block_visitor callback_visitor(callbacks,visitor);
|
||||||
|
callbacks->iterate(callback_visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -188,7 +188,7 @@ void factor_vm::primitive_modify_code_heap()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_word_xt(word.value());
|
update_word_xt(word.untagged());
|
||||||
}
|
}
|
||||||
|
|
||||||
update_code_heap_words();
|
update_code_heap_words();
|
||||||
|
@ -205,99 +205,42 @@ void factor_vm::primitive_code_room()
|
||||||
dpush(tag_fixnum(max_free / 1024));
|
dpush(tag_fixnum(max_free / 1024));
|
||||||
}
|
}
|
||||||
|
|
||||||
code_block *code_heap::forward_code_block(code_block *compiled)
|
struct code_block_forwarder {
|
||||||
{
|
mark_bits<heap_block> *forwarding_map;
|
||||||
return (code_block *)allocator->state.forward_block(compiled);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct callframe_forwarder {
|
explicit code_block_forwarder(mark_bits<heap_block> *forwarding_map_) :
|
||||||
factor_vm *parent;
|
forwarding_map(forwarding_map_) {}
|
||||||
|
|
||||||
explicit callframe_forwarder(factor_vm *parent_) : parent(parent_) {}
|
code_block *operator()(code_block *compiled)
|
||||||
|
|
||||||
void operator()(stack_frame *frame)
|
|
||||||
{
|
{
|
||||||
cell offset = (cell)FRAME_RETURN_ADDRESS(frame,parent) - (cell)frame->xt;
|
return (code_block *)forwarding_map->forward_block(compiled);
|
||||||
|
|
||||||
code_block *forwarded = parent->code->forward_code_block(parent->frame_code(frame));
|
|
||||||
frame->xt = forwarded->xt();
|
|
||||||
|
|
||||||
FRAME_RETURN_ADDRESS(frame,parent) = (void *)((cell)frame->xt + offset);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void factor_vm::forward_object_xts()
|
void factor_vm::forward_object_xts()
|
||||||
{
|
{
|
||||||
|
code_block_forwarder forwarder(&code->allocator->state);
|
||||||
|
|
||||||
begin_scan();
|
begin_scan();
|
||||||
|
|
||||||
cell obj;
|
cell obj;
|
||||||
|
|
||||||
while(to_boolean(obj = next_object()))
|
while(to_boolean(obj = next_object()))
|
||||||
{
|
visit_object_code_block(untag<object>(obj),forwarder);
|
||||||
switch(tagged<object>(obj).type())
|
|
||||||
{
|
|
||||||
case WORD_TYPE:
|
|
||||||
{
|
|
||||||
word *w = untag<word>(obj);
|
|
||||||
|
|
||||||
if(w->code)
|
|
||||||
w->code = code->forward_code_block(w->code);
|
|
||||||
if(w->profiling)
|
|
||||||
w->profiling = code->forward_code_block(w->profiling);
|
|
||||||
|
|
||||||
update_word_xt(obj);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case QUOTATION_TYPE:
|
|
||||||
{
|
|
||||||
quotation *quot = untag<quotation>(obj);
|
|
||||||
|
|
||||||
if(quot->code)
|
|
||||||
{
|
|
||||||
quot->code = code->forward_code_block(quot->code);
|
|
||||||
set_quot_xt(quot,quot->code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CALLSTACK_TYPE:
|
|
||||||
{
|
|
||||||
callstack *stack = untag<callstack>(obj);
|
|
||||||
callframe_forwarder forwarder(this);
|
|
||||||
iterate_callstack_object(stack,forwarder);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
end_scan();
|
end_scan();
|
||||||
}
|
}
|
||||||
|
|
||||||
void factor_vm::forward_context_xts()
|
void factor_vm::forward_context_xts()
|
||||||
{
|
{
|
||||||
callframe_forwarder forwarder(this);
|
code_block_forwarder forwarder(&code->allocator->state);
|
||||||
iterate_active_frames(forwarder);
|
visit_context_code_blocks(forwarder);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct callback_forwarder {
|
|
||||||
code_heap *code;
|
|
||||||
callback_heap *callbacks;
|
|
||||||
|
|
||||||
callback_forwarder(code_heap *code_, callback_heap *callbacks_) :
|
|
||||||
code(code_), callbacks(callbacks_) {}
|
|
||||||
|
|
||||||
void operator()(callback *stub)
|
|
||||||
{
|
|
||||||
stub->compiled = code->forward_code_block(stub->compiled);
|
|
||||||
callbacks->update(stub);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void factor_vm::forward_callback_xts()
|
void factor_vm::forward_callback_xts()
|
||||||
{
|
{
|
||||||
callback_forwarder forwarder(code,callbacks);
|
code_block_forwarder forwarder(&code->allocator->state);
|
||||||
callbacks->iterate(forwarder);
|
visit_callback_code_blocks(forwarder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move all free space to the end of the code heap. Live blocks must be marked
|
/* Move all free space to the end of the code heap. Live blocks must be marked
|
||||||
|
|
|
@ -26,7 +26,6 @@ struct code_heap {
|
||||||
void set_marked_p(code_block *compiled);
|
void set_marked_p(code_block *compiled);
|
||||||
void clear_mark_bits();
|
void clear_mark_bits();
|
||||||
void code_heap_free(code_block *compiled);
|
void code_heap_free(code_block *compiled);
|
||||||
code_block *forward_code_block(code_block *compiled);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
213
vm/collector.hpp
213
vm/collector.hpp
|
@ -1,20 +1,14 @@
|
||||||
namespace factor
|
namespace factor
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename TargetGeneration, typename Policy> struct collector {
|
template<typename TargetGeneration, typename Policy> struct collector_workhorse {
|
||||||
factor_vm *parent;
|
factor_vm *parent;
|
||||||
data_heap *data;
|
|
||||||
code_heap *code;
|
|
||||||
gc_state *current_gc;
|
|
||||||
generation_statistics *stats;
|
generation_statistics *stats;
|
||||||
TargetGeneration *target;
|
TargetGeneration *target;
|
||||||
Policy policy;
|
Policy policy;
|
||||||
|
|
||||||
explicit collector(factor_vm *parent_, generation_statistics *stats_, TargetGeneration *target_, Policy policy_) :
|
explicit collector_workhorse(factor_vm *parent_, generation_statistics *stats_, TargetGeneration *target_, Policy policy_) :
|
||||||
parent(parent_),
|
parent(parent_),
|
||||||
data(parent_->data),
|
|
||||||
code(parent_->code),
|
|
||||||
current_gc(parent_->current_gc),
|
|
||||||
stats(stats_),
|
stats(stats_),
|
||||||
target(target_),
|
target(target_),
|
||||||
policy(policy_) {}
|
policy(policy_) {}
|
||||||
|
@ -32,52 +26,12 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
return untagged;
|
return untagged;
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_handle(cell *handle)
|
|
||||||
{
|
|
||||||
cell pointer = *handle;
|
|
||||||
|
|
||||||
if(immediate_p(pointer)) return;
|
|
||||||
|
|
||||||
object *untagged = untag<object>(pointer);
|
|
||||||
if(!policy.should_copy_p(untagged))
|
|
||||||
{
|
|
||||||
policy.visited_object(untagged);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
object *forwarding = resolve_forwarding(untagged);
|
|
||||||
|
|
||||||
if(forwarding == untagged)
|
|
||||||
untagged = promote_object(untagged);
|
|
||||||
else if(policy.should_copy_p(forwarding))
|
|
||||||
untagged = promote_object(forwarding);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
untagged = forwarding;
|
|
||||||
policy.visited_object(untagged);
|
|
||||||
}
|
|
||||||
|
|
||||||
*handle = RETAG(untagged,TAG(pointer));
|
|
||||||
}
|
|
||||||
|
|
||||||
void trace_slots(object *ptr)
|
|
||||||
{
|
|
||||||
cell *slot = (cell *)ptr;
|
|
||||||
cell *end = (cell *)((cell)ptr + parent->binary_payload_start(ptr));
|
|
||||||
|
|
||||||
if(slot != end)
|
|
||||||
{
|
|
||||||
slot++;
|
|
||||||
for(; slot < end; slot++) trace_handle(slot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object *promote_object(object *untagged)
|
object *promote_object(object *untagged)
|
||||||
{
|
{
|
||||||
cell size = untagged->size();
|
cell size = untagged->size();
|
||||||
object *newpointer = target->allot(size);
|
object *newpointer = target->allot(size);
|
||||||
/* XXX not exception-safe */
|
/* XXX not exception-safe */
|
||||||
if(!newpointer) longjmp(current_gc->gc_unwind,1);
|
if(!newpointer) longjmp(parent->current_gc->gc_unwind,1);
|
||||||
|
|
||||||
memcpy(newpointer,untagged,size);
|
memcpy(newpointer,untagged,size);
|
||||||
untagged->h.forward_to(newpointer);
|
untagged->h.forward_to(newpointer);
|
||||||
|
@ -90,68 +44,90 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
return newpointer;
|
return newpointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_stack_elements(segment *region, cell *top)
|
object *visit_handle(object *obj)
|
||||||
{
|
{
|
||||||
for(cell *ptr = (cell *)region->start; ptr <= top; ptr++)
|
if(!policy.should_copy_p(obj))
|
||||||
trace_handle(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void trace_registered_locals()
|
|
||||||
{
|
|
||||||
std::vector<cell>::const_iterator iter = parent->gc_locals.begin();
|
|
||||||
std::vector<cell>::const_iterator end = parent->gc_locals.end();
|
|
||||||
|
|
||||||
for(; iter < end; iter++)
|
|
||||||
trace_handle((cell *)(*iter));
|
|
||||||
}
|
|
||||||
|
|
||||||
void trace_registered_bignums()
|
|
||||||
{
|
|
||||||
std::vector<cell>::const_iterator iter = parent->gc_bignums.begin();
|
|
||||||
std::vector<cell>::const_iterator end = parent->gc_bignums.end();
|
|
||||||
|
|
||||||
for(; iter < end; iter++)
|
|
||||||
{
|
{
|
||||||
cell *handle = (cell *)(*iter);
|
policy.visited_object(obj);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
if(*handle)
|
object *forwarding = resolve_forwarding(obj);
|
||||||
{
|
|
||||||
*handle |= BIGNUM_TYPE;
|
if(forwarding == obj)
|
||||||
trace_handle(handle);
|
return promote_object(obj);
|
||||||
*handle &= ~BIGNUM_TYPE;
|
else if(policy.should_copy_p(forwarding))
|
||||||
}
|
return promote_object(forwarding);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
policy.visited_object(forwarding);
|
||||||
|
return forwarding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename TargetGeneration, typename Policy>
|
||||||
|
inline static slot_visitor<collector_workhorse<TargetGeneration,Policy> > make_collector_workhorse(
|
||||||
|
factor_vm *parent,
|
||||||
|
generation_statistics *stats,
|
||||||
|
TargetGeneration *target,
|
||||||
|
Policy policy)
|
||||||
|
{
|
||||||
|
return slot_visitor<collector_workhorse<TargetGeneration,Policy> >(parent,
|
||||||
|
collector_workhorse<TargetGeneration,Policy>(parent,stats,target,policy));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
|
factor_vm *parent;
|
||||||
|
data_heap *data;
|
||||||
|
code_heap *code;
|
||||||
|
generation_statistics *stats;
|
||||||
|
TargetGeneration *target;
|
||||||
|
slot_visitor<collector_workhorse<TargetGeneration,Policy> > workhorse;
|
||||||
|
|
||||||
|
explicit collector(factor_vm *parent_, generation_statistics *stats_, TargetGeneration *target_, Policy policy_) :
|
||||||
|
parent(parent_),
|
||||||
|
data(parent_->data),
|
||||||
|
code(parent_->code),
|
||||||
|
stats(stats_),
|
||||||
|
target(target_),
|
||||||
|
workhorse(make_collector_workhorse(parent_,stats_,target_,policy_)) {}
|
||||||
|
|
||||||
|
void trace_handle(cell *handle)
|
||||||
|
{
|
||||||
|
workhorse.visit_handle(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void trace_slots(object *ptr)
|
||||||
|
{
|
||||||
|
workhorse.visit_slots(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
/* 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()
|
void trace_roots()
|
||||||
{
|
{
|
||||||
trace_handle(&parent->true_object);
|
workhorse.visit_roots();
|
||||||
trace_handle(&parent->bignum_zero);
|
|
||||||
trace_handle(&parent->bignum_pos_one);
|
|
||||||
trace_handle(&parent->bignum_neg_one);
|
|
||||||
|
|
||||||
trace_registered_locals();
|
|
||||||
trace_registered_bignums();
|
|
||||||
|
|
||||||
for(cell i = 0; i < special_object_count; i++)
|
|
||||||
trace_handle(&parent->special_objects[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_contexts()
|
void trace_contexts()
|
||||||
{
|
{
|
||||||
context *ctx = parent->ctx;
|
workhorse.visit_contexts();
|
||||||
|
}
|
||||||
|
|
||||||
while(ctx)
|
/* Trace all literals referenced from a code block. Only for aging and nursery collections */
|
||||||
|
void trace_literal_references(code_block *compiled)
|
||||||
|
{
|
||||||
|
workhorse.visit_literal_references(compiled);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_stack_elements(ctx->datastack_region,(cell *)ctx->datastack);
|
trace_literal_references(*iter);
|
||||||
trace_stack_elements(ctx->retainstack_region,(cell *)ctx->retainstack);
|
parent->gc_stats.code_blocks_scanned++;
|
||||||
|
|
||||||
trace_handle(&ctx->catchstack_save);
|
|
||||||
trace_handle(&ctx->current_callback_save);
|
|
||||||
|
|
||||||
ctx = ctx->next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,17 +143,17 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
|
|
||||||
inline cell card_deck_for_address(cell a)
|
inline cell card_deck_for_address(cell a)
|
||||||
{
|
{
|
||||||
return addr_to_deck(a - this->data->start);
|
return addr_to_deck(a - data->start);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline cell card_start_address(cell card)
|
inline cell card_start_address(cell card)
|
||||||
{
|
{
|
||||||
return (card << card_bits) + this->data->start;
|
return (card << card_bits) + data->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline cell card_end_address(cell card)
|
inline cell card_end_address(cell card)
|
||||||
{
|
{
|
||||||
return ((card + 1) << card_bits) + this->data->start;
|
return ((card + 1) << card_bits) + data->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
void trace_partial_objects(cell start, cell end, cell card_start, cell card_end)
|
void trace_partial_objects(cell start, cell end, cell card_start, cell card_end)
|
||||||
|
@ -195,7 +171,7 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
if(slot_ptr != end_ptr)
|
if(slot_ptr != end_ptr)
|
||||||
{
|
{
|
||||||
for(; slot_ptr < end_ptr; slot_ptr++)
|
for(; slot_ptr < end_ptr; slot_ptr++)
|
||||||
this->trace_handle(slot_ptr);
|
workhorse.visit_handle(slot_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,10 +181,10 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
{
|
{
|
||||||
u64 start_time = current_micros();
|
u64 start_time = current_micros();
|
||||||
|
|
||||||
card_deck *decks = this->data->decks;
|
card_deck *decks = data->decks;
|
||||||
card_deck *cards = this->data->cards;
|
card_deck *cards = data->cards;
|
||||||
|
|
||||||
cell gen_start_card = addr_to_card(gen->start - this->data->start);
|
cell gen_start_card = addr_to_card(gen->start - data->start);
|
||||||
|
|
||||||
cell first_deck = card_deck_for_address(gen->start);
|
cell first_deck = card_deck_for_address(gen->start);
|
||||||
cell last_deck = card_deck_for_address(gen->end);
|
cell last_deck = card_deck_for_address(gen->end);
|
||||||
|
@ -219,7 +195,7 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
{
|
{
|
||||||
if(decks[deck_index] & mask)
|
if(decks[deck_index] & mask)
|
||||||
{
|
{
|
||||||
this->parent->gc_stats.decks_scanned++;
|
parent->gc_stats.decks_scanned++;
|
||||||
|
|
||||||
cell first_card = first_card_in_deck(deck_index);
|
cell first_card = first_card_in_deck(deck_index);
|
||||||
cell last_card = last_card_in_deck(deck_index);
|
cell last_card = last_card_in_deck(deck_index);
|
||||||
|
@ -228,17 +204,17 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
{
|
{
|
||||||
if(cards[card_index] & mask)
|
if(cards[card_index] & mask)
|
||||||
{
|
{
|
||||||
this->parent->gc_stats.cards_scanned++;
|
parent->gc_stats.cards_scanned++;
|
||||||
|
|
||||||
if(end < card_start_address(card_index))
|
if(end < card_start_address(card_index))
|
||||||
{
|
{
|
||||||
start = gen->starts.find_object_containing_card(card_index - gen_start_card);
|
start = gen->starts.find_object_containing_card(card_index - gen_start_card);
|
||||||
binary_start = start + this->parent->binary_payload_start((object *)start);
|
binary_start = start + parent->binary_payload_start((object *)start);
|
||||||
end = start + ((object *)start)->size();
|
end = start + ((object *)start)->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FACTOR_DEBUG
|
#ifdef FACTOR_DEBUG
|
||||||
assert(addr_to_card(start - this->data->start) <= card_index);
|
assert(addr_to_card(start - data->start) <= card_index);
|
||||||
assert(start < card_end_address(card_index));
|
assert(start < card_end_address(card_index));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -253,7 +229,7 @@ scan_next_object: {
|
||||||
start = gen->next_object_after(start);
|
start = gen->next_object_after(start);
|
||||||
if(start)
|
if(start)
|
||||||
{
|
{
|
||||||
binary_start = start + this->parent->binary_payload_start((object *)start);
|
binary_start = start + parent->binary_payload_start((object *)start);
|
||||||
end = start + ((object *)start)->size();
|
end = start + ((object *)start)->size();
|
||||||
goto scan_next_object;
|
goto scan_next_object;
|
||||||
}
|
}
|
||||||
|
@ -270,24 +246,7 @@ scan_next_object: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
end: this->parent->gc_stats.card_scan_time += (current_micros() - start_time);
|
end: 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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,101 +10,36 @@ full_collector::full_collector(factor_vm *parent_) :
|
||||||
parent_->data->tenured,
|
parent_->data->tenured,
|
||||||
full_policy(parent_)) {}
|
full_policy(parent_)) {}
|
||||||
|
|
||||||
struct stack_frame_marker {
|
struct code_block_marker {
|
||||||
factor_vm *parent;
|
code_heap *code;
|
||||||
full_collector *collector;
|
full_collector *collector;
|
||||||
|
|
||||||
explicit stack_frame_marker(full_collector *collector_) :
|
explicit code_block_marker(code_heap *code_, full_collector *collector_) :
|
||||||
parent(collector_->parent), collector(collector_) {}
|
code(code_), collector(collector_) {}
|
||||||
|
|
||||||
void operator()(stack_frame *frame)
|
code_block *operator()(code_block *compiled)
|
||||||
{
|
{
|
||||||
collector->mark_code_block(parent->frame_code(frame));
|
if(!code->marked_p(compiled))
|
||||||
|
{
|
||||||
|
code->set_marked_p(compiled);
|
||||||
|
collector->trace_literal_references(compiled);
|
||||||
|
}
|
||||||
|
|
||||||
|
return compiled;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mark code blocks executing in currently active stack frames. */
|
|
||||||
void full_collector::mark_active_blocks()
|
|
||||||
{
|
|
||||||
stack_frame_marker marker(this);
|
|
||||||
parent->iterate_active_frames(marker);
|
|
||||||
}
|
|
||||||
|
|
||||||
void full_collector::mark_object_code_block(object *obj)
|
|
||||||
{
|
|
||||||
switch(obj->h.hi_tag())
|
|
||||||
{
|
|
||||||
case WORD_TYPE:
|
|
||||||
{
|
|
||||||
word *w = (word *)obj;
|
|
||||||
if(w->code)
|
|
||||||
mark_code_block(w->code);
|
|
||||||
if(w->profiling)
|
|
||||||
mark_code_block(w->profiling);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case QUOTATION_TYPE:
|
|
||||||
{
|
|
||||||
quotation *q = (quotation *)obj;
|
|
||||||
if(q->code)
|
|
||||||
mark_code_block(q->code);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CALLSTACK_TYPE:
|
|
||||||
{
|
|
||||||
callstack *stack = (callstack *)obj;
|
|
||||||
stack_frame_marker marker(this);
|
|
||||||
parent->iterate_callstack_object(stack,marker);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct callback_tracer {
|
|
||||||
full_collector *collector;
|
|
||||||
|
|
||||||
callback_tracer(full_collector *collector_) : collector(collector_) {}
|
|
||||||
|
|
||||||
void operator()(callback *stub)
|
|
||||||
{
|
|
||||||
collector->mark_code_block(stub->compiled);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void full_collector::trace_callbacks()
|
|
||||||
{
|
|
||||||
callback_tracer tracer(this);
|
|
||||||
parent->callbacks->iterate(tracer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Trace all literals referenced from a code block. Only for aging and nursery collections */
|
|
||||||
void full_collector::trace_literal_references(code_block *compiled)
|
|
||||||
{
|
|
||||||
this->trace_handle(&compiled->owner);
|
|
||||||
this->trace_handle(&compiled->literals);
|
|
||||||
this->trace_handle(&compiled->relocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark all literals referenced from a word XT. Only for tenured
|
|
||||||
collections */
|
|
||||||
void full_collector::mark_code_block(code_block *compiled)
|
|
||||||
{
|
|
||||||
if(!this->code->marked_p(compiled))
|
|
||||||
{
|
|
||||||
this->code->set_marked_p(compiled);
|
|
||||||
trace_literal_references(compiled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void full_collector::mark_reachable_objects()
|
void full_collector::mark_reachable_objects()
|
||||||
{
|
{
|
||||||
|
code_block_marker marker(code,this);
|
||||||
std::vector<object *> *mark_stack = &this->target->mark_stack;
|
std::vector<object *> *mark_stack = &this->target->mark_stack;
|
||||||
|
|
||||||
while(!mark_stack->empty())
|
while(!mark_stack->empty())
|
||||||
{
|
{
|
||||||
object *obj = mark_stack->back();
|
object *obj = mark_stack->back();
|
||||||
mark_stack->pop_back();
|
mark_stack->pop_back();
|
||||||
this->trace_slots(obj);
|
this->trace_slots(obj);
|
||||||
this->mark_object_code_block(obj);
|
parent->visit_object_code_block(obj,marker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,8 +66,9 @@ void factor_vm::collect_full_impl(bool trace_contexts_p)
|
||||||
if(trace_contexts_p)
|
if(trace_contexts_p)
|
||||||
{
|
{
|
||||||
collector.trace_contexts();
|
collector.trace_contexts();
|
||||||
collector.mark_active_blocks();
|
code_block_marker marker(code,&collector);
|
||||||
collector.trace_callbacks();
|
visit_context_code_blocks(marker);
|
||||||
|
visit_callback_code_blocks(marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
collector.mark_reachable_objects();
|
collector.mark_reachable_objects();
|
||||||
|
|
|
@ -28,11 +28,6 @@ struct full_collector : collector<tenured_space,full_policy> {
|
||||||
bool trace_contexts_p;
|
bool trace_contexts_p;
|
||||||
|
|
||||||
full_collector(factor_vm *parent_);
|
full_collector(factor_vm *parent_);
|
||||||
void mark_active_blocks();
|
|
||||||
void mark_object_code_block(object *object);
|
|
||||||
void trace_callbacks();
|
|
||||||
void trace_literal_references(code_block *compiled);
|
|
||||||
void mark_code_block(code_block *compiled);
|
|
||||||
void mark_reachable_objects();
|
void mark_reachable_objects();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -72,11 +72,13 @@ namespace factor
|
||||||
#include "vm.hpp"
|
#include "vm.hpp"
|
||||||
#include "tagged.hpp"
|
#include "tagged.hpp"
|
||||||
#include "local_roots.hpp"
|
#include "local_roots.hpp"
|
||||||
|
#include "slot_visitor.hpp"
|
||||||
#include "collector.hpp"
|
#include "collector.hpp"
|
||||||
#include "copying_collector.hpp"
|
#include "copying_collector.hpp"
|
||||||
#include "nursery_collector.hpp"
|
#include "nursery_collector.hpp"
|
||||||
#include "aging_collector.hpp"
|
#include "aging_collector.hpp"
|
||||||
#include "to_tenured_collector.hpp"
|
#include "to_tenured_collector.hpp"
|
||||||
|
#include "code_block_visitor.hpp"
|
||||||
#include "full_collector.hpp"
|
#include "full_collector.hpp"
|
||||||
#include "callstack.hpp"
|
#include "callstack.hpp"
|
||||||
#include "generic_arrays.hpp"
|
#include "generic_arrays.hpp"
|
||||||
|
|
|
@ -40,7 +40,7 @@ void factor_vm::set_profiling(bool profiling)
|
||||||
tagged<word> word(array_nth(words.untagged(),i));
|
tagged<word> word(array_nth(words.untagged(),i));
|
||||||
if(profiling)
|
if(profiling)
|
||||||
word->counter = tag_fixnum(0);
|
word->counter = tag_fixnum(0);
|
||||||
update_word_xt(word.value());
|
update_word_xt(word.untagged());
|
||||||
}
|
}
|
||||||
|
|
||||||
update_code_heap_words();
|
update_code_heap_words();
|
||||||
|
|
|
@ -338,7 +338,7 @@ void factor_vm::compile_all_words()
|
||||||
if(!word->code || !word->code->optimized_p())
|
if(!word->code || !word->code->optimized_p())
|
||||||
jit_compile_word(word.value(),word->def,false);
|
jit_compile_word(word.value(),word->def,false);
|
||||||
|
|
||||||
update_word_xt(word.value());
|
update_word_xt(word.untagged());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
namespace factor
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename Visitor> struct slot_visitor {
|
||||||
|
factor_vm *parent;
|
||||||
|
Visitor visitor;
|
||||||
|
|
||||||
|
slot_visitor<Visitor>(factor_vm *parent_, Visitor visitor_) :
|
||||||
|
parent(parent_), visitor(visitor_) {}
|
||||||
|
|
||||||
|
void visit_handle(cell *handle)
|
||||||
|
{
|
||||||
|
cell pointer = *handle;
|
||||||
|
|
||||||
|
if(immediate_p(pointer)) return;
|
||||||
|
|
||||||
|
object *untagged = untag<object>(pointer);
|
||||||
|
untagged = visitor.visit_handle(untagged);
|
||||||
|
*handle = RETAG(untagged,TAG(pointer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit_slots(object *ptr)
|
||||||
|
{
|
||||||
|
cell *slot = (cell *)ptr;
|
||||||
|
cell *end = (cell *)((cell)ptr + parent->binary_payload_start(ptr));
|
||||||
|
|
||||||
|
if(slot != end)
|
||||||
|
{
|
||||||
|
slot++;
|
||||||
|
for(; slot < end; slot++) visit_handle(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit_stack_elements(segment *region, cell *top)
|
||||||
|
{
|
||||||
|
for(cell *ptr = (cell *)region->start; ptr <= top; ptr++)
|
||||||
|
visit_handle(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit_registered_locals()
|
||||||
|
{
|
||||||
|
std::vector<cell>::const_iterator iter = parent->gc_locals.begin();
|
||||||
|
std::vector<cell>::const_iterator end = parent->gc_locals.end();
|
||||||
|
|
||||||
|
for(; iter < end; iter++)
|
||||||
|
visit_handle((cell *)(*iter));
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit_registered_bignums()
|
||||||
|
{
|
||||||
|
std::vector<cell>::const_iterator iter = parent->gc_bignums.begin();
|
||||||
|
std::vector<cell>::const_iterator end = parent->gc_bignums.end();
|
||||||
|
|
||||||
|
for(; iter < end; iter++)
|
||||||
|
{
|
||||||
|
cell *handle = (cell *)(*iter);
|
||||||
|
|
||||||
|
if(*handle)
|
||||||
|
*handle = (cell)visitor.visit_handle(*(object **)handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit_roots()
|
||||||
|
{
|
||||||
|
visit_handle(&parent->true_object);
|
||||||
|
visit_handle(&parent->bignum_zero);
|
||||||
|
visit_handle(&parent->bignum_pos_one);
|
||||||
|
visit_handle(&parent->bignum_neg_one);
|
||||||
|
|
||||||
|
visit_registered_locals();
|
||||||
|
visit_registered_bignums();
|
||||||
|
|
||||||
|
for(cell i = 0; i < special_object_count; i++)
|
||||||
|
visit_handle(&parent->special_objects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit_contexts()
|
||||||
|
{
|
||||||
|
context *ctx = parent->ctx;
|
||||||
|
|
||||||
|
while(ctx)
|
||||||
|
{
|
||||||
|
visit_stack_elements(ctx->datastack_region,(cell *)ctx->datastack);
|
||||||
|
visit_stack_elements(ctx->retainstack_region,(cell *)ctx->retainstack);
|
||||||
|
|
||||||
|
visit_handle(&ctx->catchstack_save);
|
||||||
|
visit_handle(&ctx->current_callback_save);
|
||||||
|
|
||||||
|
ctx = ctx->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit_literal_references(code_block *compiled)
|
||||||
|
{
|
||||||
|
visit_handle(&compiled->owner);
|
||||||
|
visit_handle(&compiled->literals);
|
||||||
|
visit_handle(&compiled->relocation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -353,7 +353,7 @@ struct factor_vm
|
||||||
word *allot_word(cell name_, cell vocab_, cell hashcode_);
|
word *allot_word(cell name_, cell vocab_, cell hashcode_);
|
||||||
void primitive_word();
|
void primitive_word();
|
||||||
void primitive_word_xt();
|
void primitive_word_xt();
|
||||||
void update_word_xt(cell w_);
|
void update_word_xt(word *w_);
|
||||||
void primitive_optimized_p();
|
void primitive_optimized_p();
|
||||||
void primitive_wrapper();
|
void primitive_wrapper();
|
||||||
|
|
||||||
|
@ -485,6 +485,11 @@ struct factor_vm
|
||||||
code_block *allot_code_block(cell size, code_block_type type);
|
code_block *allot_code_block(cell size, code_block_type type);
|
||||||
code_block *add_code_block(code_block_type type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_);
|
code_block *add_code_block(code_block_type type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_);
|
||||||
|
|
||||||
|
//code_block_visitor
|
||||||
|
template<typename Visitor> void visit_object_code_block(object *obj, Visitor visitor);
|
||||||
|
template<typename Visitor> void visit_context_code_blocks(Visitor visitor);
|
||||||
|
template<typename Visitor> void visit_callback_code_blocks(Visitor visitor);
|
||||||
|
|
||||||
//code heap
|
//code heap
|
||||||
inline void check_code_pointer(cell ptr)
|
inline void check_code_pointer(cell ptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,7 @@ word *factor_vm::allot_word(cell name_, cell vocab_, cell hashcode_)
|
||||||
new_word->code = NULL;
|
new_word->code = NULL;
|
||||||
|
|
||||||
jit_compile_word(new_word.value(),new_word->def,true);
|
jit_compile_word(new_word.value(),new_word->def,true);
|
||||||
update_word_xt(new_word.value());
|
update_word_xt(new_word.untagged());
|
||||||
|
|
||||||
if(profiling_p)
|
if(profiling_p)
|
||||||
relocate_code_block(new_word->profiling);
|
relocate_code_block(new_word->profiling);
|
||||||
|
@ -59,7 +59,7 @@ void factor_vm::primitive_word_xt()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocates memory */
|
/* Allocates memory */
|
||||||
void factor_vm::update_word_xt(cell w_)
|
void factor_vm::update_word_xt(word *w_)
|
||||||
{
|
{
|
||||||
gc_root<word> w(w_,this);
|
gc_root<word> w(w_,this);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue