{
StgPtr to;
step_workspace *ws;
- bdescr *bd;
/* Find out where we're going, using the handy "to" pointer in
* the step of the source object. If it turns out we need to
/* chain a new block onto the to-space for the destination step if
* necessary.
*/
- bd = ws->todo_bd;
- to = bd->free;
- if (to + size >= bd->start + BLOCK_SIZE_W) {
- bd = gc_alloc_todo_block(ws);
- to = bd->free;
+
+ ASSERT(ws->todo_free >= ws->todo_bd->free && ws->todo_free <= ws->todo_lim);
+ to = ws->todo_free;
+ if (to + size >= ws->todo_lim) {
+ to = gc_alloc_todo_block(ws);
}
- bd->free = to + size;
+ ws->todo_free = to + size;
+ ASSERT(ws->todo_free >= ws->todo_bd->free && ws->todo_free <= ws->todo_lim);
return to;
}
-
+
/* -----------------------------------------------------------------------------
The evacuate() code
-------------------------------------------------------------------------- */
prev = NULL;
while (p)
{
- ASSERT(p->header.info == &stg_BLACKHOLE_info);
+ ASSERT(p->header.info == &stg_BLACKHOLE_info
+ || p->header.info == &stg_WHITEHOLE_info);
prev = (StgSelector*)((StgClosure *)p)->payload[0];
// Update the THUNK_SELECTOR with an indirection to the
if (isPartiallyFull(stp->blocks))
{
ws->todo_bd = stp->blocks;
+ ws->todo_free = ws->todo_bd->free;
+ ws->todo_lim = ws->todo_bd->start + BLOCK_SIZE_W;
stp->blocks = stp->blocks->link;
stp->n_blocks -= 1;
ws->todo_bd->link = NULL;
// where objects to be scavenged go
bdescr * todo_bd;
+ StgPtr todo_free; // free ptr for todo_bd
+ StgPtr todo_lim; // lim for todo_bd
+
bdescr * buffer_todo_bd; // buffer to reduce contention
// on the step's todos list
// optimise it into a per-thread
// variable).
- rtsBool failed_to_evac; // failue to evacuate an object typically
- // causes it to be recorded in the mutable
- // object list
+ rtsBool failed_to_evac; // failure to evacuate an object typically
+ // causes it to be recorded in the mutable
+ // object list
rtsBool eager_promotion; // forces promotion to the evac gen
// instead of the to-space
ASSERT(countBlocks(ws->scavd_list) == ws->n_scavd_blocks));
}
-bdescr *
+StgPtr
gc_alloc_todo_block (step_workspace *ws)
{
bdescr *bd;
+ if (ws->todo_bd != NULL) {
+ ws->todo_bd->free = ws->todo_free;
+ }
+
// If we already have a todo block, it must be full, so we push it
// out: first to the buffer_todo_bd, then to the step. BUT, don't
// push out the block out if it is already the scan block.
}
ws->todo_bd = bd;
+ ws->todo_free = bd->start;
+ ws->todo_lim = bd->start + BLOCK_SIZE_W;
- return bd;
+ return ws->todo_free;
}
/* -----------------------------------------------------------------------------
void push_scan_block (bdescr *bd, step_workspace *ws);
bdescr *grab_todo_block (step_workspace *ws);
-bdescr *gc_alloc_todo_block (step_workspace *ws);
+StgPtr gc_alloc_todo_block (step_workspace *ws);
bdescr *gc_alloc_scavd_block (step_workspace *ws);
// Returns true if a block is 3/4 full. This predicate is used to try
info = get_itbl((StgClosure *)p);
q = p;
- switch (info->type) {
+ switch (((volatile StgWord *)info)[1] & 0xffff) {
case MVAR_CLEAN:
case MVAR_DIRTY:
}
ws = &gct->steps[g][s];
+ if (ws->todo_bd != NULL)
+ {
+ ws->todo_bd->free = ws->todo_free;
+ }
+
// If we have a todo block and no scan block, start
// scanning the todo block.
if (ws->scan_bd == NULL && ws->todo_bd != NULL)