src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.inline.hpp
changeset 47216 71c04702a3d5
parent 46625 edefffab74e2
child 47622 817f2a7019e4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.inline.hpp	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_CMS_CONCURRENTMARKSWEEPGENERATION_INLINE_HPP
+#define SHARE_VM_GC_CMS_CONCURRENTMARKSWEEPGENERATION_INLINE_HPP
+
+#include "gc/cms/cmsLockVerifier.hpp"
+#include "gc/cms/compactibleFreeListSpace.hpp"
+#include "gc/cms/concurrentMarkSweepGeneration.hpp"
+#include "gc/cms/concurrentMarkSweepThread.hpp"
+#include "gc/cms/parNewGeneration.hpp"
+#include "gc/shared/gcUtil.hpp"
+#include "gc/shared/genCollectedHeap.hpp"
+#include "utilities/align.hpp"
+#include "utilities/bitMap.inline.hpp"
+
+inline void CMSBitMap::clear_all() {
+  assert_locked();
+  // CMS bitmaps are usually cover large memory regions
+  _bm.clear_large();
+  return;
+}
+
+inline size_t CMSBitMap::heapWordToOffset(HeapWord* addr) const {
+  return (pointer_delta(addr, _bmStartWord)) >> _shifter;
+}
+
+inline HeapWord* CMSBitMap::offsetToHeapWord(size_t offset) const {
+  return _bmStartWord + (offset << _shifter);
+}
+
+inline size_t CMSBitMap::heapWordDiffToOffsetDiff(size_t diff) const {
+  assert((diff & ((1 << _shifter) - 1)) == 0, "argument check");
+  return diff >> _shifter;
+}
+
+inline void CMSBitMap::mark(HeapWord* addr) {
+  assert_locked();
+  assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
+         "outside underlying space?");
+  _bm.set_bit(heapWordToOffset(addr));
+}
+
+inline bool CMSBitMap::par_mark(HeapWord* addr) {
+  assert_locked();
+  assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
+         "outside underlying space?");
+  return _bm.par_at_put(heapWordToOffset(addr), true);
+}
+
+inline void CMSBitMap::par_clear(HeapWord* addr) {
+  assert_locked();
+  assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
+         "outside underlying space?");
+  _bm.par_at_put(heapWordToOffset(addr), false);
+}
+
+inline void CMSBitMap::mark_range(MemRegion mr) {
+  NOT_PRODUCT(region_invariant(mr));
+  // Range size is usually just 1 bit.
+  _bm.set_range(heapWordToOffset(mr.start()), heapWordToOffset(mr.end()),
+                BitMap::small_range);
+}
+
+inline void CMSBitMap::clear_range(MemRegion mr) {
+  NOT_PRODUCT(region_invariant(mr));
+  // Range size is usually just 1 bit.
+  _bm.clear_range(heapWordToOffset(mr.start()), heapWordToOffset(mr.end()),
+                  BitMap::small_range);
+}
+
+inline void CMSBitMap::par_mark_range(MemRegion mr) {
+  NOT_PRODUCT(region_invariant(mr));
+  // Range size is usually just 1 bit.
+  _bm.par_set_range(heapWordToOffset(mr.start()), heapWordToOffset(mr.end()),
+                    BitMap::small_range);
+}
+
+inline void CMSBitMap::par_clear_range(MemRegion mr) {
+  NOT_PRODUCT(region_invariant(mr));
+  // Range size is usually just 1 bit.
+  _bm.par_clear_range(heapWordToOffset(mr.start()), heapWordToOffset(mr.end()),
+                      BitMap::small_range);
+}
+
+inline void CMSBitMap::mark_large_range(MemRegion mr) {
+  NOT_PRODUCT(region_invariant(mr));
+  // Range size must be greater than 32 bytes.
+  _bm.set_range(heapWordToOffset(mr.start()), heapWordToOffset(mr.end()),
+                BitMap::large_range);
+}
+
+inline void CMSBitMap::clear_large_range(MemRegion mr) {
+  NOT_PRODUCT(region_invariant(mr));
+  // Range size must be greater than 32 bytes.
+  _bm.clear_range(heapWordToOffset(mr.start()), heapWordToOffset(mr.end()),
+                  BitMap::large_range);
+}
+
+inline void CMSBitMap::par_mark_large_range(MemRegion mr) {
+  NOT_PRODUCT(region_invariant(mr));
+  // Range size must be greater than 32 bytes.
+  _bm.par_set_range(heapWordToOffset(mr.start()), heapWordToOffset(mr.end()),
+                    BitMap::large_range);
+}
+
+inline void CMSBitMap::par_clear_large_range(MemRegion mr) {
+  NOT_PRODUCT(region_invariant(mr));
+  // Range size must be greater than 32 bytes.
+  _bm.par_clear_range(heapWordToOffset(mr.start()), heapWordToOffset(mr.end()),
+                      BitMap::large_range);
+}
+
+// Starting at "addr" (inclusive) return a memory region
+// corresponding to the first maximally contiguous marked ("1") region.
+inline MemRegion CMSBitMap::getAndClearMarkedRegion(HeapWord* addr) {
+  return getAndClearMarkedRegion(addr, endWord());
+}
+
+// Starting at "start_addr" (inclusive) return a memory region
+// corresponding to the first maximal contiguous marked ("1") region
+// strictly less than end_addr.
+inline MemRegion CMSBitMap::getAndClearMarkedRegion(HeapWord* start_addr,
+                                                    HeapWord* end_addr) {
+  HeapWord *start, *end;
+  assert_locked();
+  start = getNextMarkedWordAddress  (start_addr, end_addr);
+  end   = getNextUnmarkedWordAddress(start,      end_addr);
+  assert(start <= end, "Consistency check");
+  MemRegion mr(start, end);
+  if (!mr.is_empty()) {
+    clear_range(mr);
+  }
+  return mr;
+}
+
+inline bool CMSBitMap::isMarked(HeapWord* addr) const {
+  assert_locked();
+  assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
+         "outside underlying space?");
+  return _bm.at(heapWordToOffset(addr));
+}
+
+// The same as isMarked() but without a lock check.
+inline bool CMSBitMap::par_isMarked(HeapWord* addr) const {
+  assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
+         "outside underlying space?");
+  return _bm.at(heapWordToOffset(addr));
+}
+
+
+inline bool CMSBitMap::isUnmarked(HeapWord* addr) const {
+  assert_locked();
+  assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
+         "outside underlying space?");
+  return !_bm.at(heapWordToOffset(addr));
+}
+
+// Return the HeapWord address corresponding to next "1" bit
+// (inclusive).
+inline HeapWord* CMSBitMap::getNextMarkedWordAddress(HeapWord* addr) const {
+  return getNextMarkedWordAddress(addr, endWord());
+}
+
+// Return the least HeapWord address corresponding to next "1" bit
+// starting at start_addr (inclusive) but strictly less than end_addr.
+inline HeapWord* CMSBitMap::getNextMarkedWordAddress(
+  HeapWord* start_addr, HeapWord* end_addr) const {
+  assert_locked();
+  size_t nextOffset = _bm.get_next_one_offset(
+                        heapWordToOffset(start_addr),
+                        heapWordToOffset(end_addr));
+  HeapWord* nextAddr = offsetToHeapWord(nextOffset);
+  assert(nextAddr >= start_addr &&
+         nextAddr <= end_addr, "get_next_one postcondition");
+  assert((nextAddr == end_addr) ||
+         isMarked(nextAddr), "get_next_one postcondition");
+  return nextAddr;
+}
+
+
+// Return the HeapWord address corresponding to the next "0" bit
+// (inclusive).
+inline HeapWord* CMSBitMap::getNextUnmarkedWordAddress(HeapWord* addr) const {
+  return getNextUnmarkedWordAddress(addr, endWord());
+}
+
+// Return the HeapWord address corresponding to the next "0" bit
+// (inclusive).
+inline HeapWord* CMSBitMap::getNextUnmarkedWordAddress(
+  HeapWord* start_addr, HeapWord* end_addr) const {
+  assert_locked();
+  size_t nextOffset = _bm.get_next_zero_offset(
+                        heapWordToOffset(start_addr),
+                        heapWordToOffset(end_addr));
+  HeapWord* nextAddr = offsetToHeapWord(nextOffset);
+  assert(nextAddr >= start_addr &&
+         nextAddr <= end_addr, "get_next_zero postcondition");
+  assert((nextAddr == end_addr) ||
+          isUnmarked(nextAddr), "get_next_zero postcondition");
+  return nextAddr;
+}
+
+inline bool CMSBitMap::isAllClear() const {
+  assert_locked();
+  return getNextMarkedWordAddress(startWord()) >= endWord();
+}
+
+inline void CMSBitMap::iterate(BitMapClosure* cl, HeapWord* left,
+                            HeapWord* right) {
+  assert_locked();
+  left = MAX2(_bmStartWord, left);
+  right = MIN2(_bmStartWord + _bmWordSize, right);
+  if (right > left) {
+    _bm.iterate(cl, heapWordToOffset(left), heapWordToOffset(right));
+  }
+}
+
+inline void CMSCollector::save_sweep_limits() {
+  _cmsGen->save_sweep_limit();
+}
+
+inline bool CMSCollector::is_dead_obj(oop obj) const {
+  HeapWord* addr = (HeapWord*)obj;
+  assert((_cmsGen->cmsSpace()->is_in_reserved(addr)
+          && _cmsGen->cmsSpace()->block_is_obj(addr)),
+         "must be object");
+  return  should_unload_classes() &&
+          _collectorState == Sweeping &&
+         !_markBitMap.isMarked(addr);
+}
+
+inline bool CMSCollector::should_abort_preclean() const {
+  // We are in the midst of an "abortable preclean" and either
+  // scavenge is done or foreground GC wants to take over collection
+  return _collectorState == AbortablePreclean &&
+         (_abort_preclean || _foregroundGCIsActive ||
+          GenCollectedHeap::heap()->incremental_collection_will_fail(true /* consult_young */));
+}
+
+inline size_t CMSCollector::get_eden_used() const {
+  return _young_gen->eden()->used();
+}
+
+inline size_t CMSCollector::get_eden_capacity() const {
+  return _young_gen->eden()->capacity();
+}
+
+inline bool CMSStats::valid() const {
+  return _valid_bits == _ALL_VALID;
+}
+
+inline void CMSStats::record_gc0_begin() {
+  if (_gc0_begin_time.is_updated()) {
+    float last_gc0_period = _gc0_begin_time.seconds();
+    _gc0_period = AdaptiveWeightedAverage::exp_avg(_gc0_period,
+      last_gc0_period, _gc0_alpha);
+    _gc0_alpha = _saved_alpha;
+    _valid_bits |= _GC0_VALID;
+  }
+  _cms_used_at_gc0_begin = _cms_gen->cmsSpace()->used();
+
+  _gc0_begin_time.update();
+}
+
+inline void CMSStats::record_gc0_end(size_t cms_gen_bytes_used) {
+  float last_gc0_duration = _gc0_begin_time.seconds();
+  _gc0_duration = AdaptiveWeightedAverage::exp_avg(_gc0_duration,
+    last_gc0_duration, _gc0_alpha);
+
+  // Amount promoted.
+  _cms_used_at_gc0_end = cms_gen_bytes_used;
+
+  size_t promoted_bytes = 0;
+  if (_cms_used_at_gc0_end >= _cms_used_at_gc0_begin) {
+    promoted_bytes = _cms_used_at_gc0_end - _cms_used_at_gc0_begin;
+  }
+
+  // If the young gen collection was skipped, then the
+  // number of promoted bytes will be 0 and adding it to the
+  // average will incorrectly lessen the average.  It is, however,
+  // also possible that no promotion was needed.
+  //
+  // _gc0_promoted used to be calculated as
+  // _gc0_promoted = AdaptiveWeightedAverage::exp_avg(_gc0_promoted,
+  //  promoted_bytes, _gc0_alpha);
+  _cms_gen->gc_stats()->avg_promoted()->sample(promoted_bytes);
+  _gc0_promoted = (size_t) _cms_gen->gc_stats()->avg_promoted()->average();
+
+  // Amount directly allocated.
+  size_t allocated_bytes = _cms_gen->direct_allocated_words() * HeapWordSize;
+  _cms_gen->reset_direct_allocated_words();
+  _cms_allocated = AdaptiveWeightedAverage::exp_avg(_cms_allocated,
+    allocated_bytes, _gc0_alpha);
+}
+
+inline void CMSStats::record_cms_begin() {
+  _cms_timer.stop();
+
+  // This is just an approximate value, but is good enough.
+  _cms_used_at_cms_begin = _cms_used_at_gc0_end;
+
+  _cms_period = AdaptiveWeightedAverage::exp_avg((float)_cms_period,
+    (float) _cms_timer.seconds(), _cms_alpha);
+  _cms_begin_time.update();
+
+  _cms_timer.reset();
+  _cms_timer.start();
+}
+
+inline void CMSStats::record_cms_end() {
+  _cms_timer.stop();
+
+  float cur_duration = _cms_timer.seconds();
+  _cms_duration = AdaptiveWeightedAverage::exp_avg(_cms_duration,
+    cur_duration, _cms_alpha);
+
+  _cms_end_time.update();
+  _cms_alpha = _saved_alpha;
+  _allow_duty_cycle_reduction = true;
+  _valid_bits |= _CMS_VALID;
+
+  _cms_timer.start();
+}
+
+inline double CMSStats::cms_time_since_begin() const {
+  return _cms_begin_time.seconds();
+}
+
+inline double CMSStats::cms_time_since_end() const {
+  return _cms_end_time.seconds();
+}
+
+inline double CMSStats::promotion_rate() const {
+  assert(valid(), "statistics not valid yet");
+  return gc0_promoted() / gc0_period();
+}
+
+inline double CMSStats::cms_allocation_rate() const {
+  assert(valid(), "statistics not valid yet");
+  return cms_allocated() / gc0_period();
+}
+
+inline double CMSStats::cms_consumption_rate() const {
+  assert(valid(), "statistics not valid yet");
+  return (gc0_promoted() + cms_allocated()) / gc0_period();
+}
+
+inline void ConcurrentMarkSweepGeneration::save_sweep_limit() {
+  cmsSpace()->save_sweep_limit();
+}
+
+inline MemRegion ConcurrentMarkSweepGeneration::used_region_at_save_marks() const {
+  return _cmsSpace->used_region_at_save_marks();
+}
+
+inline void MarkFromRootsClosure::do_yield_check() {
+  if (ConcurrentMarkSweepThread::should_yield() &&
+      !_collector->foregroundGCIsActive() &&
+      _yield) {
+    do_yield_work();
+  }
+}
+
+inline void ParMarkFromRootsClosure::do_yield_check() {
+  if (ConcurrentMarkSweepThread::should_yield() &&
+      !_collector->foregroundGCIsActive()) {
+    do_yield_work();
+  }
+}
+
+inline void PushOrMarkClosure::do_yield_check() {
+  _parent->do_yield_check();
+}
+
+inline void ParPushOrMarkClosure::do_yield_check() {
+  _parent->do_yield_check();
+}
+
+// Return value of "true" indicates that the on-going preclean
+// should be aborted.
+inline bool ScanMarkedObjectsAgainCarefullyClosure::do_yield_check() {
+  if (ConcurrentMarkSweepThread::should_yield() &&
+      !_collector->foregroundGCIsActive() &&
+      _yield) {
+    // Sample young gen size before and after yield
+    _collector->sample_eden();
+    do_yield_work();
+    _collector->sample_eden();
+    return _collector->should_abort_preclean();
+  }
+  return false;
+}
+
+inline void SurvivorSpacePrecleanClosure::do_yield_check() {
+  if (ConcurrentMarkSweepThread::should_yield() &&
+      !_collector->foregroundGCIsActive() &&
+      _yield) {
+    // Sample young gen size before and after yield
+    _collector->sample_eden();
+    do_yield_work();
+    _collector->sample_eden();
+  }
+}
+
+inline void SweepClosure::do_yield_check(HeapWord* addr) {
+  if (ConcurrentMarkSweepThread::should_yield() &&
+      !_collector->foregroundGCIsActive() &&
+      _yield) {
+    do_yield_work(addr);
+  }
+}
+
+inline void MarkRefsIntoAndScanClosure::do_yield_check() {
+  // The conditions are ordered for the remarking phase
+  // when _yield is false.
+  if (_yield &&
+      !_collector->foregroundGCIsActive() &&
+      ConcurrentMarkSweepThread::should_yield()) {
+    do_yield_work();
+  }
+}
+
+
+inline void ModUnionClosure::do_MemRegion(MemRegion mr) {
+  // Align the end of mr so it's at a card boundary.
+  // This is superfluous except at the end of the space;
+  // we should do better than this XXX
+  MemRegion mr2(mr.start(), align_up(mr.end(),
+                 CardTableModRefBS::card_size /* bytes */));
+  _t->mark_range(mr2);
+}
+
+inline void ModUnionClosurePar::do_MemRegion(MemRegion mr) {
+  // Align the end of mr so it's at a card boundary.
+  // This is superfluous except at the end of the space;
+  // we should do better than this XXX
+  MemRegion mr2(mr.start(), align_up(mr.end(),
+                 CardTableModRefBS::card_size /* bytes */));
+  _t->par_mark_range(mr2);
+}
+
+#endif // SHARE_VM_GC_CMS_CONCURRENTMARKSWEEPGENERATION_INLINE_HPP