< prev index next >

src/share/vm/gc/shared/referenceProcessor.cpp

Print this page

        

@@ -115,13 +115,13 @@
   if (_discovered_refs == NULL) {
     vm_exit_during_initialization("Could not allocated RefProc Array");
   }
   _discoveredSoftRefs    = &_discovered_refs[0];
   _discoveredWeakRefs    = &_discoveredSoftRefs[_max_num_q];
-  _discoveredFinalRefs   = &_discoveredWeakRefs[_max_num_q];
+  _discoveredEphemerons  = &_discoveredWeakRefs[_max_num_q];
+  _discoveredFinalRefs   = &_discoveredEphemerons[_max_num_q];
   _discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_q];
-  _discoveredCleanerRefs = &_discoveredPhantomRefs[_max_num_q];
 
   // Initialize all entries to NULL
   for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
     _discovered_refs[i].set_head(NULL);
     _discovered_refs[i].set_length(0);

@@ -206,35 +206,58 @@
   // here so that we use the new value during processing of the
   // discovered soft refs.
 
   _soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock();
 
-  // Include cleaners in phantom statistics.  We expect Cleaner
-  // references to be temporary, and don't want to deal with
-  // possible incompatibilities arising from making it more visible.
   ReferenceProcessorStats stats(
       total_count(_discoveredSoftRefs),
       total_count(_discoveredWeakRefs),
+      total_count(_discoveredEphemerons),
       total_count(_discoveredFinalRefs),
-      total_count(_discoveredPhantomRefs) + total_count(_discoveredCleanerRefs));
+      total_count(_discoveredPhantomRefs));
+
+  // Ephemerons (phase2) before Soft references. This closes the hard-reachable
+  // set that arrises when the value of an ephemeron with a hard-reachable key
+  // refers to an otherwise weaker-than-hard-reachable key of some other ephemeron.
+  {
+    GCTraceTime(Debug, gc, ref) tt("Ephemeron-HardClosure", gc_timer);
+    // balance queues if needed 1st
+    balance_discovered_ephemerons(task_executor);
+    process_discovered_ephemerons_ph2(is_alive, keep_alive, complete_gc, task_executor);
+  }
 
   // Soft references
   {
     GCTraceTime(Debug, gc, ref) tt("SoftReference", gc_timer);
     process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
                                is_alive, keep_alive, complete_gc, task_executor);
   }
 
   update_soft_ref_master_clock();
 
+  // Ephemerons (phase2) again before Weak references. This closes the soft-reachable
+  // set that arrises when the value of an ephemeron with a soft-reachable key
+  // refers to an otherwise weaker-than-soft-reachable key of some other ephemeron.
+  {
+    GCTraceTime(Debug, gc, ref) tt("Ephemeron-SoftClosure", gc_timer);
+    process_discovered_ephemerons_ph2(is_alive, keep_alive, complete_gc, task_executor);
+  }
+
+
   // Weak references
   {
     GCTraceTime(Debug, gc, ref) tt("WeakReference", gc_timer);
     process_discovered_reflist(_discoveredWeakRefs, NULL, true,
                                is_alive, keep_alive, complete_gc, task_executor);
   }
 
+  // Ephemerons (phase3). This clears any remaining ephemerons.
+  {
+    GCTraceTime(Debug, gc, ref) tt("Ephemeron-Clear", gc_timer);
+    process_discovered_ephemerons_ph3(is_alive, keep_alive, complete_gc, task_executor);
+  }
+
   // Final references
   {
     GCTraceTime(Debug, gc, ref) tt("FinalReference", gc_timer);
     process_discovered_reflist(_discoveredFinalRefs, NULL, false,
                                is_alive, keep_alive, complete_gc, task_executor);

@@ -243,16 +266,10 @@
   // Phantom references
   {
     GCTraceTime(Debug, gc, ref) tt("PhantomReference", gc_timer);
     process_discovered_reflist(_discoveredPhantomRefs, NULL, true,
                                is_alive, keep_alive, complete_gc, task_executor);
-
-    // Process cleaners, but include them in phantom timing.  We expect
-    // Cleaner references to be temporary, and don't want to deal with
-    // possible incompatibilities arising from making it more visible.
-    process_discovered_reflist(_discoveredCleanerRefs, NULL, true,
-                                 is_alive, keep_alive, complete_gc, task_executor);
   }
 
   // Weak global JNI references. It would make more sense (semantically) to
   // traverse these simultaneously with the regular weak references above, but
   // that is not how the JDK1.2 specification is. See #4126360. Native code can

@@ -264,12 +281,12 @@
       task_executor->set_single_threaded_mode();
     }
     process_phaseJNI(is_alive, keep_alive, complete_gc);
   }
 
-  log_debug(gc, ref)("Ref Counts: Soft: " SIZE_FORMAT " Weak: " SIZE_FORMAT " Final: " SIZE_FORMAT " Phantom: " SIZE_FORMAT,
-                     stats.soft_count(), stats.weak_count(), stats.final_count(), stats.phantom_count());
+  log_debug(gc, ref)("Ref Counts: Soft: " SIZE_FORMAT " Weak: " SIZE_FORMAT " Ephemeron: " SIZE_FORMAT " Final: " SIZE_FORMAT " Phantom: " SIZE_FORMAT,
+                     stats.soft_count(), stats.weak_count(), stats.ephemeron_count(), stats.final_count(), stats.phantom_count());
   log_develop_trace(gc, ref)("JNI Weak Reference count: " SIZE_FORMAT, count_jni_refs());
 
   return stats;
 }
 

@@ -588,16 +605,157 @@
         iter.removed(), iter.processed(), p2i(refs_list.head()));
     }
   )
 }
 
-// Traverse the list and process the referents, by either
-// clearing them or keeping them (and their reachable
+bool
+ReferenceProcessor::pp2_ephemerons_work(DiscoveredList& refs_list,
+                                        BoolObjectClosure* is_alive,
+                                        OopClosure* keep_alive,
+                                        VoidClosure* complete_gc) {
+  assert(discovery_is_atomic(), "Error");
+  DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
+  // Temporary list used to reverse the order of ephemerons at each pass to avoid
+  // pathological cases where majority of revived ephemeron values point
+  // to ephemeron keys in the list "preceeding" this ephemeron.
+  DiscoveredList reversed_list;
+  bool ephemerons_removed = false;
+  while (iter.has_next()) {
+    iter.load_ptrs(DEBUG_ONLY(false /* allow_null_referent */));
+    oop obj = iter.obj();
+    DEBUG_ONLY(oop next = java_lang_ref_Reference::next(obj);)
+    assert(next == NULL, "Should not discover inactive Reference");
+    if (iter.is_referent_alive()) {
+      log_develop_trace(gc, ref)("Dropping strongly reachable reference (" INTPTR_FORMAT ": %s)",
+                                 p2i(obj), obj->klass()->internal_name());
+      // The referent (key) is reachable after all.
+      // Remove Ephemeron object from list.
+      iter.remove();
+      // Update the referent (key) pointer as necessary: Note that this
+      // should not entail any recursive marking because the
+      // referent must already have been traversed.
+      iter.make_referent_alive();
+      // Update the value pointer as necessary.
+      HeapWord* value_addr = java_lang_ref_Ephemeron::value_addr(obj);
+      if (UseCompressedOops) {
+        keep_alive->do_oop((narrowOop*) value_addr);
+      } else {
+        keep_alive->do_oop((oop*) value_addr);
+      }
+      ephemerons_removed = true;
+      // Close the newly reachable set as soon as the value is marked to be alive
+      // to increase the chance other ephemeron referents (keys) are revived as
+      // we proceed scanning the list.
+      complete_gc->do_void();
+    } else {
+      // Referent (key) is not alive (yet) so move the ephemeron to a reversed_list
+      // to reverse scanning in the next pass.
+      iter.remove();
+      HeapWord* discovered_addr = java_lang_ref_Reference::discovered_addr(obj);
+      oop current_head = reversed_list.head();
+      // The last ref must have its discovered field pointing to itself.
+      oop next_discovered = (current_head != NULL) ? current_head : obj;
+      oop_store_raw(discovered_addr, next_discovered);
+      reversed_list.set_head(obj);
+      reversed_list.inc_length(1);
+    }
+    iter.move_to_next();
+  }
+  assert(refs_list.length() == 0, "Should be empty");
+  // replace the list with reversed list
+  refs_list = reversed_list;
+  NOT_PRODUCT(
+    if (iter.processed() > 0) {
+      log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " active Ephemerons out of " SIZE_FORMAT
+                                 " Ephemerons in discovered list " INTPTR_FORMAT,
+                                 iter.processed() - refs_list.length(), iter.processed(),
+                                 p2i(refs_list.head()));
+    }
+  )
+  return ephemerons_removed;
+}
+
+bool
+ReferenceProcessor::pp2_ephemerons_work_concurrent_discovery(DiscoveredList& refs_list,
+                                                             BoolObjectClosure* is_alive,
+                                                             OopClosure* keep_alive,
+                                                             VoidClosure* complete_gc) {
+  assert(!discovery_is_atomic(), "Error");
+  DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
+  // Temporary list used to reverse the order of ephemerons at each pass to avoid
+  // pathological cases where majority of revived ephemeron values point
+  // to ephemeron keys in the list "preceeding" this ephemeron.
+  DiscoveredList reversed_list;
+  bool ephemerons_removed = false;
+  while (iter.has_next()) {
+    iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */));
+    oop obj = iter.obj();
+    HeapWord* next_addr = java_lang_ref_Reference::next_addr(obj);
+    oop next = java_lang_ref_Reference::next(obj);
+    if ((iter.referent() == NULL || iter.is_referent_alive() ||
+         next != NULL)) {
+      assert(next->is_oop_or_null(), "Expected an oop or NULL for next field at " PTR_FORMAT, p2i(next));
+      // Remove Reference object from list
+      iter.remove();
+      // Trace the cohorts
+      iter.make_referent_alive();
+      if (UseCompressedOops) {
+        keep_alive->do_oop((narrowOop*) next_addr);
+      } else {
+        keep_alive->do_oop((oop*) next_addr);
+      }
+      HeapWord* value_addr = java_lang_ref_Ephemeron::value_addr(obj);
+      if (UseCompressedOops) {
+        keep_alive->do_oop((narrowOop*) value_addr);
+      } else {
+        keep_alive->do_oop((oop*) value_addr);
+      }
+      ephemerons_removed = true;
+      // Close the newly reachable set as soon as the value is marked to be alive
+      // to increase the chance other ephemeron keys are revived as we proceed
+      // scanning the list
+      complete_gc->do_void();
+    } else {
+      // Referent (key) is not alive (yet) so move the ephemeron to a reversed_list
+      // to reverse scanning in the next pass.
+      iter.remove();
+      HeapWord* discovered_addr = java_lang_ref_Reference::discovered_addr(obj);
+      oop current_head = reversed_list.head();
+      // The last ref must have its discovered field pointing to itself.
+      oop next_discovered = (current_head != NULL) ? current_head : obj;
+      oop_store_raw(discovered_addr, next_discovered);
+      reversed_list.set_head(obj);
+      reversed_list.inc_length(1);
+    }
+    iter.move_to_next();
+  }
+  assert(refs_list.length() == 0, "Should be empty");
+  // replace the list with reversed list
+  refs_list = reversed_list;
+  // Now close the newly reachable set at least once after the whole list has
+  // been scanned even if there were no ephemerons
+  if (!ephemerons_removed) {
+    complete_gc->do_void();
+  }
+  NOT_PRODUCT(
+    if (iter.processed() > 0) {
+      log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " active Ephemerons out of " SIZE_FORMAT
+                                 " Ephemerons in discovered list " INTPTR_FORMAT,
+                                 iter.processed() - refs_list.length(), iter.processed(),
+                                 p2i(refs_list.head()));
+    }
+  )
+  return ephemerons_removed;
+}
+
+// Traverse the list and process the referents (and values in case of Ephemerons),
+// by either clearing them or keeping them (and their reachable
 // closure) alive.
 void
 ReferenceProcessor::process_phase3(DiscoveredList&    refs_list,
                                    bool               clear_referent,
+                                   bool               has_ephemerons,
                                    BoolObjectClosure* is_alive,
                                    OopClosure*        keep_alive,
                                    VoidClosure*       complete_gc) {
   ResourceMark rm;
   DiscoveredListIterator iter(refs_list, keep_alive, is_alive);

@@ -608,10 +766,16 @@
       iter.clear_referent();
     } else {
       // keep the referent around
       iter.make_referent_alive();
     }
+    if (has_ephemerons) {
+      assert(clear_referent, "Ephemerons should always be cleared");
+      HeapWord* value_addr = java_lang_ref_Ephemeron::value_addr(iter.obj());
+      // NULL out value pointer
+      oop_store_raw(value_addr, NULL);
+    }
     log_develop_trace(gc, ref)("Adding %sreference (" INTPTR_FORMAT ": %s) as pending",
                                clear_referent ? "cleared " : "", p2i(iter.obj()), iter.obj()->klass()->internal_name());
     assert(iter.obj()->is_oop(UseConcMarkSweepGC), "Adding a bad reference");
     iter.next();
   }

@@ -666,45 +830,57 @@
 
 class RefProcPhase2Task: public AbstractRefProcTaskExecutor::ProcessTask {
 public:
   RefProcPhase2Task(ReferenceProcessor& ref_processor,
                     DiscoveredList      refs_lists[],
+                    bool                has_ephemerons,
                     bool                marks_oops_alive)
-    : ProcessTask(ref_processor, refs_lists, marks_oops_alive)
+    : ProcessTask(ref_processor, refs_lists, marks_oops_alive),
+            _has_ephemerons(has_ephemerons), ephemerons_removed(false)
   { }
   virtual void work(unsigned int i, BoolObjectClosure& is_alive,
                     OopClosure& keep_alive,
                     VoidClosure& complete_gc)
   {
-    _ref_processor.process_phase2(_refs_lists[i],
+    bool r = _ref_processor.process_phase2(_refs_lists[i], _has_ephemerons,
                                   &is_alive, &keep_alive, &complete_gc);
+    if (r) {
+      ephemerons_removed = true;
+    }
   }
+private:
+  bool _has_ephemerons;
+public:
+  bool ephemerons_removed;
 };
 
 class RefProcPhase3Task: public AbstractRefProcTaskExecutor::ProcessTask {
 public:
   RefProcPhase3Task(ReferenceProcessor& ref_processor,
                     DiscoveredList      refs_lists[],
                     bool                clear_referent,
+                    bool                has_ephemerons,
                     bool                marks_oops_alive)
     : ProcessTask(ref_processor, refs_lists, marks_oops_alive),
-      _clear_referent(clear_referent)
+      _clear_referent(clear_referent),
+      _has_ephemerons(has_ephemerons)
   { }
   virtual void work(unsigned int i, BoolObjectClosure& is_alive,
                     OopClosure& keep_alive,
                     VoidClosure& complete_gc)
   {
     // Don't use "refs_list_index" calculated in this way because
     // balance_queues() has moved the Ref's into the first n queues.
     // Thread* thr = Thread::current();
     // int refs_list_index = ((WorkerThread*)thr)->id();
     // _ref_processor.process_phase3(_refs_lists[refs_list_index], _clear_referent,
-    _ref_processor.process_phase3(_refs_lists[i], _clear_referent,
+    _ref_processor.process_phase3(_refs_lists[i], _clear_referent, _has_ephemerons,
                                   &is_alive, &keep_alive, &complete_gc);
   }
 private:
   bool _clear_referent;
+  bool _has_ephemerons;
 };
 
 #ifndef PRODUCT
 void ReferenceProcessor::log_reflist_counts(DiscoveredList ref_lists[], size_t total_refs) {
   if (!log_is_enabled(Trace, gc, ref)) {

@@ -803,13 +979,13 @@
 }
 
 void ReferenceProcessor::balance_all_queues() {
   balance_queues(_discoveredSoftRefs);
   balance_queues(_discoveredWeakRefs);
+  balance_queues(_discoveredEphemerons);
   balance_queues(_discoveredFinalRefs);
   balance_queues(_discoveredPhantomRefs);
-  balance_queues(_discoveredCleanerRefs);
 }
 
 void ReferenceProcessor::process_discovered_reflist(
   DiscoveredList               refs_lists[],
   ReferencePolicy*             policy,

@@ -854,26 +1030,121 @@
   }
 
   // Phase 2:
   // . Traverse the list and remove any refs whose referents are alive.
   if (mt_processing) {
-    RefProcPhase2Task phase2(*this, refs_lists, !discovery_is_atomic() /*marks_oops_alive*/);
+    RefProcPhase2Task phase2(*this, refs_lists,
+                             false /*has_ephemerons*/,
+                             !discovery_is_atomic() /*marks_oops_alive*/);
     task_executor->execute(phase2);
   } else {
     for (uint i = 0; i < _max_num_q; i++) {
-      process_phase2(refs_lists[i], is_alive, keep_alive, complete_gc);
+      process_phase2(refs_lists[i],
+                     false /*has_ephemerons*/,
+                     is_alive, keep_alive, complete_gc);
     }
   }
 
   // Phase 3:
   // . Traverse the list and process referents as appropriate.
   if (mt_processing) {
-    RefProcPhase3Task phase3(*this, refs_lists, clear_referent, true /*marks_oops_alive*/);
+    RefProcPhase3Task phase3(*this, refs_lists, clear_referent,
+                             false /*has_ephemerons*/,
+                             true /*marks_oops_alive*/);
     task_executor->execute(phase3);
   } else {
     for (uint i = 0; i < _max_num_q; i++) {
       process_phase3(refs_lists[i], clear_referent,
+                     false /*has_ephemerons*/,
+                     is_alive, keep_alive, complete_gc);
+    }
+  }
+}
+
+// Balance ephemerons queues if needed
+void ReferenceProcessor::balance_discovered_ephemerons(
+  AbstractRefProcTaskExecutor* task_executor) {
+
+  bool mt_processing = task_executor != NULL && _processing_is_mt;
+  // If discovery used MT and a dynamic number of GC threads, then
+  // the queues must be balanced for correctness if fewer than the
+  // maximum number of queues were used.  The number of queue used
+  // during discovery may be different than the number to be used
+  // for processing so don't depend of _num_q < _max_num_q as part
+  // of the test.
+  bool must_balance = _discovery_is_mt;
+
+  if ((mt_processing && ParallelRefProcBalancingEnabled) ||
+      must_balance) {
+    balance_queues(_discoveredEphemerons);
+  }
+}
+
+// Process ephemerons, phase2
+void ReferenceProcessor::process_discovered_ephemerons_ph2(
+  BoolObjectClosure*           is_alive,
+  OopClosure*                  keep_alive,
+  VoidClosure*                 complete_gc,
+  AbstractRefProcTaskExecutor* task_executor) {
+
+  // Traverse the _discoveredEphemerons lists and for those ephemerons whose keys
+  // are alive, remove them from the list, mark their values alive and close the
+  // reachable set. Iterate until lists become stable while reversing the
+  // direction of scanning in each pass.
+  bool mt_processing = task_executor != NULL && _processing_is_mt;
+  bool ephemerons_removed;
+  bool forward_scan = true;
+  do {
+    if (mt_processing) {
+      RefProcPhase2Task phase2(*this, _discoveredEphemerons,
+                               true /*has_ephemerons*/,
+                               !discovery_is_atomic() /*marks_oops_alive*/);
+      task_executor->execute(phase2);
+      ephemerons_removed = phase2.ephemerons_removed;
+    } else {
+      ephemerons_removed = false;
+      // alternate direction of selecting individual lists for scanning to avoid
+      // pathological cases where majority of revived ephemeron values point
+      // to ephemeron keys in "previous" lists...
+      if (forward_scan) {
+        for (uint i = 0; i < _max_num_q; i++) {
+          ephemerons_removed |= process_phase2(_discoveredEphemerons[i],
+                                               true /*has_ephemerons*/,
+                                               is_alive, keep_alive, complete_gc);
+        }
+      } else {
+        for (uint i = _max_num_q - 1; i < (uint) - 1; i--) {
+          ephemerons_removed |= process_phase2(_discoveredEphemerons[i],
+                                               true /*has_ephemerons*/,
+                                               is_alive, keep_alive, complete_gc);
+        }
+      }
+      forward_scan = !forward_scan;
+    }
+  } while (ephemerons_removed);
+}
+
+// Process ephemerons, phase3
+void ReferenceProcessor::process_discovered_ephemerons_ph3(
+  BoolObjectClosure*           is_alive,
+  OopClosure*                  keep_alive,
+  VoidClosure*                 complete_gc,
+  AbstractRefProcTaskExecutor* task_executor) {
+
+  // Traverse the _discoveredEphemerons lists and clear ephemerons.
+  bool mt_processing = task_executor != NULL && _processing_is_mt;
+  if (mt_processing) {
+    RefProcPhase3Task phase3(*this, _discoveredEphemerons,
+                             true /*clear_referent*/,
+                             true /*has_ephemerons*/,
+                             true /*marks_oops_alive*/);
+    task_executor->execute(phase3);
+  } else {
+    for (uint i = 0; i < _max_num_q; i++) {
+      process_phase3(_discoveredEphemerons[i],
+                     true /*clear_referent*/,
+                     true /*has_ephemerons*/,
                      is_alive, keep_alive, complete_gc);
     }
   }
 }
 

@@ -904,19 +1175,19 @@
       list = &_discoveredSoftRefs[id];
       break;
     case REF_WEAK:
       list = &_discoveredWeakRefs[id];
       break;
+    case REF_EPHEMERON:
+      list = &_discoveredEphemerons[id];
+      break;
     case REF_FINAL:
       list = &_discoveredFinalRefs[id];
       break;
     case REF_PHANTOM:
       list = &_discoveredPhantomRefs[id];
       break;
-    case REF_CLEANER:
-      list = &_discoveredCleanerRefs[id];
-      break;
     case REF_NONE:
       // we should not reach here if we are an InstanceRefKlass
     default:
       ShouldNotReachHere();
   }

@@ -1114,10 +1385,43 @@
   OopClosure* keep_alive,
   VoidClosure* complete_gc,
   YieldClosure* yield,
   GCTimer* gc_timer) {
 
+  // Ephemerons - iterate until the lists become stable
+  {
+    GCTraceTime(Debug, gc, ref) tt("Preclean Ephemerons", gc_timer);
+    bool ephemerons_removed;
+    bool forward_scan = true;
+    do {
+      ephemerons_removed = false;
+      // alternate direction of selecting individual lists for scanning to avoid
+      // pathological cases where majority of revived ephemeron values point
+      // to ephemeron keys in "previous" lists...
+      if (forward_scan) {
+        for (uint i = 0; i < _max_num_q; i++) {
+          if (yield->should_return()) {
+            return;
+          }
+          ephemerons_removed |=
+            preclean_discovered_ephemerons_reflist(_discoveredEphemerons[i], is_alive,
+                                                   keep_alive, complete_gc, yield);
+        }
+      } else {
+        for (uint i = _max_num_q - 1; i < (uint) - 1; i--) {
+          if (yield->should_return()) {
+            return;
+          }
+          ephemerons_removed |=
+            preclean_discovered_ephemerons_reflist(_discoveredEphemerons[i], is_alive,
+                                                   keep_alive, complete_gc, yield);
+        }
+      }
+      forward_scan = !forward_scan;
+    } while (ephemerons_removed);
+  }
+
   // Soft references
   {
     GCTraceTime(Debug, gc, ref) tm("Preclean SoftReferences", gc_timer);
     for (uint i = 0; i < _max_num_q; i++) {
       if (yield->should_return()) {

@@ -1160,21 +1464,10 @@
         return;
       }
       preclean_discovered_reflist(_discoveredPhantomRefs[i], is_alive,
                                   keep_alive, complete_gc, yield);
     }
-
-    // Cleaner references.  Included in timing for phantom references.  We
-    // expect Cleaner references to be temporary, and don't want to deal with
-    // possible incompatibilities arising from making it more visible.
-    for (uint i = 0; i < _max_num_q; i++) {
-      if (yield->should_return()) {
-        return;
-      }
-      preclean_discovered_reflist(_discoveredCleanerRefs[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

@@ -1225,22 +1518,99 @@
       log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " Refs out of " SIZE_FORMAT " Refs in discovered list " INTPTR_FORMAT,
         iter.removed(), iter.processed(), p2i(refs_list.head()));
     }
   )
 }
+// The same as above, but specialized for ephemerons and returns true if any
+// ephemerons were removed from ref list.
+bool
+ReferenceProcessor::preclean_discovered_ephemerons_reflist(DiscoveredList& refs_list,
+                                                           BoolObjectClosure* is_alive,
+                                                           OopClosure* keep_alive,
+                                                           VoidClosure* complete_gc,
+                                                           YieldClosure* yield) {
+  DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
+  // Temporary list used to reverse the order of ephemerons at each pass to avoid
+  // pathological cases where majority of revived ephemeron values point
+  // to ephemeron keys in the list "preceeding" this ephemeron.
+  DiscoveredList reversed_list;
+  bool ephemerons_removed = false;
+  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() ||
+        next != NULL) {
+      // The referent has been cleared, or is alive, or the Reference is not
+      // active; we need to trace and mark its cohort.
+      log_develop_trace(gc, ref)("Precleaning Ephemeron (" INTPTR_FORMAT ": %s)",
+                                 p2i(obj), obj->klass()->internal_name());
+      // Remove Reference object from list
+      iter.remove();
+      // 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);
+      }
+      HeapWord* value_addr = java_lang_ref_Ephemeron::value_addr(obj);
+      if (UseCompressedOops) {
+        keep_alive->do_oop((narrowOop*) value_addr);
+      } else {
+        keep_alive->do_oop((oop*) value_addr);
+      }
+      ephemerons_removed = true;
+      // Close the newly reachable set as soon as the value is marked to be alive
+      // to increase the chance other ephemeron referents (keys) are revived as
+      // we proceed scanning the list.
+      complete_gc->do_void();
+    } else {
+      // Referent (key) is not alive (yet) so move the ephemeron to a reversed_list
+      // to reverse scanning in the next pass.
+      iter.remove();
+      HeapWord* discovered_addr = java_lang_ref_Reference::discovered_addr(obj);
+      oop current_head = reversed_list.head();
+      // The last ref must have its discovered field pointing to itself.
+      oop next_discovered = (current_head != NULL) ? current_head : obj;
+      oop_store_raw(discovered_addr, next_discovered);
+      reversed_list.set_head(obj);
+      reversed_list.inc_length(1);
+    }
+    iter.move_to_next();
+  }
+  assert(refs_list.length() == 0, "Should be empty");
+  // replace the list with reversed list
+  refs_list = reversed_list;
+  // Close the reachable set even if no ephemeron was removed from list
+  if (!ephemerons_removed) {
+    complete_gc->do_void();
+  }
+  NOT_PRODUCT(
+    if (iter.processed() > 0) {
+      log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " Ephemerons out of " SIZE_FORMAT
+                                 " Ephemerons in discovered list " INTPTR_FORMAT,
+                                 iter.processed() - refs_list.length(), iter.processed(),
+                                 p2i(refs_list.head()));
+    }
+  )
+  return ephemerons_removed;
+}
 
 const char* ReferenceProcessor::list_name(uint i) {
    assert(i <= _max_num_q * number_of_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";
-     case 3: return "PhantomRef";
-     case 4: return "CleanerRef";
+     case 2: return "Ephemeron";
+     case 3: return "FinalRef";
+     case 4: return "PhantomRef";
    }
    ShouldNotReachHere();
    return NULL;
 }
 
< prev index next >