Skip to content

Commit d0e1f51

Browse files
Y. Srinivas Ramakrishnakdnilsen
Y. Srinivas Ramakrishna
authored andcommittedMar 31, 2023
8305334: GenShen: reference processing needs a card-marking barrier
Global collections can create new cross-generational pointers during j.l.r.Reference processing which should be added to the card marking remembered set. The issue was found with dacapo during heap verification and happens somewhat rarely. I added the requisite barrier and provided a comment describing the sole situation in reference processing that should need the barrier. Assertions check this condition, but the card is also redundantly dirtied for young collections too where it's strictly not needed. I have tested with and without heap verification using product and fastdebug builds using dacapo and specjbb, and through our internal tests pipelines. I have not run any specific performance comparisons to assess the impact of the checks for applications that traffic heavily in j.l.r.Refs, but I do not expect much impact. Reviewed-by: kdnilsen, wkemper
1 parent f75b50b commit d0e1f51

File tree

1 file changed

+28
-0
lines changed

1 file changed

+28
-0
lines changed
 

‎src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp

+28
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "classfile/javaClasses.hpp"
2828
#include "gc/shared/workerThread.hpp"
2929
#include "gc/shenandoah/mode/shenandoahGenerationalMode.hpp"
30+
#include "gc/shenandoah/shenandoahGeneration.hpp"
3031
#include "gc/shenandoah/shenandoahOopClosures.inline.hpp"
3132
#include "gc/shenandoah/shenandoahReferenceProcessor.hpp"
3233
#include "gc/shenandoah/shenandoahThreadLocalData.hpp"
@@ -58,17 +59,44 @@ static const char* reference_type_name(ReferenceType type) {
5859
}
5960
}
6061

62+
template <typename T>
63+
static void card_mark_barrier(T* field, oop value) {
64+
ShenandoahHeap* heap = ShenandoahHeap::heap();
65+
assert(heap->is_in_or_null(value), "Should be in heap");
66+
if (heap->mode()->is_generational() && heap->is_in_old(field) && heap->is_in_young(value)) {
67+
// We expect this to really be needed only during global collections. Young collections
68+
// discover j.l.r.Refs in the old generation during scanning of dirty cards
69+
// and these point to (as yet unmarked) referents in the young generation (see
70+
// ShenandoahReferenceProcessor::should_discover). Those cards will continue to
71+
// remain dirty on account of this cross-generational pointer to the referent.
72+
// Similarly, old collections will never discover j.l.r.Refs in the young generation.
73+
// It is only global collections that discover in both generations. Here we can
74+
// end up with a j.l.R in the old generation on the discovered list that
75+
// is not already on a dirty card, but which may here end up with a successor in
76+
// the discovered list that is in the young generation. This is the singular case
77+
// where the card needs to be dirtied here. We, however, skip the extra global'ness check
78+
// and always mark the card (redundantly during young collections).
79+
// The asserts below check the expected invariants based on the description above.
80+
assert(!heap->active_generation()->is_old(), "Expecting only young or global");
81+
assert(heap->card_scan()->is_card_dirty(reinterpret_cast<HeapWord*>(field))
82+
|| heap->active_generation()->is_global(), "Expecting already dirty if young");
83+
heap->card_scan()->mark_card_as_dirty(reinterpret_cast<HeapWord*>(field));
84+
}
85+
}
86+
6187
template <typename T>
6288
static void set_oop_field(T* field, oop value);
6389

6490
template <>
6591
void set_oop_field<oop>(oop* field, oop value) {
6692
*field = value;
93+
card_mark_barrier(field, value);
6794
}
6895

6996
template <>
7097
void set_oop_field<narrowOop>(narrowOop* field, oop value) {
7198
*field = CompressedOops::encode(value);
99+
card_mark_barrier(field, value);
72100
}
73101

74102
static oop lrb(oop obj) {

0 commit comments

Comments
 (0)