< prev index next > src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp
Print this page
*/
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "gc/shared/workerThread.hpp"
+ #include "gc/shenandoah/mode/shenandoahGenerationalMode.hpp"
+ #include "gc/shenandoah/shenandoahGeneration.hpp"
#include "gc/shenandoah/shenandoahOopClosures.inline.hpp"
#include "gc/shenandoah/shenandoahReferenceProcessor.hpp"
#include "gc/shenandoah/shenandoahThreadLocalData.hpp"
#include "gc/shenandoah/shenandoahUtils.hpp"
#include "runtime/atomic.hpp"
ShouldNotReachHere();
return nullptr;
}
}
+ template <typename T>
+ static void card_mark_barrier(T* field, oop value) {
+ ShenandoahHeap* heap = ShenandoahHeap::heap();
+ assert(heap->is_in_or_null(value), "Should be in heap");
+ if (heap->mode()->is_generational() && heap->is_in_old(field) && heap->is_in_young(value)) {
+ // We expect this to really be needed only during global collections. Young collections
+ // discover j.l.r.Refs in the old generation during scanning of dirty cards
+ // and these point to (as yet unmarked) referents in the young generation (see
+ // ShenandoahReferenceProcessor::should_discover). Those cards will continue to
+ // remain dirty on account of this cross-generational pointer to the referent.
+ // Similarly, old collections will never discover j.l.r.Refs in the young generation.
+ // It is only global collections that discover in both generations. Here we can
+ // end up with a j.l.R in the old generation on the discovered list that
+ // is not already on a dirty card, but which may here end up with a successor in
+ // the discovered list that is in the young generation. This is the singular case
+ // where the card needs to be dirtied here. We, however, skip the extra global'ness check
+ // and always mark the card (redundantly during young collections).
+ // The asserts below check the expected invariants based on the description above.
+ assert(!heap->active_generation()->is_old(), "Expecting only young or global");
+ assert(heap->card_scan()->is_card_dirty(reinterpret_cast<HeapWord*>(field))
+ || heap->active_generation()->is_global(), "Expecting already dirty if young");
+ heap->card_scan()->mark_card_as_dirty(reinterpret_cast<HeapWord*>(field));
+ }
+ }
+
template <typename T>
static void set_oop_field(T* field, oop value);
template <>
void set_oop_field<oop>(oop* field, oop value) {
*field = value;
+ card_mark_barrier(field, value);
}
template <>
void set_oop_field<narrowOop>(narrowOop* field, oop value) {
*field = CompressedOops::encode(value);
+ card_mark_barrier(field, value);
}
static oop lrb(oop obj) {
if (obj != nullptr && ShenandoahHeap::heap()->marking_context()->is_marked(obj)) {
return ShenandoahBarrierSet::barrier_set()->load_reference_barrier(obj);
template <typename T>
bool ShenandoahReferenceProcessor::should_discover(oop reference, ReferenceType type) const {
T* referent_addr = (T*) java_lang_ref_Reference::referent_addr_raw(reference);
T heap_oop = RawAccess<>::oop_load(referent_addr);
oop referent = CompressedOops::decode(heap_oop);
+ ShenandoahHeap* heap = ShenandoahHeap::heap();
if (is_inactive<T>(reference, referent, type)) {
log_trace(gc,ref)("Reference inactive: " PTR_FORMAT, p2i(reference));
return false;
}
if (is_softly_live(reference, type)) {
log_trace(gc,ref)("Reference softly live: " PTR_FORMAT, p2i(reference));
return false;
}
+ if (!heap->is_in_active_generation(referent)) {
+ log_trace(gc,ref)("Referent outside of active generation: " PTR_FORMAT, p2i(referent));
+ return false;
+ }
+
return true;
}
template <typename T>
bool ShenandoahReferenceProcessor::should_drop(oop reference, ReferenceType type) const {
if (!RegisterReferences) {
// Reference processing disabled
return false;
}
- log_trace(gc, ref)("Encountered Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type));
+ log_trace(gc, ref)("Encountered Reference: " PTR_FORMAT " (%s, %s)",
+ p2i(reference), reference_type_name(type), affiliation_name(reference));
uint worker_id = WorkerThread::worker_id();
_ref_proc_thread_locals->inc_encountered(type);
if (UseCompressedOops) {
return discover<narrowOop>(reference, type, worker_id);
template <typename T>
oop ShenandoahReferenceProcessor::drop(oop reference, ReferenceType type) {
log_trace(gc, ref)("Dropped Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type));
- #ifdef ASSERT
+ ShenandoahHeap* heap = ShenandoahHeap::heap();
oop referent = reference_referent<T>(reference);
- assert(referent == nullptr || ShenandoahHeap::heap()->marking_context()->is_marked(referent),
- "only drop references with alive referents");
- #endif
+ assert(referent == nullptr || heap->marking_context()->is_marked(referent), "only drop references with alive referents");
// Unlink and return next in list
oop next = reference_discovered<T>(reference);
reference_set_discovered<T>(reference, nullptr);
+ // When this reference was discovered, it would not have been marked. If it ends up surviving
+ // the cycle, we need to dirty the card if the reference is old and the referent is young. Note
+ // that if the reference is not dropped, then its pointer to the referent will be nulled before
+ // evacuation begins so card does not need to be dirtied.
+ if (heap->mode()->is_generational() && heap->is_in_old(reference) && heap->is_in_young(referent)) {
+ // Note: would be sufficient to mark only the card that holds the start of this Reference object.
+ heap->card_scan()->mark_range_as_dirty(cast_from_oop<HeapWord*>(reference), reference->size());
+ }
return next;
}
template <typename T>
T* ShenandoahReferenceProcessor::keep(oop reference, ReferenceType type, uint worker_id) {
void ShenandoahReferenceProcessor::enqueue_references(bool concurrent) {
if (_pending_list == nullptr) {
// Nothing to enqueue
return;
}
-
if (!concurrent) {
// When called from mark-compact or degen-GC, the locking is done by the VMOperation,
enqueue_references_locked();
} else {
// Heap_lock protects external pending list
< prev index next >