vm: refactoring garbage collector

db4
Slava Pestov 2009-10-05 22:16:08 -05:00
parent f800285327
commit bae2240f62
8 changed files with 314 additions and 330 deletions

View File

@ -298,26 +298,6 @@ void factor_vm::update_literal_references(code_block *compiled)
}
}
/* Copy all literals referenced from a code block to newspace. Only for
aging and nursery collections */
void factor_vm::trace_literal_references(code_block *compiled)
{
if(current_gc->collecting_gen >= compiled->last_scan)
{
if(current_gc->collecting_accumulation_gen_p())
compiled->last_scan = current_gc->collecting_gen;
else
compiled->last_scan = current_gc->collecting_gen + 1;
trace_handle(&compiled->literals);
trace_handle(&compiled->relocation);
/* once we finish tracing, re-visit this code block and update
literals */
current_gc->dirty_code_blocks.insert(compiled);
}
}
/* Compute an address to store at a relocation */
void factor_vm::relocate_code_block_step(relocation_entry rel, cell index, code_block *compiled)
{
@ -377,74 +357,6 @@ void factor_vm::check_code_address(cell address)
#endif
}
/* Update references to words. This is done after a new code block
is added to the heap. */
/* Mark all literals referenced from a word XT. Only for tenured
collections */
void factor_vm::mark_code_block(code_block *compiled)
{
check_code_address((cell)compiled);
code->mark_block(compiled);
trace_handle(&compiled->literals);
trace_handle(&compiled->relocation);
}
struct stack_frame_marker {
factor_vm *myvm;
explicit stack_frame_marker(factor_vm *myvm_) : myvm(myvm_) {}
void operator()(stack_frame *frame)
{
myvm->mark_code_block(myvm->frame_code(frame));
}
};
/* Mark code blocks executing in currently active stack frames. */
void factor_vm::mark_active_blocks(context *stacks)
{
if(current_gc->collecting_tenured_p())
{
cell top = (cell)stacks->callstack_top;
cell bottom = (cell)stacks->callstack_bottom;
stack_frame_marker marker(this);
iterate_callstack(top,bottom,marker);
}
}
void factor_vm::mark_object_code_block(object *object)
{
switch(object->h.hi_tag())
{
case WORD_TYPE:
{
word *w = (word *)object;
if(w->code)
mark_code_block(w->code);
if(w->profiling)
mark_code_block(w->profiling);
break;
}
case QUOTATION_TYPE:
{
quotation *q = (quotation *)object;
if(q->code)
mark_code_block(q->code);
break;
}
case CALLSTACK_TYPE:
{
callstack *stack = (callstack *)object;
stack_frame_marker marker(this);
iterate_callstack_object(stack,marker);
break;
}
}
}
struct code_block_relocator {
factor_vm *myvm;

View File

@ -28,31 +28,6 @@ void factor_vm::jit_compile_word(cell word_, cell def_, bool relocate)
if(word->pic_tail_def != F) jit_compile(word->pic_tail_def,relocate);
}
struct literal_reference_tracer {
factor_vm *myvm;
explicit literal_reference_tracer(factor_vm *myvm_) : myvm(myvm_) {}
void operator()(code_block *compiled)
{
myvm->trace_literal_references(compiled);
}
};
/* Copy literals referenced from all code blocks to newspace. Only for
aging and nursery collections */
void factor_vm::trace_code_heap_roots()
{
code_heap_scans++;
literal_reference_tracer tracer(this);
iterate_code_heap(tracer);
if(current_gc->collecting_accumulation_gen_p())
last_code_heap_scan = current_gc->collecting_gen;
else
last_code_heap_scan = current_gc->collecting_gen + 1;
}
/* Update pointers to words referenced from all code blocks. Only after
defining a new word. */
void factor_vm::update_code_heap_words()

View File

@ -40,48 +40,31 @@ object *factor_vm::copy_object_impl(object *untagged)
return newpointer;
}
bool factor_vm::should_copy_p(object *untagged)
{
if(in_zone(current_gc->newspace,untagged))
return false;
if(current_gc->collecting_tenured_p())
return true;
else if(data->have_aging_p() && current_gc->collecting_gen == data->aging())
return !in_zone(&data->generations[data->tenured()],untagged);
else if(current_gc->collecting_nursery_p())
return in_zone(&nursery,untagged);
else
{
critical_error("Bug in should_copy_p",(cell)untagged);
return false;
}
}
/* Follow a chain of forwarding pointers */
object *factor_vm::resolve_forwarding(object *untagged)
template<typename Strategy> object *factor_vm::resolve_forwarding(object *untagged, Strategy &strategy)
{
check_data_pointer(untagged);
/* is there another forwarding pointer? */
if(untagged->h.forwarding_pointer_p())
return resolve_forwarding(untagged->h.forwarding_pointer());
return resolve_forwarding(untagged->h.forwarding_pointer(),strategy);
/* we've found the destination */
else
{
untagged->h.check_header();
if(should_copy_p(untagged))
if(strategy.should_copy_p(untagged))
return copy_object_impl(untagged);
else
return untagged;
}
}
template<typename Type> Type *factor_vm::copy_untagged_object(Type *untagged)
template<typename Type, typename Strategy> Type *factor_vm::copy_untagged_object(Type *untagged, Strategy &strategy)
{
check_data_pointer(untagged);
if(untagged->h.forwarding_pointer_p())
untagged = (Type *)resolve_forwarding(untagged->h.forwarding_pointer());
untagged = (Type *)resolve_forwarding(untagged->h.forwarding_pointer(),strategy);
else
{
untagged->h.check_header();
@ -91,12 +74,12 @@ template<typename Type> Type *factor_vm::copy_untagged_object(Type *untagged)
return untagged;
}
cell factor_vm::copy_object(cell pointer)
template<typename Strategy> cell factor_vm::copy_object(cell pointer, Strategy &strategy)
{
return RETAG(copy_untagged_object(untag<object>(pointer)),TAG(pointer));
return RETAG(copy_untagged_object(untag<object>(pointer),strategy),TAG(pointer));
}
void factor_vm::trace_handle(cell *handle)
template<typename Strategy> void factor_vm::trace_handle(cell *handle, Strategy &strategy)
{
cell pointer = *handle;
@ -104,13 +87,12 @@ void factor_vm::trace_handle(cell *handle)
{
object *obj = untag<object>(pointer);
check_data_pointer(obj);
if(should_copy_p(obj))
*handle = copy_object(pointer);
if(strategy.should_copy_p(obj))
*handle = copy_object(pointer,strategy);
}
}
/* Scan all the objects in the card */
void factor_vm::trace_card(card *ptr, cell gen, cell here)
template<typename Strategy> void factor_vm::trace_card(card *ptr, cell gen, cell here, Strategy &strategy)
{
cell card_scan = card_to_addr(ptr) + card_offset(ptr);
cell card_end = card_to_addr(ptr + 1);
@ -118,12 +100,12 @@ void factor_vm::trace_card(card *ptr, cell gen, cell here)
if(here < card_end)
card_end = here;
copy_reachable_objects(card_scan,&card_end);
strategy.copy_reachable_objects(card_scan,&card_end);
cards_scanned++;
}
void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmask)
template<typename Strategy> void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmask, Strategy &strategy)
{
card *first_card = deck_to_card(deck);
card *last_card = deck_to_card(deck + 1);
@ -144,7 +126,7 @@ void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmas
{
if(ptr[card] & mask)
{
trace_card(&ptr[card],gen,here);
trace_card(&ptr[card],gen,here,strategy);
ptr[card] &= ~unmask;
}
}
@ -155,7 +137,7 @@ void factor_vm::trace_card_deck(card_deck *deck, cell gen, card mask, card unmas
}
/* Copy all newspace objects referenced from marked cards to the destination */
void factor_vm::trace_generation_cards(cell gen)
template<typename Strategy> void factor_vm::trace_generation_cards(cell gen, Strategy &strategy)
{
card_deck *first_deck = addr_to_deck(data->generations[gen].start);
card_deck *last_deck = addr_to_deck(data->generations[gen].end);
@ -214,7 +196,7 @@ void factor_vm::trace_generation_cards(cell gen)
{
if(*ptr & mask)
{
trace_card_deck(ptr,gen,mask,unmask);
trace_card_deck(ptr,gen,mask,unmask,strategy);
*ptr &= ~unmask;
}
}
@ -222,36 +204,36 @@ void factor_vm::trace_generation_cards(cell gen)
/* Scan cards in all generations older than the one being collected, copying
old->new references */
void factor_vm::trace_cards()
template<typename Strategy> void factor_vm::trace_cards(Strategy &strategy)
{
u64 start = current_micros();
cell i;
for(i = current_gc->collecting_gen + 1; i < data->gen_count; i++)
trace_generation_cards(i);
trace_generation_cards(i,strategy);
card_scan_time += (current_micros() - start);
}
/* Copy all tagged pointers in a range of memory */
void factor_vm::trace_stack_elements(segment *region, cell top)
template<typename Strategy> void factor_vm::trace_stack_elements(segment *region, cell top, Strategy &strategy)
{
cell ptr = region->start;
for(; ptr <= top; ptr += sizeof(cell))
trace_handle((cell*)ptr);
trace_handle((cell*)ptr,strategy);
}
void factor_vm::trace_registered_locals()
template<typename Strategy> void factor_vm::trace_registered_locals(Strategy &strategy)
{
std::vector<cell>::const_iterator iter = gc_locals.begin();
std::vector<cell>::const_iterator end = gc_locals.end();
for(; iter < end; iter++)
trace_handle((cell *)(*iter));
trace_handle((cell *)(*iter),strategy);
}
void factor_vm::trace_registered_bignums()
template<typename Strategy> void factor_vm::trace_registered_bignums(Strategy &strategy)
{
std::vector<cell>::const_iterator iter = gc_bignums.begin();
std::vector<cell>::const_iterator end = gc_bignums.end();
@ -264,8 +246,8 @@ void factor_vm::trace_registered_bignums()
if(pointer)
{
check_data_pointer(pointer);
if(should_copy_p(pointer))
*handle = copy_untagged_object(pointer);
if(strategy.should_copy_p(pointer))
*handle = copy_untagged_object(pointer,strategy);
#ifdef FACTOR_DEBUG
assert((*handle)->h.hi_tag() == BIGNUM_TYPE);
#endif
@ -275,41 +257,156 @@ void factor_vm::trace_registered_bignums()
/* Copy roots over at the start of GC, namely various constants, stacks,
the user environment and extra roots registered by local_roots.hpp */
void factor_vm::trace_roots()
template<typename Strategy> void factor_vm::trace_roots(Strategy &strategy)
{
trace_handle(&T);
trace_handle(&bignum_zero);
trace_handle(&bignum_pos_one);
trace_handle(&bignum_neg_one);
trace_handle(&T,strategy);
trace_handle(&bignum_zero,strategy);
trace_handle(&bignum_pos_one,strategy);
trace_handle(&bignum_neg_one,strategy);
trace_registered_locals();
trace_registered_bignums();
trace_registered_locals(strategy);
trace_registered_bignums(strategy);
int i;
for(i = 0; i < USER_ENV; i++)
trace_handle(&userenv[i]);
trace_handle(&userenv[i],strategy);
}
void factor_vm::trace_contexts()
template<typename Strategy> struct stack_frame_marker {
factor_vm *myvm;
Strategy &strategy;
explicit stack_frame_marker(factor_vm *myvm_, Strategy &strategy_) :
myvm(myvm_), strategy(strategy_) {}
void operator()(stack_frame *frame)
{
myvm->mark_code_block(myvm->frame_code(frame),strategy);
}
};
/* Mark code blocks executing in currently active stack frames. */
template<typename Strategy> void factor_vm::mark_active_blocks(context *stacks, Strategy &strategy)
{
if(current_gc->collecting_tenured_p())
{
cell top = (cell)stacks->callstack_top;
cell bottom = (cell)stacks->callstack_bottom;
stack_frame_marker<Strategy> marker(this,strategy);
iterate_callstack(top,bottom,marker);
}
}
template<typename Strategy> void factor_vm::mark_object_code_block(object *object, Strategy &strategy)
{
switch(object->h.hi_tag())
{
case WORD_TYPE:
{
word *w = (word *)object;
if(w->code)
mark_code_block(w->code,strategy);
if(w->profiling)
mark_code_block(w->profiling,strategy);
break;
}
case QUOTATION_TYPE:
{
quotation *q = (quotation *)object;
if(q->code)
mark_code_block(q->code,strategy);
break;
}
case CALLSTACK_TYPE:
{
callstack *stack = (callstack *)object;
stack_frame_marker<Strategy> marker(this,strategy);
iterate_callstack_object(stack,marker);
break;
}
}
}
template<typename Strategy> void factor_vm::trace_contexts(Strategy &strategy)
{
save_stacks();
context *stacks = stack_chain;
while(stacks)
{
trace_stack_elements(stacks->datastack_region,stacks->datastack);
trace_stack_elements(stacks->retainstack_region,stacks->retainstack);
trace_stack_elements(stacks->datastack_region,stacks->datastack,strategy);
trace_stack_elements(stacks->retainstack_region,stacks->retainstack,strategy);
trace_handle(&stacks->catchstack_save);
trace_handle(&stacks->current_callback_save);
trace_handle(&stacks->catchstack_save,strategy);
trace_handle(&stacks->current_callback_save,strategy);
mark_active_blocks(stacks);
mark_active_blocks(stacks,strategy);
stacks = stacks->next;
}
}
cell factor_vm::copy_next_from_nursery(cell scan)
/* Copy all literals referenced from a code block to newspace. Only for
aging and nursery collections */
template<typename Strategy> void factor_vm::trace_literal_references(code_block *compiled, Strategy &strategy)
{
if(current_gc->collecting_gen >= compiled->last_scan)
{
if(current_gc->collecting_accumulation_gen_p())
compiled->last_scan = current_gc->collecting_gen;
else
compiled->last_scan = current_gc->collecting_gen + 1;
trace_handle(&compiled->literals,strategy);
trace_handle(&compiled->relocation,strategy);
/* once we finish tracing, re-visit this code block and update
literals */
current_gc->dirty_code_blocks.insert(compiled);
}
}
template<typename Strategy> struct literal_reference_tracer {
factor_vm *myvm;
Strategy strategy;
explicit literal_reference_tracer(factor_vm *myvm_, Strategy &strategy_) :
myvm(myvm_), strategy(strategy_) {}
void operator()(code_block *compiled)
{
myvm->trace_literal_references(compiled,strategy);
}
};
/* Copy literals referenced from all code blocks to newspace. Only for
aging and nursery collections */
template<typename Strategy> void factor_vm::trace_code_heap_roots(Strategy &strategy)
{
literal_reference_tracer<Strategy> tracer(this,strategy);
iterate_code_heap(tracer);
if(current_gc->collecting_accumulation_gen_p())
last_code_heap_scan = current_gc->collecting_gen;
else
last_code_heap_scan = current_gc->collecting_gen + 1;
code_heap_scans++;
}
/* Mark all literals referenced from a word XT. Only for tenured
collections */
template<typename Strategy> void factor_vm::mark_code_block(code_block *compiled, Strategy &strategy)
{
check_code_address((cell)compiled);
code->mark_block(compiled);
trace_handle(&compiled->literals,strategy);
trace_handle(&compiled->relocation,strategy);
}
template<typename Strategy> cell factor_vm::copy_next(cell scan, Strategy &strategy)
{
cell *obj = (cell *)scan;
cell *end = (cell *)(scan + binary_payload_start((object *)scan));
@ -318,113 +415,20 @@ cell factor_vm::copy_next_from_nursery(cell scan)
{
obj++;
cell nursery_start = nursery.start;
cell nursery_end = nursery.end;
for(; obj < end; obj++)
{
cell pointer = *obj;
if(!immediate_p(pointer))
{
check_data_pointer((object *)pointer);
if(pointer >= nursery_start && pointer < nursery_end)
*obj = copy_object(pointer);
}
}
trace_handle(obj,strategy);
}
return scan + untagged_object_size((object *)scan);
}
cell factor_vm::copy_next_from_aging(cell scan)
{
cell *obj = (cell *)scan;
cell *end = (cell *)(scan + binary_payload_start((object *)scan));
if(obj != end)
{
obj++;
cell tenured_start = data->generations[data->tenured()].start;
cell tenured_end = data->generations[data->tenured()].end;
cell newspace_start = current_gc->newspace->start;
cell newspace_end = current_gc->newspace->end;
for(; obj < end; obj++)
{
cell pointer = *obj;
if(!immediate_p(pointer))
{
check_data_pointer((object *)pointer);
if(!(pointer >= newspace_start && pointer < newspace_end)
&& !(pointer >= tenured_start && pointer < tenured_end))
*obj = copy_object(pointer);
}
}
}
return scan + untagged_object_size((object *)scan);
}
cell factor_vm::copy_next_from_tenured(cell scan)
{
cell *obj = (cell *)scan;
cell *end = (cell *)(scan + binary_payload_start((object *)scan));
if(obj != end)
{
obj++;
cell newspace_start = current_gc->newspace->start;
cell newspace_end = current_gc->newspace->end;
for(; obj < end; obj++)
{
cell pointer = *obj;
if(!immediate_p(pointer))
{
check_data_pointer((object *)pointer);
if(!(pointer >= newspace_start && pointer < newspace_end))
*obj = copy_object(pointer);
}
}
}
mark_object_code_block((object *)scan);
return scan + untagged_object_size((object *)scan);
}
void factor_vm::copy_reachable_objects(cell scan, cell *end)
{
if(current_gc->collecting_nursery_p())
{
while(scan < *end)
scan = copy_next_from_nursery(scan);
}
else if(data->have_aging_p() && current_gc->collecting_gen == data->aging())
{
while(scan < *end)
scan = copy_next_from_aging(scan);
}
else if(current_gc->collecting_tenured_p())
{
while(scan < *end)
scan = copy_next_from_tenured(scan);
}
}
void factor_vm::update_code_heap_roots()
template<typename Strategy> void factor_vm::update_code_heap_roots(Strategy &strategy)
{
if(current_gc->collecting_gen >= last_code_heap_scan)
{
code_heap_scans++;
trace_code_heap_roots();
trace_code_heap_roots(strategy);
if(current_gc->collecting_accumulation_gen_p())
last_code_heap_scan = current_gc->collecting_gen;
@ -498,6 +502,120 @@ void factor_vm::begin_gc(cell requested_bytes)
}
}
struct nursery_collector
{
factor_vm *myvm;
explicit nursery_collector(factor_vm *myvm_) : myvm(myvm_) {}
bool should_copy_p(object *untagged)
{
if(myvm->current_gc->newspace->contains_p(untagged))
return false;
else
return myvm->nursery.contains_p(untagged);
}
void copy_reachable_objects(cell scan, cell *end)
{
while(scan < myvm->current_gc->newspace->here)
scan = myvm->copy_next(scan,*this);
}
};
void factor_vm::collect_nursery()
{
nursery_collector collector(this);
cell scan = current_gc->newspace->here;
trace_roots(collector);
trace_contexts(collector);
trace_cards(collector);
if(current_gc->collecting_gen >= last_code_heap_scan)
update_code_heap_roots(collector);
collector.copy_reachable_objects(scan,&current_gc->newspace->here);
update_dirty_code_blocks();
}
struct aging_collector
{
factor_vm *myvm;
explicit aging_collector(factor_vm *myvm_) : myvm(myvm_) {}
bool should_copy_p(object *untagged)
{
if(myvm->current_gc->newspace->contains_p(untagged))
return false;
else
return !myvm->data->generations[myvm->data->tenured()].contains_p(untagged);
}
void copy_reachable_objects(cell scan, cell *end)
{
while(scan < myvm->current_gc->newspace->here)
scan = myvm->copy_next(scan,*this);
}
};
void factor_vm::collect_aging()
{
aging_collector collector(this);
cell scan = current_gc->newspace->here;
trace_roots(collector);
trace_contexts(collector);
trace_cards(collector);
if(current_gc->collecting_gen >= last_code_heap_scan)
update_code_heap_roots(collector);
collector.copy_reachable_objects(scan,&current_gc->newspace->here);
update_dirty_code_blocks();
}
struct tenured_collector
{
factor_vm *myvm;
explicit tenured_collector(factor_vm *myvm_) : myvm(myvm_) {}
bool should_copy_p(object *untagged)
{
return !myvm->current_gc->newspace->contains_p(untagged);
}
void copy_reachable_objects(cell scan, cell *end)
{
while(scan < myvm->current_gc->newspace->here)
{
myvm->mark_object_code_block(myvm->untag<object>(scan),*this);
scan = myvm->copy_next(scan,*this);
}
}
};
void factor_vm::collect_tenured(bool trace_contexts_)
{
tenured_collector collector(this);
cell scan = current_gc->newspace->here;
trace_roots(collector);
if(trace_contexts_)
trace_contexts(collector);
collector.copy_reachable_objects(scan,&current_gc->newspace->here);
free_unmarked_code_blocks();
}
void factor_vm::end_gc()
{
gc_stats *s = &stats[current_gc->collecting_gen];
@ -572,40 +690,13 @@ void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_
begin_gc(requested_bytes);
/* Initialize chase pointer */
cell scan = current_gc->newspace->here;
if(current_gc->collecting_nursery_p())
collect_nursery();
else if(current_gc->collecting_aging_p())
collect_aging();
else if(current_gc->collecting_tenured_p())
collect_tenured(trace_contexts_);
/* Trace objects referenced from global environment */
trace_roots();
/* Trace objects referenced from stacks, unless we're doing
save-image-and-exit in which case stack objects are irrelevant */
if(trace_contexts_) trace_contexts();
/* Trace objects referenced from older generations */
trace_cards();
/* On minor GC, trace code heap roots if it has pointers
to this generation or younger. Otherwise, tracing data heap objects
will mark all reachable code blocks, and we free the unmarked ones
after. */
if(!current_gc->collecting_tenured_p() && current_gc->collecting_gen >= last_code_heap_scan)
{
update_code_heap_roots();
}
/* do some copying -- this is where most of the work is done */
copy_reachable_objects(scan,&current_gc->newspace->here);
/* On minor GC, update literal references in code blocks, now that all
data heap objects are in their final location. On a major GC,
free all code blocks that did not get marked during tracing. */
if(current_gc->collecting_tenured_p())
free_unmarked_code_blocks();
else
update_dirty_code_blocks();
/* GC completed without any generations filling up; finish up */
end_gc();
delete current_gc;

View File

@ -44,6 +44,11 @@ struct gc_state {
return collecting_gen == data->nursery();
}
inline bool collecting_aging_p()
{
return data->have_aging_p() && collecting_gen == data->aging();
}
inline bool collecting_tenured_p()
{
return collecting_gen == data->tenured();

View File

@ -17,6 +17,11 @@ struct zone {
end = start_ + size_;
return end;
}
inline bool contains_p(object *pointer)
{
return (cell)pointer >= start && (cell)pointer < end;
}
};
struct data_heap {
@ -57,9 +62,4 @@ struct data_heap {
static const cell max_gen_count = 3;
inline static bool in_zone(zone *z, object *pointer)
{
return (cell)pointer >= z->start && (cell)pointer < z->end;
}
}

View File

@ -28,7 +28,7 @@ template<typename Array> Array *factor_vm::allot_array_internal(cell capacity)
template<typename Array> bool factor_vm::reallot_array_in_place_p(Array *array, cell capacity)
{
return in_zone(&nursery,array) && capacity <= array_capacity(array);
return nursery.contains_p(array) && capacity <= array_capacity(array);
}
template<typename Array> Array *factor_vm::reallot_array(Array *array_, cell capacity)

View File

@ -108,8 +108,8 @@ void factor_vm::primitive_string()
bool factor_vm::reallot_string_in_place_p(string *str, cell capacity)
{
return in_zone(&nursery,str)
&& (str->aux == F || in_zone(&nursery,untag<byte_array>(str->aux)))
return nursery.contains_p(str)
&& (str->aux == F || nursery.contains_p(untag<byte_array>(str->aux)))
&& capacity <= string_capacity(str);
}

View File

@ -245,28 +245,34 @@ struct factor_vm
void init_data_gc();
object *copy_untagged_object_impl(object *pointer, cell size);
object *copy_object_impl(object *untagged);
bool should_copy_p(object *untagged);
object *resolve_forwarding(object *untagged);
template<typename Type> Type *copy_untagged_object(Type *untagged);
cell copy_object(cell pointer);
void trace_handle(cell *handle);
void trace_card(card *ptr, cell gen, cell here);
void trace_card_deck(card_deck *deck, cell gen, card mask, card unmask);
void trace_generation_cards(cell gen);
void trace_cards();
void trace_stack_elements(segment *region, cell top);
void trace_registered_locals();
void trace_registered_bignums();
void trace_roots();
void trace_contexts();
void update_code_heap_roots();
cell copy_next_from_nursery(cell scan);
cell copy_next_from_aging(cell scan);
cell copy_next_from_tenured(cell scan);
void copy_reachable_objects(cell scan, cell *end);
template<typename Strategy> object *resolve_forwarding(object *untagged, Strategy &strategy);
template<typename Type, typename Strategy> Type *copy_untagged_object(Type *untagged, Strategy &strategy);
template<typename Strategy> cell copy_object(cell pointer, Strategy &strategy);
template<typename Strategy> void trace_handle(cell *handle, Strategy &strategy);
template<typename Strategy> void trace_card(card *ptr, cell gen, cell here, Strategy &strategy);
template<typename Strategy> void trace_card_deck(card_deck *deck, cell gen, card mask, card unmask, Strategy &strategy);
template<typename Strategy> void trace_generation_cards(cell gen, Strategy &strategy);
template<typename Strategy> void trace_cards(Strategy &strategy);
template<typename Strategy> void trace_stack_elements(segment *region, cell top, Strategy &strategy);
template<typename Strategy> void trace_registered_locals(Strategy &strategy);
template<typename Strategy> void trace_registered_bignums(Strategy &strategy);
template<typename Strategy> void trace_roots(Strategy &strategy);
template<typename Strategy> void mark_active_blocks(context *stacks, Strategy &strategy);
template<typename Strategy> void trace_contexts(Strategy &strategy);
template<typename Strategy> void trace_literal_references(code_block *compiled, Strategy &strategy);
template<typename Strategy> void trace_code_heap_roots(Strategy &strategy);
template<typename Strategy> void mark_code_block(code_block *compiled, Strategy &strategy);
template<typename Strategy> void mark_object_code_block(object *object, Strategy &strategy);
template<typename Strategy> cell copy_next(cell scan, Strategy &strategy);
template<typename Strategy> void update_code_heap_roots(Strategy &strategy);
void free_unmarked_code_blocks();
void update_dirty_code_blocks();
void begin_gc(cell requested_bytes);
void collect_nursery();
void collect_aging();
void collect_tenured(bool trace_contexts_);
void end_gc();
void garbage_collection(cell gen, bool growing_data_heap, bool trace_contexts, cell requested_bytes);
void gc();
@ -516,13 +522,9 @@ struct factor_vm
void store_address_masked(cell *ptr, fixnum value, cell mask, fixnum shift);
void store_address_in_code_block(cell klass, cell offset, fixnum absolute_value);
void update_literal_references(code_block *compiled);
void trace_literal_references(code_block *compiled);
void relocate_code_block_step(relocation_entry rel, cell index, code_block *compiled);
void update_word_references(code_block *compiled);
void check_code_address(cell address);
void mark_code_block(code_block *compiled);
void mark_active_blocks(context *stacks);
void mark_object_code_block(object *object);
void relocate_code_block(code_block *compiled);
void fixup_labels(array *labels, code_block *compiled);
code_block *allot_code_block(cell size);
@ -539,7 +541,6 @@ struct factor_vm
void init_code_heap(cell size);
bool in_code_heap_p(cell ptr);
void jit_compile_word(cell word_, cell def_, bool relocate);
void trace_code_heap_roots();
void update_code_heap_words();
void primitive_modify_code_heap();
void primitive_code_room();