src/share/vm/memory/referenceProcessor.cpp

Print this page

        

@@ -46,10 +46,12 @@
     }
   }
   bool   empty() const          { return head() == ReferenceProcessor::sentinel_ref(); }
   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;

@@ -434,17 +436,17 @@
 
   // 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.
+  // 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 and move to the 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); }
 

@@ -474,11 +476,10 @@
   NOT_PRODUCT(
   inline size_t processed() const { return _processed; }
   inline size_t removed() const   { return _removed; }
   )
 
-private:
   inline void move_to_next();
 
 private:
   DiscoveredList&    _refs_list;
   HeapWord*          _prev_next;

@@ -551,11 +552,11 @@
   } else {
     // Remove Reference object from list.
     oopDesc::store_heap_oop((oop*)_prev_next, _next);
   }
   NOT_PRODUCT(_removed++);
-  move_to_next();
+  _refs_list.dec_length(1);
 }
 
 inline void DiscoveredListIterator::move_to_next() {
   _ref = _next;
   assert(_ref != _first_seen, "cyclic ref_list found");

@@ -589,16 +590,17 @@
     if (referent_is_dead && !policy->should_clear_reference(iter.obj())) {
       if (TraceReferenceGC) {
         gclog_or_tty->print_cr("Dropping reference (" INTPTR_FORMAT ": %s"  ") by policy",
                                iter.obj(), iter.obj()->blueprint()->internal_name());
       }
+      // Remove Reference object from list
+      iter.remove();
       // Make the Reference object active again
       iter.make_active();
       // keep the referent around
       iter.make_referent_alive();
-      // Remove Reference object from list
-      iter.remove();
+      iter.move_to_next();
     } else {
       iter.next();
     }
   }
   // Close the reachable set

@@ -627,16 +629,17 @@
       if (TraceReferenceGC) {
         gclog_or_tty->print_cr("Dropping strongly reachable reference (" INTPTR_FORMAT ": %s)",
                                iter.obj(), iter.obj()->blueprint()->internal_name());
       }
       // The referent is reachable after all.
+      // Remove Reference object from list.
+      iter.remove();
       // Update the referent pointer as necessary: Note that this
       // should not entail any recursive marking because the
       // referent must already have been traversed.
       iter.make_referent_alive();
-      // Remove Reference object from list
-      iter.remove();
+      iter.move_to_next();
     } else {
       iter.next();
     }
   }
   NOT_PRODUCT(

@@ -668,10 +671,11 @@
       if (UseCompressedOops) {
         keep_alive->do_oop((narrowOop*)next_addr);
       } else {
         keep_alive->do_oop((oop*)next_addr);
       }
+      iter.move_to_next();
     } else {
       iter.next();
     }
   }
   // Now close the newly reachable set

@@ -830,13 +834,13 @@
           move_tail = new_head;
           new_head = java_lang_ref_Reference::discovered(new_head);
         }
         java_lang_ref_Reference::set_discovered(move_tail, ref_lists[to_idx].head());
         ref_lists[to_idx].set_head(move_head);
-        ref_lists[to_idx].set_length(ref_lists[to_idx].length() + refs_to_move);
+        ref_lists[to_idx].inc_length(refs_to_move);
         ref_lists[from_idx].set_head(new_head);
-        ref_lists[from_idx].set_length(ref_lists[from_idx].length() - refs_to_move);
+        ref_lists[from_idx].dec_length(refs_to_move);
       } else {
         ++to_idx;
       }
     }
   }

@@ -921,11 +925,10 @@
 }
 
 void ReferenceProcessor::clean_up_discovered_reflist(DiscoveredList& refs_list) {
   assert(!discovery_is_atomic(), "Else why call this method?");
   DiscoveredListIterator iter(refs_list, NULL, NULL);
-  size_t length = refs_list.length();
   while (iter.has_next()) {
     iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
     oop next = java_lang_ref_Reference::next(iter.obj());
     assert(next->is_oop_or_null(), "bad next field");
     // If referent has been cleared or Reference is not active,

@@ -939,16 +942,15 @@
             iter.obj(), next, iter.referent());
         }
       )
       // Remove Reference object from list
       iter.remove();
-      --length;
+      iter.move_to_next();
     } else {
       iter.next();
     }
   }
-  refs_list.set_length(length);
   NOT_PRODUCT(
     if (PrintGCDetails && TraceReferenceGC) {
       gclog_or_tty->print(
         " Removed %d Refs with NULL referents out of %d discovered Refs",
         iter.removed(), iter.processed());

@@ -1022,11 +1024,11 @@
   if (retest == NULL) {
     // This thread just won the right to enqueue the object.
     // We have separate lists for enqueueing so no synchronization
     // is necessary.
     refs_list.set_head(obj);
-    refs_list.set_length(refs_list.length() + 1);
+    refs_list.inc_length(1);
     if (_discovered_list_needs_barrier) {
       _bs->write_ref_field((void*)discovered_addr, current_head); guarantee(false, "Needs to be fixed: YSR");
     }
 
   } else {

@@ -1166,11 +1168,11 @@
     oop_store_raw(discovered_addr, current_head);
     if (_discovered_list_needs_barrier) {
       _bs->write_ref_field((oop*)discovered_addr, current_head);
     }
     list->set_head(obj);
-    list->set_length(list->length() + 1);
+    list->inc_length(1);
   }
 
   // In the MT discovery case, it is currently possible to see
   // the following message multiple times if several threads
   // discover a reference about the same time. Only one will

@@ -1207,68 +1209,73 @@
   // Soft references
   {
     TraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC,
               false, gclog_or_tty);
     for (int i = 0; i < _num_q; i++) {
+      if (yield->should_return()) {
+        return;
+      }
       preclean_discovered_reflist(_discoveredSoftRefs[i], is_alive,
                                   keep_alive, complete_gc, yield);
     }
   }
-  if (yield->should_return()) {
-    return;
-  }
 
   // Weak references
   {
     TraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC,
               false, gclog_or_tty);
     for (int i = 0; i < _num_q; i++) {
+      if (yield->should_return()) {
+        return;
+      }
       preclean_discovered_reflist(_discoveredWeakRefs[i], is_alive,
                                   keep_alive, complete_gc, yield);
     }
   }
-  if (yield->should_return()) {
-    return;
-  }
 
   // Final references
   {
     TraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC,
               false, gclog_or_tty);
     for (int i = 0; i < _num_q; i++) {
+      if (yield->should_return()) {
+        return;
+      }
       preclean_discovered_reflist(_discoveredFinalRefs[i], is_alive,
                                   keep_alive, complete_gc, yield);
     }
   }
-  if (yield->should_return()) {
-    return;
-  }
 
   // Phantom references
   {
     TraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC,
               false, gclog_or_tty);
     for (int i = 0; i < _num_q; i++) {
+      if (yield->should_return()) {
+        return;
+      }
       preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive,
                                   keep_alive, complete_gc, yield);
     }
   }
 }
 
 // Walk the given discovered ref list, and remove all reference objects
 // whose referents are still alive, whose referents are NULL or which
-// are not active (have a non-NULL next field). NOTE: For this to work
-// correctly, refs discovery can not be happening concurrently with this
-// step.
+// are not active (have a non-NULL next field). NOTE: When we are
+// thus precleaning the ref lists (which happens single-threaded today),
+// we do not disable refs discovery to honour the correct semantics of
+// java.lang.Reference. As a result, we need to be careful below
+// that ref removal steps interleave safely with ref discovery steps
+// (in this thread).
 void
 ReferenceProcessor::preclean_discovered_reflist(DiscoveredList&    refs_list,
                                                 BoolObjectClosure* is_alive,
                                                 OopClosure*        keep_alive,
                                                 VoidClosure*       complete_gc,
                                                 YieldClosure*      yield) {
   DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
-  size_t length = refs_list.length();
   while (iter.has_next()) {
     iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
     oop obj = iter.obj();
     oop next = java_lang_ref_Reference::next(obj);
     if (iter.referent() == NULL || iter.is_referent_alive() ||

@@ -1279,26 +1286,24 @@
         gclog_or_tty->print_cr("Precleaning Reference (" INTPTR_FORMAT ": %s)",
                                iter.obj(), iter.obj()->blueprint()->internal_name());
       }
       // Remove Reference object from list
       iter.remove();
-      --length;
       // Keep alive its cohort.
       iter.make_referent_alive();
       if (UseCompressedOops) {
         narrowOop* next_addr = (narrowOop*)java_lang_ref_Reference::next_addr(obj);
         keep_alive->do_oop(next_addr);
       } else {
         oop* next_addr = (oop*)java_lang_ref_Reference::next_addr(obj);
         keep_alive->do_oop(next_addr);
       }
+      iter.move_to_next();
     } else {
       iter.next();
     }
   }
-  refs_list.set_length(length);
-
   // Close the reachable set
   complete_gc->do_void();
 
   NOT_PRODUCT(
     if (PrintGCDetails && PrintReferenceGC) {