- Scavenge a given step until there are no more objects in this step
- to scavenge.
-
- evac_gen is set by the caller to be either zero (for a step in a
- generation < N) or G where G is the generation of the step being
- scavenged.
-
- We sometimes temporarily change evac_gen back to zero if we're
- scavenging a mutable object where early promotion isn't such a good
- idea.
- -------------------------------------------------------------------------- */
-
-void
-scavenge(step *stp)
-{
- StgPtr p, q;
- StgInfoTable *info;
- bdescr *bd;
- nat saved_evac_gen = evac_gen;
-
- p = stp->scan;
- bd = stp->scan_bd;
-
- failed_to_evac = rtsFalse;
-
- /* scavenge phase - standard breadth-first scavenging of the
- * evacuated objects
- */
-
- while (bd != stp->hp_bd || p < stp->hp) {
-
- // If we're at the end of this block, move on to the next block
- if (bd != stp->hp_bd && p == bd->free) {
- bd = bd->link;
- p = bd->start;
- continue;
- }
-
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(p));
- info = get_itbl((StgClosure *)p);
-
- ASSERT(thunk_selector_depth == 0);
-
- q = p;
- switch (info->type) {
-
- case MVAR:
- {
- StgMVar *mvar = ((StgMVar *)p);
- evac_gen = 0;
- mvar->head = (StgTSO *)evacuate((StgClosure *)mvar->head);
- mvar->tail = (StgTSO *)evacuate((StgClosure *)mvar->tail);
- mvar->value = evacuate((StgClosure *)mvar->value);
- evac_gen = saved_evac_gen;
- failed_to_evac = rtsTrue; // mutable.
- p += sizeofW(StgMVar);
- break;
- }
-
- case FUN_2_0:
- scavenge_fun_srt(info);
- ((StgClosure *)p)->payload[1] = evacuate(((StgClosure *)p)->payload[1]);
- ((StgClosure *)p)->payload[0] = evacuate(((StgClosure *)p)->payload[0]);
- p += sizeofW(StgHeader) + 2;
- break;
-
- case THUNK_2_0:
- scavenge_thunk_srt(info);
- ((StgThunk *)p)->payload[1] = evacuate(((StgThunk *)p)->payload[1]);
- ((StgThunk *)p)->payload[0] = evacuate(((StgThunk *)p)->payload[0]);
- p += sizeofW(StgThunk) + 2;
- break;
-
- case CONSTR_2_0:
- ((StgClosure *)p)->payload[1] = evacuate(((StgClosure *)p)->payload[1]);
- ((StgClosure *)p)->payload[0] = evacuate(((StgClosure *)p)->payload[0]);
- p += sizeofW(StgHeader) + 2;
- break;
-
- case THUNK_1_0:
- scavenge_thunk_srt(info);
- ((StgThunk *)p)->payload[0] = evacuate(((StgThunk *)p)->payload[0]);
- p += sizeofW(StgThunk) + 1;
- break;
-
- case FUN_1_0:
- scavenge_fun_srt(info);
- case CONSTR_1_0:
- ((StgClosure *)p)->payload[0] = evacuate(((StgClosure *)p)->payload[0]);
- p += sizeofW(StgHeader) + 1;
- break;
-
- case THUNK_0_1:
- scavenge_thunk_srt(info);
- p += sizeofW(StgThunk) + 1;
- break;
-
- case FUN_0_1:
- scavenge_fun_srt(info);
- case CONSTR_0_1:
- p += sizeofW(StgHeader) + 1;
- break;
-
- case THUNK_0_2:
- scavenge_thunk_srt(info);
- p += sizeofW(StgThunk) + 2;
- break;
-
- case FUN_0_2:
- scavenge_fun_srt(info);
- case CONSTR_0_2:
- p += sizeofW(StgHeader) + 2;
- break;
-
- case THUNK_1_1:
- scavenge_thunk_srt(info);
- ((StgThunk *)p)->payload[0] = evacuate(((StgThunk *)p)->payload[0]);
- p += sizeofW(StgThunk) + 2;
- break;
-
- case FUN_1_1:
- scavenge_fun_srt(info);
- case CONSTR_1_1:
- ((StgClosure *)p)->payload[0] = evacuate(((StgClosure *)p)->payload[0]);
- p += sizeofW(StgHeader) + 2;
- break;
-
- case FUN:
- scavenge_fun_srt(info);
- goto gen_obj;
-
- case THUNK:
- {
- StgPtr end;
-
- scavenge_thunk_srt(info);
- end = (P_)((StgThunk *)p)->payload + info->layout.payload.ptrs;
- for (p = (P_)((StgThunk *)p)->payload; p < end; p++) {
- *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
- }
- p += info->layout.payload.nptrs;
- break;
- }
-
- gen_obj:
- case CONSTR:
- case WEAK:
- case STABLE_NAME:
- {
- StgPtr end;
-
- end = (P_)((StgClosure *)p)->payload + info->layout.payload.ptrs;
- for (p = (P_)((StgClosure *)p)->payload; p < end; p++) {
- *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
- }
- p += info->layout.payload.nptrs;
- break;
- }
-
- case BCO: {
- StgBCO *bco = (StgBCO *)p;
- bco->instrs = (StgArrWords *)evacuate((StgClosure *)bco->instrs);
- bco->literals = (StgArrWords *)evacuate((StgClosure *)bco->literals);
- bco->ptrs = (StgMutArrPtrs *)evacuate((StgClosure *)bco->ptrs);
- bco->itbls = (StgArrWords *)evacuate((StgClosure *)bco->itbls);
- p += bco_sizeW(bco);
- break;
- }
-
- case IND_PERM:
- if (stp->gen->no != 0) {
-#ifdef PROFILING
- // @LDV profiling
- // No need to call LDV_recordDead_FILL_SLOP_DYNAMIC() because an
- // IND_OLDGEN_PERM closure is larger than an IND_PERM closure.
- LDV_recordDead((StgClosure *)p, sizeofW(StgInd));
-#endif
- //
- // Todo: maybe use SET_HDR() and remove LDV_RECORD_CREATE()?
- //
- SET_INFO(((StgClosure *)p), &stg_IND_OLDGEN_PERM_info);
-
- // We pretend that p has just been created.
- LDV_RECORD_CREATE((StgClosure *)p);
- }
- // fall through
- case IND_OLDGEN_PERM:
- ((StgInd *)p)->indirectee = evacuate(((StgInd *)p)->indirectee);
- p += sizeofW(StgInd);
- break;
-
- case MUT_VAR_CLEAN:
- case MUT_VAR_DIRTY: {
- rtsBool saved_eager_promotion = eager_promotion;
-
- eager_promotion = rtsFalse;
- ((StgMutVar *)p)->var = evacuate(((StgMutVar *)p)->var);
- eager_promotion = saved_eager_promotion;
-
- if (failed_to_evac) {
- ((StgClosure *)q)->header.info = &stg_MUT_VAR_DIRTY_info;
- } else {
- ((StgClosure *)q)->header.info = &stg_MUT_VAR_CLEAN_info;
- }
- p += sizeofW(StgMutVar);
- break;
- }
-
- case CAF_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
- case SE_BLACKHOLE:
- case BLACKHOLE:
- p += BLACKHOLE_sizeW();
- break;
-
- case THUNK_SELECTOR:
- {
- StgSelector *s = (StgSelector *)p;
- s->selectee = evacuate(s->selectee);
- p += THUNK_SELECTOR_sizeW();
- break;
- }
-
- // A chunk of stack saved in a heap object
- case AP_STACK:
- {
- StgAP_STACK *ap = (StgAP_STACK *)p;
-
- ap->fun = evacuate(ap->fun);
- scavenge_stack((StgPtr)ap->payload, (StgPtr)ap->payload + ap->size);
- p = (StgPtr)ap->payload + ap->size;
- break;
- }
-
- case PAP:
- p = scavenge_PAP((StgPAP *)p);
- break;
-
- case AP:
- p = scavenge_AP((StgAP *)p);
- break;
-
- case ARR_WORDS:
- // nothing to follow
- p += arr_words_sizeW((StgArrWords *)p);
- break;
-
- case MUT_ARR_PTRS_CLEAN:
- case MUT_ARR_PTRS_DIRTY:
- // follow everything
- {
- StgPtr next;
- rtsBool saved_eager;
-
- // We don't eagerly promote objects pointed to by a mutable
- // array, but if we find the array only points to objects in
- // the same or an older generation, we mark it "clean" and
- // avoid traversing it during minor GCs.
- saved_eager = eager_promotion;
- eager_promotion = rtsFalse;
- next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
- for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
- *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
- }
- eager_promotion = saved_eager;
-
- if (failed_to_evac) {
- ((StgClosure *)q)->header.info = &stg_MUT_ARR_PTRS_DIRTY_info;
- } else {
- ((StgClosure *)q)->header.info = &stg_MUT_ARR_PTRS_CLEAN_info;
- }
-
- failed_to_evac = rtsTrue; // always put it on the mutable list.
- break;
- }
-
- case MUT_ARR_PTRS_FROZEN:
- case MUT_ARR_PTRS_FROZEN0:
- // follow everything
- {
- StgPtr next;
-
- next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
- for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
- *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
- }
-
- // If we're going to put this object on the mutable list, then
- // set its info ptr to MUT_ARR_PTRS_FROZEN0 to indicate that.
- if (failed_to_evac) {
- ((StgClosure *)q)->header.info = &stg_MUT_ARR_PTRS_FROZEN0_info;
- } else {
- ((StgClosure *)q)->header.info = &stg_MUT_ARR_PTRS_FROZEN_info;
- }
- break;
- }
-
- case TSO:
- {
- StgTSO *tso = (StgTSO *)p;
- rtsBool saved_eager = eager_promotion;
-
- eager_promotion = rtsFalse;
- scavengeTSO(tso);
- eager_promotion = saved_eager;
-
- if (failed_to_evac) {
- tso->flags |= TSO_DIRTY;
- } else {
- tso->flags &= ~TSO_DIRTY;
- }
-
- failed_to_evac = rtsTrue; // always on the mutable list
- p += tso_sizeW(tso);
- break;
- }
-
- case TVAR_WATCH_QUEUE:
- {
- StgTVarWatchQueue *wq = ((StgTVarWatchQueue *) p);
- evac_gen = 0;
- wq->closure = (StgClosure*)evacuate((StgClosure*)wq->closure);
- wq->next_queue_entry = (StgTVarWatchQueue *)evacuate((StgClosure*)wq->next_queue_entry);
- wq->prev_queue_entry = (StgTVarWatchQueue *)evacuate((StgClosure*)wq->prev_queue_entry);
- evac_gen = saved_evac_gen;
- failed_to_evac = rtsTrue; // mutable
- p += sizeofW(StgTVarWatchQueue);
- break;
- }
-
- case TVAR:
- {
- StgTVar *tvar = ((StgTVar *) p);
- evac_gen = 0;
- tvar->current_value = evacuate((StgClosure*)tvar->current_value);
- tvar->first_watch_queue_entry = (StgTVarWatchQueue *)evacuate((StgClosure*)tvar->first_watch_queue_entry);
- evac_gen = saved_evac_gen;
- failed_to_evac = rtsTrue; // mutable
- p += sizeofW(StgTVar);
- break;
- }
-
- case TREC_HEADER:
- {
- StgTRecHeader *trec = ((StgTRecHeader *) p);
- evac_gen = 0;
- trec->enclosing_trec = (StgTRecHeader *)evacuate((StgClosure*)trec->enclosing_trec);
- trec->current_chunk = (StgTRecChunk *)evacuate((StgClosure*)trec->current_chunk);
- trec->invariants_to_check = (StgInvariantCheckQueue *)evacuate((StgClosure*)trec->invariants_to_check);
- evac_gen = saved_evac_gen;
- failed_to_evac = rtsTrue; // mutable
- p += sizeofW(StgTRecHeader);
- break;
- }
-
- case TREC_CHUNK:
- {
- StgWord i;
- StgTRecChunk *tc = ((StgTRecChunk *) p);
- TRecEntry *e = &(tc -> entries[0]);
- evac_gen = 0;
- tc->prev_chunk = (StgTRecChunk *)evacuate((StgClosure*)tc->prev_chunk);
- for (i = 0; i < tc -> next_entry_idx; i ++, e++ ) {
- e->tvar = (StgTVar *)evacuate((StgClosure*)e->tvar);
- e->expected_value = evacuate((StgClosure*)e->expected_value);
- e->new_value = evacuate((StgClosure*)e->new_value);
- }
- evac_gen = saved_evac_gen;
- failed_to_evac = rtsTrue; // mutable
- p += sizeofW(StgTRecChunk);
- break;
- }
-
- case ATOMIC_INVARIANT:
- {
- StgAtomicInvariant *invariant = ((StgAtomicInvariant *) p);
- evac_gen = 0;
- invariant->code = (StgClosure *)evacuate(invariant->code);
- invariant->last_execution = (StgTRecHeader *)evacuate((StgClosure*)invariant->last_execution);
- evac_gen = saved_evac_gen;
- failed_to_evac = rtsTrue; // mutable
- p += sizeofW(StgAtomicInvariant);
- break;
- }
-
- case INVARIANT_CHECK_QUEUE:
- {
- StgInvariantCheckQueue *queue = ((StgInvariantCheckQueue *) p);
- evac_gen = 0;
- queue->invariant = (StgAtomicInvariant *)evacuate((StgClosure*)queue->invariant);
- queue->my_execution = (StgTRecHeader *)evacuate((StgClosure*)queue->my_execution);
- queue->next_queue_entry = (StgInvariantCheckQueue *)evacuate((StgClosure*)queue->next_queue_entry);
- evac_gen = saved_evac_gen;
- failed_to_evac = rtsTrue; // mutable
- p += sizeofW(StgInvariantCheckQueue);
- break;
- }
-
- default:
- barf("scavenge: unimplemented/strange closure type %d @ %p",
- info->type, p);
- }
-
- /*
- * We need to record the current object on the mutable list if
- * (a) It is actually mutable, or
- * (b) It contains pointers to a younger generation.
- * Case (b) arises if we didn't manage to promote everything that
- * the current object points to into the current generation.
- */
- if (failed_to_evac) {
- failed_to_evac = rtsFalse;
- if (stp->gen_no > 0) {
- recordMutableGen((StgClosure *)q, stp->gen);
- }
- }
- }
-
- stp->scan_bd = bd;
- stp->scan = p;
-}
-
-/* -----------------------------------------------------------------------------