src/share/vm/memory/referenceProcessor.cpp
Print this page
rev 2661 : [mq]: g1-reference-processing
@@ -33,46 +33,12 @@
#include "runtime/java.hpp"
#include "runtime/jniHandles.hpp"
ReferencePolicy* ReferenceProcessor::_always_clear_soft_ref_policy = NULL;
ReferencePolicy* ReferenceProcessor::_default_soft_ref_policy = NULL;
-const int subclasses_of_ref = REF_PHANTOM - REF_OTHER;
bool ReferenceProcessor::_pending_list_uses_discovered_field = false;
-// List of discovered references.
-class DiscoveredList {
-public:
- DiscoveredList() : _len(0), _compressed_head(0), _oop_head(NULL) { }
- oop head() const {
- return UseCompressedOops ? oopDesc::decode_heap_oop(_compressed_head) :
- _oop_head;
- }
- HeapWord* adr_head() {
- return UseCompressedOops ? (HeapWord*)&_compressed_head :
- (HeapWord*)&_oop_head;
- }
- void set_head(oop o) {
- if (UseCompressedOops) {
- // Must compress the head ptr.
- _compressed_head = oopDesc::encode_heap_oop(o);
- } else {
- _oop_head = o;
- }
- }
- bool empty() const { return head() == NULL; }
- size_t length() { return _len; }
- void set_length(size_t len) { _len = len; }
- void inc_length(size_t inc) { _len += inc; assert(_len > 0, "Error"); }
- void dec_length(size_t dec) { _len -= dec; }
-private:
- // Set value depending on UseCompressedOops. This could be a template class
- // but then we have to fix all the instantiations and declarations that use this class.
- oop _oop_head;
- narrowOop _compressed_head;
- size_t _len;
-};
-
void referenceProcessor_init() {
ReferenceProcessor::init_statics();
}
void ReferenceProcessor::init_statics() {
@@ -110,19 +76,19 @@
_span = span;
_discovery_is_atomic = atomic_discovery;
_discovery_is_mt = mt_discovery;
_num_q = MAX2(1, mt_processing_degree);
_max_num_q = MAX2(_num_q, mt_discovery_degree);
- _discoveredSoftRefs = NEW_C_HEAP_ARRAY(DiscoveredList, _max_num_q * subclasses_of_ref);
+ _discoveredSoftRefs = NEW_C_HEAP_ARRAY(DiscoveredList, _max_num_q * subclasses_of_ref());
if (_discoveredSoftRefs == NULL) {
vm_exit_during_initialization("Could not allocated RefProc Array");
}
_discoveredWeakRefs = &_discoveredSoftRefs[_max_num_q];
_discoveredFinalRefs = &_discoveredWeakRefs[_max_num_q];
_discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_q];
// Initialized all entries to NULL
- for (int i = 0; i < _max_num_q * subclasses_of_ref; i++) {
+ for (int i = 0; i < _max_num_q * subclasses_of_ref(); i++) {
_discoveredSoftRefs[i].set_head(NULL);
_discoveredSoftRefs[i].set_length(0);
}
// If we do barriers, cache a copy of the barrier set.
if (discovered_list_needs_barrier) {
@@ -132,23 +98,23 @@
}
#ifndef PRODUCT
void ReferenceProcessor::verify_no_references_recorded() {
guarantee(!_discovering_refs, "Discovering refs?");
- for (int i = 0; i < _max_num_q * subclasses_of_ref; i++) {
- guarantee(_discoveredSoftRefs[i].empty(),
+ for (int i = 0; i < _max_num_q * subclasses_of_ref(); i++) {
+ guarantee(_discoveredSoftRefs[i].is_empty(),
"Found non-empty discovered list");
}
}
#endif
void ReferenceProcessor::weak_oops_do(OopClosure* f) {
// Should this instead be
- // for (int i = 0; i < subclasses_of_ref; i++_ {
+ // for (int i = 0; i < subclasses_of_ref(); i++_ {
// for (int j = 0; j < _num_q; j++) {
// int index = i * _max_num_q + j;
- for (int i = 0; i < _max_num_q * subclasses_of_ref; i++) {
+ for (int i = 0; i < _max_num_q * subclasses_of_ref(); i++) {
if (UseCompressedOops) {
f->do_oop((narrowOop*)_discoveredSoftRefs[i].adr_head());
} else {
f->do_oop((oop*)_discoveredSoftRefs[i].adr_head());
}
@@ -402,11 +368,11 @@
// (n_queues) with which that ReferenceProcessor was created. That
// is because of the "clever" way the discovered references lists were
// allocated and are indexed into.
assert(_n_queues == (int) _ref_processor.max_num_q(), "Different number not expected");
for (int j = 0;
- j < subclasses_of_ref;
+ j < ReferenceProcessor::subclasses_of_ref();
j++, index += _n_queues) {
_ref_processor.enqueue_discovered_reflist(
_refs_lists[index], _pending_list_addr);
_refs_lists[index].set_head(NULL);
_refs_lists[index].set_length(0);
@@ -422,131 +388,19 @@
RefProcEnqueueTask tsk(*this, _discoveredSoftRefs,
pending_list_addr, _max_num_q);
task_executor->execute(tsk);
} else {
// Serial code: call the parent class's implementation
- for (int i = 0; i < _max_num_q * subclasses_of_ref; i++) {
+ for (int i = 0; i < _max_num_q * subclasses_of_ref(); i++) {
enqueue_discovered_reflist(_discoveredSoftRefs[i], pending_list_addr);
_discoveredSoftRefs[i].set_head(NULL);
_discoveredSoftRefs[i].set_length(0);
}
}
}
-// Iterator for the list of discovered references.
-class DiscoveredListIterator {
-public:
- inline DiscoveredListIterator(DiscoveredList& refs_list,
- OopClosure* keep_alive,
- BoolObjectClosure* is_alive);
-
- // End Of List.
- inline bool has_next() const { return _ref != NULL; }
-
- // Get oop to the Reference object.
- inline oop obj() const { return _ref; }
-
- // Get oop to the referent object.
- inline oop referent() const { return _referent; }
-
- // Returns true if referent is alive.
- inline bool is_referent_alive() const;
-
- // Loads data for the current reference.
- // The "allow_null_referent" argument tells us to allow for the possibility
- // of a NULL referent in the discovered Reference object. This typically
- // happens in the case of concurrent collectors that may have done the
- // discovery concurrently, or interleaved, with mutator execution.
- inline void load_ptrs(DEBUG_ONLY(bool allow_null_referent));
-
- // Move to the next discovered reference.
- inline void next();
-
- // Remove the current reference from the list
- inline void remove();
-
- // Make the Reference object active again.
- inline void make_active() { java_lang_ref_Reference::set_next(_ref, NULL); }
-
- // Make the referent alive.
- inline void make_referent_alive() {
- if (UseCompressedOops) {
- _keep_alive->do_oop((narrowOop*)_referent_addr);
- } else {
- _keep_alive->do_oop((oop*)_referent_addr);
- }
- }
-
- // Update the discovered field.
- inline void update_discovered() {
- // First _prev_next ref actually points into DiscoveredList (gross).
- if (UseCompressedOops) {
- if (!oopDesc::is_null(*(narrowOop*)_prev_next)) {
- _keep_alive->do_oop((narrowOop*)_prev_next);
- }
- } else {
- if (!oopDesc::is_null(*(oop*)_prev_next)) {
- _keep_alive->do_oop((oop*)_prev_next);
- }
- }
- }
-
- // NULL out referent pointer.
- inline void clear_referent() { oop_store_raw(_referent_addr, NULL); }
-
- // Statistics
- NOT_PRODUCT(
- inline size_t processed() const { return _processed; }
- inline size_t removed() const { return _removed; }
- )
-
- inline void move_to_next();
-
-private:
- DiscoveredList& _refs_list;
- HeapWord* _prev_next;
- oop _prev;
- oop _ref;
- HeapWord* _discovered_addr;
- oop _next;
- HeapWord* _referent_addr;
- oop _referent;
- OopClosure* _keep_alive;
- BoolObjectClosure* _is_alive;
- DEBUG_ONLY(
- oop _first_seen; // cyclic linked list check
- )
- NOT_PRODUCT(
- size_t _processed;
- size_t _removed;
- )
-};
-
-inline DiscoveredListIterator::DiscoveredListIterator(DiscoveredList& refs_list,
- OopClosure* keep_alive,
- BoolObjectClosure* is_alive)
- : _refs_list(refs_list),
- _prev_next(refs_list.adr_head()),
- _prev(NULL),
- _ref(refs_list.head()),
-#ifdef ASSERT
- _first_seen(refs_list.head()),
-#endif
-#ifndef PRODUCT
- _processed(0),
- _removed(0),
-#endif
- _next(NULL),
- _keep_alive(keep_alive),
- _is_alive(is_alive)
-{ }
-
-inline bool DiscoveredListIterator::is_referent_alive() const {
- return _is_alive->do_object_b(_referent);
-}
-
-inline void DiscoveredListIterator::load_ptrs(DEBUG_ONLY(bool allow_null_referent)) {
+void DiscoveredListIterator::load_ptrs(DEBUG_ONLY(bool allow_null_referent)) {
_discovered_addr = java_lang_ref_Reference::discovered_addr(_ref);
oop discovered = java_lang_ref_Reference::discovered(_ref);
assert(_discovered_addr && discovered->is_oop_or_null(),
"discovered field is bad");
_next = discovered;
@@ -558,17 +412,11 @@
_referent->is_oop_or_null()
: _referent->is_oop(),
"bad referent");
}
-inline void DiscoveredListIterator::next() {
- _prev_next = _discovered_addr;
- _prev = _ref;
- move_to_next();
-}
-
-inline void DiscoveredListIterator::remove() {
+void DiscoveredListIterator::remove() {
assert(_ref->is_oop(), "Dropping a bad reference");
oop_store_raw(_discovered_addr, NULL);
// First _prev_next ref actually points into DiscoveredList (gross).
oop new_next;
@@ -590,19 +438,33 @@
}
NOT_PRODUCT(_removed++);
_refs_list.dec_length(1);
}
-inline void DiscoveredListIterator::move_to_next() {
- if (_ref == _next) {
- // End of the list.
- _ref = NULL;
+// Make the Reference object active again.
+void DiscoveredListIterator::make_active() {
+ // For G1 we don't want to use set_next - it
+ // will dirty the card for the next field of
+ // the reference object and will fail
+ // CT verification.
+ if (UseG1GC) {
+ BarrierSet* bs = oopDesc::bs();
+ HeapWord* next_addr = java_lang_ref_Reference::next_addr(_ref);
+
+ if (UseCompressedOops) {
+ bs->write_ref_field_pre((narrowOop*)next_addr, NULL);
} else {
- _ref = _next;
+ bs->write_ref_field_pre((oop*)next_addr, NULL);
}
- assert(_ref != _first_seen, "cyclic ref_list found");
- NOT_PRODUCT(_processed++);
+ java_lang_ref_Reference::set_next_raw(_ref, NULL);
+ } else {
+ java_lang_ref_Reference::set_next(_ref, NULL);
+ }
+}
+
+void DiscoveredListIterator::clear_referent() {
+ oop_store_raw(_referent_addr, NULL);
}
// NOTE: process_phase*() are largely similar, and at a high level
// merely iterate over the extant list applying a predicate to
// each of its elements and possibly removing that element from the
@@ -784,14 +646,13 @@
clear_discovered_references(refs_list);
}
void ReferenceProcessor::abandon_partial_discovery() {
// loop over the lists
- for (int i = 0; i < _max_num_q * subclasses_of_ref; i++) {
+ for (int i = 0; i < _max_num_q * subclasses_of_ref(); i++) {
if (TraceReferenceGC && PrintGCDetails && ((i % _max_num_q) == 0)) {
- gclog_or_tty->print_cr("\nAbandoning %s discovered list",
- list_name(i));
+ gclog_or_tty->print_cr("\nAbandoning %s discovered list", list_name(i));
}
abandon_partial_discovered_list(_discoveredSoftRefs[i]);
}
}
@@ -911,16 +772,26 @@
move_tail = new_head;
new_head = java_lang_ref_Reference::discovered(new_head);
}
// Add the chain to the to list.
+ if (_discovered_list_needs_barrier) {
if (ref_lists[to_idx].head() == NULL) {
// to list is empty. Make a loop at the end.
java_lang_ref_Reference::set_discovered(move_tail, move_tail);
} else {
java_lang_ref_Reference::set_discovered(move_tail, ref_lists[to_idx].head());
}
+ } else {
+ HeapWord* const discovered_addr = java_lang_ref_Reference::discovered_addr(move_tail);
+ if (ref_lists[to_idx].head() == NULL) {
+ // to list is empty. Make a loop at the end.
+ oop_store_raw(discovered_addr, move_tail);
+ } else {
+ oop_store_raw(discovered_addr, ref_lists[to_idx].head());
+ }
+ }
ref_lists[to_idx].set_head(move_head);
ref_lists[to_idx].inc_length(refs_to_move);
// Remove the chain from the from list.
if (move_tail == new_head) {
@@ -1037,14 +908,14 @@
}
void ReferenceProcessor::clean_up_discovered_references() {
// loop over the lists
// Should this instead be
- // for (int i = 0; i < subclasses_of_ref; i++_ {
+ // for (int i = 0; i < subclasses_of_ref(); i++) {
// for (int j = 0; j < _num_q; j++) {
// int index = i * _max_num_q + j;
- for (int i = 0; i < _max_num_q * subclasses_of_ref; i++) {
+ for (int i = 0; i < _max_num_q * subclasses_of_ref(); i++) {
if (TraceReferenceGC && PrintGCDetails && ((i % _max_num_q) == 0)) {
gclog_or_tty->print_cr(
"\nScrubbing %s discovered list of Null referents",
list_name(i));
}
@@ -1258,10 +1129,12 @@
if (!_current_soft_ref_policy->should_clear_reference(obj)) {
return false;
}
}
+ ResourceMark rm; // Needed for tracing.
+
HeapWord* const discovered_addr = java_lang_ref_Reference::discovered_addr(obj);
const oop discovered = java_lang_ref_Reference::discovered(obj);
assert(discovered->is_oop_or_null(), "bad discovered field");
if (discovered != NULL) {
// The reference has already been discovered...
@@ -1470,11 +1343,11 @@
}
)
}
const char* ReferenceProcessor::list_name(int i) {
- assert(i >= 0 && i <= _max_num_q * subclasses_of_ref, "Out of bounds index");
+ assert(i >= 0 && i <= _max_num_q * subclasses_of_ref(), "Out of bounds index");
int j = i / _max_num_q;
switch (j) {
case 0: return "SoftRef";
case 1: return "WeakRef";
case 2: return "FinalRef";
@@ -1491,11 +1364,11 @@
#endif
#ifndef PRODUCT
void ReferenceProcessor::clear_discovered_references() {
guarantee(!_discovering_refs, "Discovering refs?");
- for (int i = 0; i < _max_num_q * subclasses_of_ref; i++) {
+ for (int i = 0; i < _max_num_q * subclasses_of_ref(); i++) {
clear_discovered_references(_discoveredSoftRefs[i]);
}
}
#endif // PRODUCT