< prev index next >

src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp

Print this page

  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  *
 24  */
 25 
 26 #include "precompiled.hpp"
 27 #include "classfile/javaClasses.hpp"
 28 #include "gc/shared/workerThread.hpp"

 29 #include "gc/shenandoah/shenandoahOopClosures.inline.hpp"
 30 #include "gc/shenandoah/shenandoahReferenceProcessor.hpp"
 31 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
 32 #include "gc/shenandoah/shenandoahUtils.hpp"
 33 #include "runtime/atomic.hpp"
 34 #include "logging/log.hpp"
 35 
 36 static ReferenceType reference_type(oop reference) {
 37   return InstanceKlass::cast(reference->klass())->reference_type();
 38 }
 39 
 40 static const char* reference_type_name(ReferenceType type) {
 41   switch (type) {
 42     case REF_SOFT:
 43       return "Soft";
 44 
 45     case REF_WEAK:
 46       return "Weak";
 47 
 48     case REF_FINAL:

240 }
241 
242 bool ShenandoahReferenceProcessor::is_softly_live(oop reference, ReferenceType type) const {
243   if (type != REF_SOFT) {
244     // Not a SoftReference
245     return false;
246   }
247 
248   // Ask SoftReference policy
249   const jlong clock = java_lang_ref_SoftReference::clock();
250   assert(clock != 0, "Clock not initialized");
251   assert(_soft_reference_policy != NULL, "Policy not initialized");
252   return !_soft_reference_policy->should_clear_reference(reference, clock);
253 }
254 
255 template <typename T>
256 bool ShenandoahReferenceProcessor::should_discover(oop reference, ReferenceType type) const {
257   T* referent_addr = (T*) java_lang_ref_Reference::referent_addr_raw(reference);
258   T heap_oop = RawAccess<>::oop_load(referent_addr);
259   oop referent = CompressedOops::decode(heap_oop);

260 
261   if (is_inactive<T>(reference, referent, type)) {
262     log_trace(gc,ref)("Reference inactive: " PTR_FORMAT, p2i(reference));
263     return false;
264   }
265 
266   if (is_strongly_live(referent)) {
267     log_trace(gc,ref)("Reference strongly live: " PTR_FORMAT, p2i(reference));
268     return false;
269   }
270 
271   if (is_softly_live(reference, type)) {
272     log_trace(gc,ref)("Reference softly live: " PTR_FORMAT, p2i(reference));
273     return false;
274   }
275 





276   return true;
277 }
278 
279 template <typename T>
280 bool ShenandoahReferenceProcessor::should_drop(oop reference, ReferenceType type) const {
281   const oop referent = reference_referent<T>(reference);
282   if (referent == NULL) {
283     // Reference has been cleared, by a call to Reference.enqueue()
284     // or Reference.clear() from the application, which means we
285     // should drop the reference.
286     return true;
287   }
288 
289   // Check if the referent is still alive, in which case we should
290   // drop the reference.
291   if (type == REF_PHANTOM) {
292     return ShenandoahHeap::heap()->complete_marking_context()->is_marked(referent);
293   } else {
294     return ShenandoahHeap::heap()->complete_marking_context()->is_marked_strong(referent);
295   }

343   if (discovered_head == NULL) {
344     // Self-loop tail of list. We distinguish discovered from not-discovered references by looking at their
345     // discovered field: if it is NULL, then it is not-yet discovered, otherwise it is discovered
346     discovered_head = reference;
347   }
348   if (reference_cas_discovered<T>(reference, discovered_head)) {
349     refproc_data.set_discovered_list_head<T>(reference);
350     assert(refproc_data.discovered_list_head<T>() == reference, "reference must be new discovered head");
351     log_trace(gc, ref)("Discovered Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type));
352     _ref_proc_thread_locals[worker_id].inc_discovered(type);
353   }
354   return true;
355 }
356 
357 bool ShenandoahReferenceProcessor::discover_reference(oop reference, ReferenceType type) {
358   if (!RegisterReferences) {
359     // Reference processing disabled
360     return false;
361   }
362 
363   log_trace(gc, ref)("Encountered Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type));

364   uint worker_id = WorkerThread::worker_id();
365   _ref_proc_thread_locals->inc_encountered(type);
366 
367   if (UseCompressedOops) {
368     return discover<narrowOop>(reference, type, worker_id);
369   } else {
370     return discover<oop>(reference, type, worker_id);
371   }
372 }
373 
374 template <typename T>
375 oop ShenandoahReferenceProcessor::drop(oop reference, ReferenceType type) {
376   log_trace(gc, ref)("Dropped Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type));
377 
378 #ifdef ASSERT
379   oop referent = reference_referent<T>(reference);
380   assert(referent == NULL || ShenandoahHeap::heap()->marking_context()->is_marked(referent),
381          "only drop references with alive referents");
382 #endif
383 
384   // Unlink and return next in list
385   oop next = reference_discovered<T>(reference);
386   reference_set_discovered<T>(reference, NULL);








387   return next;
388 }
389 
390 template <typename T>
391 T* ShenandoahReferenceProcessor::keep(oop reference, ReferenceType type, uint worker_id) {
392   log_trace(gc, ref)("Enqueued Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type));
393 
394   // Update statistics
395   _ref_proc_thread_locals[worker_id].inc_enqueued(type);
396 
397   // Make reference inactive
398   make_inactive<T>(reference, type);
399 
400   // Return next in list
401   return reference_discovered_addr<T>(reference);
402 }
403 
404 template <typename T>
405 void ShenandoahReferenceProcessor::process_references(ShenandoahRefProcThreadLocal& refproc_data, uint worker_id) {;
406   log_trace(gc, ref)("Processing discovered list #%u : " PTR_FORMAT, worker_id, p2i(refproc_data.discovered_list_head<T>()));

506   collect_statistics();
507 
508   enqueue_references(concurrent);
509 }
510 
511 void ShenandoahReferenceProcessor::enqueue_references_locked() {
512   // Prepend internal pending list to external pending list
513   shenandoah_assert_not_in_cset_except(&_pending_list, _pending_list, ShenandoahHeap::heap()->cancelled_gc() || !ShenandoahLoadRefBarrier);
514   if (UseCompressedOops) {
515     *reinterpret_cast<narrowOop*>(_pending_list_tail) = CompressedOops::encode(Universe::swap_reference_pending_list(_pending_list));
516   } else {
517     *reinterpret_cast<oop*>(_pending_list_tail) = Universe::swap_reference_pending_list(_pending_list);
518   }
519 }
520 
521 void ShenandoahReferenceProcessor::enqueue_references(bool concurrent) {
522   if (_pending_list == NULL) {
523     // Nothing to enqueue
524     return;
525   }
526 
527   if (!concurrent) {
528     // When called from mark-compact or degen-GC, the locking is done by the VMOperation,
529     enqueue_references_locked();
530   } else {
531     // Heap_lock protects external pending list
532     MonitorLocker ml(Heap_lock);
533 
534     enqueue_references_locked();
535 
536     // Notify ReferenceHandler thread
537     ml.notify_all();
538   }
539 
540   // Reset internal pending list
541   _pending_list = NULL;
542   _pending_list_tail = &_pending_list;
543 }
544 
545 template<typename T>
546 void ShenandoahReferenceProcessor::clean_discovered_list(T* list) {

  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  *
 24  */
 25 
 26 #include "precompiled.hpp"
 27 #include "classfile/javaClasses.hpp"
 28 #include "gc/shared/workerThread.hpp"
 29 #include "gc/shenandoah/mode/shenandoahGenerationalMode.hpp"
 30 #include "gc/shenandoah/shenandoahOopClosures.inline.hpp"
 31 #include "gc/shenandoah/shenandoahReferenceProcessor.hpp"
 32 #include "gc/shenandoah/shenandoahThreadLocalData.hpp"
 33 #include "gc/shenandoah/shenandoahUtils.hpp"
 34 #include "runtime/atomic.hpp"
 35 #include "logging/log.hpp"
 36 
 37 static ReferenceType reference_type(oop reference) {
 38   return InstanceKlass::cast(reference->klass())->reference_type();
 39 }
 40 
 41 static const char* reference_type_name(ReferenceType type) {
 42   switch (type) {
 43     case REF_SOFT:
 44       return "Soft";
 45 
 46     case REF_WEAK:
 47       return "Weak";
 48 
 49     case REF_FINAL:

241 }
242 
243 bool ShenandoahReferenceProcessor::is_softly_live(oop reference, ReferenceType type) const {
244   if (type != REF_SOFT) {
245     // Not a SoftReference
246     return false;
247   }
248 
249   // Ask SoftReference policy
250   const jlong clock = java_lang_ref_SoftReference::clock();
251   assert(clock != 0, "Clock not initialized");
252   assert(_soft_reference_policy != NULL, "Policy not initialized");
253   return !_soft_reference_policy->should_clear_reference(reference, clock);
254 }
255 
256 template <typename T>
257 bool ShenandoahReferenceProcessor::should_discover(oop reference, ReferenceType type) const {
258   T* referent_addr = (T*) java_lang_ref_Reference::referent_addr_raw(reference);
259   T heap_oop = RawAccess<>::oop_load(referent_addr);
260   oop referent = CompressedOops::decode(heap_oop);
261   ShenandoahHeap* heap = ShenandoahHeap::heap();
262 
263   if (is_inactive<T>(reference, referent, type)) {
264     log_trace(gc,ref)("Reference inactive: " PTR_FORMAT, p2i(reference));
265     return false;
266   }
267 
268   if (is_strongly_live(referent)) {
269     log_trace(gc,ref)("Reference strongly live: " PTR_FORMAT, p2i(reference));
270     return false;
271   }
272 
273   if (is_softly_live(reference, type)) {
274     log_trace(gc,ref)("Reference softly live: " PTR_FORMAT, p2i(reference));
275     return false;
276   }
277 
278   if (!heap->is_in_active_generation(referent)) {
279     log_trace(gc,ref)("Referent outside of active generation: " PTR_FORMAT, p2i(referent));
280     return false;
281   }
282 
283   return true;
284 }
285 
286 template <typename T>
287 bool ShenandoahReferenceProcessor::should_drop(oop reference, ReferenceType type) const {
288   const oop referent = reference_referent<T>(reference);
289   if (referent == NULL) {
290     // Reference has been cleared, by a call to Reference.enqueue()
291     // or Reference.clear() from the application, which means we
292     // should drop the reference.
293     return true;
294   }
295 
296   // Check if the referent is still alive, in which case we should
297   // drop the reference.
298   if (type == REF_PHANTOM) {
299     return ShenandoahHeap::heap()->complete_marking_context()->is_marked(referent);
300   } else {
301     return ShenandoahHeap::heap()->complete_marking_context()->is_marked_strong(referent);
302   }

350   if (discovered_head == NULL) {
351     // Self-loop tail of list. We distinguish discovered from not-discovered references by looking at their
352     // discovered field: if it is NULL, then it is not-yet discovered, otherwise it is discovered
353     discovered_head = reference;
354   }
355   if (reference_cas_discovered<T>(reference, discovered_head)) {
356     refproc_data.set_discovered_list_head<T>(reference);
357     assert(refproc_data.discovered_list_head<T>() == reference, "reference must be new discovered head");
358     log_trace(gc, ref)("Discovered Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type));
359     _ref_proc_thread_locals[worker_id].inc_discovered(type);
360   }
361   return true;
362 }
363 
364 bool ShenandoahReferenceProcessor::discover_reference(oop reference, ReferenceType type) {
365   if (!RegisterReferences) {
366     // Reference processing disabled
367     return false;
368   }
369 
370   log_trace(gc, ref)("Encountered Reference: " PTR_FORMAT " (%s, %s)",
371           p2i(reference), reference_type_name(type), affiliation_name(reference));
372   uint worker_id = WorkerThread::worker_id();
373   _ref_proc_thread_locals->inc_encountered(type);
374 
375   if (UseCompressedOops) {
376     return discover<narrowOop>(reference, type, worker_id);
377   } else {
378     return discover<oop>(reference, type, worker_id);
379   }
380 }
381 
382 template <typename T>
383 oop ShenandoahReferenceProcessor::drop(oop reference, ReferenceType type) {
384   log_trace(gc, ref)("Dropped Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type));
385 
386   ShenandoahHeap* heap = ShenandoahHeap::heap();
387   oop referent = reference_referent<T>(reference);
388   assert(referent == NULL || heap->marking_context()->is_marked(referent), "only drop references with alive referents");


389 
390   // Unlink and return next in list
391   oop next = reference_discovered<T>(reference);
392   reference_set_discovered<T>(reference, NULL);
393   // When this reference was discovered, it would not have been marked. If it ends up surviving
394   // the cycle, we need to dirty the card if the reference is old and the referent is young.  Note
395   // that if the reference is not dropped, then its pointer to the referent will be nulled before
396   // evacuation begins so card does not need to be dirtied.
397   if (heap->mode()->is_generational() && heap->is_in_old(reference) && heap->is_in_young(referent)) {
398     // Note: would be sufficient to mark only the card that holds the start of this Reference object.
399     heap->card_scan()->mark_range_as_dirty(cast_from_oop<HeapWord*>(reference), reference->size());
400   }
401   return next;
402 }
403 
404 template <typename T>
405 T* ShenandoahReferenceProcessor::keep(oop reference, ReferenceType type, uint worker_id) {
406   log_trace(gc, ref)("Enqueued Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type));
407 
408   // Update statistics
409   _ref_proc_thread_locals[worker_id].inc_enqueued(type);
410 
411   // Make reference inactive
412   make_inactive<T>(reference, type);
413 
414   // Return next in list
415   return reference_discovered_addr<T>(reference);
416 }
417 
418 template <typename T>
419 void ShenandoahReferenceProcessor::process_references(ShenandoahRefProcThreadLocal& refproc_data, uint worker_id) {;
420   log_trace(gc, ref)("Processing discovered list #%u : " PTR_FORMAT, worker_id, p2i(refproc_data.discovered_list_head<T>()));

520   collect_statistics();
521 
522   enqueue_references(concurrent);
523 }
524 
525 void ShenandoahReferenceProcessor::enqueue_references_locked() {
526   // Prepend internal pending list to external pending list
527   shenandoah_assert_not_in_cset_except(&_pending_list, _pending_list, ShenandoahHeap::heap()->cancelled_gc() || !ShenandoahLoadRefBarrier);
528   if (UseCompressedOops) {
529     *reinterpret_cast<narrowOop*>(_pending_list_tail) = CompressedOops::encode(Universe::swap_reference_pending_list(_pending_list));
530   } else {
531     *reinterpret_cast<oop*>(_pending_list_tail) = Universe::swap_reference_pending_list(_pending_list);
532   }
533 }
534 
535 void ShenandoahReferenceProcessor::enqueue_references(bool concurrent) {
536   if (_pending_list == NULL) {
537     // Nothing to enqueue
538     return;
539   }

540   if (!concurrent) {
541     // When called from mark-compact or degen-GC, the locking is done by the VMOperation,
542     enqueue_references_locked();
543   } else {
544     // Heap_lock protects external pending list
545     MonitorLocker ml(Heap_lock);
546 
547     enqueue_references_locked();
548 
549     // Notify ReferenceHandler thread
550     ml.notify_all();
551   }
552 
553   // Reset internal pending list
554   _pending_list = NULL;
555   _pending_list_tail = &_pending_list;
556 }
557 
558 template<typename T>
559 void ShenandoahReferenceProcessor::clean_discovered_list(T* list) {
< prev index next >