hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp
6687581: Make CMS work with compressed oops
Summary: Make FreeChunk read markword instead of LSB in _klass pointer to indicate that it's a FreeChunk for compressed oops.
Reviewed-by: ysr, jmasa
/*
* Copyright 2001-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
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 corrsponding to the next "0" bit
// (inclusive).
inline HeapWord* CMSBitMap::getNextUnmarkedWordAddress(HeapWord* addr) const {
return getNextUnmarkedWordAddress(addr, endWord());
}
// Return the HeapWord address corrsponding 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::start_icms() {
if (CMSIncrementalMode) {
ConcurrentMarkSweepThread::start_icms();
}
}
inline void CMSCollector::stop_icms() {
if (CMSIncrementalMode) {
ConcurrentMarkSweepThread::stop_icms();
}
}
inline void CMSCollector::disable_icms() {
if (CMSIncrementalMode) {
ConcurrentMarkSweepThread::disable_icms();
}
}
inline void CMSCollector::enable_icms() {
if (CMSIncrementalMode) {
ConcurrentMarkSweepThread::enable_icms();
}
}
inline void CMSCollector::icms_wait() {
if (CMSIncrementalMode) {
cmsThread()->icms_wait();
}
}
inline void CMSCollector::save_sweep_limits() {
_cmsGen->save_sweep_limit();
_permGen->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))
||
(_permGen->cmsSpace()->is_in_reserved(addr)
&& _permGen->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());
}
inline size_t CMSCollector::get_eden_used() const {
return _young_gen->as_DefNewGeneration()->eden()->used();
}
inline size_t CMSCollector::get_eden_capacity() const {
return _young_gen->as_DefNewGeneration()->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 younger gen collections were 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);
// Avoid division by 0.
const size_t cms_used_mb = MAX2(_cms_used_at_cms_begin / M, (size_t)1);
_cms_duration_per_mb = AdaptiveWeightedAverage::exp_avg(_cms_duration_per_mb,
cur_duration / cms_used_mb,
_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 unsigned int CMSStats::icms_update_duty_cycle() {
// Update the duty cycle only if pacing is enabled and the stats are valid
// (after at least one young gen gc and one cms cycle have completed).
if (CMSIncrementalPacing && valid()) {
return icms_update_duty_cycle_impl();
}
return _icms_duty_cycle;
}
inline void ConcurrentMarkSweepGeneration::save_sweep_limit() {
cmsSpace()->save_sweep_limit();
}
inline size_t ConcurrentMarkSweepGeneration::capacity() const {
return _cmsSpace->capacity();
}
inline size_t ConcurrentMarkSweepGeneration::used() const {
return _cmsSpace->used();
}
inline size_t ConcurrentMarkSweepGeneration::free() const {
return _cmsSpace->free();
}
inline MemRegion ConcurrentMarkSweepGeneration::used_region() const {
return _cmsSpace->used_region();
}
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 Par_MarkFromRootsClosure::do_yield_check() {
if (ConcurrentMarkSweepThread::should_yield() &&
!_collector->foregroundGCIsActive() &&
_yield) {
do_yield_work();
}
}
// 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(), (HeapWord*)round_to((intptr_t)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(), (HeapWord*)round_to((intptr_t)mr.end(),
CardTableModRefBS::card_size /* bytes */));
_t->par_mark_range(mr2);
}