@@ -63,7 +63,8 @@ template <typename T>
63
63
static void card_mark_barrier (T* field, oop value) {
64
64
ShenandoahHeap* heap = ShenandoahHeap::heap ();
65
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)) {
66
+ assert (ShenandoahCardBarrier, " Card-mark barrier should be on" );
67
+ if (heap->is_in_old (field) && heap->is_in_young (value)) {
67
68
// For Shenandoah, each generation collects all the _referents_ that belong to the
68
69
// collected generation. We can end up with discovered lists that contain a mixture
69
70
// 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);
81
82
template <>
82
83
void set_oop_field<oop>(oop* field, oop value) {
83
84
*field = value;
84
- card_mark_barrier (field, value);
85
+ if (ShenandoahCardBarrier) {
86
+ card_mark_barrier (field, value);
87
+ }
85
88
}
86
89
87
90
template <>
88
91
void set_oop_field<narrowOop>(narrowOop* field, oop value) {
89
92
*field = CompressedOops::encode (value);
90
- card_mark_barrier (field, value);
93
+ if (ShenandoahCardBarrier) {
94
+ card_mark_barrier (field, value);
95
+ }
91
96
}
92
97
93
98
static oop lrb (oop obj) {
@@ -364,6 +369,9 @@ bool ShenandoahReferenceProcessor::discover(oop reference, ReferenceType type, u
364
369
}
365
370
366
371
// 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.
367
375
ShenandoahRefProcThreadLocal& refproc_data = _ref_proc_thread_locals[worker_id];
368
376
oop discovered_head = refproc_data.discovered_list_head <T>();
369
377
if (discovered_head == nullptr ) {
@@ -372,6 +380,18 @@ bool ShenandoahReferenceProcessor::discover(oop reference, ReferenceType type, u
372
380
discovered_head = reference;
373
381
}
374
382
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.
375
395
refproc_data.set_discovered_list_head <T>(reference);
376
396
assert (refproc_data.discovered_list_head <T>() == reference, " reference must be new discovered head" );
377
397
log_trace (gc, ref)(" Discovered Reference: " PTR_FORMAT " (%s)" , p2i (reference), reference_type_name (type));
@@ -468,6 +488,7 @@ void ShenandoahReferenceProcessor::process_references(ShenandoahRefProcThreadLoc
468
488
}
469
489
470
490
// Prepend discovered references to internal pending list
491
+ // set_oop_field maintains the card mark barrier as this list is constructed.
471
492
if (!CompressedOops::is_null (*list)) {
472
493
oop head = lrb (CompressedOops::decode_not_null (*list));
473
494
shenandoah_assert_not_in_cset_except (&head, head, ShenandoahHeap::heap ()->cancelled_gc () || !ShenandoahLoadRefBarrier);
@@ -544,10 +565,23 @@ void ShenandoahReferenceProcessor::process_references(ShenandoahPhaseTimings::Ph
544
565
void ShenandoahReferenceProcessor::enqueue_references_locked () {
545
566
// Prepend internal pending list to external pending list
546
567
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);
547
581
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 );
549
583
} 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 );
551
585
}
552
586
}
553
587
0 commit comments