diff options
-rw-r--r-- | rts/sm/NonMoving.h | 7 | ||||
-rw-r--r-- | rts/sm/NonMovingMark.c | 15 | ||||
-rw-r--r-- | rts/sm/NonMovingSweep.c | 3 |
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; |