gc_state::~gc_state() { }
-template<typename Strategy> object *factor_vm::resolve_forwarding(object *untagged, Strategy &strategy)
-{
- check_data_pointer(untagged);
-
- /* 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;
-}
-
-template<typename Strategy> void factor_vm::trace_handle(cell *handle, Strategy &strategy)
-{
- cell pointer = *handle;
-
- if(!immediate_p(pointer))
- {
- object *untagged = untag<object>(pointer);
- if(strategy.should_copy_p(untagged))
- {
- object *forwarding = resolve_forwarding(untagged,strategy);
-
- if(forwarding == untagged)
- untagged = strategy.copy_object(untagged);
- else if(strategy.should_copy_p(forwarding))
- untagged = strategy.copy_object(forwarding);
- else
- untagged = forwarding;
-
- *handle = RETAG(untagged,TAG(pointer));
- }
- }
-}
-
-template<typename Strategy> void factor_vm::trace_slots(object *ptr, Strategy &strategy)
-{
- cell *slot = (cell *)ptr;
- cell *end = (cell *)((cell)ptr + binary_payload_start(ptr));
-
- if(slot != end)
- {
- slot++;
- for(; slot < end; slot++) trace_handle(slot,strategy);
- }
-}
-
-template<typename Strategy> object *factor_vm::promote_object(object *untagged, Strategy &strategy)
-{
- cell size = untagged_object_size(untagged);
- object *newpointer = strategy.allot(size);
- if(!newpointer) longjmp(current_gc->gc_unwind,1);
-
- generation_statistics *s = &gc_stats.generations[current_gc->collecting_gen];
- s->object_count++;
- s->bytes_copied += size;
-
- memcpy(newpointer,untagged,size);
- untagged->h.forward_to(newpointer);
-
- return newpointer;
-}
-
-template<typename Strategy> void factor_vm::trace_card(card *ptr, old_space *gen, Strategy &strategy)
-{
- cell card_start = card_to_addr(ptr);
- cell card_scan = card_start + gen->card_offset(card_start);
- cell card_end = card_to_addr(ptr + 1);
-
- if(gen->here < card_end) card_end = gen->here;
-
- strategy.copy_reachable_objects(card_scan,&card_end);
-
- gc_stats.cards_scanned++;
-}
-
-template<typename Strategy> void factor_vm::trace_card_deck(card_deck *deck, old_space *gen, card mask, card unmask, Strategy &strategy)
-{
- card *first_card = deck_to_card(deck);
- card *last_card = deck_to_card(deck + 1);
-
- u32 *quad_ptr;
- u32 quad_mask = mask | (mask << 8) | (mask << 16) | (mask << 24);
-
- for(quad_ptr = (u32 *)first_card; quad_ptr < (u32 *)last_card; quad_ptr++)
- {
- if(*quad_ptr & quad_mask)
- {
- card *ptr = (card *)quad_ptr;
-
- int card;
- for(card = 0; card < 4; card++)
- {
- if(ptr[card] & mask)
- {
- trace_card(&ptr[card],gen,strategy);
- ptr[card] &= ~unmask;
- }
- }
- }
- }
-
- gc_stats.decks_scanned++;
-}
-
-/* Trace all objects referenced from marked cards */
-template<typename Strategy> void factor_vm::trace_cards(cell gen, old_space *z, Strategy &strategy)
-{
- u64 start_time = current_micros();
-
- card_deck *first_deck = addr_to_deck(z->start);
- card_deck *last_deck = addr_to_deck(z->end);
-
- card mask, unmask;
-
- /* if we are collecting the nursery, we care about old->nursery pointers
- but not old->aging pointers */
- if(current_gc->collecting_nursery_p())
- {
- mask = card_points_to_nursery;
-
- /* after the collection, no old->nursery pointers remain
- anywhere, but old->aging pointers might remain in tenured
- space */
- if(gen == tenured_gen)
- unmask = card_points_to_nursery;
- /* after the collection, all cards in aging space can be
- cleared */
- else if(gen == aging_gen)
- unmask = card_mark_mask;
- else
- {
- critical_error("bug in trace_generation_cards",gen);
- return;
- }
- }
- /* if we are collecting aging space into tenured space, we care about
- all old->nursery and old->aging pointers. no old->aging pointers can
- remain */
- else if(current_gc->collecting_aging_p())
- {
- if(current_gc->collecting_aging_again)
- {
- mask = card_points_to_aging;
- unmask = card_mark_mask;
- }
- /* after we collect aging space into the aging semispace, no
- old->nursery pointers remain but tenured space might still have
- pointers to aging space. */
- else
- {
- mask = card_points_to_aging;
- unmask = card_points_to_nursery;
- }
- }
- else
- {
- critical_error("bug in trace_generation_cards",gen);
- return;
- }
-
- card_deck *ptr;
-
- for(ptr = first_deck; ptr < last_deck; ptr++)
- {
- if(*ptr & mask)
- {
- trace_card_deck(ptr,z,mask,unmask,strategy);
- *ptr &= ~unmask;
- }
- }
-
- gc_stats.card_scan_time += (current_micros() - start_time);
-}
-
-/* Copy all tagged pointers in a range of memory */
-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,strategy);
-}
-
-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),strategy);
-}
-
-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();
-
- for(; iter < end; iter++)
- {
- cell *handle = (cell *)(*iter);
-
- if(*handle)
- {
- *handle |= BIGNUM_TYPE;
- trace_handle(handle,strategy);
- *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 */
-template<typename Strategy> void factor_vm::trace_roots(Strategy &strategy)
-{
- trace_handle(&T,strategy);
- trace_handle(&bignum_zero,strategy);
- trace_handle(&bignum_pos_one,strategy);
- trace_handle(&bignum_neg_one,strategy);
-
- trace_registered_locals(strategy);
- trace_registered_bignums(strategy);
-
- int i;
- for(i = 0; i < USER_ENV; i++)
- trace_handle(&userenv[i],strategy);
-}
-
-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,strategy);
- trace_stack_elements(stacks->retainstack_region,stacks->retainstack,strategy);
-
- trace_handle(&stacks->catchstack_save,strategy);
- trace_handle(&stacks->current_callback_save,strategy);
-
- mark_active_blocks(stacks,strategy);
-
- stacks = stacks->next;
- }
-}
-
-/* Trace all literals referenced from a code block. Only for aging and nursery collections */
-template<typename Strategy> void factor_vm::trace_literal_references(code_block *compiled, Strategy &strategy)
-{
- trace_handle(&compiled->owner,strategy);
- trace_handle(&compiled->literals,strategy);
- trace_handle(&compiled->relocation,strategy);
-}
-
-/* Trace literals referenced from all code blocks. Only for aging and nursery collections */
-template<typename Strategy> void factor_vm::trace_code_heap_roots(Strategy &strategy)
-{
- if(current_gc->collecting_gen >= code->youngest_referenced_generation)
- {
- unordered_map<code_block *,cell>::const_iterator iter = code->remembered_set.begin();
- unordered_map<code_block *,cell>::const_iterator end = code->remembered_set.end();
-
- for(; iter != end; iter++)
- {
- if(current_gc->collecting_gen >= iter->second)
- trace_literal_references(iter->first,strategy);
- }
-
- gc_stats.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_literal_references(compiled,strategy);
-}
-
struct literal_and_word_reference_updater {
factor_vm *myvm;
code->youngest_referenced_generation = gen;
}
-template<typename Strategy>
-cheney_collector<Strategy>::cheney_collector(factor_vm *myvm_, old_space *target_)
-: myvm(myvm_), current_gc(myvm_->current_gc), target(target_)
-{
- scan = target->here;
-}
-
-template<typename Strategy> Strategy &cheney_collector<Strategy>::strategy()
-{
- return static_cast<Strategy &>(*this);
-}
-
-template<typename Strategy> object *cheney_collector<Strategy>::allot(cell size)
-{
- return target->allot(size);
-}
-
-template<typename Strategy> object *cheney_collector<Strategy>::copy_object(object *untagged)
-{
- return myvm->promote_object(untagged,strategy());
-}
-
-template<typename Strategy> bool cheney_collector<Strategy>::should_copy_p(object *pointer)
-{
- return strategy().should_copy_p(pointer);
-}
-
-template<typename Strategy> cell cheney_collector<Strategy>::trace_next(cell scan)
-{
- object *obj = (object *)scan;
- myvm->trace_slots(obj,strategy());
- return scan + myvm->untagged_object_size(obj);
-}
-
-template<typename Strategy> void cheney_collector<Strategy>::go()
-{
- strategy().copy_reachable_objects(scan,&target->here);
-}
-
-struct nursery_strategy : cheney_collector<nursery_strategy>
-{
- explicit nursery_strategy(factor_vm *myvm_, old_space *target_) :
- cheney_collector<nursery_strategy>(myvm_,target_) {}
-
- bool should_copy_p(object *untagged)
- {
- return myvm->nursery.contains_p(untagged);
- }
-
- void copy_reachable_objects(cell scan, cell *end)
- {
- while(scan < *end) scan = trace_next(scan);
- }
-};
-
-struct aging_strategy : cheney_collector<aging_strategy>
-{
- zone *tenured;
-
- explicit aging_strategy(factor_vm *myvm_, old_space *target_) :
- cheney_collector<aging_strategy>(myvm_,target_),
- tenured(myvm->data->tenured) {}
-
- bool should_copy_p(object *untagged)
- {
- if(target->contains_p(untagged))
- return false;
- else
- return !tenured->contains_p(untagged);
- }
-
- void copy_reachable_objects(cell scan, cell *end)
- {
- while(scan < *end) scan = trace_next(scan);
- }
-};
-
-struct aging_agian_strategy : cheney_collector<aging_agian_strategy>
-{
- explicit aging_agian_strategy(factor_vm *myvm_, old_space *target_) :
- cheney_collector<aging_agian_strategy>(myvm_,target_) {}
-
- bool should_copy_p(object *untagged)
- {
- return !target->contains_p(untagged);
- }
-
- void copy_reachable_objects(cell scan, cell *end)
- {
- while(scan < *end) scan = trace_next(scan);
- }
-};
-
-struct tenured_strategy : cheney_collector<tenured_strategy>
-{
- explicit tenured_strategy(factor_vm *myvm_, old_space *target_) :
- cheney_collector<tenured_strategy>(myvm_,target_) {}
-
- bool should_copy_p(object *untagged)
- {
- return !target->contains_p(untagged);
- }
-
- void copy_reachable_objects(cell scan, cell *end)
- {
- while(scan < *end)
- {
- myvm->mark_object_code_block(myvm->untag<object>(scan),*this);
- scan = trace_next(scan);
- }
- }
-};
-
-void factor_vm::collect_nursery()
-{
- nursery_strategy collector(this,data->aging);
-
- trace_roots(collector);
- trace_contexts(collector);
- trace_cards(tenured_gen,data->tenured,collector);
- trace_cards(aging_gen,data->aging,collector);
- trace_code_heap_roots(collector);
- collector.go();
- update_dirty_code_blocks();
-
- nursery.here = nursery.start;
-}
-
-void factor_vm::collect_aging()
-{
- std::swap(data->aging,data->aging_semispace);
- reset_generation(data->aging);
-
- aging_strategy collector(this,data->aging);
-
- trace_roots(collector);
- trace_contexts(collector);
- trace_cards(tenured_gen,data->tenured,collector);
- trace_code_heap_roots(collector);
- collector.go();
- update_dirty_code_blocks();
-
- nursery.here = nursery.start;
-}
-
-void factor_vm::collect_aging_again()
-{
- aging_agian_strategy collector(this,data->tenured);
-
- trace_roots(collector);
- trace_contexts(collector);
- trace_cards(tenured_gen,data->tenured,collector);
- trace_code_heap_roots(collector);
- collector.go();
- update_dirty_code_blocks();
-
- reset_generation(data->aging);
- nursery.here = nursery.start;
-}
-
-void factor_vm::collect_tenured(cell requested_bytes, bool trace_contexts_)
-{
- if(current_gc->growing_data_heap)
- {
- current_gc->old_data_heap = data;
- set_data_heap(grow_data_heap(current_gc->old_data_heap,requested_bytes));
- }
- else
- {
- std::swap(data->tenured,data->tenured_semispace);
- reset_generation(data->tenured);
- }
-
- tenured_strategy collector(this,data->tenured);
-
- trace_roots(collector);
- if(trace_contexts_) trace_contexts(collector);
- collector.go();
- free_unmarked_code_blocks();
-
- reset_generation(data->aging);
- nursery.here = nursery.start;
-
- if(current_gc->growing_data_heap)
- delete current_gc->old_data_heap;
-}
-
void factor_vm::record_gc_stats()
{
generation_statistics *s = &gc_stats.generations[current_gc->collecting_gen];
/* Collect gen and all younger generations.
If growing_data_heap_ is true, we must grow the data heap to such a size that
an allocation of requested_bytes won't fail */
-void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_, bool trace_contexts_, cell requested_bytes)
+void factor_vm::garbage_collection(cell collecting_gen_, bool growing_data_heap_, bool trace_contexts_p, cell requested_bytes)
{
assert(!gc_off);
assert(!current_gc);
+ save_stacks();
+
current_gc = new gc_state(data,growing_data_heap_,collecting_gen_);
/* Keep trying to GC higher and higher generations until we don't run out
else if(current_gc->collecting_aging_p())
{
if(current_gc->collecting_aging_again)
- collect_aging_again();
+ collect_to_tenured();
else
collect_aging();
}
else if(current_gc->collecting_tenured_p())
- collect_tenured(requested_bytes,trace_contexts_);
+ collect_full(requested_bytes,trace_contexts_p);
record_gc_stats();