From 98f667c60253426e385ed4d979509c94518d9caa Mon Sep 17 00:00:00 2001 From: jmasa Date: Thu, 29 Mar 2012 19:46:24 -0700 Subject: [PATCH] 7131629: Generalize the CMS free list code Summary: Make the FreeChunk, FreeList, TreeList, and BinaryTreeDictionary classes usable outside CMS. Reviewed-by: brutisso, johnc, jwilhelm Contributed-by: coleen.phillimore@oracle.com --- .../concurrentMarkSweep/cmsPermGen.cpp | 2 +- .../concurrentMarkSweep/cmsPermGen.hpp | 4 +- .../compactibleFreeListSpace.cpp | 66 +-- .../compactibleFreeListSpace.hpp | 22 +- .../concurrentMarkSweepGeneration.cpp | 2 +- .../concurrentMarkSweepGeneration.hpp | 6 +- .../concurrentMarkSweep/freeChunk.cpp | 3 +- .../concurrentMarkSweep/vmStructs_cms.hpp | 22 +- .../binaryTreeDictionary.cpp | 504 ++++++++++-------- .../binaryTreeDictionary.hpp | 185 ++++--- .../freeBlockDictionary.cpp | 16 +- .../freeBlockDictionary.hpp | 23 +- .../freeList.cpp | 102 ++-- .../freeList.hpp | 60 +-- src/share/vm/memory/generationSpec.cpp | 6 +- src/share/vm/precompiled/precompiled.hpp | 3 - src/share/vm/runtime/vmStructs.cpp | 2 +- 17 files changed, 579 insertions(+), 449 deletions(-) rename src/share/vm/{gc_implementation/concurrentMarkSweep => memory}/binaryTreeDictionary.cpp (72%) rename src/share/vm/{gc_implementation/concurrentMarkSweep => memory}/binaryTreeDictionary.hpp (60%) rename src/share/vm/{gc_implementation/concurrentMarkSweep => memory}/freeBlockDictionary.cpp (76%) rename src/share/vm/{gc_implementation/concurrentMarkSweep => memory}/freeBlockDictionary.hpp (80%) rename src/share/vm/{gc_implementation/concurrentMarkSweep => memory}/freeList.cpp (84%) rename src/share/vm/{gc_implementation/concurrentMarkSweep => memory}/freeList.hpp (86%) diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/cmsPermGen.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/cmsPermGen.cpp index bdcbb467c..1c479e594 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/cmsPermGen.cpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/cmsPermGen.cpp @@ -38,7 +38,7 @@ CMSPermGen::CMSPermGen(ReservedSpace rs, size_t initial_byte_size, CardTableRS* ct, - FreeBlockDictionary::DictionaryChoice dictionaryChoice) { + FreeBlockDictionary::DictionaryChoice dictionaryChoice) { CMSPermGenGen* g = new CMSPermGenGen(rs, initial_byte_size, -1, ct); if (g == NULL) { diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/cmsPermGen.hpp b/src/share/vm/gc_implementation/concurrentMarkSweep/cmsPermGen.hpp index 6d464f717..51519750d 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/cmsPermGen.hpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/cmsPermGen.hpp @@ -45,7 +45,7 @@ class CMSPermGen: public PermGen { public: CMSPermGen(ReservedSpace rs, size_t initial_byte_size, - CardTableRS* ct, FreeBlockDictionary::DictionaryChoice); + CardTableRS* ct, FreeBlockDictionary::DictionaryChoice); HeapWord* mem_allocate(size_t size); @@ -65,7 +65,7 @@ public: // regarding not using adaptive free lists for a perm gen. ConcurrentMarkSweepGeneration(rs, initial_byte_size, // MinPermHeapExapnsion level, ct, false /* use adaptive freelists */, - (FreeBlockDictionary::DictionaryChoice)CMSDictionaryChoice) + (FreeBlockDictionary::DictionaryChoice)CMSDictionaryChoice) {} void initialize_performance_counters(); diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp index 4f78ce5dc..8263a42cb 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp @@ -69,7 +69,7 @@ void CompactibleFreeListSpace::set_cms_values() { // Constructor CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs, MemRegion mr, bool use_adaptive_freelists, - FreeBlockDictionary::DictionaryChoice dictionaryChoice) : + FreeBlockDictionary::DictionaryChoice dictionaryChoice) : _dictionaryChoice(dictionaryChoice), _adaptive_freelists(use_adaptive_freelists), _bt(bs, mr), @@ -87,6 +87,8 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs, CMSConcMarkMultiple), _collector(NULL) { + assert(sizeof(FreeChunk) / BytesPerWord <= MinChunkSize, + "FreeChunk is larger than expected"); _bt.set_space(this); initialize(mr, SpaceDecorator::Clear, SpaceDecorator::Mangle); // We have all of "mr", all of which we place in the dictionary @@ -96,13 +98,13 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs, // implementation, namely, the simple binary tree (splaying // temporarily disabled). switch (dictionaryChoice) { - case FreeBlockDictionary::dictionarySplayTree: - case FreeBlockDictionary::dictionarySkipList: + case FreeBlockDictionary::dictionarySplayTree: + case FreeBlockDictionary::dictionarySkipList: default: warning("dictionaryChoice: selected option not understood; using" " default BinaryTreeDictionary implementation instead."); - case FreeBlockDictionary::dictionaryBinaryTree: - _dictionary = new BinaryTreeDictionary(mr); + case FreeBlockDictionary::dictionaryBinaryTree: + _dictionary = new BinaryTreeDictionary(mr, use_adaptive_freelists); break; } assert(_dictionary != NULL, "CMS dictionary initialization"); @@ -448,7 +450,7 @@ const { reportIndexedFreeListStatistics(); gclog_or_tty->print_cr("Layout of Indexed Freelists"); gclog_or_tty->print_cr("---------------------------"); - FreeList::print_labels_on(st, "size"); + FreeList::print_labels_on(st, "size"); for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { _indexedFreeList[i].print_on(gclog_or_tty); for (FreeChunk* fc = _indexedFreeList[i].head(); fc != NULL; @@ -1331,7 +1333,7 @@ FreeChunk* CompactibleFreeListSpace::getChunkFromGreater(size_t numWords) { size_t currSize = numWords + MinChunkSize; assert(currSize % MinObjAlignment == 0, "currSize should be aligned"); for (i = currSize; i < IndexSetSize; i += IndexSetStride) { - FreeList* fl = &_indexedFreeList[i]; + FreeList* fl = &_indexedFreeList[i]; if (fl->head()) { ret = getFromListGreater(fl, numWords); assert(ret == NULL || ret->isFree(), "Should be returning a free chunk"); @@ -1714,7 +1716,7 @@ CompactibleFreeListSpace::returnChunkToDictionary(FreeChunk* chunk) { _dictionary->returnChunk(chunk); #ifndef PRODUCT if (CMSCollector::abstract_state() != CMSCollector::Sweeping) { - TreeChunk::as_TreeChunk(chunk)->list()->verify_stats(); + TreeChunk::as_TreeChunk(chunk)->list()->verify_stats(); } #endif // PRODUCT } @@ -1862,11 +1864,11 @@ FreeChunk* CompactibleFreeListSpace::bestFitSmall(size_t numWords) { the excess is >= MIN_CHUNK. */ size_t start = align_object_size(numWords + MinChunkSize); if (start < IndexSetSize) { - FreeList* it = _indexedFreeList; + FreeList* it = _indexedFreeList; size_t hint = _indexedFreeList[start].hint(); while (hint < IndexSetSize) { assert(hint % MinObjAlignment == 0, "hint should be aligned"); - FreeList *fl = &_indexedFreeList[hint]; + FreeList *fl = &_indexedFreeList[hint]; if (fl->surplus() > 0 && fl->head() != NULL) { // Found a list with surplus, reset original hint // and split out a free chunk which is returned. @@ -1885,7 +1887,7 @@ FreeChunk* CompactibleFreeListSpace::bestFitSmall(size_t numWords) { } /* Requires fl->size >= numWords + MinChunkSize */ -FreeChunk* CompactibleFreeListSpace::getFromListGreater(FreeList* fl, +FreeChunk* CompactibleFreeListSpace::getFromListGreater(FreeList* fl, size_t numWords) { FreeChunk *curr = fl->head(); size_t oldNumWords = curr->size(); @@ -2167,7 +2169,7 @@ void CompactibleFreeListSpace::beginSweepFLCensus( assert_locked(); size_t i; for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { - FreeList* fl = &_indexedFreeList[i]; + FreeList* fl = &_indexedFreeList[i]; if (PrintFLSStatistics > 1) { gclog_or_tty->print("size[%d] : ", i); } @@ -2186,7 +2188,7 @@ void CompactibleFreeListSpace::setFLSurplus() { assert_locked(); size_t i; for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { - FreeList *fl = &_indexedFreeList[i]; + FreeList *fl = &_indexedFreeList[i]; fl->set_surplus(fl->count() - (ssize_t)((double)fl->desired() * CMSSmallSplitSurplusPercent)); } @@ -2197,7 +2199,7 @@ void CompactibleFreeListSpace::setFLHints() { size_t i; size_t h = IndexSetSize; for (i = IndexSetSize - 1; i != 0; i -= IndexSetStride) { - FreeList *fl = &_indexedFreeList[i]; + FreeList *fl = &_indexedFreeList[i]; fl->set_hint(h); if (fl->surplus() > 0) { h = i; @@ -2209,7 +2211,7 @@ void CompactibleFreeListSpace::clearFLCensus() { assert_locked(); size_t i; for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { - FreeList *fl = &_indexedFreeList[i]; + FreeList *fl = &_indexedFreeList[i]; fl->set_prevSweep(fl->count()); fl->set_coalBirths(0); fl->set_coalDeaths(0); @@ -2236,7 +2238,7 @@ void CompactibleFreeListSpace::endSweepFLCensus(size_t sweep_count) { bool CompactibleFreeListSpace::coalOverPopulated(size_t size) { if (size < SmallForDictionary) { - FreeList *fl = &_indexedFreeList[size]; + FreeList *fl = &_indexedFreeList[size]; return (fl->coalDesired() < 0) || ((int)fl->count() > fl->coalDesired()); } else { @@ -2246,14 +2248,14 @@ bool CompactibleFreeListSpace::coalOverPopulated(size_t size) { void CompactibleFreeListSpace::smallCoalBirth(size_t size) { assert(size < SmallForDictionary, "Size too large for indexed list"); - FreeList *fl = &_indexedFreeList[size]; + FreeList *fl = &_indexedFreeList[size]; fl->increment_coalBirths(); fl->increment_surplus(); } void CompactibleFreeListSpace::smallCoalDeath(size_t size) { assert(size < SmallForDictionary, "Size too large for indexed list"); - FreeList *fl = &_indexedFreeList[size]; + FreeList *fl = &_indexedFreeList[size]; fl->increment_coalDeaths(); fl->decrement_surplus(); } @@ -2280,14 +2282,14 @@ void CompactibleFreeListSpace::coalDeath(size_t size) { void CompactibleFreeListSpace::smallSplitBirth(size_t size) { assert(size < SmallForDictionary, "Size too large for indexed list"); - FreeList *fl = &_indexedFreeList[size]; + FreeList *fl = &_indexedFreeList[size]; fl->increment_splitBirths(); fl->increment_surplus(); } void CompactibleFreeListSpace::smallSplitDeath(size_t size) { assert(size < SmallForDictionary, "Size too large for indexed list"); - FreeList *fl = &_indexedFreeList[size]; + FreeList *fl = &_indexedFreeList[size]; fl->increment_splitDeaths(); fl->decrement_surplus(); } @@ -2530,7 +2532,7 @@ void CompactibleFreeListSpace::check_free_list_consistency() const { assert(_dictionary->minSize() <= IndexSetSize, "Some sizes can't be allocated without recourse to" " linear allocation buffers"); - assert(MIN_TREE_CHUNK_SIZE*HeapWordSize == sizeof(TreeChunk), + assert(BinaryTreeDictionary::min_tree_chunk_size*HeapWordSize == sizeof(TreeChunk), "else MIN_TREE_CHUNK_SIZE is wrong"); assert((IndexSetStride == 2 && IndexSetStart == 4) || // 32-bit (IndexSetStride == 1 && IndexSetStart == 3), "just checking"); // 64-bit @@ -2543,15 +2545,15 @@ void CompactibleFreeListSpace::check_free_list_consistency() const { void CompactibleFreeListSpace::printFLCensus(size_t sweep_count) const { assert_lock_strong(&_freelistLock); - FreeList total; + FreeList total; gclog_or_tty->print("end sweep# " SIZE_FORMAT "\n", sweep_count); - FreeList::print_labels_on(gclog_or_tty, "size"); + FreeList::print_labels_on(gclog_or_tty, "size"); size_t totalFree = 0; for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) { - const FreeList *fl = &_indexedFreeList[i]; + const FreeList *fl = &_indexedFreeList[i]; totalFree += fl->count() * fl->size(); if (i % (40*IndexSetStride) == 0) { - FreeList::print_labels_on(gclog_or_tty, "size"); + FreeList::print_labels_on(gclog_or_tty, "size"); } fl->print_on(gclog_or_tty); total.set_bfrSurp( total.bfrSurp() + fl->bfrSurp() ); @@ -2634,7 +2636,7 @@ HeapWord* CFLS_LAB::alloc(size_t word_sz) { res = _cfls->getChunkFromDictionaryExact(word_sz); if (res == NULL) return NULL; } else { - FreeList* fl = &_indexedFreeList[word_sz]; + FreeList* fl = &_indexedFreeList[word_sz]; if (fl->count() == 0) { // Attempt to refill this local free list. get_from_global_pool(word_sz, fl); @@ -2654,7 +2656,7 @@ HeapWord* CFLS_LAB::alloc(size_t word_sz) { // Get a chunk of blocks of the right size and update related // book-keeping stats -void CFLS_LAB::get_from_global_pool(size_t word_sz, FreeList* fl) { +void CFLS_LAB::get_from_global_pool(size_t word_sz, FreeList* fl) { // Get the #blocks we want to claim size_t n_blks = (size_t)_blocks_to_claim[word_sz].average(); assert(n_blks > 0, "Error"); @@ -2736,7 +2738,7 @@ void CFLS_LAB::retire(int tid) { if (num_retire > 0) { _cfls->_indexedFreeList[i].prepend(&_indexedFreeList[i]); // Reset this list. - _indexedFreeList[i] = FreeList(); + _indexedFreeList[i] = FreeList(); _indexedFreeList[i].set_size(i); } } @@ -2750,7 +2752,7 @@ void CFLS_LAB::retire(int tid) { } } -void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) { +void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) { assert(fl->count() == 0, "Precondition."); assert(word_sz < CompactibleFreeListSpace::IndexSetSize, "Precondition"); @@ -2766,12 +2768,12 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n (cur_sz < CompactibleFreeListSpace::IndexSetSize) && (CMSSplitIndexedFreeListBlocks || k <= 1); k++, cur_sz = k * word_sz) { - FreeList fl_for_cur_sz; // Empty. + FreeList fl_for_cur_sz; // Empty. fl_for_cur_sz.set_size(cur_sz); { MutexLockerEx x(_indexedFreeListParLocks[cur_sz], Mutex::_no_safepoint_check_flag); - FreeList* gfl = &_indexedFreeList[cur_sz]; + FreeList* gfl = &_indexedFreeList[cur_sz]; if (gfl->count() != 0) { // nn is the number of chunks of size cur_sz that // we'd need to split k-ways each, in order to create @@ -2848,7 +2850,7 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n while (n > 0) { fc = dictionary()->getChunk(MAX2(n * word_sz, _dictionary->minSize()), - FreeBlockDictionary::atLeast); + FreeBlockDictionary::atLeast); if (fc != NULL) { _bt.allocated((HeapWord*)fc, fc->size(), true /* reducing */); // update _unallocated_blk dictionary()->dictCensusUpdate(fc->size(), diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp index c8ffba526..35eb1bfac 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_COMPACTIBLEFREELISTSPACE_HPP #define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_COMPACTIBLEFREELISTSPACE_HPP -#include "gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp" -#include "gc_implementation/concurrentMarkSweep/freeList.hpp" #include "gc_implementation/concurrentMarkSweep/promotionInfo.hpp" +#include "memory/binaryTreeDictionary.hpp" #include "memory/blockOffsetTable.inline.hpp" +#include "memory/freeList.hpp" #include "memory/space.hpp" // Classes in support of keeping track of promotions into a non-Contiguous @@ -129,10 +129,10 @@ class CompactibleFreeListSpace: public CompactibleSpace { // Linear allocation blocks LinearAllocBlock _smallLinearAllocBlock; - FreeBlockDictionary::DictionaryChoice _dictionaryChoice; - FreeBlockDictionary* _dictionary; // ptr to dictionary for large size blocks + FreeBlockDictionary::DictionaryChoice _dictionaryChoice; + FreeBlockDictionary* _dictionary; // ptr to dictionary for large size blocks - FreeList _indexedFreeList[IndexSetSize]; + FreeList _indexedFreeList[IndexSetSize]; // indexed array for small size blocks // allocation stategy bool _fitStrategy; // Use best fit strategy. @@ -169,7 +169,7 @@ class CompactibleFreeListSpace: public CompactibleSpace { // If the count of "fl" is negative, it's absolute value indicates a // number of free chunks that had been previously "borrowed" from global // list of size "word_sz", and must now be decremented. - void par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl); + void par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl); // Allocation helper functions // Allocate using a strategy that takes from the indexed free lists @@ -215,7 +215,7 @@ class CompactibleFreeListSpace: public CompactibleSpace { // and return it. The split off remainder is returned to // the free lists. The old name for getFromListGreater // was lookInListGreater. - FreeChunk* getFromListGreater(FreeList* fl, size_t numWords); + FreeChunk* getFromListGreater(FreeList* fl, size_t numWords); // Get a chunk in the indexed free list or dictionary, // by considering a larger chunk and splitting it. FreeChunk* getChunkFromGreater(size_t numWords); @@ -286,10 +286,10 @@ class CompactibleFreeListSpace: public CompactibleSpace { // Constructor... CompactibleFreeListSpace(BlockOffsetSharedArray* bs, MemRegion mr, bool use_adaptive_freelists, - FreeBlockDictionary::DictionaryChoice); + FreeBlockDictionary::DictionaryChoice); // accessors bool bestFitFirst() { return _fitStrategy == FreeBlockBestFitFirst; } - FreeBlockDictionary* dictionary() const { return _dictionary; } + FreeBlockDictionary* dictionary() const { return _dictionary; } HeapWord* nearLargestChunk() const { return _nearLargestChunk; } void set_nearLargestChunk(HeapWord* v) { _nearLargestChunk = v; } @@ -622,7 +622,7 @@ class CFLS_LAB : public CHeapObj { CompactibleFreeListSpace* _cfls; // Our local free lists. - FreeList _indexedFreeList[CompactibleFreeListSpace::IndexSetSize]; + FreeList _indexedFreeList[CompactibleFreeListSpace::IndexSetSize]; // Initialized from a command-line arg. @@ -635,7 +635,7 @@ class CFLS_LAB : public CHeapObj { size_t _num_blocks [CompactibleFreeListSpace::IndexSetSize]; // Internal work method - void get_from_global_pool(size_t word_sz, FreeList* fl); + void get_from_global_pool(size_t word_sz, FreeList* fl); public: CFLS_LAB(CompactibleFreeListSpace* cfls); diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index db8da2846..bedd9aa09 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -188,7 +188,7 @@ class CMSParGCThreadState: public CHeapObj { ConcurrentMarkSweepGeneration::ConcurrentMarkSweepGeneration( ReservedSpace rs, size_t initial_byte_size, int level, CardTableRS* ct, bool use_adaptive_freelists, - FreeBlockDictionary::DictionaryChoice dictionaryChoice) : + FreeBlockDictionary::DictionaryChoice dictionaryChoice) : CardGeneration(rs, initial_byte_size, level, ct), _dilatation_factor(((double)MinChunkSize)/((double)(CollectedHeap::min_fill_size()))), _debug_collection_type(Concurrent_collection_type) diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp index a097c5bb3..a84253888 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_CONCURRENTMARKSWEEPGENERATION_HPP #define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_CONCURRENTMARKSWEEPGENERATION_HPP -#include "gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp" #include "gc_implementation/shared/gSpaceCounters.hpp" #include "gc_implementation/shared/gcStats.hpp" #include "gc_implementation/shared/generationCounters.hpp" +#include "memory/freeBlockDictionary.hpp" #include "memory/generation.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/virtualspace.hpp" @@ -1106,7 +1106,7 @@ class ConcurrentMarkSweepGeneration: public CardGeneration { ConcurrentMarkSweepGeneration(ReservedSpace rs, size_t initial_byte_size, int level, CardTableRS* ct, bool use_adaptive_freelists, - FreeBlockDictionary::DictionaryChoice); + FreeBlockDictionary::DictionaryChoice); // Accessors CMSCollector* collector() const { return _collector; } @@ -1328,7 +1328,7 @@ class ASConcurrentMarkSweepGeneration : public ConcurrentMarkSweepGeneration { ASConcurrentMarkSweepGeneration(ReservedSpace rs, size_t initial_byte_size, int level, CardTableRS* ct, bool use_adaptive_freelists, - FreeBlockDictionary::DictionaryChoice + FreeBlockDictionary::DictionaryChoice dictionaryChoice) : ConcurrentMarkSweepGeneration(rs, initial_byte_size, level, ct, use_adaptive_freelists, dictionaryChoice) {} diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp index 84702b640..d0693ab1d 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/freeChunk.cpp @@ -23,7 +23,8 @@ */ #include "precompiled.hpp" -#include "gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp" +#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" +#include "memory/freeBlockDictionary.hpp" #include "utilities/copy.hpp" #ifndef PRODUCT diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp b/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp index 34460c19d..dc5de3668 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/vmStructs_cms.hpp @@ -44,11 +44,11 @@ nonstatic_field(FreeChunk, _next, FreeChunk*) \ nonstatic_field(FreeChunk, _prev, FreeChunk*) \ nonstatic_field(LinearAllocBlock, _word_size, size_t) \ - nonstatic_field(FreeList, _size, size_t) \ - nonstatic_field(FreeList, _count, ssize_t) \ - nonstatic_field(BinaryTreeDictionary, _totalSize, size_t) \ - nonstatic_field(CompactibleFreeListSpace, _dictionary, FreeBlockDictionary*) \ - nonstatic_field(CompactibleFreeListSpace, _indexedFreeList[0], FreeList) \ + nonstatic_field(FreeList, _size, size_t) \ + nonstatic_field(FreeList, _count, ssize_t) \ + nonstatic_field(BinaryTreeDictionary,_totalSize, size_t) \ + nonstatic_field(CompactibleFreeListSpace, _dictionary, FreeBlockDictionary*) \ + nonstatic_field(CompactibleFreeListSpace, _indexedFreeList[0], FreeList) \ nonstatic_field(CompactibleFreeListSpace, _smallLinearAllocBlock, LinearAllocBlock) @@ -70,13 +70,13 @@ declare_toplevel_type(CompactibleFreeListSpace*) \ declare_toplevel_type(CMSCollector*) \ declare_toplevel_type(FreeChunk*) \ - declare_toplevel_type(BinaryTreeDictionary*) \ - declare_toplevel_type(FreeBlockDictionary*) \ - declare_toplevel_type(FreeList*) \ - declare_toplevel_type(FreeList) \ + declare_toplevel_type(BinaryTreeDictionary*) \ + declare_toplevel_type(FreeBlockDictionary*) \ + declare_toplevel_type(FreeList*) \ + declare_toplevel_type(FreeList) \ declare_toplevel_type(LinearAllocBlock) \ - declare_toplevel_type(FreeBlockDictionary) \ - declare_type(BinaryTreeDictionary, FreeBlockDictionary) + declare_toplevel_type(FreeBlockDictionary) \ + declare_type(BinaryTreeDictionary, FreeBlockDictionary) #define VM_INT_CONSTANTS_CMS(declare_constant) \ declare_constant(Generation::ConcurrentMarkSweep) \ diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp b/src/share/vm/memory/binaryTreeDictionary.cpp similarity index 72% rename from src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp rename to src/share/vm/memory/binaryTreeDictionary.cpp index 63afa40de..98bd273ad 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp +++ b/src/share/vm/memory/binaryTreeDictionary.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -23,25 +23,29 @@ */ #include "precompiled.hpp" -#include "gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp" #include "gc_implementation/shared/allocationStats.hpp" -#include "gc_implementation/shared/spaceDecorator.hpp" -#include "memory/space.inline.hpp" +#include "memory/binaryTreeDictionary.hpp" #include "runtime/globals.hpp" #include "utilities/ostream.hpp" +#ifndef SERIALGC +#include "gc_implementation/shared/spaceDecorator.hpp" +#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" +#endif // SERIALGC //////////////////////////////////////////////////////////////////////////////// // A binary tree based search structure for free blocks. // This is currently used in the Concurrent Mark&Sweep implementation. //////////////////////////////////////////////////////////////////////////////// -TreeChunk* TreeChunk::as_TreeChunk(FreeChunk* fc) { +template +TreeChunk* TreeChunk::as_TreeChunk(Chunk* fc) { // Do some assertion checking here. - return (TreeChunk*) fc; + return (TreeChunk*) fc; } -void TreeChunk::verifyTreeChunkList() const { - TreeChunk* nextTC = (TreeChunk*)next(); +template +void TreeChunk::verifyTreeChunkList() const { + TreeChunk* nextTC = (TreeChunk*)next(); if (prev() != NULL) { // interior list node shouldn'r have tree fields guarantee(embedded_list()->parent() == NULL && embedded_list()->left() == NULL && embedded_list()->right() == NULL, "should be clear"); @@ -54,10 +58,11 @@ void TreeChunk::verifyTreeChunkList() const { } -TreeList* TreeList::as_TreeList(TreeChunk* tc) { +template +TreeList* TreeList::as_TreeList(TreeChunk* tc) { // This first free chunk in the list will be the tree list. - assert(tc->size() >= sizeof(TreeChunk), "Chunk is too small for a TreeChunk"); - TreeList* tl = tc->embedded_list(); + assert(tc->size() >= BinaryTreeDictionary::min_tree_chunk_size, "Chunk is too small for a TreeChunk"); + TreeList* tl = tc->embedded_list(); tc->set_list(tl); #ifdef ASSERT tl->set_protecting_lock(NULL); @@ -74,9 +79,10 @@ TreeList* TreeList::as_TreeList(TreeChunk* tc) { return tl; } -TreeList* TreeList::as_TreeList(HeapWord* addr, size_t size) { - TreeChunk* tc = (TreeChunk*) addr; - assert(size >= sizeof(TreeChunk), "Chunk is too small for a TreeChunk"); +template +TreeList* TreeList::as_TreeList(HeapWord* addr, size_t size) { + TreeChunk* tc = (TreeChunk*) addr; + assert(size >= BinaryTreeDictionary::min_tree_chunk_size, "Chunk is too small for a TreeChunk"); // The space in the heap will have been mangled initially but // is not remangled when a free chunk is returned to the free list // (since it is used to maintain the chunk on the free list). @@ -89,14 +95,15 @@ TreeList* TreeList::as_TreeList(HeapWord* addr, size_t size) { tc->setSize(size); tc->linkPrev(NULL); tc->linkNext(NULL); - TreeList* tl = TreeList::as_TreeList(tc); + TreeList* tl = TreeList::as_TreeList(tc); return tl; } -TreeList* TreeList::removeChunkReplaceIfNeeded(TreeChunk* tc) { +template +TreeList* TreeList::removeChunkReplaceIfNeeded(TreeChunk* tc) { - TreeList* retTL = this; - FreeChunk* list = head(); + TreeList* retTL = this; + Chunk* list = head(); assert(!list || list != list->next(), "Chunk on list twice"); assert(tc != NULL, "Chunk being removed is NULL"); assert(parent() == NULL || this == parent()->left() || @@ -105,13 +112,13 @@ TreeList* TreeList::removeChunkReplaceIfNeeded(TreeChunk* tc) { assert(head() == NULL || head()->prev() == NULL, "list invariant"); assert(tail() == NULL || tail()->next() == NULL, "list invariant"); - FreeChunk* prevFC = tc->prev(); - TreeChunk* nextTC = TreeChunk::as_TreeChunk(tc->next()); + Chunk* prevFC = tc->prev(); + TreeChunk* nextTC = TreeChunk::as_TreeChunk(tc->next()); assert(list != NULL, "should have at least the target chunk"); // Is this the first item on the list? if (tc == list) { - // The "getChunk..." functions for a TreeList will not return the + // The "getChunk..." functions for a TreeList will not return the // first chunk in the list unless it is the last chunk in the list // because the first chunk is also acting as the tree node. // When coalescing happens, however, the first chunk in the a tree @@ -120,8 +127,8 @@ TreeList* TreeList::removeChunkReplaceIfNeeded(TreeChunk* tc) { // allocated when the sweeper yields (giving up the free list lock) // to allow mutator activity. If this chunk is the first in the // list and is not the last in the list, do the work to copy the - // TreeList from the first chunk to the next chunk and update all - // the TreeList pointers in the chunks in the list. + // TreeList from the first chunk to the next chunk and update all + // the TreeList pointers in the chunks in the list. if (nextTC == NULL) { assert(prevFC == NULL, "Not last chunk in the list"); set_tail(NULL); @@ -134,11 +141,11 @@ TreeList* TreeList::removeChunkReplaceIfNeeded(TreeChunk* tc) { // This can be slow for a long list. Consider having // an option that does not allow the first chunk on the // list to be coalesced. - for (TreeChunk* curTC = nextTC; curTC != NULL; - curTC = TreeChunk::as_TreeChunk(curTC->next())) { + for (TreeChunk* curTC = nextTC; curTC != NULL; + curTC = TreeChunk::as_TreeChunk(curTC->next())) { curTC->set_list(retTL); } - // Fix the parent to point to the new TreeList. + // Fix the parent to point to the new TreeList. if (retTL->parent() != NULL) { if (this == retTL->parent()->left()) { retTL->parent()->setLeft(retTL); @@ -169,9 +176,9 @@ TreeList* TreeList::removeChunkReplaceIfNeeded(TreeChunk* tc) { prevFC->linkAfter(nextTC); } - // Below this point the embeded TreeList being used for the + // Below this point the embeded TreeList being used for the // tree node may have changed. Don't use "this" - // TreeList*. + // TreeList*. // chunk should still be a free chunk (bit set in _prev) assert(!retTL->head() || retTL->size() == retTL->head()->size(), "Wrong sized chunk in list"); @@ -181,7 +188,7 @@ TreeList* TreeList::removeChunkReplaceIfNeeded(TreeChunk* tc) { tc->set_list(NULL); bool prev_found = false; bool next_found = false; - for (FreeChunk* curFC = retTL->head(); + for (Chunk* curFC = retTL->head(); curFC != NULL; curFC = curFC->next()) { assert(curFC != tc, "Chunk is still in list"); if (curFC == prevFC) { @@ -207,7 +214,9 @@ TreeList* TreeList::removeChunkReplaceIfNeeded(TreeChunk* tc) { "list invariant"); return retTL; } -void TreeList::returnChunkAtTail(TreeChunk* chunk) { + +template +void TreeList::returnChunkAtTail(TreeChunk* chunk) { assert(chunk != NULL, "returning NULL chunk"); assert(chunk->list() == this, "list should be set for chunk"); assert(tail() != NULL, "The tree list is embedded in the first chunk"); @@ -216,12 +225,12 @@ void TreeList::returnChunkAtTail(TreeChunk* chunk) { assert(head() == NULL || head()->prev() == NULL, "list invariant"); assert(tail() == NULL || tail()->next() == NULL, "list invariant"); - FreeChunk* fc = tail(); + Chunk* fc = tail(); fc->linkAfter(chunk); link_tail(chunk); assert(!tail() || size() == tail()->size(), "Wrong sized chunk in list"); - increment_count(); + FreeList::increment_count(); debug_only(increment_returnedBytes_by(chunk->size()*sizeof(HeapWord));) assert(head() == NULL || head()->prev() == NULL, "list invariant"); assert(tail() == NULL || tail()->next() == NULL, "list invariant"); @@ -229,9 +238,10 @@ void TreeList::returnChunkAtTail(TreeChunk* chunk) { // Add this chunk at the head of the list. "At the head of the list" // is defined to be after the chunk pointer to by head(). This is -// because the TreeList is embedded in the first TreeChunk in the -// list. See the definition of TreeChunk. -void TreeList::returnChunkAtHead(TreeChunk* chunk) { +// because the TreeList is embedded in the first TreeChunk in the +// list. See the definition of TreeChunk. +template +void TreeList::returnChunkAtHead(TreeChunk* chunk) { assert(chunk->list() == this, "list should be set for chunk"); assert(head() != NULL, "The tree list is embedded in the first chunk"); assert(chunk != NULL, "returning NULL chunk"); @@ -239,7 +249,7 @@ void TreeList::returnChunkAtHead(TreeChunk* chunk) { assert(head() == NULL || head()->prev() == NULL, "list invariant"); assert(tail() == NULL || tail()->next() == NULL, "list invariant"); - FreeChunk* fc = head()->next(); + Chunk* fc = head()->next(); if (fc != NULL) { chunk->linkAfter(fc); } else { @@ -248,26 +258,28 @@ void TreeList::returnChunkAtHead(TreeChunk* chunk) { } head()->linkAfter(chunk); assert(!head() || size() == head()->size(), "Wrong sized chunk in list"); - increment_count(); + FreeList::increment_count(); debug_only(increment_returnedBytes_by(chunk->size()*sizeof(HeapWord));) assert(head() == NULL || head()->prev() == NULL, "list invariant"); assert(tail() == NULL || tail()->next() == NULL, "list invariant"); } -TreeChunk* TreeList::head_as_TreeChunk() { - assert(head() == NULL || TreeChunk::as_TreeChunk(head())->list() == this, +template +TreeChunk* TreeList::head_as_TreeChunk() { + assert(head() == NULL || TreeChunk::as_TreeChunk(head())->list() == this, "Wrong type of chunk?"); - return TreeChunk::as_TreeChunk(head()); + return TreeChunk::as_TreeChunk(head()); } -TreeChunk* TreeList::first_available() { +template +TreeChunk* TreeList::first_available() { assert(head() != NULL, "The head of the list cannot be NULL"); - FreeChunk* fc = head()->next(); - TreeChunk* retTC; + Chunk* fc = head()->next(); + TreeChunk* retTC; if (fc == NULL) { retTC = head_as_TreeChunk(); } else { - retTC = TreeChunk::as_TreeChunk(fc); + retTC = TreeChunk::as_TreeChunk(fc); } assert(retTC->list() == this, "Wrong type of chunk."); return retTC; @@ -276,32 +288,41 @@ TreeChunk* TreeList::first_available() { // Returns the block with the largest heap address amongst // those in the list for this size; potentially slow and expensive, // use with caution! -TreeChunk* TreeList::largest_address() { +template +TreeChunk* TreeList::largest_address() { assert(head() != NULL, "The head of the list cannot be NULL"); - FreeChunk* fc = head()->next(); - TreeChunk* retTC; + Chunk* fc = head()->next(); + TreeChunk* retTC; if (fc == NULL) { retTC = head_as_TreeChunk(); } else { // walk down the list and return the one with the highest // heap address among chunks of this size. - FreeChunk* last = fc; + Chunk* last = fc; while (fc->next() != NULL) { if ((HeapWord*)last < (HeapWord*)fc) { last = fc; } fc = fc->next(); } - retTC = TreeChunk::as_TreeChunk(last); + retTC = TreeChunk::as_TreeChunk(last); } assert(retTC->list() == this, "Wrong type of chunk."); return retTC; } -BinaryTreeDictionary::BinaryTreeDictionary(MemRegion mr, bool splay): - _splay(splay) +template +BinaryTreeDictionary::BinaryTreeDictionary(bool adaptive_freelists, bool splay) : + _splay(splay), _adaptive_freelists(adaptive_freelists), + _totalSize(0), _totalFreeBlocks(0), _root(0) {} + +template +BinaryTreeDictionary::BinaryTreeDictionary(MemRegion mr, + bool adaptive_freelists, + bool splay): + _adaptive_freelists(adaptive_freelists), _splay(splay) { - assert(mr.byte_size() > MIN_TREE_CHUNK_SIZE, "minimum chunk size"); + assert(mr.word_size() >= BinaryTreeDictionary::min_tree_chunk_size, "minimum chunk size"); reset(mr); assert(root()->left() == NULL, "reset check failed"); @@ -312,27 +333,32 @@ BinaryTreeDictionary::BinaryTreeDictionary(MemRegion mr, bool splay): assert(totalFreeBlocks() == 1, "reset check failed"); } -void BinaryTreeDictionary::inc_totalSize(size_t inc) { +template +void BinaryTreeDictionary::inc_totalSize(size_t inc) { _totalSize = _totalSize + inc; } -void BinaryTreeDictionary::dec_totalSize(size_t dec) { +template +void BinaryTreeDictionary::dec_totalSize(size_t dec) { _totalSize = _totalSize - dec; } -void BinaryTreeDictionary::reset(MemRegion mr) { - assert(mr.byte_size() > MIN_TREE_CHUNK_SIZE, "minimum chunk size"); - set_root(TreeList::as_TreeList(mr.start(), mr.word_size())); +template +void BinaryTreeDictionary::reset(MemRegion mr) { + assert(mr.word_size() >= BinaryTreeDictionary::min_tree_chunk_size, "minimum chunk size"); + set_root(TreeList::as_TreeList(mr.start(), mr.word_size())); set_totalSize(mr.word_size()); set_totalFreeBlocks(1); } -void BinaryTreeDictionary::reset(HeapWord* addr, size_t byte_size) { +template +void BinaryTreeDictionary::reset(HeapWord* addr, size_t byte_size) { MemRegion mr(addr, heap_word_size(byte_size)); reset(mr); } -void BinaryTreeDictionary::reset() { +template +void BinaryTreeDictionary::reset() { set_root(NULL); set_totalSize(0); set_totalFreeBlocks(0); @@ -346,12 +372,13 @@ void BinaryTreeDictionary::reset() { // (zig, zig-zig or zig-zag). A chunk of the appropriate size is then returned // if available, and if it's the last chunk, the node is deleted. A deteleted // node is replaced in place by its tree successor. -TreeChunk* -BinaryTreeDictionary::getChunkFromTree(size_t size, Dither dither, bool splay) +template +TreeChunk* +BinaryTreeDictionary::getChunkFromTree(size_t size, enum FreeBlockDictionary::Dither dither, bool splay) { - TreeList *curTL, *prevTL; - TreeChunk* retTC = NULL; - assert(size >= MIN_TREE_CHUNK_SIZE, "minimum chunk size"); + TreeList *curTL, *prevTL; + TreeChunk* retTC = NULL; + assert(size >= BinaryTreeDictionary::min_tree_chunk_size, "minimum chunk size"); if (FLSVerifyDictionary) { verifyTree(); } @@ -370,6 +397,9 @@ BinaryTreeDictionary::getChunkFromTree(size_t size, Dither dither, bool splay) } } if (curTL == NULL) { // couldn't find exact match + + if (dither == FreeBlockDictionary::exactly) return NULL; + // try and find the next larger size by walking back up the search path for (curTL = prevTL; curTL != NULL;) { if (curTL->size() >= size) break; @@ -380,14 +410,14 @@ BinaryTreeDictionary::getChunkFromTree(size_t size, Dither dither, bool splay) } if (curTL != NULL) { assert(curTL->size() >= size, "size inconsistency"); - if (UseCMSAdaptiveFreeLists) { + if (adaptive_freelists()) { // A candidate chunk has been found. If it is already under // populated, get a chunk associated with the hint for this // chunk. if (curTL->surplus() <= 0) { /* Use the hint to find a size with a surplus, and reset the hint. */ - TreeList* hintTL = curTL; + TreeList* hintTL = curTL; while (hintTL->hint() != 0) { assert(hintTL->hint() == 0 || hintTL->hint() > hintTL->size(), "hint points in the wrong direction"); @@ -435,8 +465,9 @@ BinaryTreeDictionary::getChunkFromTree(size_t size, Dither dither, bool splay) return retTC; } -TreeList* BinaryTreeDictionary::findList(size_t size) const { - TreeList* curTL; +template +TreeList* BinaryTreeDictionary::findList(size_t size) const { + TreeList* curTL; for (curTL = root(); curTL != NULL;) { if (curTL->size() == size) { // exact match break; @@ -453,9 +484,10 @@ TreeList* BinaryTreeDictionary::findList(size_t size) const { } -bool BinaryTreeDictionary::verifyChunkInFreeLists(FreeChunk* tc) const { +template +bool BinaryTreeDictionary::verifyChunkInFreeLists(Chunk* tc) const { size_t size = tc->size(); - TreeList* tl = findList(size); + TreeList* tl = findList(size); if (tl == NULL) { return false; } else { @@ -463,8 +495,9 @@ bool BinaryTreeDictionary::verifyChunkInFreeLists(FreeChunk* tc) const { } } -FreeChunk* BinaryTreeDictionary::findLargestDict() const { - TreeList *curTL = root(); +template +Chunk* BinaryTreeDictionary::findLargestDict() const { + TreeList *curTL = root(); if (curTL != NULL) { while(curTL->right() != NULL) curTL = curTL->right(); return curTL->largest_address(); @@ -477,14 +510,15 @@ FreeChunk* BinaryTreeDictionary::findLargestDict() const { // chunk in a list on a tree node, just unlink it. // If it is the last chunk in the list (the next link is NULL), // remove the node and repair the tree. -TreeChunk* -BinaryTreeDictionary::removeChunkFromTree(TreeChunk* tc) { +template +TreeChunk* +BinaryTreeDictionary::removeChunkFromTree(TreeChunk* tc) { assert(tc != NULL, "Should not call with a NULL chunk"); assert(tc->isFree(), "Header is not marked correctly"); - TreeList *newTL, *parentTL; - TreeChunk* retTC; - TreeList* tl = tc->list(); + TreeList *newTL, *parentTL; + TreeChunk* retTC; + TreeList* tl = tc->list(); debug_only( bool removing_only_chunk = false; if (tl == _root) { @@ -504,8 +538,8 @@ BinaryTreeDictionary::removeChunkFromTree(TreeChunk* tc) { retTC = tc; // Removing this chunk can have the side effect of changing the node - // (TreeList*) in the tree. If the node is the root, update it. - TreeList* replacementTL = tl->removeChunkReplaceIfNeeded(tc); + // (TreeList*) in the tree. If the node is the root, update it. + TreeList* replacementTL = tl->removeChunkReplaceIfNeeded(tc); assert(tc->isFree(), "Chunk should still be free"); assert(replacementTL->parent() == NULL || replacementTL == replacementTL->parent()->left() || @@ -519,8 +553,8 @@ BinaryTreeDictionary::removeChunkFromTree(TreeChunk* tc) { if (tl != replacementTL) { assert(replacementTL->head() != NULL, "If the tree list was replaced, it should not be a NULL list"); - TreeList* rhl = replacementTL->head_as_TreeChunk()->list(); - TreeList* rtl = TreeChunk::as_TreeChunk(replacementTL->tail())->list(); + TreeList* rhl = replacementTL->head_as_TreeChunk()->list(); + TreeList* rtl = TreeChunk::as_TreeChunk(replacementTL->tail())->list(); assert(rhl == replacementTL, "Broken head"); assert(rtl == replacementTL, "Broken tail"); assert(replacementTL->size() == tc->size(), "Broken size"); @@ -610,20 +644,21 @@ BinaryTreeDictionary::removeChunkFromTree(TreeChunk* tc) { verifyTree(); } assert(!removing_only_chunk || _root == NULL, "root should be NULL"); - return TreeChunk::as_TreeChunk(retTC); + return TreeChunk::as_TreeChunk(retTC); } // Remove the leftmost node (lm) in the tree and return it. // If lm has a right child, link it to the left node of // the parent of lm. -TreeList* BinaryTreeDictionary::removeTreeMinimum(TreeList* tl) { +template +TreeList* BinaryTreeDictionary::removeTreeMinimum(TreeList* tl) { assert(tl != NULL && tl->parent() != NULL, "really need a proper sub-tree"); // locate the subtree minimum by walking down left branches - TreeList* curTL = tl; + TreeList* curTL = tl; for (; curTL->left() != NULL; curTL = curTL->left()); // obviously curTL now has at most one child, a right child if (curTL != root()) { // Should this test just be removed? - TreeList* parentTL = curTL->parent(); + TreeList* parentTL = curTL->parent(); if (parentTL->left() == curTL) { // curTL is a left child parentTL->setLeft(curTL->right()); } else { @@ -658,7 +693,8 @@ TreeList* BinaryTreeDictionary::removeTreeMinimum(TreeList* tl) { // while getting a reasonably efficient search tree (we think). // [Measurements will be needed to (in)validate this expectation.] -void BinaryTreeDictionary::semiSplayStep(TreeList* tc) { +template +void BinaryTreeDictionary::semiSplayStep(TreeList* tc) { // apply a semi-splay step at the given node: // . if root, norting needs to be done // . if child of root, splay once @@ -668,16 +704,15 @@ void BinaryTreeDictionary::semiSplayStep(TreeList* tc) { "tree operations may be inefficient ***"); } -void BinaryTreeDictionary::insertChunkInTree(FreeChunk* fc) { - TreeList *curTL, *prevTL; +template +void BinaryTreeDictionary::insertChunkInTree(Chunk* fc) { + TreeList *curTL, *prevTL; size_t size = fc->size(); - assert(size >= MIN_TREE_CHUNK_SIZE, "too small to be a TreeList"); + assert(size >= BinaryTreeDictionary::min_tree_chunk_size, "too small to be a TreeList"); if (FLSVerifyDictionary) { verifyTree(); } - // XXX: do i need to clear the FreeChunk fields, let me do it just in case - // Revisit this later fc->clearNext(); fc->linkPrev(NULL); @@ -694,9 +729,9 @@ void BinaryTreeDictionary::insertChunkInTree(FreeChunk* fc) { curTL = curTL->right(); } } - TreeChunk* tc = TreeChunk::as_TreeChunk(fc); + TreeChunk* tc = TreeChunk::as_TreeChunk(fc); // This chunk is being returned to the binary tree. Its embedded - // TreeList should be unused at this point. + // TreeList should be unused at this point. tc->initialize(); if (curTL != NULL) { // exact match tc->set_list(curTL); @@ -704,8 +739,8 @@ void BinaryTreeDictionary::insertChunkInTree(FreeChunk* fc) { } else { // need a new node in tree tc->clearNext(); tc->linkPrev(NULL); - TreeList* newTL = TreeList::as_TreeList(tc); - assert(((TreeChunk*)tc)->list() == newTL, + TreeList* newTL = TreeList::as_TreeList(tc); + assert(((TreeChunk*)tc)->list() == newTL, "List was not initialized correctly"); if (prevTL == NULL) { // we are the only tree node assert(root() == NULL, "control point invariant"); @@ -733,27 +768,30 @@ void BinaryTreeDictionary::insertChunkInTree(FreeChunk* fc) { } } -size_t BinaryTreeDictionary::maxChunkSize() const { - verify_par_locked(); - TreeList* tc = root(); +template +size_t BinaryTreeDictionary::maxChunkSize() const { + FreeBlockDictionary::verify_par_locked(); + TreeList* tc = root(); if (tc == NULL) return 0; for (; tc->right() != NULL; tc = tc->right()); return tc->size(); } -size_t BinaryTreeDictionary::totalListLength(TreeList* tl) const { +template +size_t BinaryTreeDictionary::totalListLength(TreeList* tl) const { size_t res; res = tl->count(); #ifdef ASSERT size_t cnt; - FreeChunk* tc = tl->head(); + Chunk* tc = tl->head(); for (cnt = 0; tc != NULL; tc = tc->next(), cnt++); assert(res == cnt, "The count is not being maintained correctly"); #endif return res; } -size_t BinaryTreeDictionary::totalSizeInTree(TreeList* tl) const { +template +size_t BinaryTreeDictionary::totalSizeInTree(TreeList* tl) const { if (tl == NULL) return 0; return (tl->size() * totalListLength(tl)) + @@ -761,7 +799,8 @@ size_t BinaryTreeDictionary::totalSizeInTree(TreeList* tl) const { totalSizeInTree(tl->right()); } -double BinaryTreeDictionary::sum_of_squared_block_sizes(TreeList* const tl) const { +template +double BinaryTreeDictionary::sum_of_squared_block_sizes(TreeList* const tl) const { if (tl == NULL) { return 0.0; } @@ -772,7 +811,8 @@ double BinaryTreeDictionary::sum_of_squared_block_sizes(TreeList* const tl) cons return curr; } -size_t BinaryTreeDictionary::totalFreeBlocksInTree(TreeList* tl) const { +template +size_t BinaryTreeDictionary::totalFreeBlocksInTree(TreeList* tl) const { if (tl == NULL) return 0; return totalListLength(tl) + @@ -780,24 +820,28 @@ size_t BinaryTreeDictionary::totalFreeBlocksInTree(TreeList* tl) const { totalFreeBlocksInTree(tl->right()); } -size_t BinaryTreeDictionary::numFreeBlocks() const { +template +size_t BinaryTreeDictionary::numFreeBlocks() const { assert(totalFreeBlocksInTree(root()) == totalFreeBlocks(), "_totalFreeBlocks inconsistency"); return totalFreeBlocks(); } -size_t BinaryTreeDictionary::treeHeightHelper(TreeList* tl) const { +template +size_t BinaryTreeDictionary::treeHeightHelper(TreeList* tl) const { if (tl == NULL) return 0; return 1 + MAX2(treeHeightHelper(tl->left()), treeHeightHelper(tl->right())); } -size_t BinaryTreeDictionary::treeHeight() const { +template +size_t BinaryTreeDictionary::treeHeight() const { return treeHeightHelper(root()); } -size_t BinaryTreeDictionary::totalNodesHelper(TreeList* tl) const { +template +size_t BinaryTreeDictionary::totalNodesHelper(TreeList* tl) const { if (tl == NULL) { return 0; } @@ -805,12 +849,14 @@ size_t BinaryTreeDictionary::totalNodesHelper(TreeList* tl) const { totalNodesHelper(tl->right()); } -size_t BinaryTreeDictionary::totalNodesInTree(TreeList* tl) const { +template +size_t BinaryTreeDictionary::totalNodesInTree(TreeList* tl) const { return totalNodesHelper(root()); } -void BinaryTreeDictionary::dictCensusUpdate(size_t size, bool split, bool birth){ - TreeList* nd = findList(size); +template +void BinaryTreeDictionary::dictCensusUpdate(size_t size, bool split, bool birth){ + TreeList* nd = findList(size); if (nd) { if (split) { if (birth) { @@ -837,10 +883,11 @@ void BinaryTreeDictionary::dictCensusUpdate(size_t size, bool split, bool birth) // for the LinAB is not in the dictionary. } -bool BinaryTreeDictionary::coalDictOverPopulated(size_t size) { +template +bool BinaryTreeDictionary::coalDictOverPopulated(size_t size) { if (FLSAlwaysCoalesceLarge) return true; - TreeList* list_of_size = findList(size); + TreeList* list_of_size = findList(size); // None of requested size implies overpopulated. return list_of_size == NULL || list_of_size->coalDesired() <= 0 || list_of_size->count() > list_of_size->coalDesired(); @@ -852,16 +899,18 @@ bool BinaryTreeDictionary::coalDictOverPopulated(size_t size) { // do_tree() walks the nodes in the binary tree applying do_list() // to each list at each node. +template class TreeCensusClosure : public StackObj { protected: - virtual void do_list(FreeList* fl) = 0; + virtual void do_list(FreeList* fl) = 0; public: - virtual void do_tree(TreeList* tl) = 0; + virtual void do_tree(TreeList* tl) = 0; }; -class AscendTreeCensusClosure : public TreeCensusClosure { +template +class AscendTreeCensusClosure : public TreeCensusClosure { public: - void do_tree(TreeList* tl) { + void do_tree(TreeList* tl) { if (tl != NULL) { do_tree(tl->left()); do_list(tl); @@ -870,9 +919,10 @@ class AscendTreeCensusClosure : public TreeCensusClosure { } }; -class DescendTreeCensusClosure : public TreeCensusClosure { +template +class DescendTreeCensusClosure : public TreeCensusClosure { public: - void do_tree(TreeList* tl) { + void do_tree(TreeList* tl) { if (tl != NULL) { do_tree(tl->right()); do_list(tl); @@ -883,7 +933,8 @@ class DescendTreeCensusClosure : public TreeCensusClosure { // For each list in the tree, calculate the desired, desired // coalesce, count before sweep, and surplus before sweep. -class BeginSweepClosure : public AscendTreeCensusClosure { +template +class BeginSweepClosure : public AscendTreeCensusClosure { double _percentage; float _inter_sweep_current; float _inter_sweep_estimate; @@ -898,7 +949,7 @@ class BeginSweepClosure : public AscendTreeCensusClosure { _inter_sweep_estimate(inter_sweep_estimate), _intra_sweep_estimate(intra_sweep_estimate) { } - void do_list(FreeList* fl) { + void do_list(FreeList* fl) { double coalSurplusPercent = _percentage; fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate); fl->set_coalDesired((ssize_t)((double)fl->desired() * coalSurplusPercent)); @@ -911,17 +962,19 @@ class BeginSweepClosure : public AscendTreeCensusClosure { // Similar to TreeCensusClosure but searches the // tree and returns promptly when found. +template class TreeSearchClosure : public StackObj { protected: - virtual bool do_list(FreeList* fl) = 0; + virtual bool do_list(FreeList* fl) = 0; public: - virtual bool do_tree(TreeList* tl) = 0; + virtual bool do_tree(TreeList* tl) = 0; }; #if 0 // Don't need this yet but here for symmetry. +template class AscendTreeSearchClosure : public TreeSearchClosure { public: - bool do_tree(TreeList* tl) { + bool do_tree(TreeList* tl) { if (tl != NULL) { if (do_tree(tl->left())) return true; if (do_list(tl)) return true; @@ -932,9 +985,10 @@ class AscendTreeSearchClosure : public TreeSearchClosure { }; #endif -class DescendTreeSearchClosure : public TreeSearchClosure { +template +class DescendTreeSearchClosure : public TreeSearchClosure { public: - bool do_tree(TreeList* tl) { + bool do_tree(TreeList* tl) { if (tl != NULL) { if (do_tree(tl->right())) return true; if (do_list(tl)) return true; @@ -946,14 +1000,15 @@ class DescendTreeSearchClosure : public TreeSearchClosure { // Searches the tree for a chunk that ends at the // specified address. -class EndTreeSearchClosure : public DescendTreeSearchClosure { +template +class EndTreeSearchClosure : public DescendTreeSearchClosure { HeapWord* _target; - FreeChunk* _found; + Chunk* _found; public: EndTreeSearchClosure(HeapWord* target) : _target(target), _found(NULL) {} - bool do_list(FreeList* fl) { - FreeChunk* item = fl->head(); + bool do_list(FreeList* fl) { + Chunk* item = fl->head(); while (item != NULL) { if (item->end() == _target) { _found = item; @@ -963,20 +1018,22 @@ class EndTreeSearchClosure : public DescendTreeSearchClosure { } return false; } - FreeChunk* found() { return _found; } + Chunk* found() { return _found; } }; -FreeChunk* BinaryTreeDictionary::find_chunk_ends_at(HeapWord* target) const { - EndTreeSearchClosure etsc(target); +template +Chunk* BinaryTreeDictionary::find_chunk_ends_at(HeapWord* target) const { + EndTreeSearchClosure etsc(target); bool found_target = etsc.do_tree(root()); assert(found_target || etsc.found() == NULL, "Consistency check"); assert(!found_target || etsc.found() != NULL, "Consistency check"); return etsc.found(); } -void BinaryTreeDictionary::beginSweepDictCensus(double coalSurplusPercent, +template +void BinaryTreeDictionary::beginSweepDictCensus(double coalSurplusPercent, float inter_sweep_current, float inter_sweep_estimate, float intra_sweep_estimate) { - BeginSweepClosure bsc(coalSurplusPercent, inter_sweep_current, + BeginSweepClosure bsc(coalSurplusPercent, inter_sweep_current, inter_sweep_estimate, intra_sweep_estimate); bsc.do_tree(root()); @@ -984,76 +1041,85 @@ void BinaryTreeDictionary::beginSweepDictCensus(double coalSurplusPercent, // Closures and methods for calculating total bytes returned to the // free lists in the tree. -NOT_PRODUCT( - class InitializeDictReturnedBytesClosure : public AscendTreeCensusClosure { +#ifndef PRODUCT +template +class InitializeDictReturnedBytesClosure : public AscendTreeCensusClosure { public: - void do_list(FreeList* fl) { - fl->set_returnedBytes(0); - } - }; - - void BinaryTreeDictionary::initializeDictReturnedBytes() { - InitializeDictReturnedBytesClosure idrb; - idrb.do_tree(root()); + void do_list(FreeList* fl) { + fl->set_returnedBytes(0); } +}; - class ReturnedBytesClosure : public AscendTreeCensusClosure { - size_t _dictReturnedBytes; - public: - ReturnedBytesClosure() { _dictReturnedBytes = 0; } - void do_list(FreeList* fl) { - _dictReturnedBytes += fl->returnedBytes(); - } - size_t dictReturnedBytes() { return _dictReturnedBytes; } - }; - - size_t BinaryTreeDictionary::sumDictReturnedBytes() { - ReturnedBytesClosure rbc; - rbc.do_tree(root()); +template +void BinaryTreeDictionary::initializeDictReturnedBytes() { + InitializeDictReturnedBytesClosure idrb; + idrb.do_tree(root()); +} - return rbc.dictReturnedBytes(); +template +class ReturnedBytesClosure : public AscendTreeCensusClosure { + size_t _dictReturnedBytes; + public: + ReturnedBytesClosure() { _dictReturnedBytes = 0; } + void do_list(FreeList* fl) { + _dictReturnedBytes += fl->returnedBytes(); } + size_t dictReturnedBytes() { return _dictReturnedBytes; } +}; - // Count the number of entries in the tree. - class treeCountClosure : public DescendTreeCensusClosure { - public: - uint count; - treeCountClosure(uint c) { count = c; } - void do_list(FreeList* fl) { - count++; - } - }; +template +size_t BinaryTreeDictionary::sumDictReturnedBytes() { + ReturnedBytesClosure rbc; + rbc.do_tree(root()); + + return rbc.dictReturnedBytes(); +} - size_t BinaryTreeDictionary::totalCount() { - treeCountClosure ctc(0); - ctc.do_tree(root()); - return ctc.count; +// Count the number of entries in the tree. +template +class treeCountClosure : public DescendTreeCensusClosure { + public: + uint count; + treeCountClosure(uint c) { count = c; } + void do_list(FreeList* fl) { + count++; } -) +}; + +template +size_t BinaryTreeDictionary::totalCount() { + treeCountClosure ctc(0); + ctc.do_tree(root()); + return ctc.count; +} +#endif // PRODUCT // Calculate surpluses for the lists in the tree. -class setTreeSurplusClosure : public AscendTreeCensusClosure { +template +class setTreeSurplusClosure : public AscendTreeCensusClosure { double percentage; public: setTreeSurplusClosure(double v) { percentage = v; } - void do_list(FreeList* fl) { + void do_list(FreeList* fl) { double splitSurplusPercent = percentage; fl->set_surplus(fl->count() - (ssize_t)((double)fl->desired() * splitSurplusPercent)); } }; -void BinaryTreeDictionary::setTreeSurplus(double splitSurplusPercent) { - setTreeSurplusClosure sts(splitSurplusPercent); +template +void BinaryTreeDictionary::setTreeSurplus(double splitSurplusPercent) { + setTreeSurplusClosure sts(splitSurplusPercent); sts.do_tree(root()); } // Set hints for the lists in the tree. -class setTreeHintsClosure : public DescendTreeCensusClosure { +template +class setTreeHintsClosure : public DescendTreeCensusClosure { size_t hint; public: setTreeHintsClosure(size_t v) { hint = v; } - void do_list(FreeList* fl) { + void do_list(FreeList* fl) { fl->set_hint(hint); assert(fl->hint() == 0 || fl->hint() > fl->size(), "Current hint is inconsistent"); @@ -1063,14 +1129,16 @@ class setTreeHintsClosure : public DescendTreeCensusClosure { } }; -void BinaryTreeDictionary::setTreeHints(void) { - setTreeHintsClosure sth(0); +template +void BinaryTreeDictionary::setTreeHints(void) { + setTreeHintsClosure sth(0); sth.do_tree(root()); } // Save count before previous sweep and splits and coalesces. -class clearTreeCensusClosure : public AscendTreeCensusClosure { - void do_list(FreeList* fl) { +template +class clearTreeCensusClosure : public AscendTreeCensusClosure { + void do_list(FreeList* fl) { fl->set_prevSweep(fl->count()); fl->set_coalBirths(0); fl->set_coalDeaths(0); @@ -1079,13 +1147,15 @@ class clearTreeCensusClosure : public AscendTreeCensusClosure { } }; -void BinaryTreeDictionary::clearTreeCensus(void) { - clearTreeCensusClosure ctc; +template +void BinaryTreeDictionary::clearTreeCensus(void) { + clearTreeCensusClosure ctc; ctc.do_tree(root()); } // Do reporting and post sweep clean up. -void BinaryTreeDictionary::endSweepDictCensus(double splitSurplusPercent) { +template +void BinaryTreeDictionary::endSweepDictCensus(double splitSurplusPercent) { // Does walking the tree 3 times hurt? setTreeSurplus(splitSurplusPercent); setTreeHints(); @@ -1096,8 +1166,9 @@ void BinaryTreeDictionary::endSweepDictCensus(double splitSurplusPercent) { } // Print summary statistics -void BinaryTreeDictionary::reportStatistics() const { - verify_par_locked(); +template +void BinaryTreeDictionary::reportStatistics() const { + FreeBlockDictionary::verify_par_locked(); gclog_or_tty->print("Statistics for BinaryTreeDictionary:\n" "------------------------------------\n"); size_t totalSize = totalChunkSize(debug_only(NULL)); @@ -1114,21 +1185,22 @@ void BinaryTreeDictionary::reportStatistics() const { // Print census information - counts, births, deaths, etc. // for each list in the tree. Also print some summary // information. -class PrintTreeCensusClosure : public AscendTreeCensusClosure { +template +class PrintTreeCensusClosure : public AscendTreeCensusClosure { int _print_line; size_t _totalFree; - FreeList _total; + FreeList _total; public: PrintTreeCensusClosure() { _print_line = 0; _totalFree = 0; } - FreeList* total() { return &_total; } + FreeList* total() { return &_total; } size_t totalFree() { return _totalFree; } - void do_list(FreeList* fl) { + void do_list(FreeList* fl) { if (++_print_line >= 40) { - FreeList::print_labels_on(gclog_or_tty, "size"); + FreeList::print_labels_on(gclog_or_tty, "size"); _print_line = 0; } fl->print_on(gclog_or_tty); @@ -1146,15 +1218,16 @@ class PrintTreeCensusClosure : public AscendTreeCensusClosure { } }; -void BinaryTreeDictionary::printDictCensus(void) const { +template +void BinaryTreeDictionary::printDictCensus(void) const { gclog_or_tty->print("\nBinaryTree\n"); - FreeList::print_labels_on(gclog_or_tty, "size"); - PrintTreeCensusClosure ptc; + FreeList::print_labels_on(gclog_or_tty, "size"); + PrintTreeCensusClosure ptc; ptc.do_tree(root()); - FreeList* total = ptc.total(); - FreeList::print_labels_on(gclog_or_tty, " "); + FreeList* total = ptc.total(); + FreeList::print_labels_on(gclog_or_tty, " "); total->print_on(gclog_or_tty, "TOTAL\t"); gclog_or_tty->print( "totalFree(words): " SIZE_FORMAT_W(16) @@ -1167,7 +1240,8 @@ void BinaryTreeDictionary::printDictCensus(void) const { /(total->desired() != 0 ? (double)total->desired() : 1.0)); } -class PrintFreeListsClosure : public AscendTreeCensusClosure { +template +class PrintFreeListsClosure : public AscendTreeCensusClosure { outputStream* _st; int _print_line; @@ -1176,14 +1250,14 @@ class PrintFreeListsClosure : public AscendTreeCensusClosure { _st = st; _print_line = 0; } - void do_list(FreeList* fl) { + void do_list(FreeList* fl) { if (++_print_line >= 40) { - FreeList::print_labels_on(_st, "size"); + FreeList::print_labels_on(_st, "size"); _print_line = 0; } fl->print_on(gclog_or_tty); size_t sz = fl->size(); - for (FreeChunk* fc = fl->head(); fc != NULL; + for (Chunk* fc = fl->head(); fc != NULL; fc = fc->next()) { _st->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s", fc, (HeapWord*)fc + sz, @@ -1192,10 +1266,11 @@ class PrintFreeListsClosure : public AscendTreeCensusClosure { } }; -void BinaryTreeDictionary::print_free_lists(outputStream* st) const { +template +void BinaryTreeDictionary::print_free_lists(outputStream* st) const { - FreeList::print_labels_on(st, "size"); - PrintFreeListsClosure pflc(st); + FreeList::print_labels_on(st, "size"); + PrintFreeListsClosure pflc(st); pflc.do_tree(root()); } @@ -1203,16 +1278,18 @@ void BinaryTreeDictionary::print_free_lists(outputStream* st) const { // . _root has no parent // . parent and child point to each other // . each node's key correctly related to that of its child(ren) -void BinaryTreeDictionary::verifyTree() const { +template +void BinaryTreeDictionary::verifyTree() const { guarantee(root() == NULL || totalFreeBlocks() == 0 || totalSize() != 0, "_totalSize should't be 0?"); guarantee(root() == NULL || root()->parent() == NULL, "_root shouldn't have parent"); verifyTreeHelper(root()); } -size_t BinaryTreeDictionary::verifyPrevFreePtrs(TreeList* tl) { +template +size_t BinaryTreeDictionary::verifyPrevFreePtrs(TreeList* tl) { size_t ct = 0; - for (FreeChunk* curFC = tl->head(); curFC != NULL; curFC = curFC->next()) { + for (Chunk* curFC = tl->head(); curFC != NULL; curFC = curFC->next()) { ct++; assert(curFC->prev() == NULL || curFC->prev()->isFree(), "Chunk should be free"); @@ -1223,7 +1300,8 @@ size_t BinaryTreeDictionary::verifyPrevFreePtrs(TreeList* tl) { // Note: this helper is recursive rather than iterative, so use with // caution on very deep trees; and watch out for stack overflow errors; // In general, to be used only for debugging. -void BinaryTreeDictionary::verifyTreeHelper(TreeList* tl) const { +template +void BinaryTreeDictionary::verifyTreeHelper(TreeList* tl) const { if (tl == NULL) return; guarantee(tl->size() != 0, "A list must has a size"); @@ -1251,7 +1329,15 @@ void BinaryTreeDictionary::verifyTreeHelper(TreeList* tl) const { verifyTreeHelper(tl->right()); } -void BinaryTreeDictionary::verify() const { +template +void BinaryTreeDictionary::verify() const { verifyTree(); guarantee(totalSize() == totalSizeInTree(root()), "Total Size inconsistency"); } + +#ifndef SERIALGC +// Explicitly instantiate these types for FreeChunk. +template class BinaryTreeDictionary; +template class TreeChunk; +template class TreeList; +#endif // SERIALGC diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp b/src/share/vm/memory/binaryTreeDictionary.hpp similarity index 60% rename from src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp rename to src/share/vm/memory/binaryTreeDictionary.hpp index f06f8d385..8de138f08 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp +++ b/src/share/vm/memory/binaryTreeDictionary.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -22,51 +22,65 @@ * */ -#ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_BINARYTREEDICTIONARY_HPP -#define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_BINARYTREEDICTIONARY_HPP +#ifndef SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP +#define SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP -#include "gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp" -#include "gc_implementation/concurrentMarkSweep/freeList.hpp" +#include "memory/freeBlockDictionary.hpp" +#include "memory/freeList.hpp" /* * A binary tree based search structure for free blocks. - * This is currently used in the Concurrent Mark&Sweep implementation. + * This is currently used in the Concurrent Mark&Sweep implementation, but + * will be used for free block management for metadata. */ // A TreeList is a FreeList which can be used to maintain a // binary tree of free lists. -class TreeChunk; -class BinaryTreeDictionary; -class AscendTreeCensusClosure; -class DescendTreeCensusClosure; -class DescendTreeSearchClosure; +template class TreeChunk; +template class BinaryTreeDictionary; +template class AscendTreeCensusClosure; +template class DescendTreeCensusClosure; +template class DescendTreeSearchClosure; -class TreeList: public FreeList { - friend class TreeChunk; - friend class BinaryTreeDictionary; - friend class AscendTreeCensusClosure; - friend class DescendTreeCensusClosure; - friend class DescendTreeSearchClosure; +template +class TreeList: public FreeList { + friend class TreeChunk; + friend class BinaryTreeDictionary; + friend class AscendTreeCensusClosure; + friend class DescendTreeCensusClosure; + friend class DescendTreeSearchClosure; + + TreeList* _parent; + TreeList* _left; + TreeList* _right; protected: - TreeList* parent() const { return _parent; } - TreeList* left() const { return _left; } - TreeList* right() const { return _right; } + TreeList* parent() const { return _parent; } + TreeList* left() const { return _left; } + TreeList* right() const { return _right; } + + // Wrapper on call to base class, to get the template to compile. + Chunk* head() const { return FreeList::head(); } + Chunk* tail() const { return FreeList::tail(); } + void set_head(Chunk* head) { FreeList::set_head(head); } + void set_tail(Chunk* tail) { FreeList::set_tail(tail); } + + size_t size() const { return FreeList::size(); } // Accessors for links in tree. - void setLeft(TreeList* tl) { + void setLeft(TreeList* tl) { _left = tl; if (tl != NULL) tl->setParent(this); } - void setRight(TreeList* tl) { + void setRight(TreeList* tl) { _right = tl; if (tl != NULL) tl->setParent(this); } - void setParent(TreeList* tl) { _parent = tl; } + void setParent(TreeList* tl) { _parent = tl; } void clearLeft() { _left = NULL; } void clearRight() { _right = NULL; } @@ -75,20 +89,20 @@ class TreeList: public FreeList { // For constructing a TreeList from a Tree chunk or // address and size. - static TreeList* as_TreeList(TreeChunk* tc); - static TreeList* as_TreeList(HeapWord* addr, size_t size); + static TreeList* as_TreeList(TreeChunk* tc); + static TreeList* as_TreeList(HeapWord* addr, size_t size); // Returns the head of the free list as a pointer to a TreeChunk. - TreeChunk* head_as_TreeChunk(); + TreeChunk* head_as_TreeChunk(); // Returns the first available chunk in the free list as a pointer // to a TreeChunk. - TreeChunk* first_available(); + TreeChunk* first_available(); // Returns the block with the largest heap address amongst // those in the list for this size; potentially slow and expensive, // use with caution! - TreeChunk* largest_address(); + TreeChunk* largest_address(); // removeChunkReplaceIfNeeded() removes the given "tc" from the TreeList. // If "tc" is the first chunk in the list, it is also the @@ -96,13 +110,13 @@ class TreeList: public FreeList { // returns the possibly replaced TreeList* for the node in // the tree. It also updates the parent of the original // node to point to the new node. - TreeList* removeChunkReplaceIfNeeded(TreeChunk* tc); + TreeList* removeChunkReplaceIfNeeded(TreeChunk* tc); // See FreeList. - void returnChunkAtHead(TreeChunk* tc); - void returnChunkAtTail(TreeChunk* tc); + void returnChunkAtHead(TreeChunk* tc); + void returnChunkAtTail(TreeChunk* tc); }; -// A TreeChunk is a subclass of a FreeChunk that additionally +// A TreeChunk is a subclass of a Chunk that additionally // maintains a pointer to the free list on which it is currently // linked. // A TreeChunk is also used as a node in the binary tree. This @@ -115,92 +129,111 @@ class TreeList: public FreeList { // on the free list for a node in the tree and is only removed if // it is the last chunk on the free list. -class TreeChunk : public FreeChunk { - friend class TreeList; - TreeList* _list; - TreeList _embedded_list; // if non-null, this chunk is on _list +template +class TreeChunk : public Chunk { + friend class TreeList; + TreeList* _list; + TreeList _embedded_list; // if non-null, this chunk is on _list protected: - TreeList* embedded_list() const { return (TreeList*) &_embedded_list; } - void set_embedded_list(TreeList* v) { _embedded_list = *v; } + TreeList* embedded_list() const { return (TreeList*) &_embedded_list; } + void set_embedded_list(TreeList* v) { _embedded_list = *v; } public: - TreeList* list() { return _list; } - void set_list(TreeList* v) { _list = v; } - static TreeChunk* as_TreeChunk(FreeChunk* fc); + TreeList* list() { return _list; } + void set_list(TreeList* v) { _list = v; } + static TreeChunk* as_TreeChunk(Chunk* fc); // Initialize fields in a TreeChunk that should be // initialized when the TreeChunk is being added to // a free list in the tree. void initialize() { embedded_list()->initialize(); } + Chunk* next() const { return Chunk::next(); } + Chunk* prev() const { return Chunk::prev(); } + size_t size() const volatile { return Chunk::size(); } + // debugging void verifyTreeChunkList() const; }; -const size_t MIN_TREE_CHUNK_SIZE = sizeof(TreeChunk)/HeapWordSize; -class BinaryTreeDictionary: public FreeBlockDictionary { +template +class BinaryTreeDictionary: public FreeBlockDictionary { friend class VMStructs; bool _splay; size_t _totalSize; size_t _totalFreeBlocks; - TreeList* _root; + TreeList* _root; + bool _adaptive_freelists; // private accessors bool splay() const { return _splay; } void set_splay(bool v) { _splay = v; } - size_t totalSize() const { return _totalSize; } void set_totalSize(size_t v) { _totalSize = v; } virtual void inc_totalSize(size_t v); virtual void dec_totalSize(size_t v); size_t totalFreeBlocks() const { return _totalFreeBlocks; } void set_totalFreeBlocks(size_t v) { _totalFreeBlocks = v; } - TreeList* root() const { return _root; } - void set_root(TreeList* v) { _root = v; } + TreeList* root() const { return _root; } + void set_root(TreeList* v) { _root = v; } + bool adaptive_freelists() { return _adaptive_freelists; } + + // This field is added and can be set to point to the + // the Mutex used to synchronize access to the + // dictionary so that assertion checking can be done. + // For example it is set to point to _parDictionaryAllocLock. + NOT_PRODUCT(Mutex* _lock;) // Remove a chunk of size "size" or larger from the tree and // return it. If the chunk // is the last chunk of that size, remove the node for that size // from the tree. - TreeChunk* getChunkFromTree(size_t size, Dither dither, bool splay); + TreeChunk* getChunkFromTree(size_t size, enum FreeBlockDictionary::Dither dither, bool splay); // Return a list of the specified size or NULL from the tree. // The list is not removed from the tree. - TreeList* findList (size_t size) const; + TreeList* findList (size_t size) const; // Remove this chunk from the tree. If the removal results // in an empty list in the tree, remove the empty list. - TreeChunk* removeChunkFromTree(TreeChunk* tc); + TreeChunk* removeChunkFromTree(TreeChunk* tc); // Remove the node in the trees starting at tl that has the // minimum value and return it. Repair the tree as needed. - TreeList* removeTreeMinimum(TreeList* tl); - void semiSplayStep(TreeList* tl); + TreeList* removeTreeMinimum(TreeList* tl); + void semiSplayStep(TreeList* tl); // Add this free chunk to the tree. - void insertChunkInTree(FreeChunk* freeChunk); + void insertChunkInTree(Chunk* freeChunk); public: + + static const size_t min_tree_chunk_size = sizeof(TreeChunk)/HeapWordSize; + void verifyTree() const; // verify that the given chunk is in the tree. - bool verifyChunkInFreeLists(FreeChunk* tc) const; + bool verifyChunkInFreeLists(Chunk* tc) const; private: - void verifyTreeHelper(TreeList* tl) const; - static size_t verifyPrevFreePtrs(TreeList* tl); + void verifyTreeHelper(TreeList* tl) const; + static size_t verifyPrevFreePtrs(TreeList* tl); // Returns the total number of chunks in the list. - size_t totalListLength(TreeList* tl) const; + size_t totalListLength(TreeList* tl) const; // Returns the total number of words in the chunks in the tree // starting at "tl". - size_t totalSizeInTree(TreeList* tl) const; + size_t totalSizeInTree(TreeList* tl) const; // Returns the sum of the square of the size of each block // in the tree starting at "tl". - double sum_of_squared_block_sizes(TreeList* const tl) const; + double sum_of_squared_block_sizes(TreeList* const tl) const; // Returns the total number of free blocks in the tree starting // at "tl". - size_t totalFreeBlocksInTree(TreeList* tl) const; + size_t totalFreeBlocksInTree(TreeList* tl) const; size_t numFreeBlocks() const; size_t treeHeight() const; - size_t treeHeightHelper(TreeList* tl) const; - size_t totalNodesInTree(TreeList* tl) const; - size_t totalNodesHelper(TreeList* tl) const; + size_t treeHeightHelper(TreeList* tl) const; + size_t totalNodesInTree(TreeList* tl) const; + size_t totalNodesHelper(TreeList* tl) const; public: // Constructor - BinaryTreeDictionary(MemRegion mr, bool splay = false); + BinaryTreeDictionary(bool adaptive_freelists, bool splay = false); + BinaryTreeDictionary(MemRegion mr, bool adaptive_freelists, bool splay = false); + + // Public accessors + size_t totalSize() const { return _totalSize; } // Reset the dictionary to the initial conditions with // a single free chunk. @@ -212,22 +245,22 @@ class BinaryTreeDictionary: public FreeBlockDictionary { // Return a chunk of size "size" or greater from // the tree. // want a better dynamic splay strategy for the future. - FreeChunk* getChunk(size_t size, Dither dither) { - verify_par_locked(); - FreeChunk* res = getChunkFromTree(size, dither, splay()); + Chunk* getChunk(size_t size, enum FreeBlockDictionary::Dither dither) { + FreeBlockDictionary::verify_par_locked(); + Chunk* res = getChunkFromTree(size, dither, splay()); assert(res == NULL || res->isFree(), "Should be returning a free chunk"); return res; } - void returnChunk(FreeChunk* chunk) { - verify_par_locked(); + void returnChunk(Chunk* chunk) { + FreeBlockDictionary::verify_par_locked(); insertChunkInTree(chunk); } - void removeChunk(FreeChunk* chunk) { - verify_par_locked(); - removeChunkFromTree((TreeChunk*)chunk); + void removeChunk(Chunk* chunk) { + FreeBlockDictionary::verify_par_locked(); + removeChunkFromTree((TreeChunk*)chunk); assert(chunk->isFree(), "Should still be a free chunk"); } @@ -243,14 +276,14 @@ class BinaryTreeDictionary: public FreeBlockDictionary { } size_t minSize() const { - return MIN_TREE_CHUNK_SIZE; + return min_tree_chunk_size; } double sum_of_squared_block_sizes() const { return sum_of_squared_block_sizes(root()); } - FreeChunk* find_chunk_ends_at(HeapWord* target) const; + Chunk* find_chunk_ends_at(HeapWord* target) const; // Find the list with size "size" in the binary tree and update // the statistics in the list according to "split" (chunk was @@ -269,7 +302,7 @@ class BinaryTreeDictionary: public FreeBlockDictionary { // statistics for the sweep. void endSweepDictCensus(double splitSurplusPercent); // Return the largest free chunk in the tree. - FreeChunk* findLargestDict() const; + Chunk* findLargestDict() const; // Accessors for statistics void setTreeSurplus(double splitSurplusPercent); void setTreeHints(void); @@ -293,4 +326,4 @@ class BinaryTreeDictionary: public FreeBlockDictionary { void verify() const; }; -#endif // SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_BINARYTREEDICTIONARY_HPP +#endif // SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.cpp b/src/share/vm/memory/freeBlockDictionary.cpp similarity index 76% rename from src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.cpp rename to src/share/vm/memory/freeBlockDictionary.cpp index 1870c1f1b..03314ebbe 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.cpp +++ b/src/share/vm/memory/freeBlockDictionary.cpp @@ -23,7 +23,10 @@ */ #include "precompiled.hpp" -#include "gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp" +#ifndef SERIALGC +#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" +#endif // SERIALGC +#include "memory/freeBlockDictionary.hpp" #ifdef TARGET_OS_FAMILY_linux # include "thread_linux.inline.hpp" #endif @@ -38,15 +41,15 @@ #endif #ifndef PRODUCT -Mutex* FreeBlockDictionary::par_lock() const { +template Mutex* FreeBlockDictionary::par_lock() const { return _lock; } -void FreeBlockDictionary::set_par_lock(Mutex* lock) { +template void FreeBlockDictionary::set_par_lock(Mutex* lock) { _lock = lock; } -void FreeBlockDictionary::verify_par_locked() const { +template void FreeBlockDictionary::verify_par_locked() const { #ifdef ASSERT if (ParallelGCThreads > 0) { Thread* myThread = Thread::current(); @@ -58,3 +61,8 @@ void FreeBlockDictionary::verify_par_locked() const { #endif // ASSERT } #endif + +#ifndef SERIALGC +// Explicitly instantiate for FreeChunk +template class FreeBlockDictionary; +#endif // SERIALGC diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp b/src/share/vm/memory/freeBlockDictionary.hpp similarity index 80% rename from src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp rename to src/share/vm/memory/freeBlockDictionary.hpp index 538662028..431488373 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp +++ b/src/share/vm/memory/freeBlockDictionary.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -22,12 +22,10 @@ * */ -#ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_FREEBLOCKDICTIONARY_HPP -#define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_FREEBLOCKDICTIONARY_HPP +#ifndef SHARE_VM_MEMORY_FREEBLOCKDICTIONARY_HPP +#define SHARE_VM_MEMORY_FREEBLOCKDICTIONARY_HPP -#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" #include "memory/allocation.hpp" -#include "memory/memRegion.hpp" #include "runtime/mutex.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" @@ -35,6 +33,7 @@ // A FreeBlockDictionary is an abstract superclass that will allow // a number of alternative implementations in the future. +template class FreeBlockDictionary: public CHeapObj { public: enum Dither { @@ -52,9 +51,9 @@ class FreeBlockDictionary: public CHeapObj { NOT_PRODUCT(Mutex* _lock;) public: - virtual void removeChunk(FreeChunk* fc) = 0; - virtual FreeChunk* getChunk(size_t size, Dither dither = atLeast) = 0; - virtual void returnChunk(FreeChunk* chunk) = 0; + virtual void removeChunk(Chunk* fc) = 0; + virtual Chunk* getChunk(size_t size, Dither dither = atLeast) = 0; + virtual void returnChunk(Chunk* chunk) = 0; virtual size_t totalChunkSize(debug_only(const Mutex* lock)) const = 0; virtual size_t maxChunkSize() const = 0; virtual size_t minSize() const = 0; @@ -69,14 +68,14 @@ class FreeBlockDictionary: public CHeapObj { float inter_sweep_current, float inter_sweep_estimate, float intra__sweep_current) = 0; virtual void endSweepDictCensus(double splitSurplusPercent) = 0; - virtual FreeChunk* findLargestDict() const = 0; + virtual Chunk* findLargestDict() const = 0; // verify that the given chunk is in the dictionary. - virtual bool verifyChunkInFreeLists(FreeChunk* tc) const = 0; + virtual bool verifyChunkInFreeLists(Chunk* tc) const = 0; // Sigma_{all_free_blocks} (block_size^2) virtual double sum_of_squared_block_sizes() const = 0; - virtual FreeChunk* find_chunk_ends_at(HeapWord* target) const = 0; + virtual Chunk* find_chunk_ends_at(HeapWord* target) const = 0; virtual void inc_totalSize(size_t v) = 0; virtual void dec_totalSize(size_t v) = 0; @@ -100,4 +99,4 @@ class FreeBlockDictionary: public CHeapObj { void verify_par_locked() const PRODUCT_RETURN; }; -#endif // SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_FREEBLOCKDICTIONARY_HPP +#endif // SHARE_VM_MEMORY_FREEBLOCKDICTIONARY_HPP diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp b/src/share/vm/memory/freeList.cpp similarity index 84% rename from src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp rename to src/share/vm/memory/freeList.cpp index 192b05548..0ffd8f52f 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.cpp +++ b/src/share/vm/memory/freeList.cpp @@ -23,20 +23,25 @@ */ #include "precompiled.hpp" -#include "gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp" -#include "gc_implementation/concurrentMarkSweep/freeList.hpp" +#include "memory/freeBlockDictionary.hpp" +#include "memory/freeList.hpp" #include "memory/sharedHeap.hpp" #include "runtime/globals.hpp" #include "runtime/mutex.hpp" #include "runtime/vmThread.hpp" +#ifndef SERIALGC +#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" +#endif // SERIALGC + // Free list. A FreeList is used to access a linked list of chunks // of space in the heap. The head and tail are maintained so that // items can be (as in the current implementation) added at the // at the tail of the list and removed from the head of the list to // maintain a FIFO queue. -FreeList::FreeList() : +template +FreeList::FreeList() : _head(NULL), _tail(NULL) #ifdef ASSERT , _protecting_lock(NULL) @@ -48,7 +53,8 @@ FreeList::FreeList() : init_statistics(); } -FreeList::FreeList(FreeChunk* fc) : +template +FreeList::FreeList(Chunk* fc) : _head(fc), _tail(fc) #ifdef ASSERT , _protecting_lock(NULL) @@ -63,40 +69,27 @@ FreeList::FreeList(FreeChunk* fc) : #endif } -FreeList::FreeList(HeapWord* addr, size_t size) : - _head((FreeChunk*) addr), _tail((FreeChunk*) addr) -#ifdef ASSERT - , _protecting_lock(NULL) -#endif -{ - assert(size > sizeof(FreeChunk), "size is too small"); - head()->setSize(size); - _size = size; - _count = 1; - init_statistics(); -#ifndef PRODUCT - _allocation_stats.set_returnedBytes(_size * HeapWordSize); -#endif -} - -void FreeList::reset(size_t hint) { +template +void FreeList::reset(size_t hint) { set_count(0); set_head(NULL); set_tail(NULL); set_hint(hint); } -void FreeList::init_statistics(bool split_birth) { +template +void FreeList::init_statistics(bool split_birth) { _allocation_stats.initialize(split_birth); } -FreeChunk* FreeList::getChunkAtHead() { +template +Chunk* FreeList::getChunkAtHead() { assert_proper_lock_protection(); assert(head() == NULL || head()->prev() == NULL, "list invariant"); assert(tail() == NULL || tail()->next() == NULL, "list invariant"); - FreeChunk* fc = head(); + Chunk* fc = head(); if (fc != NULL) { - FreeChunk* nextFC = fc->next(); + Chunk* nextFC = fc->next(); if (nextFC != NULL) { // The chunk fc being removed has a "next". Set the "next" to the // "prev" of fc. @@ -113,20 +106,21 @@ FreeChunk* FreeList::getChunkAtHead() { } -void FreeList::getFirstNChunksFromList(size_t n, FreeList* fl) { +template +void FreeList::getFirstNChunksFromList(size_t n, FreeList* fl) { assert_proper_lock_protection(); assert(fl->count() == 0, "Precondition"); if (count() > 0) { int k = 1; fl->set_head(head()); n--; - FreeChunk* tl = head(); + Chunk* tl = head(); while (tl->next() != NULL && n > 0) { tl = tl->next(); n--; k++; } assert(tl != NULL, "Loop Inv."); // First, fix up the list we took from. - FreeChunk* new_head = tl->next(); + Chunk* new_head = tl->next(); set_head(new_head); set_count(count() - k); if (new_head == NULL) { @@ -143,7 +137,8 @@ void FreeList::getFirstNChunksFromList(size_t n, FreeList* fl) { } // Remove this chunk from the list -void FreeList::removeChunk(FreeChunk*fc) { +template +void FreeList::removeChunk(Chunk*fc) { assert_proper_lock_protection(); assert(head() != NULL, "Remove from empty list"); assert(fc != NULL, "Remove a NULL chunk"); @@ -151,8 +146,8 @@ void FreeList::removeChunk(FreeChunk*fc) { assert(head() == NULL || head()->prev() == NULL, "list invariant"); assert(tail() == NULL || tail()->next() == NULL, "list invariant"); - FreeChunk* prevFC = fc->prev(); - FreeChunk* nextFC = fc->next(); + Chunk* prevFC = fc->prev(); + Chunk* nextFC = fc->next(); if (nextFC != NULL) { // The chunk fc being removed has a "next". Set the "next" to the // "prev" of fc. @@ -185,14 +180,15 @@ void FreeList::removeChunk(FreeChunk*fc) { } // Add this chunk at the head of the list. -void FreeList::returnChunkAtHead(FreeChunk* chunk, bool record_return) { +template +void FreeList::returnChunkAtHead(Chunk* chunk, bool record_return) { assert_proper_lock_protection(); assert(chunk != NULL, "insert a NULL chunk"); assert(size() == chunk->size(), "Wrong size"); assert(head() == NULL || head()->prev() == NULL, "list invariant"); assert(tail() == NULL || tail()->next() == NULL, "list invariant"); - FreeChunk* oldHead = head(); + Chunk* oldHead = head(); assert(chunk != oldHead, "double insertion"); chunk->linkAfter(oldHead); link_head(chunk); @@ -212,20 +208,22 @@ void FreeList::returnChunkAtHead(FreeChunk* chunk, bool record_return) { assert(tail() == NULL || tail()->size() == size(), "wrong item on list"); } -void FreeList::returnChunkAtHead(FreeChunk* chunk) { +template +void FreeList::returnChunkAtHead(Chunk* chunk) { assert_proper_lock_protection(); returnChunkAtHead(chunk, true); } // Add this chunk at the tail of the list. -void FreeList::returnChunkAtTail(FreeChunk* chunk, bool record_return) { +template +void FreeList::returnChunkAtTail(Chunk* chunk, bool record_return) { assert_proper_lock_protection(); assert(head() == NULL || head()->prev() == NULL, "list invariant"); assert(tail() == NULL || tail()->next() == NULL, "list invariant"); assert(chunk != NULL, "insert a NULL chunk"); assert(size() == chunk->size(), "wrong size"); - FreeChunk* oldTail = tail(); + Chunk* oldTail = tail(); assert(chunk != oldTail, "double insertion"); if (oldTail != NULL) { oldTail->linkAfter(chunk); @@ -246,11 +244,13 @@ void FreeList::returnChunkAtTail(FreeChunk* chunk, bool record_return) { assert(tail() == NULL || tail()->size() == size(), "wrong item on list"); } -void FreeList::returnChunkAtTail(FreeChunk* chunk) { +template +void FreeList::returnChunkAtTail(Chunk* chunk) { returnChunkAtTail(chunk, true); } -void FreeList::prepend(FreeList* fl) { +template +void FreeList::prepend(FreeList* fl) { assert_proper_lock_protection(); if (fl->count() > 0) { if (count() == 0) { @@ -259,8 +259,8 @@ void FreeList::prepend(FreeList* fl) { set_count(fl->count()); } else { // Both are non-empty. - FreeChunk* fl_tail = fl->tail(); - FreeChunk* this_head = head(); + Chunk* fl_tail = fl->tail(); + Chunk* this_head = head(); assert(fl_tail->next() == NULL, "Well-formedness of fl"); fl_tail->linkNext(this_head); this_head->linkPrev(fl_tail); @@ -275,11 +275,12 @@ void FreeList::prepend(FreeList* fl) { // verifyChunkInFreeLists() is used to verify that an item is in this free list. // It is used as a debugging aid. -bool FreeList::verifyChunkInFreeLists(FreeChunk* fc) const { +template +bool FreeList::verifyChunkInFreeLists(Chunk* fc) const { // This is an internal consistency check, not part of the check that the // chunk is in the free lists. guarantee(fc->size() == size(), "Wrong list is being searched"); - FreeChunk* curFC = head(); + Chunk* curFC = head(); while (curFC) { // This is an internal consistency check. guarantee(size() == curFC->size(), "Chunk is in wrong list."); @@ -292,7 +293,8 @@ bool FreeList::verifyChunkInFreeLists(FreeChunk* fc) const { } #ifndef PRODUCT -void FreeList::verify_stats() const { +template +void FreeList::verify_stats() const { // The +1 of the LH comparand is to allow some "looseness" in // checking: we usually call this interface when adding a block // and we'll subsequently update the stats; we cannot update the @@ -317,7 +319,8 @@ void FreeList::verify_stats() const { _allocation_stats.coalDeaths(), count())); } -void FreeList::assert_proper_lock_protection_work() const { +template +void FreeList::assert_proper_lock_protection_work() const { assert(_protecting_lock != NULL, "Don't call this directly"); assert(ParallelGCThreads > 0, "Don't call this directly"); Thread* thr = Thread::current(); @@ -334,7 +337,8 @@ void FreeList::assert_proper_lock_protection_work() const { #endif // Print the "label line" for free list stats. -void FreeList::print_labels_on(outputStream* st, const char* c) { +template +void FreeList::print_labels_on(outputStream* st, const char* c) { st->print("%16s\t", c); st->print("%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t" "\n", @@ -346,7 +350,8 @@ void FreeList::print_labels_on(outputStream* st, const char* c) { // to the call is a non-null string, it is printed in the first column; // otherwise, if the argument is null (the default), then the size of the // (free list) block is printed in the first column. -void FreeList::print_on(outputStream* st, const char* c) const { +template +void FreeList::print_on(outputStream* st, const char* c) const { if (c != NULL) { st->print("%16s", c); } else { @@ -358,3 +363,8 @@ void FreeList::print_on(outputStream* st, const char* c) const { bfrSurp(), surplus(), desired(), prevSweep(), beforeSweep(), count(), coalBirths(), coalDeaths(), splitBirths(), splitDeaths()); } + +#ifndef SERIALGC +// Needs to be after the definitions have been seen. +template class FreeList; +#endif // SERIALGC diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp b/src/share/vm/memory/freeList.hpp similarity index 86% rename from src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp rename to src/share/vm/memory/freeList.hpp index 44afe8e56..77e42053b 100644 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/freeList.hpp +++ b/src/share/vm/memory/freeList.hpp @@ -22,39 +22,36 @@ * */ -#ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_FREELIST_HPP -#define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_FREELIST_HPP +#ifndef SHARE_VM_MEMORY_FREELIST_HPP +#define SHARE_VM_MEMORY_FREELIST_HPP #include "gc_implementation/shared/allocationStats.hpp" class CompactibleFreeListSpace; -// A class for maintaining a free list of FreeChunk's. The FreeList +// A class for maintaining a free list of Chunk's. The FreeList // maintains a the structure of the list (head, tail, etc.) plus // statistics for allocations from the list. The links between items // are not part of FreeList. The statistics are -// used to make decisions about coalescing FreeChunk's when they +// used to make decisions about coalescing Chunk's when they // are swept during collection. // // See the corresponding .cpp file for a description of the specifics // for that implementation. class Mutex; -class TreeList; +template class TreeList; +template class PrintTreeCensusClosure; +template class FreeList VALUE_OBJ_CLASS_SPEC { friend class CompactibleFreeListSpace; friend class VMStructs; - friend class PrintTreeCensusClosure; - - protected: - TreeList* _parent; - TreeList* _left; - TreeList* _right; + friend class PrintTreeCensusClosure; private: - FreeChunk* _head; // Head of list of free chunks - FreeChunk* _tail; // Tail of list of free chunks + Chunk* _head; // Head of list of free chunks + Chunk* _tail; // Tail of list of free chunks size_t _size; // Size in Heap words of each chunk ssize_t _count; // Number of entries in list size_t _hint; // next larger size list with a positive surplus @@ -92,10 +89,7 @@ class FreeList VALUE_OBJ_CLASS_SPEC { // Construct a list without any entries. FreeList(); // Construct a list with "fc" as the first (and lone) entry in the list. - FreeList(FreeChunk* fc); - // Construct a list which will have a FreeChunk at address "addr" and - // of size "size" as the first (and lone) entry in the list. - FreeList(HeapWord* addr, size_t size); + FreeList(Chunk* fc); // Reset the head, tail, hint, and count of a free list. void reset(size_t hint); @@ -108,18 +102,18 @@ class FreeList VALUE_OBJ_CLASS_SPEC { #endif // Accessors. - FreeChunk* head() const { + Chunk* head() const { assert_proper_lock_protection(); return _head; } - void set_head(FreeChunk* v) { + void set_head(Chunk* v) { assert_proper_lock_protection(); _head = v; assert(!_head || _head->size() == _size, "bad chunk size"); } // Set the head of the list and set the prev field of non-null // values to NULL. - void link_head(FreeChunk* v) { + void link_head(Chunk* v) { assert_proper_lock_protection(); set_head(v); // If this method is not used (just set the head instead), @@ -129,18 +123,18 @@ class FreeList VALUE_OBJ_CLASS_SPEC { } } - FreeChunk* tail() const { + Chunk* tail() const { assert_proper_lock_protection(); return _tail; } - void set_tail(FreeChunk* v) { + void set_tail(Chunk* v) { assert_proper_lock_protection(); _tail = v; assert(!_tail || _tail->size() == _size, "bad chunk size"); } // Set the tail of the list and set the next field of non-null // values to NULL. - void link_tail(FreeChunk* v) { + void link_tail(Chunk* v) { assert_proper_lock_protection(); set_tail(v); if (v != NULL) { @@ -298,31 +292,31 @@ class FreeList VALUE_OBJ_CLASS_SPEC { // Unlink head of list and return it. Returns NULL if // the list is empty. - FreeChunk* getChunkAtHead(); + Chunk* getChunkAtHead(); // Remove the first "n" or "count", whichever is smaller, chunks from the // list, setting "fl", which is required to be empty, to point to them. - void getFirstNChunksFromList(size_t n, FreeList* fl); + void getFirstNChunksFromList(size_t n, FreeList* fl); // Unlink this chunk from it's free list - void removeChunk(FreeChunk* fc); + void removeChunk(Chunk* fc); // Add this chunk to this free list. - void returnChunkAtHead(FreeChunk* fc); - void returnChunkAtTail(FreeChunk* fc); + void returnChunkAtHead(Chunk* fc); + void returnChunkAtTail(Chunk* fc); // Similar to returnChunk* but also records some diagnostic // information. - void returnChunkAtHead(FreeChunk* fc, bool record_return); - void returnChunkAtTail(FreeChunk* fc, bool record_return); + void returnChunkAtHead(Chunk* fc, bool record_return); + void returnChunkAtTail(Chunk* fc, bool record_return); // Prepend "fl" (whose size is required to be the same as that of "this") // to the front of "this" list. - void prepend(FreeList* fl); + void prepend(FreeList* fl); // Verify that the chunk is in the list. // found. Return NULL if "fc" is not found. - bool verifyChunkInFreeLists(FreeChunk* fc) const; + bool verifyChunkInFreeLists(Chunk* fc) const; // Stats verification void verify_stats() const PRODUCT_RETURN; @@ -332,4 +326,4 @@ class FreeList VALUE_OBJ_CLASS_SPEC { void print_on(outputStream* st, const char* c = NULL) const; }; -#endif // SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_FREELIST_HPP +#endif // SHARE_VM_MEMORY_FREELIST_HPP diff --git a/src/share/vm/memory/generationSpec.cpp b/src/share/vm/memory/generationSpec.cpp index bbe63ce48..4b2c3fc49 100644 --- a/src/share/vm/memory/generationSpec.cpp +++ b/src/share/vm/memory/generationSpec.cpp @@ -68,7 +68,7 @@ Generation* GenerationSpec::init(ReservedSpace rs, int level, ConcurrentMarkSweepGeneration* g = NULL; g = new ConcurrentMarkSweepGeneration(rs, init_size(), level, ctrs, UseCMSAdaptiveFreeLists, - (FreeBlockDictionary::DictionaryChoice)CMSDictionaryChoice); + (FreeBlockDictionary::DictionaryChoice)CMSDictionaryChoice); g->initialize_performance_counters(); @@ -88,7 +88,7 @@ Generation* GenerationSpec::init(ReservedSpace rs, int level, ASConcurrentMarkSweepGeneration* g = NULL; g = new ASConcurrentMarkSweepGeneration(rs, init_size(), level, ctrs, UseCMSAdaptiveFreeLists, - (FreeBlockDictionary::DictionaryChoice)CMSDictionaryChoice); + (FreeBlockDictionary::DictionaryChoice)CMSDictionaryChoice); g->initialize_performance_counters(); @@ -175,7 +175,7 @@ PermGen* PermanentGenerationSpec::init(ReservedSpace rs, } // XXXPERM return new CMSPermGen(perm_rs, init_size, ctrs, - (FreeBlockDictionary::DictionaryChoice)CMSDictionaryChoice); + (FreeBlockDictionary::DictionaryChoice)CMSDictionaryChoice); } #endif // SERIALGC default: diff --git a/src/share/vm/precompiled/precompiled.hpp b/src/share/vm/precompiled/precompiled.hpp index 686f25669..0414e070a 100644 --- a/src/share/vm/precompiled/precompiled.hpp +++ b/src/share/vm/precompiled/precompiled.hpp @@ -293,13 +293,10 @@ # include "c1/c1_globals.hpp" #endif // COMPILER1 #ifndef SERIALGC -# include "gc_implementation/concurrentMarkSweep/binaryTreeDictionary.hpp" # include "gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp" # include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp" # include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp" -# include "gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp" # include "gc_implementation/concurrentMarkSweep/freeChunk.hpp" -# include "gc_implementation/concurrentMarkSweep/freeList.hpp" # include "gc_implementation/concurrentMarkSweep/promotionInfo.hpp" # include "gc_implementation/g1/dirtyCardQueue.hpp" # include "gc_implementation/g1/g1BlockOffsetTable.hpp" diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp index 25d3b5b41..cc2d07834 100644 --- a/src/share/vm/runtime/vmStructs.cpp +++ b/src/share/vm/runtime/vmStructs.cpp @@ -44,7 +44,6 @@ #include "code/vmreg.hpp" #include "compiler/oopMap.hpp" #include "compiler/compileBroker.hpp" -#include "gc_implementation/concurrentMarkSweep/freeBlockDictionary.hpp" #include "gc_implementation/shared/immutableSpace.hpp" #include "gc_implementation/shared/markSweep.hpp" #include "gc_implementation/shared/mutableSpace.hpp" @@ -55,6 +54,7 @@ #include "memory/cardTableRS.hpp" #include "memory/compactPermGen.hpp" #include "memory/defNewGeneration.hpp" +#include "memory/freeBlockDictionary.hpp" #include "memory/genCollectedHeap.hpp" #include "memory/generation.hpp" #include "memory/generationSpec.hpp" -- GitLab