summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rts/sm/NonMoving.h7
-rw-r--r--rts/sm/NonMovingMark.c15
-rw-r--r--rts/sm/NonMovingSweep.c3
3 files changed, 22 insertions, 3 deletions
diff --git a/rts/sm/NonMoving.h b/rts/sm/NonMoving.h
index 45351e54d7..ad8ebee81b 100644
--- a/rts/sm/NonMoving.h
+++ b/rts/sm/NonMoving.h
@@ -38,6 +38,7 @@ struct NonmovingSegment {
struct NonmovingSegment *link; // for linking together segments into lists
struct NonmovingSegment *todo_link; // NULL when not in todo list
nonmoving_block_idx next_free; // index of the next unallocated block
+ uint8_t filled_epoch;
uint8_t bitmap[]; // liveness bitmap
// After the liveness bitmap comes the data blocks. Note that we need to
// ensure that the size of this struct (including the bitmap) is a multiple
@@ -109,6 +110,8 @@ extern memcount nonmoving_live_words;
extern bool concurrent_coll_running;
#endif
+extern uint8_t nonmovingMarkEpoch;
+
void nonmovingInit(void);
void nonmovingStop(void);
void nonmovingExit(void);
@@ -166,6 +169,7 @@ INLINE_HEADER void nonmovingPushFilledSegment(struct NonmovingSegment *seg)
nonmovingHeap.allocators[nonmovingSegmentLogBlockSize(seg) - NONMOVING_ALLOCA0];
ACQUIRE_LOCK(&alloc->mutex);
+ seg->filled_epoch = nonmovingMarkEpoch;
seg->link = alloc->new_filled;
alloc->new_filled = seg;
RELEASE_LOCK(&alloc->mutex);
@@ -253,9 +257,6 @@ INLINE_HEADER nonmoving_block_idx nonmovingGetBlockIdx(StgPtr p)
return (nonmoving_block_idx) (offset >> nonmovingSegmentLogBlockSize(seg));
}
-// TODO: Eliminate this
-extern uint8_t nonmovingMarkEpoch;
-
INLINE_HEADER void nonmovingSetMark(struct NonmovingSegment *seg, nonmoving_block_idx i)
{
seg->bitmap[i] = nonmovingMarkEpoch;
diff --git a/rts/sm/NonMovingMark.c b/rts/sm/NonMovingMark.c
index 03e342806a..7df349b6c8 100644
--- a/rts/sm/NonMovingMark.c
+++ b/rts/sm/NonMovingMark.c
@@ -1768,6 +1768,21 @@ bool nonmovingIsAlive (StgClosure *p)
// all objects alive in the snapshot would be marked.
//
return mark == nonmovingMarkEpoch || mark == 0;
+ } else if (seg->next_free == nonmovingSegmentBlockCount(seg)) {
+ // If the segment is filled then we check whether it was filled
+ // during the current GC cycle.
+ //
+ // * If so, then we must consider the object to be alive since we
+ // cleared the bitmap when the segment was filled but haven't
+ // yet marked it.
+ // * If it was filled in the previous cycle then the object's
+ // liveness is reflected by its bitmap bit.
+ //
+ if (seg->filled_epoch == nonmovingMarkEpoch) {
+ return true;
+ } else {
+ return mark == nonmovingMarkEpoch;
+ }
} else {
// If the object is below next_free_snap then the snapshot
// invariant guarantees that it is marked if reachable.
diff --git a/rts/sm/NonMovingSweep.c b/rts/sm/NonMovingSweep.c
index 3ee8e9e367..51c4a9b893 100644
--- a/rts/sm/NonMovingSweep.c
+++ b/rts/sm/NonMovingSweep.c
@@ -141,10 +141,12 @@ GNUC_ATTR_HOT void nonmovingSweep(void)
switch (ret) {
case SEGMENT_FREE:
IF_DEBUG(sanity, clear_segment(seg));
+ seg->filled_epoch = 0;
nonmovingPushFreeSegment(seg);
break;
case SEGMENT_PARTIAL:
IF_DEBUG(sanity, clear_segment_free_blocks(seg));
+ seg->filled_epoch = 0;
nonmovingPushActiveSegment(seg);
break;
case SEGMENT_FILLED:
@@ -152,6 +154,7 @@ GNUC_ATTR_HOT void nonmovingSweep(void)
nonmovingClearBitmap(seg);
// Set snapshot
nonmovingSegmentInfo(seg)->next_free_snap = seg->next_free;
+ seg->filled_epoch = nonmovingMarkEpoch;
seg->link = new_sweep_list;
new_sweep_list = seg;
break;