提交 98f667c6 编写于 作者: J jmasa

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