Skip to content

Commit c4d0a24

Browse files
committed
8315044: GenShen: Verifier detects clean card should be dirty
Reviewed-by: ysr, wkemper
1 parent 2d76fb1 commit c4d0a24

File tree

1 file changed

+39
-5
lines changed

1 file changed

+39
-5
lines changed

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

+39-5
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ template <typename T>
6363
static void card_mark_barrier(T* field, oop value) {
6464
ShenandoahHeap* heap = ShenandoahHeap::heap();
6565
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)) {
66+
assert(ShenandoahCardBarrier, "Card-mark barrier should be on");
67+
if (heap->is_in_old(field) && heap->is_in_young(value)) {
6768
// For Shenandoah, each generation collects all the _referents_ that belong to the
6869
// collected generation. We can end up with discovered lists that contain a mixture
6970
// of old and young _references_. These references are linked together through the
@@ -81,13 +82,17 @@ static void set_oop_field(T* field, oop value);
8182
template <>
8283
void set_oop_field<oop>(oop* field, oop value) {
8384
*field = value;
84-
card_mark_barrier(field, value);
85+
if (ShenandoahCardBarrier) {
86+
card_mark_barrier(field, value);
87+
}
8588
}
8689

8790
template <>
8891
void set_oop_field<narrowOop>(narrowOop* field, oop value) {
8992
*field = CompressedOops::encode(value);
90-
card_mark_barrier(field, value);
93+
if (ShenandoahCardBarrier) {
94+
card_mark_barrier(field, value);
95+
}
9196
}
9297

9398
static oop lrb(oop obj) {
@@ -364,6 +369,9 @@ bool ShenandoahReferenceProcessor::discover(oop reference, ReferenceType type, u
364369
}
365370

366371
// Add reference to discovered list
372+
// Each worker thread has a private copy of refproc_data, which includes a private discovered list. This means
373+
// there's no risk that a different worker thread will try to manipulate my discovered list head while I'm making
374+
// reference the head of my discovered list.
367375
ShenandoahRefProcThreadLocal& refproc_data = _ref_proc_thread_locals[worker_id];
368376
oop discovered_head = refproc_data.discovered_list_head<T>();
369377
if (discovered_head == nullptr) {
@@ -372,6 +380,18 @@ bool ShenandoahReferenceProcessor::discover(oop reference, ReferenceType type, u
372380
discovered_head = reference;
373381
}
374382
if (reference_cas_discovered<T>(reference, discovered_head)) {
383+
// We successfully set this reference object's next pointer to discovered_head. This marks reference as discovered.
384+
// If reference_cas_discovered fails, that means some other worker thread took credit for discovery of this reference,
385+
// and that other thread will place reference on its discovered list, so I can ignore reference.
386+
387+
// In case we have created an interesting pointer, mark the remembered set card as dirty.
388+
ShenandoahHeap* heap = ShenandoahHeap::heap();
389+
if (ShenandoahCardBarrier) {
390+
T* addr = reinterpret_cast<T*>(java_lang_ref_Reference::discovered_addr_raw(reference));
391+
card_mark_barrier(addr, discovered_head);
392+
}
393+
394+
// Make the discovered_list_head point to reference.
375395
refproc_data.set_discovered_list_head<T>(reference);
376396
assert(refproc_data.discovered_list_head<T>() == reference, "reference must be new discovered head");
377397
log_trace(gc, ref)("Discovered Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type));
@@ -468,6 +488,7 @@ void ShenandoahReferenceProcessor::process_references(ShenandoahRefProcThreadLoc
468488
}
469489

470490
// Prepend discovered references to internal pending list
491+
// set_oop_field maintains the card mark barrier as this list is constructed.
471492
if (!CompressedOops::is_null(*list)) {
472493
oop head = lrb(CompressedOops::decode_not_null(*list));
473494
shenandoah_assert_not_in_cset_except(&head, head, ShenandoahHeap::heap()->cancelled_gc() || !ShenandoahLoadRefBarrier);
@@ -544,10 +565,23 @@ void ShenandoahReferenceProcessor::process_references(ShenandoahPhaseTimings::Ph
544565
void ShenandoahReferenceProcessor::enqueue_references_locked() {
545566
// Prepend internal pending list to external pending list
546567
shenandoah_assert_not_in_cset_except(&_pending_list, _pending_list, ShenandoahHeap::heap()->cancelled_gc() || !ShenandoahLoadRefBarrier);
568+
569+
// During reference processing, we maintain a local list of references that are identified by
570+
// _pending_list and _pending_list_tail. _pending_list_tail points to the next field of the last Reference object on
571+
// the local list.
572+
//
573+
// There is also a global list of reference identified by Universe::_reference_pending_list
574+
575+
// The following code has the effect of:
576+
// 1. Making the global Universe::_reference_pending_list point to my local list
577+
// 2. Overwriting the next field of the last Reference on my local list to point at the previous head of the
578+
// global Universe::_reference_pending_list
579+
580+
oop former_head_of_global_list = Universe::swap_reference_pending_list(_pending_list);
547581
if (UseCompressedOops) {
548-
*reinterpret_cast<narrowOop*>(_pending_list_tail) = CompressedOops::encode(Universe::swap_reference_pending_list(_pending_list));
582+
set_oop_field<narrowOop>(reinterpret_cast<narrowOop*>(_pending_list_tail), former_head_of_global_list);
549583
} else {
550-
*reinterpret_cast<oop*>(_pending_list_tail) = Universe::swap_reference_pending_list(_pending_list);
584+
set_oop_field<oop>(reinterpret_cast<oop*>(_pending_list_tail), former_head_of_global_list);
551585
}
552586
}
553587

0 commit comments

Comments
 (0)