2011-01-19 19:30:42 -05:00
/*
2014-02-28 15:27:09 +01:00
* Copyright ( c ) 2011 , 2014 , Oracle and / or its affiliates . All rights reserved .
2011-01-19 19:30:42 -05:00
* 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 .
*
*/
# include "precompiled.hpp"
2014-08-18 16:10:44 +02:00
# include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
2014-03-14 10:15:46 +01:00
# include "gc_implementation/g1/heapRegionRemSet.hpp"
2011-01-19 19:30:42 -05:00
# include "gc_implementation/g1/heapRegionSet.inline.hpp"
2014-05-09 16:50:54 -04:00
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
2014-03-14 10:15:46 +01:00
uint FreeRegionList : : _unrealistically_long_length = 0 ;
2011-01-19 19:30:42 -05:00
2011-03-04 17:13:19 -05:00
void HeapRegionSetBase : : fill_in_ext_msg ( hrs_ext_msg * msg , const char * message ) {
2014-03-14 10:15:46 +01:00
msg - > append ( " [%s] %s ln: %u cy: " SIZE_FORMAT ,
name ( ) , message , length ( ) , total_capacity_bytes ( ) ) ;
2011-01-19 19:30:42 -05:00
fill_in_ext_msg_extra ( msg ) ;
}
2014-03-14 10:15:46 +01:00
# ifndef PRODUCT
void HeapRegionSetBase : : verify_region ( HeapRegion * hr ) {
assert ( hr - > containing_set ( ) = = this , err_msg ( " Inconsistent containing set for %u " , hr - > hrs_index ( ) ) ) ;
assert ( ! hr - > is_young ( ) , err_msg ( " Adding young region %u " , hr - > hrs_index ( ) ) ) ; // currently we don't use these sets for young regions
assert ( hr - > isHumongous ( ) = = regions_humongous ( ) , err_msg ( " Wrong humongous state for region %u and set %s " , hr - > hrs_index ( ) , name ( ) ) ) ;
assert ( hr - > is_empty ( ) = = regions_empty ( ) , err_msg ( " Wrong empty state for region %u and set %s " , hr - > hrs_index ( ) , name ( ) ) ) ;
assert ( hr - > rem_set ( ) - > verify_ready_for_par_iteration ( ) , err_msg ( " Wrong iteration state %u " , hr - > hrs_index ( ) ) ) ;
2011-01-19 19:30:42 -05:00
}
2014-03-14 10:15:46 +01:00
# endif
2011-01-19 19:30:42 -05:00
void HeapRegionSetBase : : verify ( ) {
// It's important that we also observe the MT safety protocol even
// for the verification calls. If we do verification without the
// appropriate locks and the set changes underneath our feet
// verification might fail and send us on a wild goose chase.
2014-03-14 10:15:46 +01:00
check_mt_safety ( ) ;
2011-01-19 19:30:42 -05:00
2014-03-14 10:15:46 +01:00
guarantee ( ( is_empty ( ) & & length ( ) = = 0 & & total_capacity_bytes ( ) = = 0 ) | |
( ! is_empty ( ) & & length ( ) > = 0 & & total_capacity_bytes ( ) > = 0 ) ,
2011-03-04 17:13:19 -05:00
hrs_ext_msg ( this , " invariant " ) ) ;
2011-01-19 19:30:42 -05:00
}
void HeapRegionSetBase : : verify_start ( ) {
// See comment in verify() about MT safety and verification.
2014-03-14 10:15:46 +01:00
check_mt_safety ( ) ;
2011-01-19 19:30:42 -05:00
assert ( ! _verify_in_progress ,
2011-03-04 17:13:19 -05:00
hrs_ext_msg ( this , " verification should not be in progress " ) ) ;
2011-01-19 19:30:42 -05:00
// Do the basic verification first before we do the checks over the regions.
HeapRegionSetBase : : verify ( ) ;
2014-08-18 16:10:44 +02:00
_verify_in_progress = true ;
2011-01-19 19:30:42 -05:00
}
void HeapRegionSetBase : : verify_end ( ) {
// See comment in verify() about MT safety and verification.
2014-03-14 10:15:46 +01:00
check_mt_safety ( ) ;
2011-01-19 19:30:42 -05:00
assert ( _verify_in_progress ,
2011-03-04 17:13:19 -05:00
hrs_ext_msg ( this , " verification should be in progress " ) ) ;
2011-01-19 19:30:42 -05:00
_verify_in_progress = false ;
}
void HeapRegionSetBase : : print_on ( outputStream * out , bool print_contents ) {
out - > cr ( ) ;
out - > print_cr ( " Set: %s ( " PTR_FORMAT " ) " , name ( ) , this ) ;
out - > print_cr ( " Region Assumptions " ) ;
out - > print_cr ( " humongous : %s " , BOOL_TO_STR ( regions_humongous ( ) ) ) ;
out - > print_cr ( " empty : %s " , BOOL_TO_STR ( regions_empty ( ) ) ) ;
out - > print_cr ( " Attributes " ) ;
2012-04-18 07:21:15 -04:00
out - > print_cr ( " length : %14u " , length ( ) ) ;
2011-01-19 19:30:42 -05:00
out - > print_cr ( " total capacity : " SIZE_FORMAT_W ( 14 ) " bytes " ,
total_capacity_bytes ( ) ) ;
}
2014-03-14 10:15:46 +01:00
HeapRegionSetBase : : HeapRegionSetBase ( const char * name , bool humongous , bool empty , HRSMtSafeChecker * mt_safety_checker )
2011-01-19 19:30:42 -05:00
: _name ( name ) , _verify_in_progress ( false ) ,
2014-03-14 10:15:46 +01:00
_is_humongous ( humongous ) , _is_empty ( empty ) , _mt_safety_checker ( mt_safety_checker ) ,
_count ( )
{ }
2011-01-19 19:30:42 -05:00
2014-03-14 10:15:46 +01:00
void FreeRegionList : : set_unrealistically_long_length ( uint len ) {
guarantee ( _unrealistically_long_length = = 0 , " should only be set once " ) ;
_unrealistically_long_length = len ;
2011-01-19 19:30:42 -05:00
}
2014-03-14 10:15:46 +01:00
void FreeRegionList : : fill_in_ext_msg_extra ( hrs_ext_msg * msg ) {
2014-08-18 16:10:44 +02:00
msg - > append ( " hd: " PTR_FORMAT " tl: " PTR_FORMAT , _head , _tail ) ;
2011-01-19 19:30:42 -05:00
}
2014-03-14 10:15:46 +01:00
void FreeRegionList : : remove_all ( ) {
check_mt_safety ( ) ;
2011-01-19 19:30:42 -05:00
verify_optional ( ) ;
HeapRegion * curr = _head ;
while ( curr ! = NULL ) {
2014-03-14 10:15:46 +01:00
verify_region ( curr ) ;
2011-01-19 19:30:42 -05:00
HeapRegion * next = curr - > next ( ) ;
curr - > set_next ( NULL ) ;
2014-02-28 15:27:09 +01:00
curr - > set_prev ( NULL ) ;
2011-01-19 19:30:42 -05:00
curr - > set_containing_set ( NULL ) ;
curr = next ;
}
clear ( ) ;
verify_optional ( ) ;
}
2014-02-28 15:27:09 +01:00
void FreeRegionList : : add_ordered ( FreeRegionList * from_list ) {
check_mt_safety ( ) ;
from_list - > check_mt_safety ( ) ;
verify_optional ( ) ;
from_list - > verify_optional ( ) ;
if ( from_list - > is_empty ( ) ) {
return ;
}
# ifdef ASSERT
FreeRegionListIterator iter ( from_list ) ;
while ( iter . more_available ( ) ) {
HeapRegion * hr = iter . get_next ( ) ;
// In set_containing_set() we check that we either set the value
// from NULL to non-NULL or vice versa to catch bugs. So, we have
// to NULL it first before setting it to the value.
hr - > set_containing_set ( NULL ) ;
hr - > set_containing_set ( this ) ;
}
# endif // ASSERT
2014-08-18 16:10:44 +02:00
if ( is_empty ( ) ) {
assert ( length ( ) = = 0 & & _tail = = NULL , hrs_ext_msg ( this , " invariant " ) ) ;
_head = from_list - > _head ;
_tail = from_list - > _tail ;
} else {
HeapRegion * curr_to = _head ;
HeapRegion * curr_from = from_list - > _head ;
2014-02-28 15:27:09 +01:00
2014-08-18 16:10:44 +02:00
while ( curr_from ! = NULL ) {
while ( curr_to ! = NULL & & curr_to - > hrs_index ( ) < curr_from - > hrs_index ( ) ) {
curr_to = curr_to - > next ( ) ;
}
2014-02-28 15:27:09 +01:00
2014-08-18 16:10:44 +02:00
if ( curr_to = = NULL ) {
// The rest of the from list should be added as tail
_tail - > set_next ( curr_from ) ;
curr_from - > set_prev ( _tail ) ;
curr_from = NULL ;
2014-02-28 15:27:09 +01:00
} else {
2014-08-18 16:10:44 +02:00
HeapRegion * next_from = curr_from - > next ( ) ;
curr_from - > set_next ( curr_to ) ;
curr_from - > set_prev ( curr_to - > prev ( ) ) ;
if ( curr_to - > prev ( ) = = NULL ) {
_head = curr_from ;
} else {
curr_to - > prev ( ) - > set_next ( curr_from ) ;
}
curr_to - > set_prev ( curr_from ) ;
curr_from = next_from ;
2014-02-28 15:27:09 +01:00
}
}
2014-08-18 16:10:44 +02:00
if ( _tail - > hrs_index ( ) < from_list - > _tail - > hrs_index ( ) ) {
_tail = from_list - > _tail ;
}
2014-02-28 15:27:09 +01:00
}
_count . increment ( from_list - > length ( ) , from_list - > total_capacity_bytes ( ) ) ;
from_list - > clear ( ) ;
verify_optional ( ) ;
from_list - > verify_optional ( ) ;
}
2014-08-18 16:10:44 +02:00
void FreeRegionList : : remove_starting_at ( HeapRegion * first , uint num_regions ) {
2014-03-14 10:15:46 +01:00
check_mt_safety ( ) ;
2014-08-18 16:10:44 +02:00
assert ( num_regions > = 1 , hrs_ext_msg ( this , " pre-condition " ) ) ;
2011-03-04 17:13:19 -05:00
assert ( ! is_empty ( ) , hrs_ext_msg ( this , " pre-condition " ) ) ;
2011-01-19 19:30:42 -05:00
verify_optional ( ) ;
2012-04-18 07:21:15 -04:00
DEBUG_ONLY ( uint old_length = length ( ) ; )
2011-01-19 19:30:42 -05:00
2014-08-18 16:10:44 +02:00
HeapRegion * curr = first ;
2012-04-18 07:21:15 -04:00
uint count = 0 ;
2014-08-18 16:10:44 +02:00
while ( count < num_regions ) {
2014-03-14 10:15:46 +01:00
verify_region ( curr ) ;
2011-01-19 19:30:42 -05:00
HeapRegion * next = curr - > next ( ) ;
2014-02-28 15:27:09 +01:00
HeapRegion * prev = curr - > prev ( ) ;
2011-01-19 19:30:42 -05:00
2014-08-18 16:10:44 +02:00
assert ( count < num_regions ,
hrs_err_msg ( " [%s] should not come across more regions "
" pending for removal than num_regions: %u " ,
name ( ) , num_regions ) ) ;
2011-01-19 19:30:42 -05:00
2014-08-18 16:10:44 +02:00
if ( prev = = NULL ) {
assert ( _head = = curr , hrs_ext_msg ( this , " invariant " ) ) ;
_head = next ;
} else {
assert ( _head ! = curr , hrs_ext_msg ( this , " invariant " ) ) ;
prev - > set_next ( next ) ;
}
if ( next = = NULL ) {
assert ( _tail = = curr , hrs_ext_msg ( this , " invariant " ) ) ;
_tail = prev ;
} else {
assert ( _tail ! = curr , hrs_ext_msg ( this , " invariant " ) ) ;
next - > set_prev ( prev ) ;
}
if ( _last = curr ) {
_last = NULL ;
}
2011-01-19 19:30:42 -05:00
2014-08-18 16:10:44 +02:00
curr - > set_next ( NULL ) ;
curr - > set_prev ( NULL ) ;
remove ( curr ) ;
2011-01-19 19:30:42 -05:00
2014-08-18 16:10:44 +02:00
count + + ;
2011-01-19 19:30:42 -05:00
curr = next ;
}
2014-08-18 16:10:44 +02:00
assert ( count = = num_regions ,
hrs_err_msg ( " [%s] count: %u should be == num_regions: %u " ,
name ( ) , count , num_regions ) ) ;
assert ( length ( ) + num_regions = = old_length ,
2011-03-04 17:13:19 -05:00
hrs_err_msg ( " [%s] new length should be consistent "
2014-08-18 16:10:44 +02:00
" new length: %u old length: %u num_regions: %u " ,
name ( ) , length ( ) , old_length , num_regions ) ) ;
2011-01-19 19:30:42 -05:00
verify_optional ( ) ;
}
2014-03-14 10:15:46 +01:00
void FreeRegionList : : verify ( ) {
2011-01-19 19:30:42 -05:00
// See comment in HeapRegionSetBase::verify() about MT safety and
// verification.
2014-03-14 10:15:46 +01:00
check_mt_safety ( ) ;
2011-01-19 19:30:42 -05:00
// This will also do the basic verification too.
verify_start ( ) ;
2014-03-14 10:15:46 +01:00
verify_list ( ) ;
2011-01-19 19:30:42 -05:00
verify_end ( ) ;
}
2014-03-14 10:15:46 +01:00
void FreeRegionList : : clear ( ) {
_count = HeapRegionSetCount ( ) ;
2011-01-19 19:30:42 -05:00
_head = NULL ;
_tail = NULL ;
2014-02-28 15:27:09 +01:00
_last = NULL ;
2011-01-19 19:30:42 -05:00
}
2014-03-14 10:15:46 +01:00
void FreeRegionList : : print_on ( outputStream * out , bool print_contents ) {
2011-01-19 19:30:42 -05:00
HeapRegionSetBase : : print_on ( out , print_contents ) ;
out - > print_cr ( " Linking " ) ;
out - > print_cr ( " head : " PTR_FORMAT , _head ) ;
out - > print_cr ( " tail : " PTR_FORMAT , _tail ) ;
if ( print_contents ) {
out - > print_cr ( " Contents " ) ;
2014-03-14 10:15:46 +01:00
FreeRegionListIterator iter ( this ) ;
2011-01-19 19:30:42 -05:00
while ( iter . more_available ( ) ) {
HeapRegion * hr = iter . get_next ( ) ;
hr - > print_on ( out ) ;
}
}
2014-08-18 16:10:44 +02:00
out - > cr ( ) ;
2011-01-19 19:30:42 -05:00
}
2014-03-17 13:42:16 +01:00
void FreeRegionList : : verify_list ( ) {
2014-08-18 16:10:44 +02:00
HeapRegion * curr = _head ;
2014-03-17 13:42:16 +01:00
HeapRegion * prev1 = NULL ;
HeapRegion * prev0 = NULL ;
uint count = 0 ;
size_t capacity = 0 ;
2014-02-28 15:27:09 +01:00
uint last_index = 0 ;
guarantee ( _head = = NULL | | _head - > prev ( ) = = NULL , " _head should not have a prev " ) ;
2014-03-17 13:42:16 +01:00
while ( curr ! = NULL ) {
verify_region ( curr ) ;
count + + ;
guarantee ( count < _unrealistically_long_length ,
hrs_err_msg ( " [%s] the calculated length: %u seems very long, is there maybe a cycle? curr: " PTR_FORMAT " prev0: " PTR_FORMAT " " " prev1: " PTR_FORMAT " length: %u " , name ( ) , count , curr , prev0 , prev1 , length ( ) ) ) ;
2014-02-28 15:27:09 +01:00
if ( curr - > next ( ) ! = NULL ) {
guarantee ( curr - > next ( ) - > prev ( ) = = curr , " Next or prev pointers messed up " ) ;
}
guarantee ( curr - > hrs_index ( ) = = 0 | | curr - > hrs_index ( ) > last_index , " List should be sorted " ) ;
last_index = curr - > hrs_index ( ) ;
2014-03-17 13:42:16 +01:00
capacity + = curr - > capacity ( ) ;
prev1 = prev0 ;
prev0 = curr ;
curr = curr - > next ( ) ;
}
2014-08-18 16:10:44 +02:00
guarantee ( _tail = = prev0 , err_msg ( " Expected %s to end with %u but it ended with %u. " , name ( ) , _tail - > hrs_index ( ) , prev0 - > hrs_index ( ) ) ) ;
2014-02-28 15:27:09 +01:00
guarantee ( _tail = = NULL | | _tail - > next ( ) = = NULL , " _tail should not have a next " ) ;
2014-03-17 13:42:16 +01:00
guarantee ( length ( ) = = count , err_msg ( " %s count mismatch. Expected %u, actual %u. " , name ( ) , length ( ) , count ) ) ;
guarantee ( total_capacity_bytes ( ) = = capacity , err_msg ( " %s capacity mismatch. Expected " SIZE_FORMAT " , actual " SIZE_FORMAT ,
name ( ) , total_capacity_bytes ( ) , capacity ) ) ;
}
// Note on the check_mt_safety() methods below:
//
// Verification of the "master" heap region sets / lists that are
// maintained by G1CollectedHeap is always done during a STW pause and
// by the VM thread at the start / end of the pause. The standard
// verification methods all assert check_mt_safety(). This is
// important as it ensures that verification is done without
// concurrent updates taking place at the same time. It follows, that,
// for the "master" heap region sets / lists, the check_mt_safety()
// method should include the VM thread / STW case.
void MasterFreeRegionListMtSafeChecker : : check ( ) {
// Master Free List MT safety protocol:
// (a) If we're at a safepoint, operations on the master free list
// should be invoked by either the VM thread (which will serialize
// them) or by the GC workers while holding the
// FreeList_lock.
// (b) If we're not at a safepoint, operations on the master free
// list should be invoked while holding the Heap_lock.
if ( SafepointSynchronize : : is_at_safepoint ( ) ) {
guarantee ( Thread : : current ( ) - > is_VM_thread ( ) | |
FreeList_lock - > owned_by_self ( ) , " master free list MT safety protocol at a safepoint " ) ;
} else {
guarantee ( Heap_lock - > owned_by_self ( ) , " master free list MT safety protocol outside a safepoint " ) ;
}
}
void SecondaryFreeRegionListMtSafeChecker : : check ( ) {
// Secondary Free List MT safety protocol:
// Operations on the secondary free list should always be invoked
// while holding the SecondaryFreeList_lock.
guarantee ( SecondaryFreeList_lock - > owned_by_self ( ) , " secondary free list MT safety protocol " ) ;
}
void OldRegionSetMtSafeChecker : : check ( ) {
// Master Old Set MT safety protocol:
// (a) If we're at a safepoint, operations on the master old set
// should be invoked:
// - by the VM thread (which will serialize them), or
// - by the GC workers while holding the FreeList_lock, if we're
// at a safepoint for an evacuation pause (this lock is taken
// anyway when an GC alloc region is retired so that a new one
// is allocated from the free list), or
// - by the GC workers while holding the OldSets_lock, if we're at a
// safepoint for a cleanup pause.
// (b) If we're not at a safepoint, operations on the master old set
// should be invoked while holding the Heap_lock.
if ( SafepointSynchronize : : is_at_safepoint ( ) ) {
guarantee ( Thread : : current ( ) - > is_VM_thread ( )
| | FreeList_lock - > owned_by_self ( ) | | OldSets_lock - > owned_by_self ( ) ,
" master old set MT safety protocol at a safepoint " ) ;
} else {
guarantee ( Heap_lock - > owned_by_self ( ) , " master old set MT safety protocol outside a safepoint " ) ;
}
}
void HumongousRegionSetMtSafeChecker : : check ( ) {
// Humongous Set MT safety protocol:
// (a) If we're at a safepoint, operations on the master humongous
// set should be invoked by either the VM thread (which will
// serialize them) or by the GC workers while holding the
// OldSets_lock.
// (b) If we're not at a safepoint, operations on the master
// humongous set should be invoked while holding the Heap_lock.
if ( SafepointSynchronize : : is_at_safepoint ( ) ) {
guarantee ( Thread : : current ( ) - > is_VM_thread ( ) | |
OldSets_lock - > owned_by_self ( ) ,
" master humongous set MT safety protocol at a safepoint " ) ;
} else {
guarantee ( Heap_lock - > owned_by_self ( ) ,
" master humongous set MT safety protocol outside a safepoint " ) ;
}
}