+ p = gen->mut_once_list;
+ new_list = END_MUT_LIST;
+ next = p->mut_link;
+
+ evac_gen = gen->no;
+ failed_to_evac = rtsFalse;
+
+ for (; p != END_MUT_LIST; p = next, next = p->mut_link) {
+
+ /* make sure the info pointer is into text space */
+ ASSERT(p && (LOOKS_LIKE_GHC_INFO(GET_INFO(p))
+ || IS_HUGS_CONSTR_INFO(GET_INFO(p))));
+
+ info = get_itbl(p);
+ /*
+ if (info->type==RBH)
+ info = REVERT_INFOPTR(info); // if it's an RBH, look at the orig closure
+ */
+ switch(info->type) {
+
+ case IND_OLDGEN:
+ case IND_OLDGEN_PERM:
+ case IND_STATIC:
+ /* Try to pull the indirectee into this generation, so we can
+ * remove the indirection from the mutable list.
+ */
+ ((StgIndOldGen *)p)->indirectee =
+ evacuate(((StgIndOldGen *)p)->indirectee);
+
+#ifdef DEBUG
+ if (RtsFlags.DebugFlags.gc)
+ /* Debugging code to print out the size of the thing we just
+ * promoted
+ */
+ {
+ StgPtr start = gen->steps[0].scan;
+ bdescr *start_bd = gen->steps[0].scan_bd;
+ nat size = 0;
+ scavenge(&gen->steps[0]);
+ if (start_bd != gen->steps[0].scan_bd) {
+ size += (P_)BLOCK_ROUND_UP(start) - start;
+ start_bd = start_bd->link;
+ while (start_bd != gen->steps[0].scan_bd) {
+ size += BLOCK_SIZE_W;
+ start_bd = start_bd->link;
+ }
+ size += gen->steps[0].scan -
+ (P_)BLOCK_ROUND_DOWN(gen->steps[0].scan);
+ } else {
+ size = gen->steps[0].scan - start;
+ }
+ fprintf(stderr,"evac IND_OLDGEN: %d bytes\n", size * sizeof(W_));
+ }
+#endif
+
+ /* failed_to_evac might happen if we've got more than two
+ * generations, we're collecting only generation 0, the
+ * indirection resides in generation 2 and the indirectee is
+ * in generation 1.
+ */
+ if (failed_to_evac) {
+ failed_to_evac = rtsFalse;
+ p->mut_link = new_list;
+ new_list = p;
+ } else {
+ /* the mut_link field of an IND_STATIC is overloaded as the
+ * static link field too (it just so happens that we don't need
+ * both at the same time), so we need to NULL it out when
+ * removing this object from the mutable list because the static
+ * link fields are all assumed to be NULL before doing a major
+ * collection.
+ */
+ p->mut_link = NULL;
+ }
+ continue;
+
+ case MUT_VAR:
+ /* MUT_CONS is a kind of MUT_VAR, except it that we try to remove
+ * it from the mutable list if possible by promoting whatever it
+ * points to.
+ */
+ ASSERT(p->header.info == &MUT_CONS_info);
+ if (scavenge_one(((StgMutVar *)p)->var) == rtsTrue) {
+ /* didn't manage to promote everything, so put the
+ * MUT_CONS back on the list.
+ */
+ p->mut_link = new_list;
+ new_list = p;
+ }
+ continue;
+
+ case CAF_ENTERED:
+ {
+ StgCAF *caf = (StgCAF *)p;
+ caf->body = evacuate(caf->body);
+ caf->value = evacuate(caf->value);
+ if (failed_to_evac) {
+ failed_to_evac = rtsFalse;
+ p->mut_link = new_list;
+ new_list = p;
+ } else {
+ p->mut_link = NULL;
+ }
+ }
+ continue;
+
+ case CAF_UNENTERED:
+ {
+ StgCAF *caf = (StgCAF *)p;
+ caf->body = evacuate(caf->body);
+ if (failed_to_evac) {
+ failed_to_evac = rtsFalse;
+ p->mut_link = new_list;
+ new_list = p;
+ } else {
+ p->mut_link = NULL;
+ }
+ }
+ continue;
+
+ default:
+ /* shouldn't have anything else on the mutables list */
+ barf("scavenge_mut_once_list: strange object? %d", (int)(info->type));
+ }
+ }
+
+ gen->mut_once_list = new_list;
+}
+
+//@cindex scavenge_mutable_list
+
+static void
+scavenge_mutable_list(generation *gen)
+{
+ const StgInfoTable *info;
+ StgMutClosure *p, *next;