in rts/sm/MarkWeak.c [228:309]
static bool tidyWeakList(generation *gen)
{
StgWeak *w, **last_w, *next_w;
const StgInfoTable *info;
StgClosure *new;
bool flag = false;
last_w = &gen->old_weak_ptr_list;
for (w = gen->old_weak_ptr_list; w != NULL; w = next_w) {
/* There might be a DEAD_WEAK on the list if finalizeWeak# was
* called on a live weak pointer object. Just remove it.
*/
if (w->header.info == &stg_DEAD_WEAK_info) {
next_w = w->link;
*last_w = next_w;
continue;
}
info = get_itbl((StgClosure *)w);
switch (info->type) {
case WEAK:
/* Now, check whether the key is reachable.
*/
new = isAlive(w->key);
if (new != NULL) {
generation *new_gen;
w->key = new;
// Find out which generation this weak ptr is in, and
// move it onto the weak ptr list of that generation.
new_gen = Bdescr((P_)w)->gen;
gct->evac_gen_no = new_gen->no;
gct->failed_to_evac = false;
// evacuate the fields of the weak ptr
scavengeLiveWeak(w);
if (gct->failed_to_evac) {
debugTrace(DEBUG_weak,
"putting weak pointer %p into mutable list",
w);
gct->failed_to_evac = false;
recordMutableGen_GC((StgClosure *)w, new_gen->no);
}
// remove this weak ptr from the old_weak_ptr list
*last_w = w->link;
next_w = w->link;
// and put it on the correct weak ptr list.
w->link = new_gen->weak_ptr_list;
new_gen->weak_ptr_list = w;
flag = true;
if (gen->no != new_gen->no) {
debugTrace(DEBUG_weak,
"moving weak pointer %p from %d to %d",
w, gen->no, new_gen->no);
}
debugTrace(DEBUG_weak,
"weak pointer still alive at %p -> %p",
w, w->key);
continue;
}
else {
last_w = &(w->link);
next_w = w->link;
continue;
}
default:
barf("tidyWeakList: not WEAK: %d, %p", info->type, w);
}
}
return flag;
}