summaryrefslogtreecommitdiff
path: root/rts
diff options
context:
space:
mode:
authorSimon Marlow <smarlow@fb.com>2015-07-30 07:34:43 -0700
committerSimon Marlow <marlowsd@gmail.com>2015-07-31 19:19:05 +0100
commit7cf87dfbf93f9839fa1e3b66a0233ac86f85a5f7 (patch)
treea865111bd106fea891f7c04dcab0dc9a36664c8d /rts
parenta66e1ba60d9be67dda2a57a71bde96bc6f8dc5f0 (diff)
downloadhaskell-7cf87dfbf93f9839fa1e3b66a0233ac86f85a5f7.tar.gz
Fix #7919 (again)
Summary: The fix is a bit clunky, and is perhaps not the best fix, but I'm not sure how much work it would be to fix it the other way (see comments for more info). Test Plan: T7919 doesn't crash Reviewers: austin, rwbarton, ezyang, bgamari Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1113 GHC Trac Issues: #7919
Diffstat (limited to 'rts')
-rw-r--r--rts/sm/GCUtils.c48
1 files changed, 35 insertions, 13 deletions
diff --git a/rts/sm/GCUtils.c b/rts/sm/GCUtils.c
index 84a620e8e7..1c6a93c3b2 100644
--- a/rts/sm/GCUtils.c
+++ b/rts/sm/GCUtils.c
@@ -138,9 +138,11 @@ push_scanned_block (bdescr *bd, gen_workspace *ws)
ASSERT(bd->gen == ws->gen);
ASSERT(bd->u.scan == bd->free);
- if (bd->start + bd->blocks * BLOCK_SIZE_W - bd->free > WORK_UNIT_WORDS)
+ if (bd->blocks == 1 &&
+ bd->start + BLOCK_SIZE_W - bd->free > WORK_UNIT_WORDS)
{
- // a partially full block: put it on the part_list list.
+ // A partially full block: put it on the part_list list.
+ // Only for single objects - see Note [big objects]
bd->link = ws->part_list;
ws->part_list = bd;
ws->n_part_blocks += bd->blocks;
@@ -158,6 +160,35 @@ push_scanned_block (bdescr *bd, gen_workspace *ws)
}
}
+/* Note [big objects]
+
+ We can get an ordinary object (CONSTR, FUN, THUNK etc.) that is
+ larger than a block (see #7919). Let's call these "big objects".
+ These objects don't behave like large objects - they live in
+ ordinary heap space (not the large_objects list), and are copied by
+ evacuate().
+
+ Clearly to copy one of these objects we need a block group, not an
+ ordinary block, so when alloc_todo_block() will correctly allocate a
+ block group.
+
+ The question is what to do with the space that is left at the end
+ of the block group after copying the big object into it. We could
+ continue to copy more objects into that space, but unfortunately
+ the rest of the GC is not set up to handle objects that start in
+ the second or later blocks of a group. We just about manage this
+ in the nursery (see scheduleHandleHeapOverflow()) so evacuate() can
+ handle this, but other parts of the GC can't. We could probably
+ fix this, but it's a rare case, so for now we ensure that we never
+ copy objects into the second and subsequent blocks of a block
+ group.
+
+ To ensure this:
+ - alloc_todo_block() sets todo_lim to be exactly the size of the
+ large object
+ - push_scanned_block doesn't put these blocks on the part_list
+*/
+
StgPtr
todo_block_full (nat size, gen_workspace *ws)
{
@@ -193,17 +224,7 @@ todo_block_full (nat size, gen_workspace *ws)
// We can extend the limit for the current block if there's enough
// room for the current object, *and* we're not into the second or
- // subsequent block of a large block. The second condition occurs
- // when we evacuate an object that is larger than a block. In
- // that case, alloc_todo_block() sets todo_lim to be exactly the
- // size of the large object, and we don't evacuate any more
- // objects into this block. The reason is that the rest of the GC
- // is not set up to handle objects that start in the second or
- // later blocks of a group. We just about manage this in the
- // nursery (see scheduleHandleHeapOverflow()) so evacuate() can
- // handle this, but other parts of the GC can't. We could
- // probably fix this, but it's a rare case anyway.
- //
+ // subsequent block of a large block (see Note [big objects]).
can_extend =
ws->todo_free + size <= bd->start + bd->blocks * BLOCK_SIZE_W
&& ws->todo_free < ws->todo_bd->start + BLOCK_SIZE_W;
@@ -316,6 +337,7 @@ alloc_todo_block (gen_workspace *ws, nat size)
ws->todo_free = bd->free;
ws->todo_lim = stg_min(bd->start + bd->blocks * BLOCK_SIZE_W,
bd->free + stg_max(WORK_UNIT_WORDS,size));
+ // See Note [big objects]
debugTrace(DEBUG_gc, "alloc new todo block %p for gen %d",
bd->free, ws->gen->no);