diff options
Diffstat (limited to 'rts/sm')
-rw-r--r-- | rts/sm/Scav.c | 36 |
1 files changed, 20 insertions, 16 deletions
diff --git a/rts/sm/Scav.c b/rts/sm/Scav.c index 29a69950a3..1b671a097c 100644 --- a/rts/sm/Scav.c +++ b/rts/sm/Scav.c @@ -1575,13 +1575,11 @@ scavenge_stack(StgPtr p, StgPtr stack_end) // threadPaused(). We could traverse the whole stack again // before GC, but that seems like overkill. // - // So, if the frame points to an indirection, it will get - // shorted out when we evacuate. If this happens, we have no - // closure to update any more. In the past we solved this by - // replacing the IND with an IND_PERM, but a better solution - // is to replace the update frame with a frame that no longer - // does the update and just uses the value already computed by - // the other thread, so that is what we now do. + // Scavenging this update frame as normal would be disastrous; + // the updatee would end up pointing to the value. So we turn + // the indirection into an IND_PERM, so that evacuate will + // copy the indirection into the old generation instead of + // discarding it. // // Note [upd-black-hole] // One slight hiccup is that the THUNK_SELECTOR machinery can @@ -1592,16 +1590,22 @@ scavenge_stack(StgPtr p, StgPtr stack_end) // the updatee is never a THUNK_SELECTOR and we're ok. // NB. this is a new invariant: blackholing is not optional. { - StgClosure *v; - StgUpdateFrame *frame = (StgUpdateFrame *)p; - - evacuate(&frame->updatee); - v = frame->updatee; - if (GET_CLOSURE_TAG(v) != 0 || - (get_itbl(v)->type != BLACKHOLE && - get_itbl(v)->type != CAF_BLACKHOLE)) { - frame->header.info = (const StgInfoTable*)&stg_gc_unpt_r1_info; + nat type; + const StgInfoTable *i; + StgClosure *updatee; + + updatee = ((StgUpdateFrame *)p)->updatee; + i = updatee->header.info; + if (!IS_FORWARDING_PTR(i)) { + type = get_itbl(updatee)->type; + if (type == IND) { + updatee->header.info = &stg_IND_PERM_info; + } else if (type == IND_OLDGEN) { + updatee->header.info = &stg_IND_OLDGEN_PERM_info; + } } + evacuate(&((StgUpdateFrame *)p)->updatee); + ASSERT(GET_CLOSURE_TAG(((StgUpdateFrame *)p)->updatee) == 0); p += sizeofW(StgUpdateFrame); continue; } |