# HG changeset patch # User amurillo # Date 1413555611 25200 # Node ID f10fe402dfb1543723b4b117a7cba3ea3d4159f1 # Parent 9cf6c920a0ac839606db56b937464495b7cb373f# Parent fffbcc20bf6120803557bc990a08aabf0c6f9bf9 Merge diff -r 9cf6c920a0ac -r f10fe402dfb1 make/hotspot_version --- a/make/hotspot_version Wed Oct 15 11:14:18 2014 -0700 +++ b/make/hotspot_version Fri Oct 17 07:20:11 2014 -0700 @@ -35,7 +35,7 @@ HS_MAJOR_VER=25 HS_MINOR_VER=40 -HS_BUILD_NUMBER=14 +HS_BUILD_NUMBER=15 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff -r 9cf6c920a0ac -r f10fe402dfb1 make/windows/makefiles/projectcreator.make --- a/make/windows/makefiles/projectcreator.make Wed Oct 15 11:14:18 2014 -0700 +++ b/make/windows/makefiles/projectcreator.make Fri Oct 17 07:20:11 2014 -0700 @@ -72,6 +72,7 @@ -ignorePath arm \ -ignorePath ppc \ -ignorePath zero \ + -ignorePath aix \ -hidePath .hg diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Fri Oct 17 07:20:11 2014 -0700 @@ -130,7 +130,10 @@ storage->set_mapping_changed_listener(&_listener); } -void CMBitMapMappingChangedListener::on_commit(uint start_region, size_t num_regions) { +void CMBitMapMappingChangedListener::on_commit(uint start_region, size_t num_regions, bool zero_filled) { + if (zero_filled) { + return; + } // We need to clear the bitmap on commit, removing any existing information. MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_region), num_regions * HeapRegion::GrainWords); _bm->clearRange(mr); diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/concurrentMark.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp Fri Oct 17 07:20:11 2014 -0700 @@ -127,7 +127,7 @@ void set_bitmap(CMBitMap* bm) { _bm = bm; } - virtual void on_commit(uint start_idx, size_t num_regions); + virtual void on_commit(uint start_idx, size_t num_regions, bool zero_filled); }; class CMBitMap : public CMBitMapRO { diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp --- a/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp Fri Oct 17 07:20:11 2014 -0700 @@ -32,13 +32,6 @@ PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC -void G1BlockOffsetSharedArrayMappingChangedListener::on_commit(uint start_idx, size_t num_regions) { - // Nothing to do. The BOT is hard-wired to be part of the HeapRegion, and we cannot - // retrieve it here since this would cause firing of several asserts. The code - // executed after commit of a region already needs to do some re-initialization of - // the HeapRegion, so we combine that. -} - ////////////////////////////////////////////////////////////////////// // G1BlockOffsetSharedArray ////////////////////////////////////////////////////////////////////// @@ -72,26 +65,16 @@ return (delta & right_n_bits(LogN_words)) == (size_t)NoBits; } -void G1BlockOffsetSharedArray::set_offset_array(HeapWord* left, HeapWord* right, u_char offset) { - set_offset_array(index_for(left), index_for(right -1), offset); -} - ////////////////////////////////////////////////////////////////////// // G1BlockOffsetArray ////////////////////////////////////////////////////////////////////// G1BlockOffsetArray::G1BlockOffsetArray(G1BlockOffsetSharedArray* array, - MemRegion mr, bool init_to_zero) : + MemRegion mr) : G1BlockOffsetTable(mr.start(), mr.end()), _unallocated_block(_bottom), - _array(array), _gsp(NULL), - _init_to_zero(init_to_zero) { + _array(array), _gsp(NULL) { assert(_bottom <= _end, "arguments out of order"); - if (!_init_to_zero) { - // initialize cards to point back to mr.start() - set_remainder_to_point_to_start(mr.start() + N_words, mr.end()); - _array->set_offset_array(0, 0); // set first card to 0 - } } void G1BlockOffsetArray::set_space(G1OffsetTableContigSpace* sp) { @@ -181,93 +164,6 @@ DEBUG_ONLY(check_all_cards(start_card, end_card);) } -// The block [blk_start, blk_end) has been allocated; -// adjust the block offset table to represent this information; -// right-open interval: [blk_start, blk_end) -void -G1BlockOffsetArray::alloc_block(HeapWord* blk_start, HeapWord* blk_end) { - mark_block(blk_start, blk_end); - allocated(blk_start, blk_end); -} - -// Adjust BOT to show that a previously whole block has been split -// into two. -void G1BlockOffsetArray::split_block(HeapWord* blk, size_t blk_size, - size_t left_blk_size) { - // Verify that the BOT shows [blk, blk + blk_size) to be one block. - verify_single_block(blk, blk_size); - // Update the BOT to indicate that [blk + left_blk_size, blk + blk_size) - // is one single block. - mark_block(blk + left_blk_size, blk + blk_size); -} - - -// Action_mark - update the BOT for the block [blk_start, blk_end). -// Current typical use is for splitting a block. -// Action_single - update the BOT for an allocation. -// Action_verify - BOT verification. -void G1BlockOffsetArray::do_block_internal(HeapWord* blk_start, - HeapWord* blk_end, - Action action) { - assert(Universe::heap()->is_in_reserved(blk_start), - "reference must be into the heap"); - assert(Universe::heap()->is_in_reserved(blk_end-1), - "limit must be within the heap"); - // This is optimized to make the test fast, assuming we only rarely - // cross boundaries. - uintptr_t end_ui = (uintptr_t)(blk_end - 1); - uintptr_t start_ui = (uintptr_t)blk_start; - // Calculate the last card boundary preceding end of blk - intptr_t boundary_before_end = (intptr_t)end_ui; - clear_bits(boundary_before_end, right_n_bits(LogN)); - if (start_ui <= (uintptr_t)boundary_before_end) { - // blk starts at or crosses a boundary - // Calculate index of card on which blk begins - size_t start_index = _array->index_for(blk_start); - // Index of card on which blk ends - size_t end_index = _array->index_for(blk_end - 1); - // Start address of card on which blk begins - HeapWord* boundary = _array->address_for_index(start_index); - assert(boundary <= blk_start, "blk should start at or after boundary"); - if (blk_start != boundary) { - // blk starts strictly after boundary - // adjust card boundary and start_index forward to next card - boundary += N_words; - start_index++; - } - assert(start_index <= end_index, "monotonicity of index_for()"); - assert(boundary <= (HeapWord*)boundary_before_end, "tautology"); - switch (action) { - case Action_mark: { - if (init_to_zero()) { - _array->set_offset_array(start_index, boundary, blk_start); - break; - } // Else fall through to the next case - } - case Action_single: { - _array->set_offset_array(start_index, boundary, blk_start); - // We have finished marking the "offset card". We need to now - // mark the subsequent cards that this blk spans. - if (start_index < end_index) { - HeapWord* rem_st = _array->address_for_index(start_index) + N_words; - HeapWord* rem_end = _array->address_for_index(end_index) + N_words; - set_remainder_to_point_to_start(rem_st, rem_end); - } - break; - } - case Action_check: { - _array->check_offset_array(start_index, boundary, blk_start); - // We have finished checking the "offset card". We need to now - // check the subsequent cards that this blk spans. - check_all_cards(start_index + 1, end_index); - break; - } - default: - ShouldNotReachHere(); - } - } -} - // The card-interval [start_card, end_card] is a closed interval; this // is an expensive check -- use with care and only under protection of // suitable flag. @@ -306,25 +202,6 @@ } } -// The range [blk_start, blk_end) represents a single contiguous block -// of storage; modify the block offset table to represent this -// information; Right-open interval: [blk_start, blk_end) -// NOTE: this method does _not_ adjust _unallocated_block. -void -G1BlockOffsetArray::single_block(HeapWord* blk_start, HeapWord* blk_end) { - do_block_internal(blk_start, blk_end, Action_single); -} - -// Mark the BOT such that if [blk_start, blk_end) straddles a card -// boundary, the card following the first such boundary is marked -// with the appropriate offset. -// NOTE: this method does _not_ adjust _unallocated_block or -// any cards subsequent to the first one. -void -G1BlockOffsetArray::mark_block(HeapWord* blk_start, HeapWord* blk_end) { - do_block_internal(blk_start, blk_end, Action_mark); -} - HeapWord* G1BlockOffsetArray::block_start_unsafe(const void* addr) { assert(_bottom <= addr && addr < _end, "addr must be covered by this Array"); @@ -397,57 +274,13 @@ return forward_to_block_containing_addr_const(q, n, addr); } -HeapWord* G1BlockOffsetArray::block_start_careful(const void* addr) const { - assert(_array->offset_array(0) == 0, "objects can't cross covered areas"); - - assert(_bottom <= addr && addr < _end, - "addr must be covered by this Array"); - // Must read this exactly once because it can be modified by parallel - // allocation. - HeapWord* ub = _unallocated_block; - if (BlockOffsetArrayUseUnallocatedBlock && addr >= ub) { - assert(ub < _end, "tautology (see above)"); - return ub; - } - - // Otherwise, find the block start using the table, but taking - // care (cf block_start_unsafe() above) not to parse any objects/blocks - // on the cards themsleves. - size_t index = _array->index_for(addr); - assert(_array->address_for_index(index) == addr, - "arg should be start of card"); - - HeapWord* q = (HeapWord*)addr; - uint offset; - do { - offset = _array->offset_array(index--); - q -= offset; - } while (offset == N_words); - assert(q <= addr, "block start should be to left of arg"); - return q; -} - // Note that the committed size of the covered space may have changed, // so the table size might also wish to change. void G1BlockOffsetArray::resize(size_t new_word_size) { HeapWord* new_end = _bottom + new_word_size; - if (_end < new_end && !init_to_zero()) { - // verify that the old and new boundaries are also card boundaries - assert(_array->is_card_boundary(_end), - "_end not a card boundary"); - assert(_array->is_card_boundary(new_end), - "new _end would not be a card boundary"); - // set all the newly added cards - _array->set_offset_array(_end, new_end, N_words); - } _end = new_end; // update _end } -void G1BlockOffsetArray::set_region(MemRegion mr) { - _bottom = mr.start(); - _end = mr.end(); -} - // // threshold_ // | _index_ @@ -607,7 +440,7 @@ G1BlockOffsetArrayContigSpace:: G1BlockOffsetArrayContigSpace(G1BlockOffsetSharedArray* array, MemRegion mr) : - G1BlockOffsetArray(array, mr, true) + G1BlockOffsetArray(array, mr) { _next_offset_threshold = NULL; _next_offset_index = 0; @@ -642,15 +475,6 @@ return _next_offset_threshold; } -void G1BlockOffsetArrayContigSpace::zero_bottom_entry() { - assert(!Universe::heap()->is_in_reserved(_array->_offset_array), - "just checking"); - size_t bottom_index = _array->index_for(_bottom); - assert(_array->address_for_index(bottom_index) == _bottom, - "Precondition of call"); - _array->set_offset_array(bottom_index, 0); -} - void G1BlockOffsetArrayContigSpace::set_for_starts_humongous(HeapWord* new_top) { assert(new_top <= _end, "_end should have already been updated"); diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp --- a/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp Fri Oct 17 07:20:11 2014 -0700 @@ -109,7 +109,12 @@ class G1BlockOffsetSharedArrayMappingChangedListener : public G1MappingChangedListener { public: - virtual void on_commit(uint start_idx, size_t num_regions); + virtual void on_commit(uint start_idx, size_t num_regions, bool zero_filled) { + // Nothing to do. The BOT is hard-wired to be part of the HeapRegion, and we cannot + // retrieve it here since this would cause firing of several asserts. The code + // executed after commit of a region already needs to do some re-initialization of + // the HeapRegion, so we combine that. + } }; // This implementation of "G1BlockOffsetTable" divides the covered region @@ -153,8 +158,6 @@ // For performance these have to devolve to array accesses in product builds. inline u_char offset_array(size_t index) const; - void set_offset_array(HeapWord* left, HeapWord* right, u_char offset); - void set_offset_array_raw(size_t index, u_char offset) { _offset_array[index] = offset; } @@ -165,8 +168,6 @@ inline void set_offset_array(size_t left, size_t right, u_char offset); - inline void check_offset_array(size_t index, HeapWord* high, HeapWord* low) const; - bool is_card_boundary(HeapWord* p) const; public: @@ -193,8 +194,6 @@ // G1BlockOffsetTable(s) to initialize cards. G1BlockOffsetSharedArray(MemRegion heap, G1RegionToSpaceMapper* storage); - void set_bottom(HeapWord* new_bottom); - // Return the appropriate index into "_offset_array" for "p". inline size_t index_for(const void* p) const; inline size_t index_for_raw(const void* p) const; @@ -220,14 +219,6 @@ LogN = G1BlockOffsetSharedArray::LogN }; - // The following enums are used by do_block_helper - enum Action { - Action_single, // BOT records a single block (see single_block()) - Action_mark, // BOT marks the start of a block (see mark_block()) - Action_check // Check that BOT records block correctly - // (see verify_single_block()). - }; - // This is the array, which can be shared by several BlockOffsetArray's // servicing different G1BlockOffsetSharedArray* _array; @@ -235,10 +226,6 @@ // The space that owns this subregion. G1OffsetTableContigSpace* _gsp; - // If true, array entries are initialized to 0; otherwise, they are - // initialized to point backwards to the beginning of the covered region. - bool _init_to_zero; - // The portion [_unallocated_block, _sp.end()) of the space that // is a single block known not to contain any objects. // NOTE: See BlockOffsetArrayUseUnallocatedBlock flag. @@ -253,9 +240,6 @@ // that is closed: [start_index, end_index] void set_remainder_to_point_to_start_incl(size_t start, size_t end); - // A helper function for BOT adjustment/verification work - void do_block_internal(HeapWord* blk_start, HeapWord* blk_end, Action action); - protected: G1OffsetTableContigSpace* gsp() const { return _gsp; } @@ -303,11 +287,9 @@ public: // The space may not have it's bottom and top set yet, which is why the - // region is passed as a parameter. If "init_to_zero" is true, the - // elements of the array are initialized to zero. Otherwise, they are - // initialized to point backwards to the beginning. - G1BlockOffsetArray(G1BlockOffsetSharedArray* array, MemRegion mr, - bool init_to_zero); + // region is passed as a parameter. The elements of the array are + // initialized to zero. + G1BlockOffsetArray(G1BlockOffsetSharedArray* array, MemRegion mr); // Note: this ought to be part of the constructor, but that would require // "this" to be passed as a parameter to a member constructor for @@ -315,114 +297,19 @@ // This would be legal C++, but MS VC++ doesn't allow it. void set_space(G1OffsetTableContigSpace* sp); - // Resets the covered region to the given "mr". - void set_region(MemRegion mr); - // Resets the covered region to one with the same _bottom as before but // the "new_word_size". void resize(size_t new_word_size); - // These must be guaranteed to work properly (i.e., do nothing) - // when "blk_start" ("blk" for second version) is "NULL". - virtual void alloc_block(HeapWord* blk_start, HeapWord* blk_end); - virtual void alloc_block(HeapWord* blk, size_t size) { - alloc_block(blk, blk + size); - } - - // The following methods are useful and optimized for a - // general, non-contiguous space. - - // Given a block [blk_start, blk_start + full_blk_size), and - // a left_blk_size < full_blk_size, adjust the BOT to show two - // blocks [blk_start, blk_start + left_blk_size) and - // [blk_start + left_blk_size, blk_start + full_blk_size). - // It is assumed (and verified in the non-product VM) that the - // BOT was correct for the original block. - void split_block(HeapWord* blk_start, size_t full_blk_size, - size_t left_blk_size); - - // Adjust the BOT to show that it has a single block in the - // range [blk_start, blk_start + size). All necessary BOT - // cards are adjusted, but _unallocated_block isn't. - void single_block(HeapWord* blk_start, HeapWord* blk_end); - void single_block(HeapWord* blk, size_t size) { - single_block(blk, blk + size); - } - - // Adjust BOT to show that it has a block in the range - // [blk_start, blk_start + size). Only the first card - // of BOT is touched. It is assumed (and verified in the - // non-product VM) that the remaining cards of the block - // are correct. - void mark_block(HeapWord* blk_start, HeapWord* blk_end); - void mark_block(HeapWord* blk, size_t size) { - mark_block(blk, blk + size); - } - - // Adjust _unallocated_block to indicate that a particular - // block has been newly allocated or freed. It is assumed (and - // verified in the non-product VM) that the BOT is correct for - // the given block. - inline void allocated(HeapWord* blk_start, HeapWord* blk_end) { - // Verify that the BOT shows [blk, blk + blk_size) to be one block. - verify_single_block(blk_start, blk_end); - if (BlockOffsetArrayUseUnallocatedBlock) { - _unallocated_block = MAX2(_unallocated_block, blk_end); - } - } - - inline void allocated(HeapWord* blk, size_t size) { - allocated(blk, blk + size); - } - - inline void freed(HeapWord* blk_start, HeapWord* blk_end); - - inline void freed(HeapWord* blk, size_t size); - virtual HeapWord* block_start_unsafe(const void* addr); virtual HeapWord* block_start_unsafe_const(const void* addr) const; - // Requires "addr" to be the start of a card and returns the - // start of the block that contains the given address. - HeapWord* block_start_careful(const void* addr) const; - - // If true, initialize array slots with no allocated blocks to zero. - // Otherwise, make them point back to the front. - bool init_to_zero() { return _init_to_zero; } - - // Verification & debugging - ensure that the offset table reflects the fact - // that the block [blk_start, blk_end) or [blk, blk + size) is a - // single block of storage. NOTE: can;t const this because of - // call to non-const do_block_internal() below. - inline void verify_single_block(HeapWord* blk_start, HeapWord* blk_end) { - if (VerifyBlockOffsetArray) { - do_block_internal(blk_start, blk_end, Action_check); - } - } - - inline void verify_single_block(HeapWord* blk, size_t size) { - verify_single_block(blk, blk + size); - } - // Used by region verification. Checks that the contents of the // BOT reflect that there's a single object that spans the address // range [obj_start, obj_start + word_size); returns true if this is // the case, returns false if it's not. bool verify_for_object(HeapWord* obj_start, size_t word_size) const; - // Verify that the given block is before _unallocated_block - inline void verify_not_unallocated(HeapWord* blk_start, - HeapWord* blk_end) const { - if (BlockOffsetArrayUseUnallocatedBlock) { - assert(blk_start < blk_end, "Block inconsistency?"); - assert(blk_end <= _unallocated_block, "_unallocated_block problem"); - } - } - - inline void verify_not_unallocated(HeapWord* blk, size_t size) const { - verify_not_unallocated(blk, blk + size); - } - void check_all_cards(size_t left_card, size_t right_card) const; virtual void print_on(outputStream* out) PRODUCT_RETURN; @@ -445,14 +332,12 @@ blk_start, blk_end); } - // Variant of zero_bottom_entry that does not check for availability of the + // Zero out the entry for _bottom (offset will be zero). Does not check for availability of the // memory first. void zero_bottom_entry_raw(); // Variant of initialize_threshold that does not check for availability of the // memory first. HeapWord* initialize_threshold_raw(); - // Zero out the entry for _bottom (offset will be zero). - void zero_bottom_entry(); public: G1BlockOffsetArrayContigSpace(G1BlockOffsetSharedArray* array, MemRegion mr); diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp --- a/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.inline.hpp Fri Oct 17 07:20:11 2014 -0700 @@ -91,13 +91,6 @@ } } -void G1BlockOffsetSharedArray::check_offset_array(size_t index, HeapWord* high, HeapWord* low) const { - check_index(index, "index out of range"); - assert(high >= low, "addresses out of order"); - check_offset(pointer_delta(high, low), "offset too large"); - assert(_offset_array[index] == pointer_delta(high, low), "Wrong offset"); -} - // Variant of index_for that does not check the index for validity. inline size_t G1BlockOffsetSharedArray::index_for_raw(const void* p) const { return pointer_delta((char*)p, _reserved.start(), sizeof(char)) >> LogN; @@ -193,28 +186,4 @@ return q; } -////////////////////////////////////////////////////////////////////////// -// BlockOffsetArrayNonContigSpace inlines -////////////////////////////////////////////////////////////////////////// -inline void G1BlockOffsetArray::freed(HeapWord* blk_start, HeapWord* blk_end) { - // Verify that the BOT shows [blk_start, blk_end) to be one block. - verify_single_block(blk_start, blk_end); - // adjust _unallocated_block upward or downward - // as appropriate - if (BlockOffsetArrayUseUnallocatedBlock) { - assert(_unallocated_block <= _end, - "Inconsistent value for _unallocated_block"); - if (blk_end >= _unallocated_block && blk_start <= _unallocated_block) { - // CMS-specific note: a block abutting _unallocated_block to - // its left is being freed, a new block is being added or - // we are resetting following a compaction - _unallocated_block = blk_start; - } - } -} - -inline void G1BlockOffsetArray::freed(HeapWord* blk, size_t size) { - freed(blk, blk + size); -} - #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1BLOCKOFFSETTABLE_INLINE_HPP diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/g1CardCounts.cpp --- a/src/share/vm/gc_implementation/g1/g1CardCounts.cpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CardCounts.cpp Fri Oct 17 07:20:11 2014 -0700 @@ -33,7 +33,10 @@ PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC -void G1CardCountsMappingChangedListener::on_commit(uint start_idx, size_t num_regions) { +void G1CardCountsMappingChangedListener::on_commit(uint start_idx, size_t num_regions, bool zero_filled) { + if (zero_filled) { + return; + } MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_idx), num_regions * HeapRegion::GrainWords); _counts->clear_range(mr); } diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/g1CardCounts.hpp --- a/src/share/vm/gc_implementation/g1/g1CardCounts.hpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CardCounts.hpp Fri Oct 17 07:20:11 2014 -0700 @@ -42,7 +42,7 @@ public: void set_cardcounts(G1CardCounts* counts) { _counts = counts; } - virtual void on_commit(uint start_idx, size_t num_regions); + virtual void on_commit(uint start_idx, size_t num_regions, bool zero_filled); }; // Table to track the number of times a card has been refined. Once diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Oct 17 07:20:11 2014 -0700 @@ -385,7 +385,9 @@ OtherRegionsTable::invalidate(start_idx, num_regions); } -void G1RegionMappingChangedListener::on_commit(uint start_idx, size_t num_regions) { +void G1RegionMappingChangedListener::on_commit(uint start_idx, size_t num_regions, bool zero_filled) { + // The from card cache is not the memory that is actually committed. So we cannot + // take advantage of the zero_filled parameter. reset_from_card_cache(start_idx, num_regions); } diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Oct 17 07:20:11 2014 -0700 @@ -172,7 +172,7 @@ private: void reset_from_card_cache(uint start_idx, size_t num_regions); public: - virtual void on_commit(uint start_idx, size_t num_regions); + virtual void on_commit(uint start_idx, size_t num_regions, bool zero_filled); }; class G1CollectedHeap : public SharedHeap { diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp --- a/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.cpp Fri Oct 17 07:20:11 2014 -0700 @@ -69,7 +69,7 @@ virtual void commit_regions(uintptr_t start_idx, size_t num_regions) { _storage.commit(start_idx * _pages_per_region, num_regions * _pages_per_region); _commit_map.set_range(start_idx, start_idx + num_regions); - fire_on_commit(start_idx, num_regions); + fire_on_commit(start_idx, num_regions, true); } virtual void uncommit_regions(uintptr_t start_idx, size_t num_regions) { @@ -115,12 +115,14 @@ assert(!_commit_map.at(i), err_msg("Trying to commit storage at region "INTPTR_FORMAT" that is already committed", i)); uintptr_t idx = region_idx_to_page_idx(i); uint old_refcount = _refcounts.get_by_index(idx); + bool zero_filled = false; if (old_refcount == 0) { _storage.commit(idx, 1); + zero_filled = true; } _refcounts.set_by_index(idx, old_refcount + 1); _commit_map.set_bit(i); - fire_on_commit(i, 1); + fire_on_commit(i, 1, zero_filled); } } @@ -139,9 +141,9 @@ } }; -void G1RegionToSpaceMapper::fire_on_commit(uint start_idx, size_t num_regions) { +void G1RegionToSpaceMapper::fire_on_commit(uint start_idx, size_t num_regions, bool zero_filled) { if (_listener != NULL) { - _listener->on_commit(start_idx, num_regions); + _listener->on_commit(start_idx, num_regions, zero_filled); } } diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp --- a/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/g1RegionToSpaceMapper.hpp Fri Oct 17 07:20:11 2014 -0700 @@ -33,7 +33,9 @@ public: // Fired after commit of the memory, i.e. the memory this listener is registered // for can be accessed. - virtual void on_commit(uint start_idx, size_t num_regions) = 0; + // Zero_filled indicates that the memory can be considered as filled with zero bytes + // when called. + virtual void on_commit(uint start_idx, size_t num_regions, bool zero_filled) = 0; }; // Maps region based commit/uncommit requests to the underlying page sized virtual @@ -51,7 +53,7 @@ G1RegionToSpaceMapper(ReservedSpace rs, size_t commit_granularity, size_t region_granularity, MemoryType type); - void fire_on_commit(uint start_idx, size_t num_regions); + void fire_on_commit(uint start_idx, size_t num_regions, bool zero_filled); public: MemRegion reserved() { return _storage.reserved(); } diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp --- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.cpp Fri Oct 17 07:20:11 2014 -0700 @@ -124,7 +124,8 @@ } #endif -void G1SATBCardTableLoggingModRefBSChangedListener::on_commit(uint start_idx, size_t num_regions) { +void G1SATBCardTableLoggingModRefBSChangedListener::on_commit(uint start_idx, size_t num_regions, bool zero_filled) { + // Default value for a clean card on the card table is -1. So we cannot take advantage of the zero_filled parameter. MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_idx), num_regions * HeapRegion::GrainWords); _card_table->clear(mr); } diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp --- a/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp Fri Oct 17 07:20:11 2014 -0700 @@ -136,7 +136,7 @@ void set_card_table(G1SATBCardTableLoggingModRefBS* card_table) { _card_table = card_table; } - virtual void on_commit(uint start_idx, size_t num_regions); + virtual void on_commit(uint start_idx, size_t num_regions, bool zero_filled); }; // Adds card-table logging to the post-barrier. diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/g1_globals.hpp --- a/src/share/vm/gc_implementation/g1/g1_globals.hpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp Fri Oct 17 07:20:11 2014 -0700 @@ -270,12 +270,12 @@ "Percentage (0-100) of the heap size to use as default " \ " maximum young gen size.") \ \ - experimental(uintx, G1MixedGCLiveThresholdPercent, 65, \ + experimental(uintx, G1MixedGCLiveThresholdPercent, 85, \ "Threshold for regions to be considered for inclusion in the " \ "collection set of mixed GCs. " \ "Regions with live bytes exceeding this will not be collected.") \ \ - product(uintx, G1HeapWastePercent, 10, \ + product(uintx, G1HeapWastePercent, 5, \ "Amount of space, expressed as a percentage of the heap size, " \ "that G1 is willing not to collect to avoid expensive GCs.") \ \ diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/heapRegion.cpp --- a/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Fri Oct 17 07:20:11 2014 -0700 @@ -304,29 +304,6 @@ return false; } -HeapWord* HeapRegion::next_block_start_careful(HeapWord* addr) { - HeapWord* low = addr; - HeapWord* high = end(); - while (low < high) { - size_t diff = pointer_delta(high, low); - // Must add one below to bias toward the high amount. Otherwise, if - // "high" were at the desired value, and "low" were one less, we - // would not converge on "high". This is not symmetric, because - // we set "high" to a block start, which might be the right one, - // which we don't do for "low". - HeapWord* middle = low + (diff+1)/2; - if (middle == high) return high; - HeapWord* mid_bs = block_start_careful(middle); - if (mid_bs < addr) { - low = middle; - } else { - high = mid_bs; - } - } - assert(low == high && low >= addr, "Didn't work."); - return low; -} - HeapRegion::HeapRegion(uint hrm_index, G1BlockOffsetSharedArray* sharedOffsetArray, MemRegion mr) : diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/gc_implementation/g1/heapRegion.hpp --- a/src/share/vm/gc_implementation/g1/heapRegion.hpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp Fri Oct 17 07:20:11 2014 -0700 @@ -203,10 +203,6 @@ _offsets.reset_bot(); } - void update_bot_for_object(HeapWord* start, size_t word_size) { - _offsets.alloc_block(start, word_size); - } - void print_bot_on(outputStream* out) { _offsets.print_on(out); } @@ -737,18 +733,6 @@ bool filter_young, jbyte* card_ptr); - // A version of block start that is guaranteed to find *some* block - // boundary at or before "p", but does not object iteration, and may - // therefore be used safely when the heap is unparseable. - HeapWord* block_start_careful(const void* p) const { - return _offsets.block_start_careful(p); - } - - // Requires that "addr" is within the region. Returns the start of the - // first ("careful") block that starts at or after "addr", or else the - // "end" of the region if there is no such block. - HeapWord* next_block_start_careful(HeapWord* addr); - size_t recorded_rs_length() const { return _recorded_rs_length; } double predicted_elapsed_time_ms() const { return _predicted_elapsed_time_ms; } size_t predicted_bytes_to_copy() const { return _predicted_bytes_to_copy; } diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/memory/metaspace.cpp --- a/src/share/vm/memory/metaspace.cpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/memory/metaspace.cpp Fri Oct 17 07:20:11 2014 -0700 @@ -1414,10 +1414,31 @@ return value; } -size_t MetaspaceGC::inc_capacity_until_GC(size_t v) { +bool MetaspaceGC::inc_capacity_until_GC(size_t v, size_t* new_cap_until_GC, size_t* old_cap_until_GC) { assert_is_size_aligned(v, Metaspace::commit_alignment()); - return (size_t)Atomic::add_ptr(v, &_capacity_until_GC); + size_t capacity_until_GC = (size_t) _capacity_until_GC; + size_t new_value = capacity_until_GC + v; + + if (new_value < capacity_until_GC) { + // The addition wrapped around, set new_value to aligned max value. + new_value = align_size_down(max_uintx, Metaspace::commit_alignment()); + } + + intptr_t expected = (intptr_t) capacity_until_GC; + intptr_t actual = Atomic::cmpxchg_ptr((intptr_t) new_value, &_capacity_until_GC, expected); + + if (expected != actual) { + return false; + } + + if (new_cap_until_GC != NULL) { + *new_cap_until_GC = new_value; + } + if (old_cap_until_GC != NULL) { + *old_cap_until_GC = capacity_until_GC; + } + return true; } size_t MetaspaceGC::dec_capacity_until_GC(size_t v) { @@ -1517,7 +1538,10 @@ expand_bytes = align_size_up(expand_bytes, Metaspace::commit_alignment()); // Don't expand unless it's significant if (expand_bytes >= MinMetaspaceExpansion) { - size_t new_capacity_until_GC = MetaspaceGC::inc_capacity_until_GC(expand_bytes); + size_t new_capacity_until_GC = 0; + bool succeeded = MetaspaceGC::inc_capacity_until_GC(expand_bytes, &new_capacity_until_GC); + assert(succeeded, "Should always succesfully increment HWM when at safepoint"); + Metaspace::tracer()->report_gc_threshold(capacity_until_GC, new_capacity_until_GC, MetaspaceGCThresholdUpdater::ComputeNewSize); @@ -3319,19 +3343,29 @@ size_t delta_bytes = MetaspaceGC::delta_capacity_until_GC(word_size * BytesPerWord); assert(delta_bytes > 0, "Must be"); - size_t after_inc = MetaspaceGC::inc_capacity_until_GC(delta_bytes); - - // capacity_until_GC might be updated concurrently, must calculate previous value. - size_t before_inc = after_inc - delta_bytes; - - tracer()->report_gc_threshold(before_inc, after_inc, - MetaspaceGCThresholdUpdater::ExpandAndAllocate); - if (PrintGCDetails && Verbose) { - gclog_or_tty->print_cr("Increase capacity to GC from " SIZE_FORMAT - " to " SIZE_FORMAT, before_inc, after_inc); + size_t before = 0; + size_t after = 0; + MetaWord* res; + bool incremented; + + // Each thread increments the HWM at most once. Even if the thread fails to increment + // the HWM, an allocation is still attempted. This is because another thread must then + // have incremented the HWM and therefore the allocation might still succeed. + do { + incremented = MetaspaceGC::inc_capacity_until_GC(delta_bytes, &after, &before); + res = allocate(word_size, mdtype); + } while (!incremented && res == NULL); + + if (incremented) { + tracer()->report_gc_threshold(before, after, + MetaspaceGCThresholdUpdater::ExpandAndAllocate); + if (PrintGCDetails && Verbose) { + gclog_or_tty->print_cr("Increase capacity to GC from " SIZE_FORMAT + " to " SIZE_FORMAT, before, after); + } } - return allocate(word_size, mdtype); + return res; } // Space allocated in the Metaspace. This may diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/memory/metaspace.hpp --- a/src/share/vm/memory/metaspace.hpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/memory/metaspace.hpp Fri Oct 17 07:20:11 2014 -0700 @@ -404,7 +404,9 @@ static void post_initialize(); static size_t capacity_until_GC(); - static size_t inc_capacity_until_GC(size_t v); + static bool inc_capacity_until_GC(size_t v, + size_t* new_cap_until_GC = NULL, + size_t* old_cap_until_GC = NULL); static size_t dec_capacity_until_GC(size_t v); static bool should_concurrent_collect() { return _should_concurrent_collect; } diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/prims/whitebox.cpp Fri Oct 17 07:20:11 2014 -0700 @@ -794,6 +794,33 @@ MetadataFactory::free_array(cld, (Array*)(uintptr_t)addr); WB_END +WB_ENTRY(jlong, WB_IncMetaspaceCapacityUntilGC(JNIEnv* env, jobject wb, jlong inc)) + if (inc < 0) { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("WB_IncMetaspaceCapacityUntilGC: inc is negative: " JLONG_FORMAT, inc)); + } + + jlong max_size_t = (jlong) ((size_t) -1); + if (inc > max_size_t) { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("WB_IncMetaspaceCapacityUntilGC: inc does not fit in size_t: " JLONG_FORMAT, inc)); + } + + size_t new_cap_until_GC = 0; + size_t aligned_inc = align_size_down((size_t) inc, Metaspace::commit_alignment()); + bool success = MetaspaceGC::inc_capacity_until_GC(aligned_inc, &new_cap_until_GC); + if (!success) { + THROW_MSG_0(vmSymbols::java_lang_IllegalStateException(), + "WB_IncMetaspaceCapacityUntilGC: could not increase capacity until GC " + "due to contention with another thread"); + } + return (jlong) new_cap_until_GC; +WB_END + +WB_ENTRY(jlong, WB_MetaspaceCapacityUntilGC(JNIEnv* env, jobject wb)) + return (jlong) MetaspaceGC::capacity_until_GC(); +WB_END + //Some convenience methods to deal with objects from java int WhiteBox::offset_for_field(const char* field_name, oop object, Symbol* signature_symbol) { @@ -962,6 +989,8 @@ CC"(Ljava/lang/ClassLoader;J)J", (void*)&WB_AllocateMetaspace }, {CC"freeMetaspace", CC"(Ljava/lang/ClassLoader;JJ)V", (void*)&WB_FreeMetaspace }, + {CC"incMetaspaceCapacityUntilGC", CC"(J)J", (void*)&WB_IncMetaspaceCapacityUntilGC }, + {CC"metaspaceCapacityUntilGC", CC"()J", (void*)&WB_MetaspaceCapacityUntilGC }, {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, {CC"getNMethod", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", (void*)&WB_GetNMethod }, diff -r 9cf6c920a0ac -r f10fe402dfb1 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Wed Oct 15 11:14:18 2014 -0700 +++ b/src/share/vm/runtime/arguments.cpp Fri Oct 17 07:20:11 2014 -0700 @@ -2389,6 +2389,9 @@ status = status && verify_percentage(MarkSweepDeadRatio, "MarkSweepDeadRatio"); status = status && verify_min_value(MarkSweepAlwaysCompactCount, 1, "MarkSweepAlwaysCompactCount"); +#ifdef COMPILER1 + status = status && verify_min_value(ValueMapInitialSize, 1, "ValueMapInitialSize"); +#endif if (PrintNMTStatistics) { #if INCLUDE_NMT diff -r 9cf6c920a0ac -r f10fe402dfb1 test/TEST.groups --- a/test/TEST.groups Wed Oct 15 11:14:18 2014 -0700 +++ b/test/TEST.groups Fri Oct 17 07:20:11 2014 -0700 @@ -144,6 +144,13 @@ gc/metaspace/TestMetaspaceMemoryPool.java \ gc/arguments/TestDynMinHeapFreeRatio.java \ gc/arguments/TestDynMaxHeapFreeRatio.java \ + gc/g1/TestShrinkAuxiliaryData00.java \ + gc/g1/TestShrinkAuxiliaryData05.java \ + gc/g1/TestShrinkAuxiliaryData10.java \ + gc/g1/TestShrinkAuxiliaryData15.java \ + gc/g1/TestShrinkAuxiliaryData20.java \ + gc/g1/TestShrinkAuxiliaryData25.java \ + gc/g1/TestShrinkAuxiliaryData30.java \ runtime/InternalApi/ThreadCpuTimesDeadlock.java \ serviceability/threads/TestFalseDeadLock.java \ serviceability/jvmti/GetObjectSizeOverflow.java \ diff -r 9cf6c920a0ac -r f10fe402dfb1 test/gc/g1/TestShrinkAuxiliaryData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestShrinkAuxiliaryData.java Fri Oct 17 07:20:11 2014 -0700 @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2014, 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. + */ + +import static com.oracle.java.testlibrary.Asserts.assertLessThanOrEqual; +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.Platform; +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.Utils; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryUsage; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import sun.misc.Unsafe; + +public class TestShrinkAuxiliaryData { + + private final static String[] initialOpts = new String[]{ + "-XX:MinHeapFreeRatio=10", + "-XX:MaxHeapFreeRatio=11", + "-XX:+UseG1GC", + "-XX:G1HeapRegionSize=1m", + "-XX:+PrintGCDetails" + }; + + private final int RSetCacheSize; + + protected TestShrinkAuxiliaryData(int RSetCacheSize) { + this.RSetCacheSize = RSetCacheSize; + } + + protected void test() throws Exception { + ArrayList vmOpts = new ArrayList(); + Collections.addAll(vmOpts, initialOpts); + + int maxCacheSize = Math.max(0, Math.min(31, getMaxCacheSize())); + if (maxCacheSize < RSetCacheSize) { + System.out.format("Skiping test for %d cache size due max cache size %d", + RSetCacheSize, maxCacheSize + ); + return; + } + + printTestInfo(maxCacheSize); + + vmOpts.add("-XX:G1ConcRSLogCacheSize=" + RSetCacheSize); + + vmOpts.addAll(Arrays.asList(Utils.getFilteredTestJavaOpts( + ShrinkAuxiliaryDataTest.prohibitedVmOptions))); + + // for 32 bits ObjectAlignmentInBytes is not a option + if (Platform.is32bit()) { + ArrayList vmOptsWithoutAlign = new ArrayList(vmOpts); + vmOptsWithoutAlign.add(ShrinkAuxiliaryDataTest.class.getName()); + performTest(vmOptsWithoutAlign); + return; + } + + for (int alignment = 3; alignment <= 8; alignment++) { + ArrayList vmOptsWithAlign = new ArrayList(vmOpts); + vmOptsWithAlign.add("-XX:ObjectAlignmentInBytes=" + + (int) Math.pow(2, alignment)); + vmOptsWithAlign.add(ShrinkAuxiliaryDataTest.class.getName()); + + performTest(vmOptsWithAlign); + } + } + + private void performTest(List opts) throws Exception { + ProcessBuilder pb + = ProcessTools.createJavaProcessBuilder( + opts.toArray(new String[opts.size()]) + ); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } + + private void printTestInfo(int maxCacheSize) { + + DecimalFormat grouped = new DecimalFormat("000,000"); + DecimalFormatSymbols formatSymbols = grouped.getDecimalFormatSymbols(); + formatSymbols.setGroupingSeparator(' '); + grouped.setDecimalFormatSymbols(formatSymbols); + + System.out.format("Test will use %s bytes of memory of %s available%n" + + "Available memory is %s with %d bytes pointer size - can save %s pointers%n" + + "Max cache size: 2^%d = %s elements%n", + grouped.format(ShrinkAuxiliaryDataTest.getMemoryUsedByTest()), + grouped.format(Runtime.getRuntime().freeMemory()), + grouped.format(Runtime.getRuntime().freeMemory() + - ShrinkAuxiliaryDataTest.getMemoryUsedByTest()), + Unsafe.ADDRESS_SIZE, + grouped.format((Runtime.getRuntime().freeMemory() + - ShrinkAuxiliaryDataTest.getMemoryUsedByTest()) + / Unsafe.ADDRESS_SIZE), + maxCacheSize, + grouped.format((int) Math.pow(2, maxCacheSize)) + ); + } + + /** + * Detects maximum possible size of G1ConcRSLogCacheSize available for + * current process based on maximum available process memory size + * + * @return power of two + */ + private static int getMaxCacheSize() { + long availableMemory = Runtime.getRuntime().freeMemory() + - ShrinkAuxiliaryDataTest.getMemoryUsedByTest() - 1l; + if (availableMemory <= 0) { + return 0; + } + long availablePointersCount = availableMemory / Unsafe.ADDRESS_SIZE; + return (63 - (int) Long.numberOfLeadingZeros(availablePointersCount)); + } + + static class ShrinkAuxiliaryDataTest { + + public static void main(String[] args) throws IOException { + int iterateCount = DEFAULT_ITERATION_COUNT; + + if (args.length > 0) { + try { + iterateCount = Integer.parseInt(args[0]); + } catch (NumberFormatException e) { + //num_iterate remains default + } + } + + new ShrinkAuxiliaryDataTest().test(iterateCount); + } + + class GarbageObject { + + private final List payload = new ArrayList(); + private final List ref = new LinkedList(); + + public GarbageObject(int size) { + payload.add(new byte[size]); + } + + public void addRef(GarbageObject g) { + ref.add(g); + } + + public void mutate() { + if (!payload.isEmpty() && payload.get(0).length > 0) { + payload.get(0)[0] = (byte) (Math.random() * Byte.MAX_VALUE); + } + } + } + + private final List garbage = new ArrayList(); + + public void test(int num_iterate) throws IOException { + + allocate(); + link(); + mutate(); + deallocate(); + + MemoryUsage muBeforeHeap + = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + MemoryUsage muBeforeNonHeap + = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage(); + + for (int i = 0; i < num_iterate; i++) { + allocate(); + link(); + mutate(); + deallocate(); + } + + System.gc(); + MemoryUsage muAfterHeap + = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + MemoryUsage muAfterNonHeap + = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage(); + + assertLessThanOrEqual(muAfterHeap.getCommitted(), muBeforeHeap.getCommitted(), + String.format("heap decommit failed - after > before: %d > %d", + muAfterHeap.getCommitted(), muBeforeHeap.getCommitted() + ) + ); + + if (muAfterHeap.getCommitted() < muBeforeHeap.getCommitted()) { + assertLessThanOrEqual(muAfterNonHeap.getCommitted(), muBeforeNonHeap.getCommitted(), + String.format("non-heap decommit failed - after > before: %d > %d", + muAfterNonHeap.getCommitted(), muBeforeNonHeap.getCommitted() + ) + ); + } + } + + private void allocate() { + for (int r = 0; r < REGIONS_TO_ALLOCATE; r++) { + for (int i = 0; i < NUM_OBJECTS_PER_REGION; i++) { + GarbageObject g = new GarbageObject(REGION_SIZE + / NUM_OBJECTS_PER_REGION); + garbage.add(g); + } + } + } + + /** + * Iterate through all allocated objects, and link to objects in another + * regions + */ + private void link() { + for (int ig = 0; ig < garbage.size(); ig++) { + int regionNumber = ig / NUM_OBJECTS_PER_REGION; + + for (int i = 0; i < NUM_LINKS; i++) { + int regionToLink; + do { + regionToLink = (int) (Math.random() + * REGIONS_TO_ALLOCATE); + } while (regionToLink == regionNumber); + + // get random garbage object from random region + garbage.get(ig).addRef(garbage.get(regionToLink + * NUM_OBJECTS_PER_REGION + (int) (Math.random() + * NUM_OBJECTS_PER_REGION))); + } + } + } + + private void mutate() { + for (int ig = 0; ig < garbage.size(); ig++) { + garbage.get(ig).mutate(); + } + } + + private void deallocate() { + garbage.clear(); + System.gc(); + } + + static long getMemoryUsedByTest() { + return REGIONS_TO_ALLOCATE * REGION_SIZE; + } + + private static final int REGION_SIZE = 1024 * 1024; + private static final int DEFAULT_ITERATION_COUNT = 1; // iterate main scenario + private static final int REGIONS_TO_ALLOCATE = 5; + private static final int NUM_OBJECTS_PER_REGION = 10; + private static final int NUM_LINKS = 20; // how many links create for each object + + private static final String[] prohibitedVmOptions = { + // remove this when @requires option will be on duty + "-XX:\\+UseParallelGC", + "-XX:\\+UseSerialGC", + "-XX:\\+UseConcMarkSweepGC", + "-XX:\\+UseParallelOldGC", + "-XX:\\+UseParNewGC", + "-Xconcgc", + "-Xincgc" + }; + } +} diff -r 9cf6c920a0ac -r f10fe402dfb1 test/gc/g1/TestShrinkAuxiliaryData00.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestShrinkAuxiliaryData00.java Fri Oct 17 07:20:11 2014 -0700 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * @test TestShrinkAuxiliaryData00 + * @bug 8038423 + * @summary Checks that decommitment occurs for JVM with different + * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @library /testlibrary /testlibrary/whitebox + * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData00 + * @run driver/timeout=720 TestShrinkAuxiliaryData00 + */ +public class TestShrinkAuxiliaryData00 { + + public static void main(String[] args) throws Exception { + new TestShrinkAuxiliaryData(0).test(); + } +} diff -r 9cf6c920a0ac -r f10fe402dfb1 test/gc/g1/TestShrinkAuxiliaryData05.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestShrinkAuxiliaryData05.java Fri Oct 17 07:20:11 2014 -0700 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * @test TestShrinkAuxiliaryData05 + * @bug 8038423 + * @summary Checks that decommitment occurs for JVM with different + * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @library /testlibrary /testlibrary/whitebox + * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData05 + * @run driver/timeout=720 TestShrinkAuxiliaryData05 + */ +public class TestShrinkAuxiliaryData05 { + + public static void main(String[] args) throws Exception { + new TestShrinkAuxiliaryData(5).test(); + } +} diff -r 9cf6c920a0ac -r f10fe402dfb1 test/gc/g1/TestShrinkAuxiliaryData10.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestShrinkAuxiliaryData10.java Fri Oct 17 07:20:11 2014 -0700 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * @test TestShrinkAuxiliaryData10 + * @bug 8038423 + * @summary Checks that decommitment occurs for JVM with different + * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @library /testlibrary /testlibrary/whitebox + * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData10 + * @run driver/timeout=720 TestShrinkAuxiliaryData10 + */ +public class TestShrinkAuxiliaryData10 { + + public static void main(String[] args) throws Exception { + new TestShrinkAuxiliaryData(10).test(); + } +} diff -r 9cf6c920a0ac -r f10fe402dfb1 test/gc/g1/TestShrinkAuxiliaryData15.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestShrinkAuxiliaryData15.java Fri Oct 17 07:20:11 2014 -0700 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * @test TestShrinkAuxiliaryData15 + * @bug 8038423 + * @summary Checks that decommitment occurs for JVM with different + * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @library /testlibrary /testlibrary/whitebox + * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData15 + * @run driver/timeout=720 TestShrinkAuxiliaryData15 + */ +public class TestShrinkAuxiliaryData15 { + + public static void main(String[] args) throws Exception { + new TestShrinkAuxiliaryData(15).test(); + } +} diff -r 9cf6c920a0ac -r f10fe402dfb1 test/gc/g1/TestShrinkAuxiliaryData20.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestShrinkAuxiliaryData20.java Fri Oct 17 07:20:11 2014 -0700 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * @test TestShrinkAuxiliaryData20 + * @bug 8038423 + * @summary Checks that decommitment occurs for JVM with different + * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @library /testlibrary /testlibrary/whitebox + * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData20 + * @run driver/timeout=720 TestShrinkAuxiliaryData20 + */ +public class TestShrinkAuxiliaryData20 { + + public static void main(String[] args) throws Exception { + new TestShrinkAuxiliaryData(20).test(); + } +} diff -r 9cf6c920a0ac -r f10fe402dfb1 test/gc/g1/TestShrinkAuxiliaryData25.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestShrinkAuxiliaryData25.java Fri Oct 17 07:20:11 2014 -0700 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * @test TestShrinkAuxiliaryData25 + * @bug 8038423 + * @summary Checks that decommitment occurs for JVM with different + * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @library /testlibrary /testlibrary/whitebox + * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData25 + * @run driver/timeout=720 TestShrinkAuxiliaryData25 + */ +public class TestShrinkAuxiliaryData25 { + + public static void main(String[] args) throws Exception { + new TestShrinkAuxiliaryData(25).test(); + } +} diff -r 9cf6c920a0ac -r f10fe402dfb1 test/gc/g1/TestShrinkAuxiliaryData30.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestShrinkAuxiliaryData30.java Fri Oct 17 07:20:11 2014 -0700 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, 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. + */ + +/** + * @test TestShrinkAuxiliaryData30 + * @bug 8038423 + * @summary Checks that decommitment occurs for JVM with different + * G1ConcRSLogCacheSize and ObjectAlignmentInBytes options values + * @library /testlibrary /testlibrary/whitebox + * @build TestShrinkAuxiliaryData TestShrinkAuxiliaryData30 + * @run driver/timeout=720 TestShrinkAuxiliaryData30 + */ +public class TestShrinkAuxiliaryData30 { + + public static void main(String[] args) throws Exception { + new TestShrinkAuxiliaryData(30).test(); + } +} diff -r 9cf6c920a0ac -r f10fe402dfb1 test/gc/g1/TestSummarizeRSetStatsThreads.java --- a/test/gc/g1/TestSummarizeRSetStatsThreads.java Wed Oct 15 11:14:18 2014 -0700 +++ b/test/gc/g1/TestSummarizeRSetStatsThreads.java Fri Oct 17 07:20:11 2014 -0700 @@ -53,8 +53,8 @@ // a zero in refinement thread numbers indicates that the value in ParallelGCThreads should be used. // Additionally use at least one thread. - int expectedNumRefinementThreads = refinementThreads == 0 ? workerThreads : refinementThreads; - expectedNumRefinementThreads = Math.max(1, expectedNumRefinementThreads); + int expectedNumRefinementThreads = refinementThreads; + // create the pattern made up of n copies of a floating point number pattern String numberPattern = String.format("%0" + expectedNumRefinementThreads + "d", 0) .replace("0", "\\s+\\d+\\.\\d+"); @@ -73,9 +73,9 @@ return; } // different valid combinations of number of refinement and gc worker threads - runTest(0, 0); - runTest(0, 5); - runTest(5, 0); + runTest(1, 1); + runTest(1, 5); + runTest(5, 1); runTest(10, 10); runTest(1, 2); runTest(4, 3); diff -r 9cf6c920a0ac -r f10fe402dfb1 test/gc/metaspace/TestCapacityUntilGCWrapAround.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/metaspace/TestCapacityUntilGCWrapAround.java Fri Oct 17 07:20:11 2014 -0700 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * @test + * @key gc + * @bug 8049831 + * @library /testlibrary /testlibrary/whitebox + * @build TestCapacityUntilGCWrapAround + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCapacityUntilGCWrapAround + */ + +import sun.hotspot.WhiteBox; + +import com.oracle.java.testlibrary.Asserts; +import com.oracle.java.testlibrary.Platform; + +public class TestCapacityUntilGCWrapAround { + private static long MB = 1024 * 1024; + private static long GB = 1024 * MB; + private static long MAX_UINT = 4 * GB - 1; // On 32-bit platforms + + public static void main(String[] args) { + if (Platform.is32bit()) { + WhiteBox wb = WhiteBox.getWhiteBox(); + + long before = wb.metaspaceCapacityUntilGC(); + // Now force possible overflow of capacity_until_GC. + long after = wb.incMetaspaceCapacityUntilGC(MAX_UINT); + + Asserts.assertGTE(after, before, + "Increasing with MAX_UINT should not cause wrap around: " + after + " < " + before); + Asserts.assertLTE(after, MAX_UINT, + "Increasing with MAX_UINT should not cause value larger than MAX_UINT:" + after); + } + } +} diff -r 9cf6c920a0ac -r f10fe402dfb1 test/testlibrary/whitebox/sun/hotspot/WhiteBox.java --- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Wed Oct 15 11:14:18 2014 -0700 +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Fri Oct 17 07:20:11 2014 -0700 @@ -152,6 +152,8 @@ public native void readReservedMemory(); public native long allocateMetaspace(ClassLoader classLoader, long size); public native void freeMetaspace(ClassLoader classLoader, long addr, long size); + public native long incMetaspaceCapacityUntilGC(long increment); + public native long metaspaceCapacityUntilGC(); // force Young GC public native void youngGC();