void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p) { assert(!gc_off); assert(!current_gc); current_gc = new gc_state(op,this); /* Keep trying to GC higher and higher generations until we don't run out of space */ if(setjmp(current_gc->gc_unwind)) { /* We come back here if a generation is full */ start_gc_again(); } current_gc->event->op = current_gc->op; switch(current_gc->op) { case collect_nursery_op: collect_nursery(); break; case collect_aging_op: collect_aging(); if(data->high_fragmentation_p()) { current_gc->op = collect_full_op; current_gc->event->op = collect_full_op; collect_full(trace_contexts_p); } break; case collect_to_tenured_op: collect_to_tenured(); if(data->high_fragmentation_p()) { current_gc->op = collect_full_op; current_gc->event->op = collect_full_op; collect_full(trace_contexts_p); } break; case collect_full_op: collect_full(trace_contexts_p); break; case collect_compact_op: collect_compact(trace_contexts_p); break; case collect_growing_heap_op: collect_growing_heap(requested_bytes,trace_contexts_p); break; default: critical_error("Bad GC op",current_gc->op); break; } end_gc(); delete current_gc; current_gc = NULL; }
void factor_vm::gc(gc_op op, cell requested_size) { FACTOR_ASSERT(!gc_off); FACTOR_ASSERT(!current_gc); /* Important invariant: tenured space must have enough contiguous free space to fit the entire contents of the aging space and nursery. This is because when doing a full collection, objects from younger generations are promoted before any unreachable tenured objects are freed. */ FACTOR_ASSERT(!data->high_fragmentation_p()); current_gc = new gc_state(op, this); if (ctx) ctx->callstack_seg->set_border_locked(false); atomic::store(¤t_gc_p, true); /* Keep trying to GC higher and higher generations until we don't run out of space in the target generation. */ for (;;) { try { if (gc_events) current_gc->event->op = current_gc->op; switch (current_gc->op) { case collect_nursery_op: collect_nursery(); break; case collect_aging_op: /* We end up here if the above fails. */ collect_aging(); if (data->high_fragmentation_p()) { /* Change GC op so that if we fail again, we crash. */ set_current_gc_op(collect_full_op); collect_full(); } break; case collect_to_tenured_op: /* We end up here if the above fails. */ collect_to_tenured(); if (data->high_fragmentation_p()) { /* Change GC op so that if we fail again, we crash. */ set_current_gc_op(collect_full_op); collect_full(); } break; case collect_full_op: collect_full(); break; case collect_compact_op: collect_compact(); break; case collect_growing_heap_op: collect_growing_heap(requested_size); break; default: critical_error("in gc, bad GC op", current_gc->op); break; } break; } catch (const must_start_gc_again&) { /* We come back here if the target generation is full. */ start_gc_again(); continue; } } end_gc(); atomic::store(¤t_gc_p, false); if (ctx) ctx->callstack_seg->set_border_locked(true); delete current_gc; current_gc = NULL; /* Check the invariant again, just in case. */ FACTOR_ASSERT(!data->high_fragmentation_p()); }