+ ASSERT(bd->step == ws->step);
+ ASSERT(bd->u.scan == bd->free);
+
+ if (bd->start + bd->blocks * BLOCK_SIZE_W - bd->free > WORK_UNIT_WORDS)
+ {
+ // a partially full block: put it on the part_list list.
+ bd->link = ws->part_list;
+ ws->part_list = bd;
+ ws->n_part_blocks += bd->blocks;
+ IF_DEBUG(sanity,
+ ASSERT(countBlocks(ws->part_list) == ws->n_part_blocks));
+ }
+ else
+ {
+ // put the scan block on the ws->scavd_list.
+ bd->link = ws->scavd_list;
+ ws->scavd_list = bd;
+ ws->n_scavd_blocks += bd->blocks;
+ IF_DEBUG(sanity,
+ ASSERT(countBlocks(ws->scavd_list) == ws->n_scavd_blocks));
+ }
+}
+
+StgPtr
+todo_block_full (nat size, step_workspace *ws)
+{
+ StgPtr p;
+ bdescr *bd;
+
+ // todo_free has been pre-incremented by Evac.c:alloc_for_copy(). We
+ // are expected to leave it bumped when we've finished here.
+ ws->todo_free -= size;
+
+ bd = ws->todo_bd;
+
+ ASSERT(bd != NULL);
+ ASSERT(bd->link == NULL);
+ ASSERT(bd->step == ws->step);
+
+ // If the global list is not empty, or there's not much work in
+ // this block to push, and there's enough room in
+ // this block to evacuate the current object, then just increase
+ // the limit.
+ if (!looksEmptyWSDeque(ws->todo_q) ||
+ (ws->todo_free - bd->u.scan < WORK_UNIT_WORDS / 2)) {
+ if (ws->todo_free + size < bd->start + bd->blocks * BLOCK_SIZE_W) {
+ ws->todo_lim = stg_min(bd->start + bd->blocks * BLOCK_SIZE_W,
+ ws->todo_lim + stg_max(WORK_UNIT_WORDS,size));
+ debugTrace(DEBUG_gc, "increasing limit for %p to %p", bd->start, ws->todo_lim);
+ p = ws->todo_free;
+ ws->todo_free += size;
+ return p;
+ }
+ }
+
+ gct->copied += ws->todo_free - bd->free;
+ bd->free = ws->todo_free;