fixing a bug in card mark stealing #117968
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
this fixes a problem with card mark stealing where we missed clamping the card clearing by the card stealing unit in
card_transition
. for this bug to appear the following conditions need to be met -an object A straddles the 2mb card stealing unit and originally for that object a card below the 2mb boundary and a card that corresponds to at least 256 bytes above the 2mb boundary are set. and there are no reference fields inbetween.
one thread T0 is working on the 1st 2mb and discovers A and the first set card bit. this card doesn't need to be set, so
poo
is set the address that's described by the 2nd card since there're no reference fields inbetween. socard_transition
is called which will callclear_cards
on [1st card, (2nd card. and it stops at this line -card_table [end_word] &= highbits (~0, bits);
where it sees
end_card
with the 2nd card still set, but before it writes it back tocard_table[end_word]
meanwhile, another thread T1 needs to be working on the memory starting from this 2mb boundary. it discovers the 2nd card doesn't need to be set, and none of the cards that correspond to the card bundle bit needs to be set so it clears the cards and the card bundle bit.
now T0 writes back to
card_table[end_word]
with the 2nd card bit set.it's not a problem when a card that shouldn't be set is set, given that its corresponding card bundle bit is also set. but it's definitely a problem if a card is set but its card bundle bit isn't, because next time when we have a cross gen reference, what's supposed to happen in the write barrier is either the card isn't already set and the WB will set the card and its corresponding card bundle bit, or the card is set and the WB wouldn't do anything. but now we have a situation where the card is set but the card bundle bit isn't, it just means the next GC that should be looking at this card wouldn't, if there were no other cards covered by that card bundle bit got newly set by the WB.
the cleanest fix is to make sure we don't step outside of the 2mb boundary when we call
clear_cards
incard_transition
.this issue was very hard to observe and debug - full credit goes to @ChrisAhna who also verified the fix.