--- a/hotspot/src/share/vm/memory/referenceProcessor.hpp Thu Sep 22 07:18:51 2011 -0400
+++ b/hotspot/src/share/vm/memory/referenceProcessor.hpp Thu Sep 22 10:57:37 2011 -0700
@@ -48,18 +48,175 @@
// forward references
class ReferencePolicy;
class AbstractRefProcTaskExecutor;
-class DiscoveredList;
+
+// 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 is_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;
+};
+
+// Iterator for the list of discovered references.
+class DiscoveredListIterator {
+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;
+ )
+
+public:
+ inline 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)
+{ }
+
+ // 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 {
+ return _is_alive->do_object_b(_referent);
+ }
+
+ // 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.
+ void load_ptrs(DEBUG_ONLY(bool allow_null_referent));
+
+ // Move to the next discovered reference.
+ inline void next() {
+ _prev_next = _discovered_addr;
+ _prev = _ref;
+ move_to_next();
+ }
+
+ // Remove the current reference from the list
+ void remove();
+
+ // Make the Reference object active again.
+ void make_active();
+
+ // 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.
+ void clear_referent();
+
+ // Statistics
+ NOT_PRODUCT(
+ inline size_t processed() const { return _processed; }
+ inline size_t removed() const { return _removed; }
+ )
+
+ inline void move_to_next() {
+ if (_ref == _next) {
+ // End of the list.
+ _ref = NULL;
+ } else {
+ _ref = _next;
+ }
+ assert(_ref != _first_seen, "cyclic ref_list found");
+ NOT_PRODUCT(_processed++);
+ }
+
+};
class ReferenceProcessor : public CHeapObj {
protected:
// Compatibility with pre-4965777 JDK's
static bool _pending_list_uses_discovered_field;
- MemRegion _span; // (right-open) interval of heap
- // subject to wkref discovery
- bool _discovering_refs; // true when discovery enabled
- bool _discovery_is_atomic; // if discovery is atomic wrt
- // other collectors in configuration
- bool _discovery_is_mt; // true if reference discovery is MT.
+
+ MemRegion _span; // (right-open) interval of heap
+ // subject to wkref discovery
+
+ bool _discovering_refs; // true when discovery enabled
+ bool _discovery_is_atomic; // if discovery is atomic wrt
+ // other collectors in configuration
+ bool _discovery_is_mt; // true if reference discovery is MT.
+
// If true, setting "next" field of a discovered refs list requires
// write barrier(s). (Must be true if used in a collector in which
// elements of a discovered list may be moved during discovery: for
@@ -67,18 +224,19 @@
// long-term concurrent marking phase that does weak reference
// discovery.)
bool _discovered_list_needs_barrier;
- BarrierSet* _bs; // Cached copy of BarrierSet.
- bool _enqueuing_is_done; // true if all weak references enqueued
- bool _processing_is_mt; // true during phases when
- // reference processing is MT.
- int _next_id; // round-robin mod _num_q counter in
- // support of work distribution
- // For collectors that do not keep GC marking information
+ BarrierSet* _bs; // Cached copy of BarrierSet.
+ bool _enqueuing_is_done; // true if all weak references enqueued
+ bool _processing_is_mt; // true during phases when
+ // reference processing is MT.
+ int _next_id; // round-robin mod _num_q counter in
+ // support of work distribution
+
+ // For collectors that do not keep GC liveness information
// in the object header, this field holds a closure that
// helps the reference processor determine the reachability
- // of an oop (the field is currently initialized to NULL for
- // all collectors but the CMS collector).
+ // of an oop. It is currently initialized to NULL for all
+ // collectors except for CMS and G1.
BoolObjectClosure* _is_alive_non_header;
// Soft ref clearing policies
@@ -102,10 +260,13 @@
DiscoveredList* _discoveredPhantomRefs;
public:
- int num_q() { return _num_q; }
- int max_num_q() { return _max_num_q; }
- void set_active_mt_degree(int v) { _num_q = v; }
- DiscoveredList* discovered_soft_refs() { return _discoveredSoftRefs; }
+ static int number_of_subclasses_of_ref() { return (REF_PHANTOM - REF_OTHER); }
+
+ int num_q() { return _num_q; }
+ int max_num_q() { return _max_num_q; }
+ void set_active_mt_degree(int v) { _num_q = v; }
+ DiscoveredList* discovered_soft_refs() { return _discoveredSoftRefs; }
+
ReferencePolicy* setup_policy(bool always_clear) {
_current_soft_ref_policy = always_clear ?
_always_clear_soft_ref_policy : _default_soft_ref_policy;
@@ -205,6 +366,11 @@
void enqueue_discovered_reflists(HeapWord* pending_list_addr, AbstractRefProcTaskExecutor* task_executor);
protected:
+ // Set the 'discovered' field of the given reference to
+ // the given value - emitting barriers depending upon
+ // the value of _discovered_list_needs_barrier.
+ void set_discovered(oop ref, oop value);
+
// "Preclean" the given discovered reference list
// by removing references with strongly reachable referents.
// Currently used in support of CMS only.
@@ -290,7 +456,19 @@
void set_span(MemRegion span) { _span = span; }
// start and stop weak ref discovery
- void enable_discovery() { _discovering_refs = true; }
+ void enable_discovery(bool verify_disabled, bool check_no_refs) {
+#ifdef ASSERT
+ // Verify that we're not currently discovering refs
+ assert(!verify_disabled || !_discovering_refs, "nested call?");
+
+ if (check_no_refs) {
+ // Verify that the discovered lists are empty
+ verify_no_references_recorded();
+ }
+#endif // ASSERT
+ _discovering_refs = true;
+ }
+
void disable_discovery() { _discovering_refs = false; }
bool discovery_enabled() { return _discovering_refs; }
@@ -365,7 +543,7 @@
~NoRefDiscovery() {
if (_was_discovering_refs) {
- _rp->enable_discovery();
+ _rp->enable_discovery(true /*verify_disabled*/, false /*check_no_refs*/);
}
}
};