8200735: Move CMS specific code from binaryTreeDictionary and freeList to CMS files
Reviewed-by: shade, adinn
--- a/src/hotspot/share/gc/cms/adaptiveFreeList.cpp Fri Apr 06 03:53:28 2018 +0200
+++ b/src/hotspot/share/gc/cms/adaptiveFreeList.cpp Fri Apr 06 11:37:26 2018 +0200
@@ -26,6 +26,7 @@
#include "gc/cms/adaptiveFreeList.hpp"
#include "gc/cms/freeChunk.hpp"
#include "gc/shared/collectedHeap.hpp"
+#include "memory/freeList.inline.hpp"
#include "runtime/globals.hpp"
#include "runtime/mutex.hpp"
#include "runtime/orderAccess.inline.hpp"
--- a/src/hotspot/share/gc/cms/compactibleFreeListSpace.cpp Fri Apr 06 03:53:28 2018 +0200
+++ b/src/hotspot/share/gc/cms/compactibleFreeListSpace.cpp Fri Apr 06 11:37:26 2018 +0200
@@ -35,6 +35,7 @@
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
+#include "memory/binaryTreeDictionary.inline.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/access.inline.hpp"
@@ -49,6 +50,244 @@
#include "utilities/align.hpp"
#include "utilities/copy.hpp"
+// Specialize for AdaptiveFreeList which tries to avoid
+// splitting a chunk of a size that is under populated in favor of
+// an over populated size. The general get_better_list() just returns
+// the current list.
+template <>
+TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >*
+TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >::get_better_list(
+ BinaryTreeDictionary<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* dictionary) {
+ // A candidate chunk has been found. If it is already under
+ // populated, get a chunk associated with the hint for this
+ // chunk.
+
+ TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* curTL = this;
+ if (curTL->surplus() <= 0) {
+ /* Use the hint to find a size with a surplus, and reset the hint. */
+ TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* hintTL = this;
+ while (hintTL->hint() != 0) {
+ assert(hintTL->hint() > hintTL->size(),
+ "hint points in the wrong direction");
+ hintTL = dictionary->find_list(hintTL->hint());
+ assert(curTL != hintTL, "Infinite loop");
+ if (hintTL == NULL ||
+ hintTL == curTL /* Should not happen but protect against it */ ) {
+ // No useful hint. Set the hint to NULL and go on.
+ curTL->set_hint(0);
+ break;
+ }
+ assert(hintTL->size() > curTL->size(), "hint is inconsistent");
+ if (hintTL->surplus() > 0) {
+ // The hint led to a list that has a surplus. Use it.
+ // Set the hint for the candidate to an overpopulated
+ // size.
+ curTL->set_hint(hintTL->size());
+ // Change the candidate.
+ curTL = hintTL;
+ break;
+ }
+ }
+ }
+ return curTL;
+}
+
+void AFLBinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth) {
+ TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* nd = find_list(size);
+ if (nd) {
+ if (split) {
+ if (birth) {
+ nd->increment_split_births();
+ nd->increment_surplus();
+ } else {
+ nd->increment_split_deaths();
+ nd->decrement_surplus();
+ }
+ } else {
+ if (birth) {
+ nd->increment_coal_births();
+ nd->increment_surplus();
+ } else {
+ nd->increment_coal_deaths();
+ nd->decrement_surplus();
+ }
+ }
+ }
+ // A list for this size may not be found (nd == 0) if
+ // This is a death where the appropriate list is now
+ // empty and has been removed from the list.
+ // This is a birth associated with a LinAB. The chunk
+ // for the LinAB is not in the dictionary.
+}
+
+bool AFLBinaryTreeDictionary::coal_dict_over_populated(size_t size) {
+ if (FLSAlwaysCoalesceLarge) return true;
+
+ TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* list_of_size = find_list(size);
+ // None of requested size implies overpopulated.
+ return list_of_size == NULL || list_of_size->coal_desired() <= 0 ||
+ list_of_size->count() > list_of_size->coal_desired();
+}
+
+// For each list in the tree, calculate the desired, desired
+// coalesce, count before sweep, and surplus before sweep.
+class BeginSweepClosure : public AscendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
+ double _percentage;
+ float _inter_sweep_current;
+ float _inter_sweep_estimate;
+ float _intra_sweep_estimate;
+
+ public:
+ BeginSweepClosure(double p, float inter_sweep_current,
+ float inter_sweep_estimate,
+ float intra_sweep_estimate) :
+ _percentage(p),
+ _inter_sweep_current(inter_sweep_current),
+ _inter_sweep_estimate(inter_sweep_estimate),
+ _intra_sweep_estimate(intra_sweep_estimate) { }
+
+ void do_list(AdaptiveFreeList<FreeChunk>* fl) {
+ double coalSurplusPercent = _percentage;
+ fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate);
+ fl->set_coal_desired((ssize_t)((double)fl->desired() * coalSurplusPercent));
+ fl->set_before_sweep(fl->count());
+ fl->set_bfr_surp(fl->surplus());
+ }
+};
+
+void AFLBinaryTreeDictionary::begin_sweep_dict_census(double coalSurplusPercent,
+ float inter_sweep_current, float inter_sweep_estimate, float intra_sweep_estimate) {
+ BeginSweepClosure bsc(coalSurplusPercent, inter_sweep_current,
+ inter_sweep_estimate,
+ intra_sweep_estimate);
+ bsc.do_tree(root());
+}
+
+// Calculate surpluses for the lists in the tree.
+class setTreeSurplusClosure : public AscendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
+ double percentage;
+ public:
+ setTreeSurplusClosure(double v) { percentage = v; }
+
+ void do_list(AdaptiveFreeList<FreeChunk>* fl) {
+ double splitSurplusPercent = percentage;
+ fl->set_surplus(fl->count() -
+ (ssize_t)((double)fl->desired() * splitSurplusPercent));
+ }
+};
+
+void AFLBinaryTreeDictionary::set_tree_surplus(double splitSurplusPercent) {
+ setTreeSurplusClosure sts(splitSurplusPercent);
+ sts.do_tree(root());
+}
+
+// Set hints for the lists in the tree.
+class setTreeHintsClosure : public DescendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
+ size_t hint;
+ public:
+ setTreeHintsClosure(size_t v) { hint = v; }
+
+ void do_list(AdaptiveFreeList<FreeChunk>* fl) {
+ fl->set_hint(hint);
+ assert(fl->hint() == 0 || fl->hint() > fl->size(),
+ "Current hint is inconsistent");
+ if (fl->surplus() > 0) {
+ hint = fl->size();
+ }
+ }
+};
+
+void AFLBinaryTreeDictionary::set_tree_hints(void) {
+ setTreeHintsClosure sth(0);
+ sth.do_tree(root());
+}
+
+// Save count before previous sweep and splits and coalesces.
+class clearTreeCensusClosure : public AscendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
+ void do_list(AdaptiveFreeList<FreeChunk>* fl) {
+ fl->set_prev_sweep(fl->count());
+ fl->set_coal_births(0);
+ fl->set_coal_deaths(0);
+ fl->set_split_births(0);
+ fl->set_split_deaths(0);
+ }
+};
+
+void AFLBinaryTreeDictionary::clear_tree_census(void) {
+ clearTreeCensusClosure ctc;
+ ctc.do_tree(root());
+}
+
+// Do reporting and post sweep clean up.
+void AFLBinaryTreeDictionary::end_sweep_dict_census(double splitSurplusPercent) {
+ // Does walking the tree 3 times hurt?
+ set_tree_surplus(splitSurplusPercent);
+ set_tree_hints();
+ LogTarget(Trace, gc, freelist, stats) log;
+ if (log.is_enabled()) {
+ LogStream out(log);
+ report_statistics(&out);
+ }
+ clear_tree_census();
+}
+
+// Print census information - counts, births, deaths, etc.
+// for each list in the tree. Also print some summary
+// information.
+class PrintTreeCensusClosure : public AscendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
+ int _print_line;
+ size_t _total_free;
+ AdaptiveFreeList<FreeChunk> _total;
+
+ public:
+ PrintTreeCensusClosure() {
+ _print_line = 0;
+ _total_free = 0;
+ }
+ AdaptiveFreeList<FreeChunk>* total() { return &_total; }
+ size_t total_free() { return _total_free; }
+
+ void do_list(AdaptiveFreeList<FreeChunk>* fl) {
+ LogStreamHandle(Debug, gc, freelist, census) out;
+
+ if (++_print_line >= 40) {
+ AdaptiveFreeList<FreeChunk>::print_labels_on(&out, "size");
+ _print_line = 0;
+ }
+ fl->print_on(&out);
+ _total_free += fl->count() * fl->size() ;
+ total()->set_count( total()->count() + fl->count() );
+ total()->set_bfr_surp( total()->bfr_surp() + fl->bfr_surp() );
+ total()->set_surplus( total()->split_deaths() + fl->surplus() );
+ total()->set_desired( total()->desired() + fl->desired() );
+ total()->set_prev_sweep( total()->prev_sweep() + fl->prev_sweep() );
+ total()->set_before_sweep(total()->before_sweep() + fl->before_sweep());
+ total()->set_coal_births( total()->coal_births() + fl->coal_births() );
+ total()->set_coal_deaths( total()->coal_deaths() + fl->coal_deaths() );
+ total()->set_split_births(total()->split_births() + fl->split_births());
+ total()->set_split_deaths(total()->split_deaths() + fl->split_deaths());
+ }
+};
+
+void AFLBinaryTreeDictionary::print_dict_census(outputStream* st) const {
+
+ st->print_cr("BinaryTree");
+ AdaptiveFreeList<FreeChunk>::print_labels_on(st, "size");
+ PrintTreeCensusClosure ptc;
+ ptc.do_tree(root());
+
+ AdaptiveFreeList<FreeChunk>* total = ptc.total();
+ AdaptiveFreeList<FreeChunk>::print_labels_on(st, " ");
+ total->print_on(st, "TOTAL\t");
+ st->print_cr("total_free(words): " SIZE_FORMAT_W(16) " growth: %8.5f deficit: %8.5f",
+ ptc.total_free(),
+ (double)(total->split_births() + total->coal_births()
+ - total->split_deaths() - total->coal_deaths())
+ /(total->prev_sweep() != 0 ? (double)total->prev_sweep() : 1.0),
+ (double)(total->desired() - total->count())
+ /(total->desired() != 0 ? (double)total->desired() : 1.0));
+}
+
/////////////////////////////////////////////////////////////////////////
//// CompactibleFreeListSpace
/////////////////////////////////////////////////////////////////////////
--- a/src/hotspot/share/gc/cms/compactibleFreeListSpace.hpp Fri Apr 06 03:53:28 2018 +0200
+++ b/src/hotspot/share/gc/cms/compactibleFreeListSpace.hpp Fri Apr 06 11:37:26 2018 +0200
@@ -48,6 +48,37 @@
class ObjectClosureCareful;
class Klass;
+class AFLBinaryTreeDictionary : public BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> > {
+ public:
+ AFLBinaryTreeDictionary(MemRegion mr)
+ : BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> >(mr) {}
+
+ // Find the list with size "size" in the binary tree and update
+ // the statistics in the list according to "split" (chunk was
+ // split or coalesce) and "birth" (chunk was added or removed).
+ void dict_census_update(size_t size, bool split, bool birth);
+ // Return true if the dictionary is overpopulated (more chunks of
+ // this size than desired) for size "size".
+ bool coal_dict_over_populated(size_t size);
+ // Methods called at the beginning of a sweep to prepare the
+ // statistics for the sweep.
+ void begin_sweep_dict_census(double coalSurplusPercent,
+ float inter_sweep_current,
+ float inter_sweep_estimate,
+ float intra_sweep_estimate);
+ // Methods called after the end of a sweep to modify the
+ // statistics for the sweep.
+ void end_sweep_dict_census(double splitSurplusPercent);
+ // Accessors for statistics
+ void set_tree_surplus(double splitSurplusPercent);
+ void set_tree_hints(void);
+ // Reset statistics for all the lists in the tree.
+ void clear_tree_census(void);
+ // Print the statistics for all the lists in the tree. Also may
+ // print out summaries.
+ void print_dict_census(outputStream* st) const;
+};
+
class LinearAllocBlock {
public:
LinearAllocBlock() : _ptr(0), _word_size(0), _refillSize(0),
--- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp Fri Apr 06 03:53:28 2018 +0200
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp Fri Apr 06 11:37:26 2018 +0200
@@ -59,6 +59,7 @@
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.hpp"
+#include "memory/binaryTreeDictionary.inline.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/padded.hpp"
#include "memory/resourceArea.hpp"
--- a/src/hotspot/share/memory/binaryTreeDictionary.cpp Fri Apr 06 03:53:28 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1429 +0,0 @@
-/*
- * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "gc/cms/allocationStats.hpp"
-#include "gc/shared/spaceDecorator.hpp"
-#include "logging/log.hpp"
-#include "logging/logStream.hpp"
-#include "memory/binaryTreeDictionary.hpp"
-#include "memory/freeList.hpp"
-#include "memory/metachunk.hpp"
-#include "memory/resourceArea.hpp"
-#include "runtime/globals.hpp"
-#include "utilities/macros.hpp"
-#include "utilities/ostream.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/cms/adaptiveFreeList.hpp"
-#include "gc/cms/freeChunk.hpp"
-#endif // INCLUDE_ALL_GCS
-
-////////////////////////////////////////////////////////////////////////////////
-// A binary tree based search structure for free blocks.
-// This is currently used in the Concurrent Mark&Sweep implementation.
-////////////////////////////////////////////////////////////////////////////////
-
-template <class Chunk_t, class FreeList_t>
-TreeChunk<Chunk_t, FreeList_t>* TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(Chunk_t* fc) {
- // Do some assertion checking here.
- return (TreeChunk<Chunk_t, FreeList_t>*) fc;
-}
-
-template <class Chunk_t, class FreeList_t>
-void TreeChunk<Chunk_t, FreeList_t>::verify_tree_chunk_list() const {
- TreeChunk<Chunk_t, FreeList_t>* nextTC = (TreeChunk<Chunk_t, FreeList_t>*)next();
- if (prev() != NULL) { // interior list node shouldn't have tree fields
- guarantee(embedded_list()->parent() == NULL && embedded_list()->left() == NULL &&
- embedded_list()->right() == NULL, "should be clear");
- }
- if (nextTC != NULL) {
- guarantee(as_TreeChunk(nextTC->prev()) == this, "broken chain");
- guarantee(nextTC->size() == size(), "wrong size");
- nextTC->verify_tree_chunk_list();
- }
-}
-
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>::TreeList() : _parent(NULL),
- _left(NULL), _right(NULL) {}
-
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>*
-TreeList<Chunk_t, FreeList_t>::as_TreeList(TreeChunk<Chunk_t,FreeList_t>* tc) {
- // This first free chunk in the list will be the tree list.
- assert((tc->size() >= (TreeChunk<Chunk_t, FreeList_t>::min_size())),
- "Chunk is too small for a TreeChunk");
- TreeList<Chunk_t, FreeList_t>* tl = tc->embedded_list();
- tl->initialize();
- tc->set_list(tl);
- tl->set_size(tc->size());
- tl->link_head(tc);
- tl->link_tail(tc);
- tl->set_count(1);
- assert(tl->parent() == NULL, "Should be clear");
- return tl;
-}
-
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>*
-TreeList<Chunk_t, FreeList_t>::as_TreeList(HeapWord* addr, size_t size) {
- TreeChunk<Chunk_t, FreeList_t>* tc = (TreeChunk<Chunk_t, FreeList_t>*) addr;
- assert((size >= TreeChunk<Chunk_t, FreeList_t>::min_size()),
- "Chunk is too small for a TreeChunk");
- // The space will have been mangled initially but
- // is not remangled when a Chunk_t is returned to the free list
- // (since it is used to maintain the chunk on the free list).
- tc->assert_is_mangled();
- tc->set_size(size);
- tc->link_prev(NULL);
- tc->link_next(NULL);
- TreeList<Chunk_t, FreeList_t>* tl = TreeList<Chunk_t, FreeList_t>::as_TreeList(tc);
- return tl;
-}
-
-
-#if INCLUDE_ALL_GCS
-// Specialize for AdaptiveFreeList which tries to avoid
-// splitting a chunk of a size that is under populated in favor of
-// an over populated size. The general get_better_list() just returns
-// the current list.
-template <>
-TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >*
-TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >::get_better_list(
- BinaryTreeDictionary<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* dictionary) {
- // A candidate chunk has been found. If it is already under
- // populated, get a chunk associated with the hint for this
- // chunk.
-
- TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* curTL = this;
- if (curTL->surplus() <= 0) {
- /* Use the hint to find a size with a surplus, and reset the hint. */
- TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* hintTL = this;
- while (hintTL->hint() != 0) {
- assert(hintTL->hint() > hintTL->size(),
- "hint points in the wrong direction");
- hintTL = dictionary->find_list(hintTL->hint());
- assert(curTL != hintTL, "Infinite loop");
- if (hintTL == NULL ||
- hintTL == curTL /* Should not happen but protect against it */ ) {
- // No useful hint. Set the hint to NULL and go on.
- curTL->set_hint(0);
- break;
- }
- assert(hintTL->size() > curTL->size(), "hint is inconsistent");
- if (hintTL->surplus() > 0) {
- // The hint led to a list that has a surplus. Use it.
- // Set the hint for the candidate to an overpopulated
- // size.
- curTL->set_hint(hintTL->size());
- // Change the candidate.
- curTL = hintTL;
- break;
- }
- }
- }
- return curTL;
-}
-#endif // INCLUDE_ALL_GCS
-
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>*
-TreeList<Chunk_t, FreeList_t>::get_better_list(
- BinaryTreeDictionary<Chunk_t, FreeList_t>* dictionary) {
- return this;
-}
-
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::remove_chunk_replace_if_needed(TreeChunk<Chunk_t, FreeList_t>* tc) {
-
- TreeList<Chunk_t, FreeList_t>* retTL = this;
- Chunk_t* list = head();
- assert(!list || list != list->next(), "Chunk on list twice");
- assert(tc != NULL, "Chunk being removed is NULL");
- assert(parent() == NULL || this == parent()->left() ||
- this == parent()->right(), "list is inconsistent");
- assert(tc->is_free(), "Header is not marked correctly");
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-
- Chunk_t* prevFC = tc->prev();
- TreeChunk<Chunk_t, FreeList_t>* nextTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(tc->next());
- assert(list != NULL, "should have at least the target chunk");
-
- // Is this the first item on the list?
- if (tc == list) {
- // The "getChunk..." functions for a TreeList<Chunk_t, FreeList_t> will not return the
- // first chunk in the list unless it is the last chunk in the list
- // because the first chunk is also acting as the tree node.
- // When coalescing happens, however, the first chunk in the a tree
- // list can be the start of a free range. Free ranges are removed
- // from the free lists so that they are not available to be
- // allocated when the sweeper yields (giving up the free list lock)
- // to allow mutator activity. If this chunk is the first in the
- // list and is not the last in the list, do the work to copy the
- // TreeList<Chunk_t, FreeList_t> from the first chunk to the next chunk and update all
- // the TreeList<Chunk_t, FreeList_t> pointers in the chunks in the list.
- if (nextTC == NULL) {
- assert(prevFC == NULL, "Not last chunk in the list");
- set_tail(NULL);
- set_head(NULL);
- } else {
- // copy embedded list.
- nextTC->set_embedded_list(tc->embedded_list());
- retTL = nextTC->embedded_list();
- // Fix the pointer to the list in each chunk in the list.
- // This can be slow for a long list. Consider having
- // an option that does not allow the first chunk on the
- // list to be coalesced.
- for (TreeChunk<Chunk_t, FreeList_t>* curTC = nextTC; curTC != NULL;
- curTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(curTC->next())) {
- curTC->set_list(retTL);
- }
- // Fix the parent to point to the new TreeList<Chunk_t, FreeList_t>.
- if (retTL->parent() != NULL) {
- if (this == retTL->parent()->left()) {
- retTL->parent()->set_left(retTL);
- } else {
- assert(this == retTL->parent()->right(), "Parent is incorrect");
- retTL->parent()->set_right(retTL);
- }
- }
- // Fix the children's parent pointers to point to the
- // new list.
- assert(right() == retTL->right(), "Should have been copied");
- if (retTL->right() != NULL) {
- retTL->right()->set_parent(retTL);
- }
- assert(left() == retTL->left(), "Should have been copied");
- if (retTL->left() != NULL) {
- retTL->left()->set_parent(retTL);
- }
- retTL->link_head(nextTC);
- assert(nextTC->is_free(), "Should be a free chunk");
- }
- } else {
- if (nextTC == NULL) {
- // Removing chunk at tail of list
- this->link_tail(prevFC);
- }
- // Chunk is interior to the list
- prevFC->link_after(nextTC);
- }
-
- // Below this point the embedded TreeList<Chunk_t, FreeList_t> being used for the
- // tree node may have changed. Don't use "this"
- // TreeList<Chunk_t, FreeList_t>*.
- // chunk should still be a free chunk (bit set in _prev)
- assert(!retTL->head() || retTL->size() == retTL->head()->size(),
- "Wrong sized chunk in list");
- debug_only(
- tc->link_prev(NULL);
- tc->link_next(NULL);
- tc->set_list(NULL);
- bool prev_found = false;
- bool next_found = false;
- for (Chunk_t* curFC = retTL->head();
- curFC != NULL; curFC = curFC->next()) {
- assert(curFC != tc, "Chunk is still in list");
- if (curFC == prevFC) {
- prev_found = true;
- }
- if (curFC == nextTC) {
- next_found = true;
- }
- }
- assert(prevFC == NULL || prev_found, "Chunk was lost from list");
- assert(nextTC == NULL || next_found, "Chunk was lost from list");
- assert(retTL->parent() == NULL ||
- retTL == retTL->parent()->left() ||
- retTL == retTL->parent()->right(),
- "list is inconsistent");
- )
- retTL->decrement_count();
-
- assert(tc->is_free(), "Should still be a free chunk");
- assert(retTL->head() == NULL || retTL->head()->prev() == NULL,
- "list invariant");
- assert(retTL->tail() == NULL || retTL->tail()->next() == NULL,
- "list invariant");
- return retTL;
-}
-
-template <class Chunk_t, class FreeList_t>
-void TreeList<Chunk_t, FreeList_t>::return_chunk_at_tail(TreeChunk<Chunk_t, FreeList_t>* chunk) {
- assert(chunk != NULL, "returning NULL chunk");
- assert(chunk->list() == this, "list should be set for chunk");
- assert(tail() != NULL, "The tree list is embedded in the first chunk");
- // which means that the list can never be empty.
- assert(!this->verify_chunk_in_free_list(chunk), "Double entry");
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-
- Chunk_t* fc = tail();
- fc->link_after(chunk);
- this->link_tail(chunk);
-
- assert(!tail() || size() == tail()->size(), "Wrong sized chunk in list");
- FreeList_t::increment_count();
- debug_only(this->increment_returned_bytes_by(chunk->size()*sizeof(HeapWord));)
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-}
-
-// Add this chunk at the head of the list. "At the head of the list"
-// is defined to be after the chunk pointer to by head(). This is
-// because the TreeList<Chunk_t, FreeList_t> is embedded in the first TreeChunk<Chunk_t, FreeList_t> in the
-// list. See the definition of TreeChunk<Chunk_t, FreeList_t>.
-template <class Chunk_t, class FreeList_t>
-void TreeList<Chunk_t, FreeList_t>::return_chunk_at_head(TreeChunk<Chunk_t, FreeList_t>* chunk) {
- assert(chunk->list() == this, "list should be set for chunk");
- assert(head() != NULL, "The tree list is embedded in the first chunk");
- assert(chunk != NULL, "returning NULL chunk");
- assert(!this->verify_chunk_in_free_list(chunk), "Double entry");
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-
- Chunk_t* fc = head()->next();
- if (fc != NULL) {
- chunk->link_after(fc);
- } else {
- assert(tail() == NULL, "List is inconsistent");
- this->link_tail(chunk);
- }
- head()->link_after(chunk);
- assert(!head() || size() == head()->size(), "Wrong sized chunk in list");
- FreeList_t::increment_count();
- debug_only(this->increment_returned_bytes_by(chunk->size()*sizeof(HeapWord));)
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-}
-
-template <class Chunk_t, class FreeList_t>
-void TreeChunk<Chunk_t, FreeList_t>::assert_is_mangled() const {
- assert((ZapUnusedHeapArea &&
- SpaceMangler::is_mangled((HeapWord*) Chunk_t::size_addr()) &&
- SpaceMangler::is_mangled((HeapWord*) Chunk_t::prev_addr()) &&
- SpaceMangler::is_mangled((HeapWord*) Chunk_t::next_addr())) ||
- (size() == 0 && prev() == NULL && next() == NULL),
- "Space should be clear or mangled");
-}
-
-template <class Chunk_t, class FreeList_t>
-TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::head_as_TreeChunk() {
- assert(head() == NULL || (TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(head())->list() == this),
- "Wrong type of chunk?");
- return TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(head());
-}
-
-template <class Chunk_t, class FreeList_t>
-TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::first_available() {
- assert(head() != NULL, "The head of the list cannot be NULL");
- Chunk_t* fc = head()->next();
- TreeChunk<Chunk_t, FreeList_t>* retTC;
- if (fc == NULL) {
- retTC = head_as_TreeChunk();
- } else {
- retTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(fc);
- }
- assert(retTC->list() == this, "Wrong type of chunk.");
- return retTC;
-}
-
-// Returns the block with the largest heap address amongst
-// those in the list for this size; potentially slow and expensive,
-// use with caution!
-template <class Chunk_t, class FreeList_t>
-TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::largest_address() {
- assert(head() != NULL, "The head of the list cannot be NULL");
- Chunk_t* fc = head()->next();
- TreeChunk<Chunk_t, FreeList_t>* retTC;
- if (fc == NULL) {
- retTC = head_as_TreeChunk();
- } else {
- // walk down the list and return the one with the highest
- // heap address among chunks of this size.
- Chunk_t* last = fc;
- while (fc->next() != NULL) {
- if ((HeapWord*)last < (HeapWord*)fc) {
- last = fc;
- }
- fc = fc->next();
- }
- retTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(last);
- }
- assert(retTC->list() == this, "Wrong type of chunk.");
- return retTC;
-}
-
-template <class Chunk_t, class FreeList_t>
-BinaryTreeDictionary<Chunk_t, FreeList_t>::BinaryTreeDictionary(MemRegion mr) {
- assert((mr.byte_size() > min_size()), "minimum chunk size");
-
- reset(mr);
- assert(root()->left() == NULL, "reset check failed");
- assert(root()->right() == NULL, "reset check failed");
- assert(root()->head()->next() == NULL, "reset check failed");
- assert(root()->head()->prev() == NULL, "reset check failed");
- assert(total_size() == root()->size(), "reset check failed");
- assert(total_free_blocks() == 1, "reset check failed");
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::inc_total_size(size_t inc) {
- _total_size = _total_size + inc;
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::dec_total_size(size_t dec) {
- _total_size = _total_size - dec;
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset(MemRegion mr) {
- assert((mr.byte_size() > min_size()), "minimum chunk size");
- set_root(TreeList<Chunk_t, FreeList_t>::as_TreeList(mr.start(), mr.word_size()));
- set_total_size(mr.word_size());
- set_total_free_blocks(1);
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset(HeapWord* addr, size_t byte_size) {
- MemRegion mr(addr, heap_word_size(byte_size));
- reset(mr);
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset() {
- set_root(NULL);
- set_total_size(0);
- set_total_free_blocks(0);
-}
-
-// Get a free block of size at least size from tree, or NULL.
-template <class Chunk_t, class FreeList_t>
-TreeChunk<Chunk_t, FreeList_t>*
-BinaryTreeDictionary<Chunk_t, FreeList_t>::get_chunk_from_tree(size_t size)
-{
- TreeList<Chunk_t, FreeList_t> *curTL, *prevTL;
- TreeChunk<Chunk_t, FreeList_t>* retTC = NULL;
-
- assert((size >= min_size()), "minimum chunk size");
- if (FLSVerifyDictionary) {
- verify_tree();
- }
- // starting at the root, work downwards trying to find match.
- // Remember the last node of size too great or too small.
- for (prevTL = curTL = root(); curTL != NULL;) {
- if (curTL->size() == size) { // exact match
- break;
- }
- prevTL = curTL;
- if (curTL->size() < size) { // proceed to right sub-tree
- curTL = curTL->right();
- } else { // proceed to left sub-tree
- assert(curTL->size() > size, "size inconsistency");
- curTL = curTL->left();
- }
- }
- if (curTL == NULL) { // couldn't find exact match
-
- // try and find the next larger size by walking back up the search path
- for (curTL = prevTL; curTL != NULL;) {
- if (curTL->size() >= size) break;
- else curTL = curTL->parent();
- }
- assert(curTL == NULL || curTL->count() > 0,
- "An empty list should not be in the tree");
- }
- if (curTL != NULL) {
- assert(curTL->size() >= size, "size inconsistency");
-
- curTL = curTL->get_better_list(this);
-
- retTC = curTL->first_available();
- assert((retTC != NULL) && (curTL->count() > 0),
- "A list in the binary tree should not be NULL");
- assert(retTC->size() >= size,
- "A chunk of the wrong size was found");
- remove_chunk_from_tree(retTC);
- assert(retTC->is_free(), "Header is not marked correctly");
- }
-
- if (FLSVerifyDictionary) {
- verify();
- }
- return retTC;
-}
-
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_list(size_t size) const {
- TreeList<Chunk_t, FreeList_t>* curTL;
- for (curTL = root(); curTL != NULL;) {
- if (curTL->size() == size) { // exact match
- break;
- }
-
- if (curTL->size() < size) { // proceed to right sub-tree
- curTL = curTL->right();
- } else { // proceed to left sub-tree
- assert(curTL->size() > size, "size inconsistency");
- curTL = curTL->left();
- }
- }
- return curTL;
-}
-
-
-template <class Chunk_t, class FreeList_t>
-bool BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_chunk_in_free_list(Chunk_t* tc) const {
- size_t size = tc->size();
- TreeList<Chunk_t, FreeList_t>* tl = find_list(size);
- if (tl == NULL) {
- return false;
- } else {
- return tl->verify_chunk_in_free_list(tc);
- }
-}
-
-template <class Chunk_t, class FreeList_t>
-Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_largest_dict() const {
- TreeList<Chunk_t, FreeList_t> *curTL = root();
- if (curTL != NULL) {
- while(curTL->right() != NULL) curTL = curTL->right();
- return curTL->largest_address();
- } else {
- return NULL;
- }
-}
-
-// Remove the current chunk from the tree. If it is not the last
-// chunk in a list on a tree node, just unlink it.
-// If it is the last chunk in the list (the next link is NULL),
-// remove the node and repair the tree.
-template <class Chunk_t, class FreeList_t>
-TreeChunk<Chunk_t, FreeList_t>*
-BinaryTreeDictionary<Chunk_t, FreeList_t>::remove_chunk_from_tree(TreeChunk<Chunk_t, FreeList_t>* tc) {
- assert(tc != NULL, "Should not call with a NULL chunk");
- assert(tc->is_free(), "Header is not marked correctly");
-
- TreeList<Chunk_t, FreeList_t> *newTL, *parentTL;
- TreeChunk<Chunk_t, FreeList_t>* retTC;
- TreeList<Chunk_t, FreeList_t>* tl = tc->list();
- debug_only(
- bool removing_only_chunk = false;
- if (tl == _root) {
- if ((_root->left() == NULL) && (_root->right() == NULL)) {
- if (_root->count() == 1) {
- assert(_root->head() == tc, "Should only be this one chunk");
- removing_only_chunk = true;
- }
- }
- }
- )
- assert(tl != NULL, "List should be set");
- assert(tl->parent() == NULL || tl == tl->parent()->left() ||
- tl == tl->parent()->right(), "list is inconsistent");
-
- bool complicated_splice = false;
-
- retTC = tc;
- // Removing this chunk can have the side effect of changing the node
- // (TreeList<Chunk_t, FreeList_t>*) in the tree. If the node is the root, update it.
- TreeList<Chunk_t, FreeList_t>* replacementTL = tl->remove_chunk_replace_if_needed(tc);
- assert(tc->is_free(), "Chunk should still be free");
- assert(replacementTL->parent() == NULL ||
- replacementTL == replacementTL->parent()->left() ||
- replacementTL == replacementTL->parent()->right(),
- "list is inconsistent");
- if (tl == root()) {
- assert(replacementTL->parent() == NULL, "Incorrectly replacing root");
- set_root(replacementTL);
- }
-#ifdef ASSERT
- if (tl != replacementTL) {
- assert(replacementTL->head() != NULL,
- "If the tree list was replaced, it should not be a NULL list");
- TreeList<Chunk_t, FreeList_t>* rhl = replacementTL->head_as_TreeChunk()->list();
- TreeList<Chunk_t, FreeList_t>* rtl =
- TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(replacementTL->tail())->list();
- assert(rhl == replacementTL, "Broken head");
- assert(rtl == replacementTL, "Broken tail");
- assert(replacementTL->size() == tc->size(), "Broken size");
- }
-#endif
-
- // Does the tree need to be repaired?
- if (replacementTL->count() == 0) {
- assert(replacementTL->head() == NULL &&
- replacementTL->tail() == NULL, "list count is incorrect");
- // Find the replacement node for the (soon to be empty) node being removed.
- // if we have a single (or no) child, splice child in our stead
- if (replacementTL->left() == NULL) {
- // left is NULL so pick right. right may also be NULL.
- newTL = replacementTL->right();
- debug_only(replacementTL->clear_right();)
- } else if (replacementTL->right() == NULL) {
- // right is NULL
- newTL = replacementTL->left();
- debug_only(replacementTL->clear_left();)
- } else { // we have both children, so, by patriarchal convention,
- // my replacement is least node in right sub-tree
- complicated_splice = true;
- newTL = remove_tree_minimum(replacementTL->right());
- assert(newTL != NULL && newTL->left() == NULL &&
- newTL->right() == NULL, "sub-tree minimum exists");
- }
- // newTL is the replacement for the (soon to be empty) node.
- // newTL may be NULL.
- // should verify; we just cleanly excised our replacement
- if (FLSVerifyDictionary) {
- verify_tree();
- }
- // first make newTL my parent's child
- if ((parentTL = replacementTL->parent()) == NULL) {
- // newTL should be root
- assert(tl == root(), "Incorrectly replacing root");
- set_root(newTL);
- if (newTL != NULL) {
- newTL->clear_parent();
- }
- } else if (parentTL->right() == replacementTL) {
- // replacementTL is a right child
- parentTL->set_right(newTL);
- } else { // replacementTL is a left child
- assert(parentTL->left() == replacementTL, "should be left child");
- parentTL->set_left(newTL);
- }
- debug_only(replacementTL->clear_parent();)
- if (complicated_splice) { // we need newTL to get replacementTL's
- // two children
- assert(newTL != NULL &&
- newTL->left() == NULL && newTL->right() == NULL,
- "newTL should not have encumbrances from the past");
- // we'd like to assert as below:
- // assert(replacementTL->left() != NULL && replacementTL->right() != NULL,
- // "else !complicated_splice");
- // ... however, the above assertion is too strong because we aren't
- // guaranteed that replacementTL->right() is still NULL.
- // Recall that we removed
- // the right sub-tree minimum from replacementTL.
- // That may well have been its right
- // child! So we'll just assert half of the above:
- assert(replacementTL->left() != NULL, "else !complicated_splice");
- newTL->set_left(replacementTL->left());
- newTL->set_right(replacementTL->right());
- debug_only(
- replacementTL->clear_right();
- replacementTL->clear_left();
- )
- }
- assert(replacementTL->right() == NULL &&
- replacementTL->left() == NULL &&
- replacementTL->parent() == NULL,
- "delete without encumbrances");
- }
-
- assert(total_size() >= retTC->size(), "Incorrect total size");
- dec_total_size(retTC->size()); // size book-keeping
- assert(total_free_blocks() > 0, "Incorrect total count");
- set_total_free_blocks(total_free_blocks() - 1);
-
- assert(retTC != NULL, "null chunk?");
- assert(retTC->prev() == NULL && retTC->next() == NULL,
- "should return without encumbrances");
- if (FLSVerifyDictionary) {
- verify_tree();
- }
- assert(!removing_only_chunk || _root == NULL, "root should be NULL");
- return TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(retTC);
-}
-
-// Remove the leftmost node (lm) in the tree and return it.
-// If lm has a right child, link it to the left node of
-// the parent of lm.
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::remove_tree_minimum(TreeList<Chunk_t, FreeList_t>* tl) {
- assert(tl != NULL && tl->parent() != NULL, "really need a proper sub-tree");
- // locate the subtree minimum by walking down left branches
- TreeList<Chunk_t, FreeList_t>* curTL = tl;
- for (; curTL->left() != NULL; curTL = curTL->left());
- // obviously curTL now has at most one child, a right child
- if (curTL != root()) { // Should this test just be removed?
- TreeList<Chunk_t, FreeList_t>* parentTL = curTL->parent();
- if (parentTL->left() == curTL) { // curTL is a left child
- parentTL->set_left(curTL->right());
- } else {
- // If the list tl has no left child, then curTL may be
- // the right child of parentTL.
- assert(parentTL->right() == curTL, "should be a right child");
- parentTL->set_right(curTL->right());
- }
- } else {
- // The only use of this method would not pass the root of the
- // tree (as indicated by the assertion above that the tree list
- // has a parent) but the specification does not explicitly exclude the
- // passing of the root so accommodate it.
- set_root(NULL);
- }
- debug_only(
- curTL->clear_parent(); // Test if this needs to be cleared
- curTL->clear_right(); // recall, above, left child is already null
- )
- // we just excised a (non-root) node, we should still verify all tree invariants
- if (FLSVerifyDictionary) {
- verify_tree();
- }
- return curTL;
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::insert_chunk_in_tree(Chunk_t* fc) {
- TreeList<Chunk_t, FreeList_t> *curTL, *prevTL;
- size_t size = fc->size();
-
- assert((size >= min_size()),
- SIZE_FORMAT " is too small to be a TreeChunk<Chunk_t, FreeList_t> " SIZE_FORMAT,
- size, min_size());
- if (FLSVerifyDictionary) {
- verify_tree();
- }
-
- fc->clear_next();
- fc->link_prev(NULL);
-
- // work down from the _root, looking for insertion point
- for (prevTL = curTL = root(); curTL != NULL;) {
- if (curTL->size() == size) // exact match
- break;
- prevTL = curTL;
- if (curTL->size() > size) { // follow left branch
- curTL = curTL->left();
- } else { // follow right branch
- assert(curTL->size() < size, "size inconsistency");
- curTL = curTL->right();
- }
- }
- TreeChunk<Chunk_t, FreeList_t>* tc = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(fc);
- // This chunk is being returned to the binary tree. Its embedded
- // TreeList<Chunk_t, FreeList_t> should be unused at this point.
- tc->initialize();
- if (curTL != NULL) { // exact match
- tc->set_list(curTL);
- curTL->return_chunk_at_tail(tc);
- } else { // need a new node in tree
- tc->clear_next();
- tc->link_prev(NULL);
- TreeList<Chunk_t, FreeList_t>* newTL = TreeList<Chunk_t, FreeList_t>::as_TreeList(tc);
- assert(((TreeChunk<Chunk_t, FreeList_t>*)tc)->list() == newTL,
- "List was not initialized correctly");
- if (prevTL == NULL) { // we are the only tree node
- assert(root() == NULL, "control point invariant");
- set_root(newTL);
- } else { // insert under prevTL ...
- if (prevTL->size() < size) { // am right child
- assert(prevTL->right() == NULL, "control point invariant");
- prevTL->set_right(newTL);
- } else { // am left child
- assert(prevTL->size() > size && prevTL->left() == NULL, "cpt pt inv");
- prevTL->set_left(newTL);
- }
- }
- }
- assert(tc->list() != NULL, "Tree list should be set");
-
- inc_total_size(size);
- // Method 'total_size_in_tree' walks through the every block in the
- // tree, so it can cause significant performance loss if there are
- // many blocks in the tree
- assert(!FLSVerifyDictionary || total_size_in_tree(root()) == total_size(), "_total_size inconsistency");
- set_total_free_blocks(total_free_blocks() + 1);
- if (FLSVerifyDictionary) {
- verify_tree();
- }
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::max_chunk_size() const {
- verify_par_locked();
- TreeList<Chunk_t, FreeList_t>* tc = root();
- if (tc == NULL) return 0;
- for (; tc->right() != NULL; tc = tc->right());
- return tc->size();
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_list_length(TreeList<Chunk_t, FreeList_t>* tl) const {
- size_t res;
- res = tl->count();
-#ifdef ASSERT
- size_t cnt;
- Chunk_t* tc = tl->head();
- for (cnt = 0; tc != NULL; tc = tc->next(), cnt++);
- assert(res == cnt, "The count is not being maintained correctly");
-#endif
- return res;
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_size_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
- if (tl == NULL)
- return 0;
- return (tl->size() * total_list_length(tl)) +
- total_size_in_tree(tl->left()) +
- total_size_in_tree(tl->right());
-}
-
-template <class Chunk_t, class FreeList_t>
-double BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_of_squared_block_sizes(TreeList<Chunk_t, FreeList_t>* const tl) const {
- if (tl == NULL) {
- return 0.0;
- }
- double size = (double)(tl->size());
- double curr = size * size * total_list_length(tl);
- curr += sum_of_squared_block_sizes(tl->left());
- curr += sum_of_squared_block_sizes(tl->right());
- return curr;
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_free_blocks_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
- if (tl == NULL)
- return 0;
- return total_list_length(tl) +
- total_free_blocks_in_tree(tl->left()) +
- total_free_blocks_in_tree(tl->right());
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::num_free_blocks() const {
- assert(total_free_blocks_in_tree(root()) == total_free_blocks(),
- "_total_free_blocks inconsistency");
- return total_free_blocks();
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::tree_height_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
- if (tl == NULL)
- return 0;
- return 1 + MAX2(tree_height_helper(tl->left()),
- tree_height_helper(tl->right()));
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::tree_height() const {
- return tree_height_helper(root());
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
- if (tl == NULL) {
- return 0;
- }
- return 1 + total_nodes_helper(tl->left()) +
- total_nodes_helper(tl->right());
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
- return total_nodes_helper(root());
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::dict_census_update(size_t size, bool split, bool birth){}
-
-#if INCLUDE_ALL_GCS
-template <>
-void AFLBinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth) {
- TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* nd = find_list(size);
- if (nd) {
- if (split) {
- if (birth) {
- nd->increment_split_births();
- nd->increment_surplus();
- } else {
- nd->increment_split_deaths();
- nd->decrement_surplus();
- }
- } else {
- if (birth) {
- nd->increment_coal_births();
- nd->increment_surplus();
- } else {
- nd->increment_coal_deaths();
- nd->decrement_surplus();
- }
- }
- }
- // A list for this size may not be found (nd == 0) if
- // This is a death where the appropriate list is now
- // empty and has been removed from the list.
- // This is a birth associated with a LinAB. The chunk
- // for the LinAB is not in the dictionary.
-}
-#endif // INCLUDE_ALL_GCS
-
-template <class Chunk_t, class FreeList_t>
-bool BinaryTreeDictionary<Chunk_t, FreeList_t>::coal_dict_over_populated(size_t size) {
- // For the general type of freelists, encourage coalescing by
- // returning true.
- return true;
-}
-
-#if INCLUDE_ALL_GCS
-template <>
-bool AFLBinaryTreeDictionary::coal_dict_over_populated(size_t size) {
- if (FLSAlwaysCoalesceLarge) return true;
-
- TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* list_of_size = find_list(size);
- // None of requested size implies overpopulated.
- return list_of_size == NULL || list_of_size->coal_desired() <= 0 ||
- list_of_size->count() > list_of_size->coal_desired();
-}
-#endif // INCLUDE_ALL_GCS
-
-// Closures for walking the binary tree.
-// do_list() walks the free list in a node applying the closure
-// to each free chunk in the list
-// do_tree() walks the nodes in the binary tree applying do_list()
-// to each list at each node.
-
-template <class Chunk_t, class FreeList_t>
-class TreeCensusClosure : public StackObj {
- protected:
- virtual void do_list(FreeList_t* fl) = 0;
- public:
- virtual void do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
-};
-
-template <class Chunk_t, class FreeList_t>
-class AscendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
- public:
- void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
- if (tl != NULL) {
- do_tree(tl->left());
- this->do_list(tl);
- do_tree(tl->right());
- }
- }
-};
-
-template <class Chunk_t, class FreeList_t>
-class DescendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
- public:
- void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
- if (tl != NULL) {
- do_tree(tl->right());
- this->do_list(tl);
- do_tree(tl->left());
- }
- }
-};
-
-// For each list in the tree, calculate the desired, desired
-// coalesce, count before sweep, and surplus before sweep.
-template <class Chunk_t, class FreeList_t>
-class BeginSweepClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- double _percentage;
- float _inter_sweep_current;
- float _inter_sweep_estimate;
- float _intra_sweep_estimate;
-
- public:
- BeginSweepClosure(double p, float inter_sweep_current,
- float inter_sweep_estimate,
- float intra_sweep_estimate) :
- _percentage(p),
- _inter_sweep_current(inter_sweep_current),
- _inter_sweep_estimate(inter_sweep_estimate),
- _intra_sweep_estimate(intra_sweep_estimate) { }
-
- void do_list(FreeList<Chunk_t>* fl) {}
-
-#if INCLUDE_ALL_GCS
- void do_list(AdaptiveFreeList<Chunk_t>* fl) {
- double coalSurplusPercent = _percentage;
- fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate);
- fl->set_coal_desired((ssize_t)((double)fl->desired() * coalSurplusPercent));
- fl->set_before_sweep(fl->count());
- fl->set_bfr_surp(fl->surplus());
- }
-#endif // INCLUDE_ALL_GCS
-};
-
-// Used to search the tree until a condition is met.
-// Similar to TreeCensusClosure but searches the
-// tree and returns promptly when found.
-
-template <class Chunk_t, class FreeList_t>
-class TreeSearchClosure : public StackObj {
- protected:
- virtual bool do_list(FreeList_t* fl) = 0;
- public:
- virtual bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
-};
-
-#if 0 // Don't need this yet but here for symmetry.
-template <class Chunk_t, class FreeList_t>
-class AscendTreeSearchClosure : public TreeSearchClosure<Chunk_t> {
- public:
- bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
- if (tl != NULL) {
- if (do_tree(tl->left())) return true;
- if (do_list(tl)) return true;
- if (do_tree(tl->right())) return true;
- }
- return false;
- }
-};
-#endif
-
-template <class Chunk_t, class FreeList_t>
-class DescendTreeSearchClosure : public TreeSearchClosure<Chunk_t, FreeList_t> {
- public:
- bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
- if (tl != NULL) {
- if (do_tree(tl->right())) return true;
- if (this->do_list(tl)) return true;
- if (do_tree(tl->left())) return true;
- }
- return false;
- }
-};
-
-// Searches the tree for a chunk that ends at the
-// specified address.
-template <class Chunk_t, class FreeList_t>
-class EndTreeSearchClosure : public DescendTreeSearchClosure<Chunk_t, FreeList_t> {
- HeapWord* _target;
- Chunk_t* _found;
-
- public:
- EndTreeSearchClosure(HeapWord* target) : _target(target), _found(NULL) {}
- bool do_list(FreeList_t* fl) {
- Chunk_t* item = fl->head();
- while (item != NULL) {
- if (item->end() == (uintptr_t*) _target) {
- _found = item;
- return true;
- }
- item = item->next();
- }
- return false;
- }
- Chunk_t* found() { return _found; }
-};
-
-template <class Chunk_t, class FreeList_t>
-Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_chunk_ends_at(HeapWord* target) const {
- EndTreeSearchClosure<Chunk_t, FreeList_t> etsc(target);
- bool found_target = etsc.do_tree(root());
- assert(found_target || etsc.found() == NULL, "Consistency check");
- assert(!found_target || etsc.found() != NULL, "Consistency check");
- return etsc.found();
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::begin_sweep_dict_census(double coalSurplusPercent,
- float inter_sweep_current, float inter_sweep_estimate, float intra_sweep_estimate) {
- BeginSweepClosure<Chunk_t, FreeList_t> bsc(coalSurplusPercent, inter_sweep_current,
- inter_sweep_estimate,
- intra_sweep_estimate);
- bsc.do_tree(root());
-}
-
-// Closures and methods for calculating total bytes returned to the
-// free lists in the tree.
-#ifndef PRODUCT
-template <class Chunk_t, class FreeList_t>
-class InitializeDictReturnedBytesClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- public:
- void do_list(FreeList_t* fl) {
- fl->set_returned_bytes(0);
- }
-};
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::initialize_dict_returned_bytes() {
- InitializeDictReturnedBytesClosure<Chunk_t, FreeList_t> idrb;
- idrb.do_tree(root());
-}
-
-template <class Chunk_t, class FreeList_t>
-class ReturnedBytesClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- size_t _dict_returned_bytes;
- public:
- ReturnedBytesClosure() { _dict_returned_bytes = 0; }
- void do_list(FreeList_t* fl) {
- _dict_returned_bytes += fl->returned_bytes();
- }
- size_t dict_returned_bytes() { return _dict_returned_bytes; }
-};
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_dict_returned_bytes() {
- ReturnedBytesClosure<Chunk_t, FreeList_t> rbc;
- rbc.do_tree(root());
-
- return rbc.dict_returned_bytes();
-}
-
-// Count the number of entries in the tree.
-template <class Chunk_t, class FreeList_t>
-class treeCountClosure : public DescendTreeCensusClosure<Chunk_t, FreeList_t> {
- public:
- uint count;
- treeCountClosure(uint c) { count = c; }
- void do_list(FreeList_t* fl) {
- count++;
- }
-};
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_count() {
- treeCountClosure<Chunk_t, FreeList_t> ctc(0);
- ctc.do_tree(root());
- return ctc.count;
-}
-
-template <class Chunk_t, class FreeList_t>
-Mutex* BinaryTreeDictionary<Chunk_t, FreeList_t>::par_lock() const {
- return _lock;
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_par_lock(Mutex* lock) {
- _lock = lock;
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_par_locked() const {
-#ifdef ASSERT
- Thread* my_thread = Thread::current();
- if (my_thread->is_GC_task_thread()) {
- assert(par_lock() != NULL, "Should be using locking?");
- assert_lock_strong(par_lock());
- }
-#endif // ASSERT
-}
-#endif // PRODUCT
-
-// Calculate surpluses for the lists in the tree.
-template <class Chunk_t, class FreeList_t>
-class setTreeSurplusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- double percentage;
- public:
- setTreeSurplusClosure(double v) { percentage = v; }
- void do_list(FreeList<Chunk_t>* fl) {}
-
-#if INCLUDE_ALL_GCS
- void do_list(AdaptiveFreeList<Chunk_t>* fl) {
- double splitSurplusPercent = percentage;
- fl->set_surplus(fl->count() -
- (ssize_t)((double)fl->desired() * splitSurplusPercent));
- }
-#endif // INCLUDE_ALL_GCS
-};
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_tree_surplus(double splitSurplusPercent) {
- setTreeSurplusClosure<Chunk_t, FreeList_t> sts(splitSurplusPercent);
- sts.do_tree(root());
-}
-
-// Set hints for the lists in the tree.
-template <class Chunk_t, class FreeList_t>
-class setTreeHintsClosure : public DescendTreeCensusClosure<Chunk_t, FreeList_t> {
- size_t hint;
- public:
- setTreeHintsClosure(size_t v) { hint = v; }
- void do_list(FreeList<Chunk_t>* fl) {}
-
-#if INCLUDE_ALL_GCS
- void do_list(AdaptiveFreeList<Chunk_t>* fl) {
- fl->set_hint(hint);
- assert(fl->hint() == 0 || fl->hint() > fl->size(),
- "Current hint is inconsistent");
- if (fl->surplus() > 0) {
- hint = fl->size();
- }
- }
-#endif // INCLUDE_ALL_GCS
-};
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_tree_hints(void) {
- setTreeHintsClosure<Chunk_t, FreeList_t> sth(0);
- sth.do_tree(root());
-}
-
-// Save count before previous sweep and splits and coalesces.
-template <class Chunk_t, class FreeList_t>
-class clearTreeCensusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- void do_list(FreeList<Chunk_t>* fl) {}
-
-#if INCLUDE_ALL_GCS
- void do_list(AdaptiveFreeList<Chunk_t>* fl) {
- fl->set_prev_sweep(fl->count());
- fl->set_coal_births(0);
- fl->set_coal_deaths(0);
- fl->set_split_births(0);
- fl->set_split_deaths(0);
- }
-#endif // INCLUDE_ALL_GCS
-};
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::clear_tree_census(void) {
- clearTreeCensusClosure<Chunk_t, FreeList_t> ctc;
- ctc.do_tree(root());
-}
-
-// Do reporting and post sweep clean up.
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::end_sweep_dict_census(double splitSurplusPercent) {
- // Does walking the tree 3 times hurt?
- set_tree_surplus(splitSurplusPercent);
- set_tree_hints();
- LogTarget(Trace, gc, freelist, stats) log;
- if (log.is_enabled()) {
- LogStream out(log);
- report_statistics(&out);
- }
- clear_tree_census();
-}
-
-// Print summary statistics
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::report_statistics(outputStream* st) const {
- verify_par_locked();
- st->print_cr("Statistics for BinaryTreeDictionary:");
- st->print_cr("------------------------------------");
- size_t total_size = total_chunk_size(debug_only(NULL));
- size_t free_blocks = num_free_blocks();
- st->print_cr("Total Free Space: " SIZE_FORMAT, total_size);
- st->print_cr("Max Chunk Size: " SIZE_FORMAT, max_chunk_size());
- st->print_cr("Number of Blocks: " SIZE_FORMAT, free_blocks);
- if (free_blocks > 0) {
- st->print_cr("Av. Block Size: " SIZE_FORMAT, total_size/free_blocks);
- }
- st->print_cr("Tree Height: " SIZE_FORMAT, tree_height());
-}
-
-// Print census information - counts, births, deaths, etc.
-// for each list in the tree. Also print some summary
-// information.
-template <class Chunk_t, class FreeList_t>
-class PrintTreeCensusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- int _print_line;
- size_t _total_free;
- FreeList_t _total;
-
- public:
- PrintTreeCensusClosure() {
- _print_line = 0;
- _total_free = 0;
- }
- FreeList_t* total() { return &_total; }
- size_t total_free() { return _total_free; }
- void do_list(FreeList<Chunk_t>* fl) {
- LogStreamHandle(Debug, gc, freelist, census) out;
-
- if (++_print_line >= 40) {
- FreeList_t::print_labels_on(&out, "size");
- _print_line = 0;
- }
- fl->print_on(&out);
- _total_free += fl->count() * fl->size();
- total()->set_count(total()->count() + fl->count());
- }
-
-#if INCLUDE_ALL_GCS
- void do_list(AdaptiveFreeList<Chunk_t>* fl) {
- LogStreamHandle(Debug, gc, freelist, census) out;
-
- if (++_print_line >= 40) {
- FreeList_t::print_labels_on(&out, "size");
- _print_line = 0;
- }
- fl->print_on(&out);
- _total_free += fl->count() * fl->size() ;
- total()->set_count( total()->count() + fl->count() );
- total()->set_bfr_surp( total()->bfr_surp() + fl->bfr_surp() );
- total()->set_surplus( total()->split_deaths() + fl->surplus() );
- total()->set_desired( total()->desired() + fl->desired() );
- total()->set_prev_sweep( total()->prev_sweep() + fl->prev_sweep() );
- total()->set_before_sweep(total()->before_sweep() + fl->before_sweep());
- total()->set_coal_births( total()->coal_births() + fl->coal_births() );
- total()->set_coal_deaths( total()->coal_deaths() + fl->coal_deaths() );
- total()->set_split_births(total()->split_births() + fl->split_births());
- total()->set_split_deaths(total()->split_deaths() + fl->split_deaths());
- }
-#endif // INCLUDE_ALL_GCS
-};
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::print_dict_census(outputStream* st) const {
-
- st->print("BinaryTree");
- FreeList_t::print_labels_on(st, "size");
- PrintTreeCensusClosure<Chunk_t, FreeList_t> ptc;
- ptc.do_tree(root());
-
- FreeList_t* total = ptc.total();
- FreeList_t::print_labels_on(st, " ");
-}
-
-#if INCLUDE_ALL_GCS
-template <>
-void AFLBinaryTreeDictionary::print_dict_census(outputStream* st) const {
-
- st->print_cr("BinaryTree");
- AdaptiveFreeList<FreeChunk>::print_labels_on(st, "size");
- PrintTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > ptc;
- ptc.do_tree(root());
-
- AdaptiveFreeList<FreeChunk>* total = ptc.total();
- AdaptiveFreeList<FreeChunk>::print_labels_on(st, " ");
- total->print_on(st, "TOTAL\t");
- st->print_cr("total_free(words): " SIZE_FORMAT_W(16) " growth: %8.5f deficit: %8.5f",
- ptc.total_free(),
- (double)(total->split_births() + total->coal_births()
- - total->split_deaths() - total->coal_deaths())
- /(total->prev_sweep() != 0 ? (double)total->prev_sweep() : 1.0),
- (double)(total->desired() - total->count())
- /(total->desired() != 0 ? (double)total->desired() : 1.0));
-}
-#endif // INCLUDE_ALL_GCS
-
-template <class Chunk_t, class FreeList_t>
-class PrintFreeListsClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- outputStream* _st;
- int _print_line;
-
- public:
- PrintFreeListsClosure(outputStream* st) {
- _st = st;
- _print_line = 0;
- }
- void do_list(FreeList_t* fl) {
- if (++_print_line >= 40) {
- FreeList_t::print_labels_on(_st, "size");
- _print_line = 0;
- }
- fl->print_on(_st);
- size_t sz = fl->size();
- for (Chunk_t* fc = fl->head(); fc != NULL;
- fc = fc->next()) {
- _st->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s",
- p2i(fc), p2i((HeapWord*)fc + sz),
- fc->cantCoalesce() ? "\t CC" : "");
- }
- }
-};
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::print_free_lists(outputStream* st) const {
-
- FreeList_t::print_labels_on(st, "size");
- PrintFreeListsClosure<Chunk_t, FreeList_t> pflc(st);
- pflc.do_tree(root());
-}
-
-// Verify the following tree invariants:
-// . _root has no parent
-// . parent and child point to each other
-// . each node's key correctly related to that of its child(ren)
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree() const {
- guarantee(root() == NULL || total_free_blocks() == 0 ||
- total_size() != 0, "_total_size shouldn't be 0?");
- guarantee(root() == NULL || root()->parent() == NULL, "_root shouldn't have parent");
- verify_tree_helper(root());
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_prev_free_ptrs(TreeList<Chunk_t, FreeList_t>* tl) {
- size_t ct = 0;
- for (Chunk_t* curFC = tl->head(); curFC != NULL; curFC = curFC->next()) {
- ct++;
- assert(curFC->prev() == NULL || curFC->prev()->is_free(),
- "Chunk should be free");
- }
- return ct;
-}
-
-// Note: this helper is recursive rather than iterative, so use with
-// caution on very deep trees; and watch out for stack overflow errors;
-// In general, to be used only for debugging.
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
- if (tl == NULL)
- return;
- guarantee(tl->size() != 0, "A list must has a size");
- guarantee(tl->left() == NULL || tl->left()->parent() == tl,
- "parent<-/->left");
- guarantee(tl->right() == NULL || tl->right()->parent() == tl,
- "parent<-/->right");;
- guarantee(tl->left() == NULL || tl->left()->size() < tl->size(),
- "parent !> left");
- guarantee(tl->right() == NULL || tl->right()->size() > tl->size(),
- "parent !< left");
- guarantee(tl->head() == NULL || tl->head()->is_free(), "!Free");
- guarantee(tl->head() == NULL || tl->head_as_TreeChunk()->list() == tl,
- "list inconsistency");
- guarantee(tl->count() > 0 || (tl->head() == NULL && tl->tail() == NULL),
- "list count is inconsistent");
- guarantee(tl->count() > 1 || tl->head() == tl->tail(),
- "list is incorrectly constructed");
- size_t count = verify_prev_free_ptrs(tl);
- guarantee(count == (size_t)tl->count(), "Node count is incorrect");
- if (tl->head() != NULL) {
- tl->head_as_TreeChunk()->verify_tree_chunk_list();
- }
- verify_tree_helper(tl->left());
- verify_tree_helper(tl->right());
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify() const {
- verify_tree();
- guarantee(total_size() == total_size_in_tree(root()), "Total Size inconsistency");
-}
-
-template class TreeList<Metablock, FreeList<Metablock> >;
-template class BinaryTreeDictionary<Metablock, FreeList<Metablock> >;
-template class TreeChunk<Metablock, FreeList<Metablock> >;
-
-template class TreeList<Metachunk, FreeList<Metachunk> >;
-template class BinaryTreeDictionary<Metachunk, FreeList<Metachunk> >;
-template class TreeChunk<Metachunk, FreeList<Metachunk> >;
-
-
-#if INCLUDE_ALL_GCS
-// Explicitly instantiate these types for FreeChunk.
-template class TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >;
-template class BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> >;
-template class TreeChunk<FreeChunk, AdaptiveFreeList<FreeChunk> >;
-
-#endif // INCLUDE_ALL_GCS
--- a/src/hotspot/share/memory/binaryTreeDictionary.hpp Fri Apr 06 03:53:28 2018 +0200
+++ b/src/hotspot/share/memory/binaryTreeDictionary.hpp Fri Apr 06 11:37:26 2018 +0200
@@ -42,10 +42,6 @@
template <class Chunk_t, class FreeList_t> class DescendTreeCensusClosure;
template <class Chunk_t, class FreeList_t> class DescendTreeSearchClosure;
-class FreeChunk;
-template <class> class AdaptiveFreeList;
-typedef BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> > AFLBinaryTreeDictionary;
-
template <class Chunk_t, class FreeList_t>
class TreeList : public FreeList_t {
friend class TreeChunk<Chunk_t, FreeList_t>;
@@ -177,6 +173,8 @@
template <class Chunk_t, class FreeList_t>
class BinaryTreeDictionary: public CHeapObj<mtGC> {
friend class VMStructs;
+
+ protected:
size_t _total_size;
size_t _total_free_blocks;
TreeList<Chunk_t, FreeList_t>* _root;
@@ -298,32 +296,9 @@
Chunk_t* find_chunk_ends_at(HeapWord* target) const;
- // Find the list with size "size" in the binary tree and update
- // the statistics in the list according to "split" (chunk was
- // split or coalesce) and "birth" (chunk was added or removed).
- void dict_census_update(size_t size, bool split, bool birth);
- // Return true if the dictionary is overpopulated (more chunks of
- // this size than desired) for size "size".
- bool coal_dict_over_populated(size_t size);
- // Methods called at the beginning of a sweep to prepare the
- // statistics for the sweep.
- void begin_sweep_dict_census(double coalSurplusPercent,
- float inter_sweep_current,
- float inter_sweep_estimate,
- float intra_sweep_estimate);
- // Methods called after the end of a sweep to modify the
- // statistics for the sweep.
- void end_sweep_dict_census(double splitSurplusPercent);
// Return the largest free chunk in the tree.
Chunk_t* find_largest_dict() const;
- // Accessors for statistics
- void set_tree_surplus(double splitSurplusPercent);
- void set_tree_hints(void);
- // Reset statistics for all the lists in the tree.
- void clear_tree_census(void);
- // Print the statistics for all the lists in the tree. Also may
- // print out summaries.
- void print_dict_census(outputStream* st) const;
+
void print_free_lists(outputStream* st) const;
// For debugging. Returns the sum of the _returned_bytes for
@@ -343,4 +318,83 @@
void verify_par_locked() const PRODUCT_RETURN;
};
+
+// Closures for walking the binary tree.
+// do_list() walks the free list in a node applying the closure
+// to each free chunk in the list
+// do_tree() walks the nodes in the binary tree applying do_list()
+// to each list at each node.
+
+template <class Chunk_t, class FreeList_t>
+class TreeCensusClosure : public StackObj {
+ protected:
+ virtual void do_list(FreeList_t* fl) = 0;
+ public:
+ virtual void do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
+};
+
+template <class Chunk_t, class FreeList_t>
+class AscendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
+ public:
+ void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
+ if (tl != NULL) {
+ do_tree(tl->left());
+ this->do_list(tl);
+ do_tree(tl->right());
+ }
+ }
+};
+
+template <class Chunk_t, class FreeList_t>
+class DescendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
+ public:
+ void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
+ if (tl != NULL) {
+ do_tree(tl->right());
+ this->do_list(tl);
+ do_tree(tl->left());
+ }
+ }
+};
+
+// Used to search the tree until a condition is met.
+// Similar to TreeCensusClosure but searches the
+// tree and returns promptly when found.
+
+template <class Chunk_t, class FreeList_t>
+class TreeSearchClosure : public StackObj {
+ protected:
+ virtual bool do_list(FreeList_t* fl) = 0;
+ public:
+ virtual bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
+};
+
+#if 0 // Don't need this yet but here for symmetry.
+template <class Chunk_t, class FreeList_t>
+class AscendTreeSearchClosure : public TreeSearchClosure<Chunk_t> {
+ public:
+ bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
+ if (tl != NULL) {
+ if (do_tree(tl->left())) return true;
+ if (do_list(tl)) return true;
+ if (do_tree(tl->right())) return true;
+ }
+ return false;
+ }
+};
+#endif
+
+template <class Chunk_t, class FreeList_t>
+class DescendTreeSearchClosure : public TreeSearchClosure<Chunk_t, FreeList_t> {
+ public:
+ bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
+ if (tl != NULL) {
+ if (do_tree(tl->right())) return true;
+ if (this->do_list(tl)) return true;
+ if (do_tree(tl->left())) return true;
+ }
+ return false;
+ }
+};
+
#endif // SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/memory/binaryTreeDictionary.inline.hpp Fri Apr 06 11:37:26 2018 +0200
@@ -0,0 +1,1025 @@
+/*
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_MEMORY_BINARYTREEDICTIONARY_INLINE_HPP
+#define SHARE_VM_MEMORY_BINARYTREEDICTIONARY_INLINE_HPP
+
+#include "gc/shared/spaceDecorator.hpp"
+#include "logging/log.hpp"
+#include "logging/logStream.hpp"
+#include "memory/binaryTreeDictionary.hpp"
+#include "memory/freeList.inline.hpp"
+#include "memory/metachunk.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/globals.hpp"
+#include "utilities/macros.hpp"
+#include "utilities/ostream.hpp"
+
+////////////////////////////////////////////////////////////////////////////////
+// A binary tree based search structure for free blocks.
+// This is currently used in the Concurrent Mark&Sweep implementation.
+////////////////////////////////////////////////////////////////////////////////
+
+template <class Chunk_t, class FreeList_t>
+TreeChunk<Chunk_t, FreeList_t>* TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(Chunk_t* fc) {
+ // Do some assertion checking here.
+ return (TreeChunk<Chunk_t, FreeList_t>*) fc;
+}
+
+template <class Chunk_t, class FreeList_t>
+void TreeChunk<Chunk_t, FreeList_t>::verify_tree_chunk_list() const {
+ TreeChunk<Chunk_t, FreeList_t>* nextTC = (TreeChunk<Chunk_t, FreeList_t>*)next();
+ if (prev() != NULL) { // interior list node shouldn't have tree fields
+ guarantee(embedded_list()->parent() == NULL && embedded_list()->left() == NULL &&
+ embedded_list()->right() == NULL, "should be clear");
+ }
+ if (nextTC != NULL) {
+ guarantee(as_TreeChunk(nextTC->prev()) == this, "broken chain");
+ guarantee(nextTC->size() == size(), "wrong size");
+ nextTC->verify_tree_chunk_list();
+ }
+}
+
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>::TreeList() : _parent(NULL),
+ _left(NULL), _right(NULL) {}
+
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>*
+TreeList<Chunk_t, FreeList_t>::as_TreeList(TreeChunk<Chunk_t,FreeList_t>* tc) {
+ // This first free chunk in the list will be the tree list.
+ assert((tc->size() >= (TreeChunk<Chunk_t, FreeList_t>::min_size())),
+ "Chunk is too small for a TreeChunk");
+ TreeList<Chunk_t, FreeList_t>* tl = tc->embedded_list();
+ tl->initialize();
+ tc->set_list(tl);
+ tl->set_size(tc->size());
+ tl->link_head(tc);
+ tl->link_tail(tc);
+ tl->set_count(1);
+ assert(tl->parent() == NULL, "Should be clear");
+ return tl;
+}
+
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>*
+TreeList<Chunk_t, FreeList_t>::as_TreeList(HeapWord* addr, size_t size) {
+ TreeChunk<Chunk_t, FreeList_t>* tc = (TreeChunk<Chunk_t, FreeList_t>*) addr;
+ assert((size >= TreeChunk<Chunk_t, FreeList_t>::min_size()),
+ "Chunk is too small for a TreeChunk");
+ // The space will have been mangled initially but
+ // is not remangled when a Chunk_t is returned to the free list
+ // (since it is used to maintain the chunk on the free list).
+ tc->assert_is_mangled();
+ tc->set_size(size);
+ tc->link_prev(NULL);
+ tc->link_next(NULL);
+ TreeList<Chunk_t, FreeList_t>* tl = TreeList<Chunk_t, FreeList_t>::as_TreeList(tc);
+ return tl;
+}
+
+
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>*
+TreeList<Chunk_t, FreeList_t>::get_better_list(
+ BinaryTreeDictionary<Chunk_t, FreeList_t>* dictionary) {
+ return this;
+}
+
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::remove_chunk_replace_if_needed(TreeChunk<Chunk_t, FreeList_t>* tc) {
+
+ TreeList<Chunk_t, FreeList_t>* retTL = this;
+ Chunk_t* list = head();
+ assert(!list || list != list->next(), "Chunk on list twice");
+ assert(tc != NULL, "Chunk being removed is NULL");
+ assert(parent() == NULL || this == parent()->left() ||
+ this == parent()->right(), "list is inconsistent");
+ assert(tc->is_free(), "Header is not marked correctly");
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+
+ Chunk_t* prevFC = tc->prev();
+ TreeChunk<Chunk_t, FreeList_t>* nextTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(tc->next());
+ assert(list != NULL, "should have at least the target chunk");
+
+ // Is this the first item on the list?
+ if (tc == list) {
+ // The "getChunk..." functions for a TreeList<Chunk_t, FreeList_t> will not return the
+ // first chunk in the list unless it is the last chunk in the list
+ // because the first chunk is also acting as the tree node.
+ // When coalescing happens, however, the first chunk in the a tree
+ // list can be the start of a free range. Free ranges are removed
+ // from the free lists so that they are not available to be
+ // allocated when the sweeper yields (giving up the free list lock)
+ // to allow mutator activity. If this chunk is the first in the
+ // list and is not the last in the list, do the work to copy the
+ // TreeList<Chunk_t, FreeList_t> from the first chunk to the next chunk and update all
+ // the TreeList<Chunk_t, FreeList_t> pointers in the chunks in the list.
+ if (nextTC == NULL) {
+ assert(prevFC == NULL, "Not last chunk in the list");
+ set_tail(NULL);
+ set_head(NULL);
+ } else {
+ // copy embedded list.
+ nextTC->set_embedded_list(tc->embedded_list());
+ retTL = nextTC->embedded_list();
+ // Fix the pointer to the list in each chunk in the list.
+ // This can be slow for a long list. Consider having
+ // an option that does not allow the first chunk on the
+ // list to be coalesced.
+ for (TreeChunk<Chunk_t, FreeList_t>* curTC = nextTC; curTC != NULL;
+ curTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(curTC->next())) {
+ curTC->set_list(retTL);
+ }
+ // Fix the parent to point to the new TreeList<Chunk_t, FreeList_t>.
+ if (retTL->parent() != NULL) {
+ if (this == retTL->parent()->left()) {
+ retTL->parent()->set_left(retTL);
+ } else {
+ assert(this == retTL->parent()->right(), "Parent is incorrect");
+ retTL->parent()->set_right(retTL);
+ }
+ }
+ // Fix the children's parent pointers to point to the
+ // new list.
+ assert(right() == retTL->right(), "Should have been copied");
+ if (retTL->right() != NULL) {
+ retTL->right()->set_parent(retTL);
+ }
+ assert(left() == retTL->left(), "Should have been copied");
+ if (retTL->left() != NULL) {
+ retTL->left()->set_parent(retTL);
+ }
+ retTL->link_head(nextTC);
+ assert(nextTC->is_free(), "Should be a free chunk");
+ }
+ } else {
+ if (nextTC == NULL) {
+ // Removing chunk at tail of list
+ this->link_tail(prevFC);
+ }
+ // Chunk is interior to the list
+ prevFC->link_after(nextTC);
+ }
+
+ // Below this point the embedded TreeList<Chunk_t, FreeList_t> being used for the
+ // tree node may have changed. Don't use "this"
+ // TreeList<Chunk_t, FreeList_t>*.
+ // chunk should still be a free chunk (bit set in _prev)
+ assert(!retTL->head() || retTL->size() == retTL->head()->size(),
+ "Wrong sized chunk in list");
+ debug_only(
+ tc->link_prev(NULL);
+ tc->link_next(NULL);
+ tc->set_list(NULL);
+ bool prev_found = false;
+ bool next_found = false;
+ for (Chunk_t* curFC = retTL->head();
+ curFC != NULL; curFC = curFC->next()) {
+ assert(curFC != tc, "Chunk is still in list");
+ if (curFC == prevFC) {
+ prev_found = true;
+ }
+ if (curFC == nextTC) {
+ next_found = true;
+ }
+ }
+ assert(prevFC == NULL || prev_found, "Chunk was lost from list");
+ assert(nextTC == NULL || next_found, "Chunk was lost from list");
+ assert(retTL->parent() == NULL ||
+ retTL == retTL->parent()->left() ||
+ retTL == retTL->parent()->right(),
+ "list is inconsistent");
+ )
+ retTL->decrement_count();
+
+ assert(tc->is_free(), "Should still be a free chunk");
+ assert(retTL->head() == NULL || retTL->head()->prev() == NULL,
+ "list invariant");
+ assert(retTL->tail() == NULL || retTL->tail()->next() == NULL,
+ "list invariant");
+ return retTL;
+}
+
+template <class Chunk_t, class FreeList_t>
+void TreeList<Chunk_t, FreeList_t>::return_chunk_at_tail(TreeChunk<Chunk_t, FreeList_t>* chunk) {
+ assert(chunk != NULL, "returning NULL chunk");
+ assert(chunk->list() == this, "list should be set for chunk");
+ assert(tail() != NULL, "The tree list is embedded in the first chunk");
+ // which means that the list can never be empty.
+ assert(!this->verify_chunk_in_free_list(chunk), "Double entry");
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+
+ Chunk_t* fc = tail();
+ fc->link_after(chunk);
+ this->link_tail(chunk);
+
+ assert(!tail() || size() == tail()->size(), "Wrong sized chunk in list");
+ FreeList_t::increment_count();
+ debug_only(this->increment_returned_bytes_by(chunk->size()*sizeof(HeapWord));)
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+}
+
+// Add this chunk at the head of the list. "At the head of the list"
+// is defined to be after the chunk pointer to by head(). This is
+// because the TreeList<Chunk_t, FreeList_t> is embedded in the first TreeChunk<Chunk_t, FreeList_t> in the
+// list. See the definition of TreeChunk<Chunk_t, FreeList_t>.
+template <class Chunk_t, class FreeList_t>
+void TreeList<Chunk_t, FreeList_t>::return_chunk_at_head(TreeChunk<Chunk_t, FreeList_t>* chunk) {
+ assert(chunk->list() == this, "list should be set for chunk");
+ assert(head() != NULL, "The tree list is embedded in the first chunk");
+ assert(chunk != NULL, "returning NULL chunk");
+ assert(!this->verify_chunk_in_free_list(chunk), "Double entry");
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+
+ Chunk_t* fc = head()->next();
+ if (fc != NULL) {
+ chunk->link_after(fc);
+ } else {
+ assert(tail() == NULL, "List is inconsistent");
+ this->link_tail(chunk);
+ }
+ head()->link_after(chunk);
+ assert(!head() || size() == head()->size(), "Wrong sized chunk in list");
+ FreeList_t::increment_count();
+ debug_only(this->increment_returned_bytes_by(chunk->size()*sizeof(HeapWord));)
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+}
+
+template <class Chunk_t, class FreeList_t>
+void TreeChunk<Chunk_t, FreeList_t>::assert_is_mangled() const {
+ assert((ZapUnusedHeapArea &&
+ SpaceMangler::is_mangled((HeapWord*) Chunk_t::size_addr()) &&
+ SpaceMangler::is_mangled((HeapWord*) Chunk_t::prev_addr()) &&
+ SpaceMangler::is_mangled((HeapWord*) Chunk_t::next_addr())) ||
+ (size() == 0 && prev() == NULL && next() == NULL),
+ "Space should be clear or mangled");
+}
+
+template <class Chunk_t, class FreeList_t>
+TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::head_as_TreeChunk() {
+ assert(head() == NULL || (TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(head())->list() == this),
+ "Wrong type of chunk?");
+ return TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(head());
+}
+
+template <class Chunk_t, class FreeList_t>
+TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::first_available() {
+ assert(head() != NULL, "The head of the list cannot be NULL");
+ Chunk_t* fc = head()->next();
+ TreeChunk<Chunk_t, FreeList_t>* retTC;
+ if (fc == NULL) {
+ retTC = head_as_TreeChunk();
+ } else {
+ retTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(fc);
+ }
+ assert(retTC->list() == this, "Wrong type of chunk.");
+ return retTC;
+}
+
+// Returns the block with the largest heap address amongst
+// those in the list for this size; potentially slow and expensive,
+// use with caution!
+template <class Chunk_t, class FreeList_t>
+TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::largest_address() {
+ assert(head() != NULL, "The head of the list cannot be NULL");
+ Chunk_t* fc = head()->next();
+ TreeChunk<Chunk_t, FreeList_t>* retTC;
+ if (fc == NULL) {
+ retTC = head_as_TreeChunk();
+ } else {
+ // walk down the list and return the one with the highest
+ // heap address among chunks of this size.
+ Chunk_t* last = fc;
+ while (fc->next() != NULL) {
+ if ((HeapWord*)last < (HeapWord*)fc) {
+ last = fc;
+ }
+ fc = fc->next();
+ }
+ retTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(last);
+ }
+ assert(retTC->list() == this, "Wrong type of chunk.");
+ return retTC;
+}
+
+template <class Chunk_t, class FreeList_t>
+BinaryTreeDictionary<Chunk_t, FreeList_t>::BinaryTreeDictionary(MemRegion mr) {
+ assert((mr.byte_size() > min_size()), "minimum chunk size");
+
+ reset(mr);
+ assert(root()->left() == NULL, "reset check failed");
+ assert(root()->right() == NULL, "reset check failed");
+ assert(root()->head()->next() == NULL, "reset check failed");
+ assert(root()->head()->prev() == NULL, "reset check failed");
+ assert(total_size() == root()->size(), "reset check failed");
+ assert(total_free_blocks() == 1, "reset check failed");
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::inc_total_size(size_t inc) {
+ _total_size = _total_size + inc;
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::dec_total_size(size_t dec) {
+ _total_size = _total_size - dec;
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset(MemRegion mr) {
+ assert((mr.byte_size() > min_size()), "minimum chunk size");
+ set_root(TreeList<Chunk_t, FreeList_t>::as_TreeList(mr.start(), mr.word_size()));
+ set_total_size(mr.word_size());
+ set_total_free_blocks(1);
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset(HeapWord* addr, size_t byte_size) {
+ MemRegion mr(addr, heap_word_size(byte_size));
+ reset(mr);
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset() {
+ set_root(NULL);
+ set_total_size(0);
+ set_total_free_blocks(0);
+}
+
+// Get a free block of size at least size from tree, or NULL.
+template <class Chunk_t, class FreeList_t>
+TreeChunk<Chunk_t, FreeList_t>*
+BinaryTreeDictionary<Chunk_t, FreeList_t>::get_chunk_from_tree(size_t size)
+{
+ TreeList<Chunk_t, FreeList_t> *curTL, *prevTL;
+ TreeChunk<Chunk_t, FreeList_t>* retTC = NULL;
+
+ assert((size >= min_size()), "minimum chunk size");
+ if (FLSVerifyDictionary) {
+ verify_tree();
+ }
+ // starting at the root, work downwards trying to find match.
+ // Remember the last node of size too great or too small.
+ for (prevTL = curTL = root(); curTL != NULL;) {
+ if (curTL->size() == size) { // exact match
+ break;
+ }
+ prevTL = curTL;
+ if (curTL->size() < size) { // proceed to right sub-tree
+ curTL = curTL->right();
+ } else { // proceed to left sub-tree
+ assert(curTL->size() > size, "size inconsistency");
+ curTL = curTL->left();
+ }
+ }
+ if (curTL == NULL) { // couldn't find exact match
+
+ // try and find the next larger size by walking back up the search path
+ for (curTL = prevTL; curTL != NULL;) {
+ if (curTL->size() >= size) break;
+ else curTL = curTL->parent();
+ }
+ assert(curTL == NULL || curTL->count() > 0,
+ "An empty list should not be in the tree");
+ }
+ if (curTL != NULL) {
+ assert(curTL->size() >= size, "size inconsistency");
+
+ curTL = curTL->get_better_list(this);
+
+ retTC = curTL->first_available();
+ assert((retTC != NULL) && (curTL->count() > 0),
+ "A list in the binary tree should not be NULL");
+ assert(retTC->size() >= size,
+ "A chunk of the wrong size was found");
+ remove_chunk_from_tree(retTC);
+ assert(retTC->is_free(), "Header is not marked correctly");
+ }
+
+ if (FLSVerifyDictionary) {
+ verify();
+ }
+ return retTC;
+}
+
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_list(size_t size) const {
+ TreeList<Chunk_t, FreeList_t>* curTL;
+ for (curTL = root(); curTL != NULL;) {
+ if (curTL->size() == size) { // exact match
+ break;
+ }
+
+ if (curTL->size() < size) { // proceed to right sub-tree
+ curTL = curTL->right();
+ } else { // proceed to left sub-tree
+ assert(curTL->size() > size, "size inconsistency");
+ curTL = curTL->left();
+ }
+ }
+ return curTL;
+}
+
+
+template <class Chunk_t, class FreeList_t>
+bool BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_chunk_in_free_list(Chunk_t* tc) const {
+ size_t size = tc->size();
+ TreeList<Chunk_t, FreeList_t>* tl = find_list(size);
+ if (tl == NULL) {
+ return false;
+ } else {
+ return tl->verify_chunk_in_free_list(tc);
+ }
+}
+
+template <class Chunk_t, class FreeList_t>
+Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_largest_dict() const {
+ TreeList<Chunk_t, FreeList_t> *curTL = root();
+ if (curTL != NULL) {
+ while(curTL->right() != NULL) curTL = curTL->right();
+ return curTL->largest_address();
+ } else {
+ return NULL;
+ }
+}
+
+// Remove the current chunk from the tree. If it is not the last
+// chunk in a list on a tree node, just unlink it.
+// If it is the last chunk in the list (the next link is NULL),
+// remove the node and repair the tree.
+template <class Chunk_t, class FreeList_t>
+TreeChunk<Chunk_t, FreeList_t>*
+BinaryTreeDictionary<Chunk_t, FreeList_t>::remove_chunk_from_tree(TreeChunk<Chunk_t, FreeList_t>* tc) {
+ assert(tc != NULL, "Should not call with a NULL chunk");
+ assert(tc->is_free(), "Header is not marked correctly");
+
+ TreeList<Chunk_t, FreeList_t> *newTL, *parentTL;
+ TreeChunk<Chunk_t, FreeList_t>* retTC;
+ TreeList<Chunk_t, FreeList_t>* tl = tc->list();
+ debug_only(
+ bool removing_only_chunk = false;
+ if (tl == _root) {
+ if ((_root->left() == NULL) && (_root->right() == NULL)) {
+ if (_root->count() == 1) {
+ assert(_root->head() == tc, "Should only be this one chunk");
+ removing_only_chunk = true;
+ }
+ }
+ }
+ )
+ assert(tl != NULL, "List should be set");
+ assert(tl->parent() == NULL || tl == tl->parent()->left() ||
+ tl == tl->parent()->right(), "list is inconsistent");
+
+ bool complicated_splice = false;
+
+ retTC = tc;
+ // Removing this chunk can have the side effect of changing the node
+ // (TreeList<Chunk_t, FreeList_t>*) in the tree. If the node is the root, update it.
+ TreeList<Chunk_t, FreeList_t>* replacementTL = tl->remove_chunk_replace_if_needed(tc);
+ assert(tc->is_free(), "Chunk should still be free");
+ assert(replacementTL->parent() == NULL ||
+ replacementTL == replacementTL->parent()->left() ||
+ replacementTL == replacementTL->parent()->right(),
+ "list is inconsistent");
+ if (tl == root()) {
+ assert(replacementTL->parent() == NULL, "Incorrectly replacing root");
+ set_root(replacementTL);
+ }
+#ifdef ASSERT
+ if (tl != replacementTL) {
+ assert(replacementTL->head() != NULL,
+ "If the tree list was replaced, it should not be a NULL list");
+ TreeList<Chunk_t, FreeList_t>* rhl = replacementTL->head_as_TreeChunk()->list();
+ TreeList<Chunk_t, FreeList_t>* rtl =
+ TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(replacementTL->tail())->list();
+ assert(rhl == replacementTL, "Broken head");
+ assert(rtl == replacementTL, "Broken tail");
+ assert(replacementTL->size() == tc->size(), "Broken size");
+ }
+#endif
+
+ // Does the tree need to be repaired?
+ if (replacementTL->count() == 0) {
+ assert(replacementTL->head() == NULL &&
+ replacementTL->tail() == NULL, "list count is incorrect");
+ // Find the replacement node for the (soon to be empty) node being removed.
+ // if we have a single (or no) child, splice child in our stead
+ if (replacementTL->left() == NULL) {
+ // left is NULL so pick right. right may also be NULL.
+ newTL = replacementTL->right();
+ debug_only(replacementTL->clear_right();)
+ } else if (replacementTL->right() == NULL) {
+ // right is NULL
+ newTL = replacementTL->left();
+ debug_only(replacementTL->clear_left();)
+ } else { // we have both children, so, by patriarchal convention,
+ // my replacement is least node in right sub-tree
+ complicated_splice = true;
+ newTL = remove_tree_minimum(replacementTL->right());
+ assert(newTL != NULL && newTL->left() == NULL &&
+ newTL->right() == NULL, "sub-tree minimum exists");
+ }
+ // newTL is the replacement for the (soon to be empty) node.
+ // newTL may be NULL.
+ // should verify; we just cleanly excised our replacement
+ if (FLSVerifyDictionary) {
+ verify_tree();
+ }
+ // first make newTL my parent's child
+ if ((parentTL = replacementTL->parent()) == NULL) {
+ // newTL should be root
+ assert(tl == root(), "Incorrectly replacing root");
+ set_root(newTL);
+ if (newTL != NULL) {
+ newTL->clear_parent();
+ }
+ } else if (parentTL->right() == replacementTL) {
+ // replacementTL is a right child
+ parentTL->set_right(newTL);
+ } else { // replacementTL is a left child
+ assert(parentTL->left() == replacementTL, "should be left child");
+ parentTL->set_left(newTL);
+ }
+ debug_only(replacementTL->clear_parent();)
+ if (complicated_splice) { // we need newTL to get replacementTL's
+ // two children
+ assert(newTL != NULL &&
+ newTL->left() == NULL && newTL->right() == NULL,
+ "newTL should not have encumbrances from the past");
+ // we'd like to assert as below:
+ // assert(replacementTL->left() != NULL && replacementTL->right() != NULL,
+ // "else !complicated_splice");
+ // ... however, the above assertion is too strong because we aren't
+ // guaranteed that replacementTL->right() is still NULL.
+ // Recall that we removed
+ // the right sub-tree minimum from replacementTL.
+ // That may well have been its right
+ // child! So we'll just assert half of the above:
+ assert(replacementTL->left() != NULL, "else !complicated_splice");
+ newTL->set_left(replacementTL->left());
+ newTL->set_right(replacementTL->right());
+ debug_only(
+ replacementTL->clear_right();
+ replacementTL->clear_left();
+ )
+ }
+ assert(replacementTL->right() == NULL &&
+ replacementTL->left() == NULL &&
+ replacementTL->parent() == NULL,
+ "delete without encumbrances");
+ }
+
+ assert(total_size() >= retTC->size(), "Incorrect total size");
+ dec_total_size(retTC->size()); // size book-keeping
+ assert(total_free_blocks() > 0, "Incorrect total count");
+ set_total_free_blocks(total_free_blocks() - 1);
+
+ assert(retTC != NULL, "null chunk?");
+ assert(retTC->prev() == NULL && retTC->next() == NULL,
+ "should return without encumbrances");
+ if (FLSVerifyDictionary) {
+ verify_tree();
+ }
+ assert(!removing_only_chunk || _root == NULL, "root should be NULL");
+ return TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(retTC);
+}
+
+// Remove the leftmost node (lm) in the tree and return it.
+// If lm has a right child, link it to the left node of
+// the parent of lm.
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::remove_tree_minimum(TreeList<Chunk_t, FreeList_t>* tl) {
+ assert(tl != NULL && tl->parent() != NULL, "really need a proper sub-tree");
+ // locate the subtree minimum by walking down left branches
+ TreeList<Chunk_t, FreeList_t>* curTL = tl;
+ for (; curTL->left() != NULL; curTL = curTL->left());
+ // obviously curTL now has at most one child, a right child
+ if (curTL != root()) { // Should this test just be removed?
+ TreeList<Chunk_t, FreeList_t>* parentTL = curTL->parent();
+ if (parentTL->left() == curTL) { // curTL is a left child
+ parentTL->set_left(curTL->right());
+ } else {
+ // If the list tl has no left child, then curTL may be
+ // the right child of parentTL.
+ assert(parentTL->right() == curTL, "should be a right child");
+ parentTL->set_right(curTL->right());
+ }
+ } else {
+ // The only use of this method would not pass the root of the
+ // tree (as indicated by the assertion above that the tree list
+ // has a parent) but the specification does not explicitly exclude the
+ // passing of the root so accommodate it.
+ set_root(NULL);
+ }
+ debug_only(
+ curTL->clear_parent(); // Test if this needs to be cleared
+ curTL->clear_right(); // recall, above, left child is already null
+ )
+ // we just excised a (non-root) node, we should still verify all tree invariants
+ if (FLSVerifyDictionary) {
+ verify_tree();
+ }
+ return curTL;
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::insert_chunk_in_tree(Chunk_t* fc) {
+ TreeList<Chunk_t, FreeList_t> *curTL, *prevTL;
+ size_t size = fc->size();
+
+ assert((size >= min_size()),
+ SIZE_FORMAT " is too small to be a TreeChunk<Chunk_t, FreeList_t> " SIZE_FORMAT,
+ size, min_size());
+ if (FLSVerifyDictionary) {
+ verify_tree();
+ }
+
+ fc->clear_next();
+ fc->link_prev(NULL);
+
+ // work down from the _root, looking for insertion point
+ for (prevTL = curTL = root(); curTL != NULL;) {
+ if (curTL->size() == size) // exact match
+ break;
+ prevTL = curTL;
+ if (curTL->size() > size) { // follow left branch
+ curTL = curTL->left();
+ } else { // follow right branch
+ assert(curTL->size() < size, "size inconsistency");
+ curTL = curTL->right();
+ }
+ }
+ TreeChunk<Chunk_t, FreeList_t>* tc = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(fc);
+ // This chunk is being returned to the binary tree. Its embedded
+ // TreeList<Chunk_t, FreeList_t> should be unused at this point.
+ tc->initialize();
+ if (curTL != NULL) { // exact match
+ tc->set_list(curTL);
+ curTL->return_chunk_at_tail(tc);
+ } else { // need a new node in tree
+ tc->clear_next();
+ tc->link_prev(NULL);
+ TreeList<Chunk_t, FreeList_t>* newTL = TreeList<Chunk_t, FreeList_t>::as_TreeList(tc);
+ assert(((TreeChunk<Chunk_t, FreeList_t>*)tc)->list() == newTL,
+ "List was not initialized correctly");
+ if (prevTL == NULL) { // we are the only tree node
+ assert(root() == NULL, "control point invariant");
+ set_root(newTL);
+ } else { // insert under prevTL ...
+ if (prevTL->size() < size) { // am right child
+ assert(prevTL->right() == NULL, "control point invariant");
+ prevTL->set_right(newTL);
+ } else { // am left child
+ assert(prevTL->size() > size && prevTL->left() == NULL, "cpt pt inv");
+ prevTL->set_left(newTL);
+ }
+ }
+ }
+ assert(tc->list() != NULL, "Tree list should be set");
+
+ inc_total_size(size);
+ // Method 'total_size_in_tree' walks through the every block in the
+ // tree, so it can cause significant performance loss if there are
+ // many blocks in the tree
+ assert(!FLSVerifyDictionary || total_size_in_tree(root()) == total_size(), "_total_size inconsistency");
+ set_total_free_blocks(total_free_blocks() + 1);
+ if (FLSVerifyDictionary) {
+ verify_tree();
+ }
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::max_chunk_size() const {
+ verify_par_locked();
+ TreeList<Chunk_t, FreeList_t>* tc = root();
+ if (tc == NULL) return 0;
+ for (; tc->right() != NULL; tc = tc->right());
+ return tc->size();
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_list_length(TreeList<Chunk_t, FreeList_t>* tl) const {
+ size_t res;
+ res = tl->count();
+#ifdef ASSERT
+ size_t cnt;
+ Chunk_t* tc = tl->head();
+ for (cnt = 0; tc != NULL; tc = tc->next(), cnt++);
+ assert(res == cnt, "The count is not being maintained correctly");
+#endif
+ return res;
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_size_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
+ if (tl == NULL)
+ return 0;
+ return (tl->size() * total_list_length(tl)) +
+ total_size_in_tree(tl->left()) +
+ total_size_in_tree(tl->right());
+}
+
+template <class Chunk_t, class FreeList_t>
+double BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_of_squared_block_sizes(TreeList<Chunk_t, FreeList_t>* const tl) const {
+ if (tl == NULL) {
+ return 0.0;
+ }
+ double size = (double)(tl->size());
+ double curr = size * size * total_list_length(tl);
+ curr += sum_of_squared_block_sizes(tl->left());
+ curr += sum_of_squared_block_sizes(tl->right());
+ return curr;
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_free_blocks_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
+ if (tl == NULL)
+ return 0;
+ return total_list_length(tl) +
+ total_free_blocks_in_tree(tl->left()) +
+ total_free_blocks_in_tree(tl->right());
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::num_free_blocks() const {
+ assert(total_free_blocks_in_tree(root()) == total_free_blocks(),
+ "_total_free_blocks inconsistency");
+ return total_free_blocks();
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::tree_height_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
+ if (tl == NULL)
+ return 0;
+ return 1 + MAX2(tree_height_helper(tl->left()),
+ tree_height_helper(tl->right()));
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::tree_height() const {
+ return tree_height_helper(root());
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
+ if (tl == NULL) {
+ return 0;
+ }
+ return 1 + total_nodes_helper(tl->left()) +
+ total_nodes_helper(tl->right());
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
+ return total_nodes_helper(root());
+}
+
+// Searches the tree for a chunk that ends at the
+// specified address.
+template <class Chunk_t, class FreeList_t>
+class EndTreeSearchClosure : public DescendTreeSearchClosure<Chunk_t, FreeList_t> {
+ HeapWord* _target;
+ Chunk_t* _found;
+
+ public:
+ EndTreeSearchClosure(HeapWord* target) : _target(target), _found(NULL) {}
+ bool do_list(FreeList_t* fl) {
+ Chunk_t* item = fl->head();
+ while (item != NULL) {
+ if (item->end() == (uintptr_t*) _target) {
+ _found = item;
+ return true;
+ }
+ item = item->next();
+ }
+ return false;
+ }
+ Chunk_t* found() { return _found; }
+};
+
+template <class Chunk_t, class FreeList_t>
+Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_chunk_ends_at(HeapWord* target) const {
+ EndTreeSearchClosure<Chunk_t, FreeList_t> etsc(target);
+ bool found_target = etsc.do_tree(root());
+ assert(found_target || etsc.found() == NULL, "Consistency check");
+ assert(!found_target || etsc.found() != NULL, "Consistency check");
+ return etsc.found();
+}
+
+// Closures and methods for calculating total bytes returned to the
+// free lists in the tree.
+#ifndef PRODUCT
+template <class Chunk_t, class FreeList_t>
+class InitializeDictReturnedBytesClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
+ public:
+ void do_list(FreeList_t* fl) {
+ fl->set_returned_bytes(0);
+ }
+};
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::initialize_dict_returned_bytes() {
+ InitializeDictReturnedBytesClosure<Chunk_t, FreeList_t> idrb;
+ idrb.do_tree(root());
+}
+
+template <class Chunk_t, class FreeList_t>
+class ReturnedBytesClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
+ size_t _dict_returned_bytes;
+ public:
+ ReturnedBytesClosure() { _dict_returned_bytes = 0; }
+ void do_list(FreeList_t* fl) {
+ _dict_returned_bytes += fl->returned_bytes();
+ }
+ size_t dict_returned_bytes() { return _dict_returned_bytes; }
+};
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_dict_returned_bytes() {
+ ReturnedBytesClosure<Chunk_t, FreeList_t> rbc;
+ rbc.do_tree(root());
+
+ return rbc.dict_returned_bytes();
+}
+
+// Count the number of entries in the tree.
+template <class Chunk_t, class FreeList_t>
+class treeCountClosure : public DescendTreeCensusClosure<Chunk_t, FreeList_t> {
+ public:
+ uint count;
+ treeCountClosure(uint c) { count = c; }
+ void do_list(FreeList_t* fl) {
+ count++;
+ }
+};
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_count() {
+ treeCountClosure<Chunk_t, FreeList_t> ctc(0);
+ ctc.do_tree(root());
+ return ctc.count;
+}
+
+template <class Chunk_t, class FreeList_t>
+Mutex* BinaryTreeDictionary<Chunk_t, FreeList_t>::par_lock() const {
+ return _lock;
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_par_lock(Mutex* lock) {
+ _lock = lock;
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_par_locked() const {
+#ifdef ASSERT
+ Thread* my_thread = Thread::current();
+ if (my_thread->is_GC_task_thread()) {
+ assert(par_lock() != NULL, "Should be using locking?");
+ assert_lock_strong(par_lock());
+ }
+#endif // ASSERT
+}
+#endif // PRODUCT
+
+// Print summary statistics
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::report_statistics(outputStream* st) const {
+ verify_par_locked();
+ st->print_cr("Statistics for BinaryTreeDictionary:");
+ st->print_cr("------------------------------------");
+ size_t total_size = total_chunk_size(debug_only(NULL));
+ size_t free_blocks = num_free_blocks();
+ st->print_cr("Total Free Space: " SIZE_FORMAT, total_size);
+ st->print_cr("Max Chunk Size: " SIZE_FORMAT, max_chunk_size());
+ st->print_cr("Number of Blocks: " SIZE_FORMAT, free_blocks);
+ if (free_blocks > 0) {
+ st->print_cr("Av. Block Size: " SIZE_FORMAT, total_size/free_blocks);
+ }
+ st->print_cr("Tree Height: " SIZE_FORMAT, tree_height());
+}
+
+template <class Chunk_t, class FreeList_t>
+class PrintFreeListsClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
+ outputStream* _st;
+ int _print_line;
+
+ public:
+ PrintFreeListsClosure(outputStream* st) {
+ _st = st;
+ _print_line = 0;
+ }
+ void do_list(FreeList_t* fl) {
+ if (++_print_line >= 40) {
+ FreeList_t::print_labels_on(_st, "size");
+ _print_line = 0;
+ }
+ fl->print_on(_st);
+ size_t sz = fl->size();
+ for (Chunk_t* fc = fl->head(); fc != NULL;
+ fc = fc->next()) {
+ _st->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s",
+ p2i(fc), p2i((HeapWord*)fc + sz),
+ fc->cantCoalesce() ? "\t CC" : "");
+ }
+ }
+};
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::print_free_lists(outputStream* st) const {
+
+ FreeList_t::print_labels_on(st, "size");
+ PrintFreeListsClosure<Chunk_t, FreeList_t> pflc(st);
+ pflc.do_tree(root());
+}
+
+// Verify the following tree invariants:
+// . _root has no parent
+// . parent and child point to each other
+// . each node's key correctly related to that of its child(ren)
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree() const {
+ guarantee(root() == NULL || total_free_blocks() == 0 ||
+ total_size() != 0, "_total_size shouldn't be 0?");
+ guarantee(root() == NULL || root()->parent() == NULL, "_root shouldn't have parent");
+ verify_tree_helper(root());
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_prev_free_ptrs(TreeList<Chunk_t, FreeList_t>* tl) {
+ size_t ct = 0;
+ for (Chunk_t* curFC = tl->head(); curFC != NULL; curFC = curFC->next()) {
+ ct++;
+ assert(curFC->prev() == NULL || curFC->prev()->is_free(),
+ "Chunk should be free");
+ }
+ return ct;
+}
+
+// Note: this helper is recursive rather than iterative, so use with
+// caution on very deep trees; and watch out for stack overflow errors;
+// In general, to be used only for debugging.
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
+ if (tl == NULL)
+ return;
+ guarantee(tl->size() != 0, "A list must has a size");
+ guarantee(tl->left() == NULL || tl->left()->parent() == tl,
+ "parent<-/->left");
+ guarantee(tl->right() == NULL || tl->right()->parent() == tl,
+ "parent<-/->right");;
+ guarantee(tl->left() == NULL || tl->left()->size() < tl->size(),
+ "parent !> left");
+ guarantee(tl->right() == NULL || tl->right()->size() > tl->size(),
+ "parent !< left");
+ guarantee(tl->head() == NULL || tl->head()->is_free(), "!Free");
+ guarantee(tl->head() == NULL || tl->head_as_TreeChunk()->list() == tl,
+ "list inconsistency");
+ guarantee(tl->count() > 0 || (tl->head() == NULL && tl->tail() == NULL),
+ "list count is inconsistent");
+ guarantee(tl->count() > 1 || tl->head() == tl->tail(),
+ "list is incorrectly constructed");
+ size_t count = verify_prev_free_ptrs(tl);
+ guarantee(count == (size_t)tl->count(), "Node count is incorrect");
+ if (tl->head() != NULL) {
+ tl->head_as_TreeChunk()->verify_tree_chunk_list();
+ }
+ verify_tree_helper(tl->left());
+ verify_tree_helper(tl->right());
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify() const {
+ verify_tree();
+ guarantee(total_size() == total_size_in_tree(root()), "Total Size inconsistency");
+}
+
+#endif // SHARE_VM_MEMORY_BINARYTREEDICTIONARY_INLINE_HPP
--- a/src/hotspot/share/memory/freeList.cpp Fri Apr 06 03:53:28 2018 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,336 +0,0 @@
-/*
- * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "gc/shared/collectedHeap.hpp"
-#include "memory/freeList.hpp"
-#include "memory/metachunk.hpp"
-#include "runtime/globals.hpp"
-#include "runtime/mutex.hpp"
-#include "runtime/vmThread.hpp"
-#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/cms/freeChunk.hpp"
-#endif // INCLUDE_ALL_GCS
-
-// Free list. A FreeList is used to access a linked list of chunks
-// of space in the heap. The head and tail are maintained so that
-// items can be (as in the current implementation) added at the
-// at the tail of the list and removed from the head of the list to
-// maintain a FIFO queue.
-
-template <class Chunk>
-FreeList<Chunk>::FreeList() :
- _head(NULL), _tail(NULL)
-#ifdef ASSERT
- , _protecting_lock(NULL)
-#endif
-{
- _size = 0;
- _count = 0;
-}
-
-template <class Chunk>
-void FreeList<Chunk>::link_head(Chunk* v) {
- assert_proper_lock_protection();
- set_head(v);
- // If this method is not used (just set the head instead),
- // this check can be avoided.
- if (v != NULL) {
- v->link_prev(NULL);
- }
-}
-
-
-
-template <class Chunk>
-void FreeList<Chunk>::reset() {
- // Don't set the _size to 0 because this method is
- // used with a existing list that has a size but which has
- // been emptied.
- // Don't clear the _protecting_lock of an existing list.
- set_count(0);
- set_head(NULL);
- set_tail(NULL);
-}
-
-template <class Chunk>
-void FreeList<Chunk>::initialize() {
-#ifdef ASSERT
- // Needed early because it might be checked in other initializing code.
- set_protecting_lock(NULL);
-#endif
- reset();
- set_size(0);
-}
-
-template <class Chunk_t>
-Chunk_t* FreeList<Chunk_t>::get_chunk_at_head() {
- assert_proper_lock_protection();
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
- Chunk_t* fc = head();
- if (fc != NULL) {
- Chunk_t* nextFC = fc->next();
- if (nextFC != NULL) {
- // The chunk fc being removed has a "next". Set the "next" to the
- // "prev" of fc.
- nextFC->link_prev(NULL);
- } else { // removed tail of list
- link_tail(NULL);
- }
- link_head(nextFC);
- decrement_count();
- }
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
- return fc;
-}
-
-
-template <class Chunk>
-void FreeList<Chunk>::getFirstNChunksFromList(size_t n, FreeList<Chunk>* fl) {
- assert_proper_lock_protection();
- assert(fl->count() == 0, "Precondition");
- if (count() > 0) {
- int k = 1;
- fl->set_head(head()); n--;
- Chunk* tl = head();
- while (tl->next() != NULL && n > 0) {
- tl = tl->next(); n--; k++;
- }
- assert(tl != NULL, "Loop Inv.");
-
- // First, fix up the list we took from.
- Chunk* new_head = tl->next();
- set_head(new_head);
- set_count(count() - k);
- if (new_head == NULL) {
- set_tail(NULL);
- } else {
- new_head->link_prev(NULL);
- }
- // Now we can fix up the tail.
- tl->link_next(NULL);
- // And return the result.
- fl->set_tail(tl);
- fl->set_count(k);
- }
-}
-
-// Remove this chunk from the list
-template <class Chunk>
-void FreeList<Chunk>::remove_chunk(Chunk*fc) {
- assert_proper_lock_protection();
- assert(head() != NULL, "Remove from empty list");
- assert(fc != NULL, "Remove a NULL chunk");
- assert(size() == fc->size(), "Wrong list");
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-
- Chunk* prevFC = fc->prev();
- Chunk* nextFC = fc->next();
- if (nextFC != NULL) {
- // The chunk fc being removed has a "next". Set the "next" to the
- // "prev" of fc.
- nextFC->link_prev(prevFC);
- } else { // removed tail of list
- link_tail(prevFC);
- }
- if (prevFC == NULL) { // removed head of list
- link_head(nextFC);
- assert(nextFC == NULL || nextFC->prev() == NULL,
- "Prev of head should be NULL");
- } else {
- prevFC->link_next(nextFC);
- assert(tail() != prevFC || prevFC->next() == NULL,
- "Next of tail should be NULL");
- }
- decrement_count();
- assert(((head() == NULL) + (tail() == NULL) + (count() == 0)) % 3 == 0,
- "H/T/C Inconsistency");
- // clear next and prev fields of fc, debug only
- NOT_PRODUCT(
- fc->link_prev(NULL);
- fc->link_next(NULL);
- )
- assert(fc->is_free(), "Should still be a free chunk");
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
- assert(head() == NULL || head()->size() == size(), "wrong item on list");
- assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
-}
-
-// Add this chunk at the head of the list.
-template <class Chunk>
-void FreeList<Chunk>::return_chunk_at_head(Chunk* chunk, bool record_return) {
- assert_proper_lock_protection();
- assert(chunk != NULL, "insert a NULL chunk");
- assert(size() == chunk->size(), "Wrong size");
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-
- Chunk* oldHead = head();
- assert(chunk != oldHead, "double insertion");
- chunk->link_after(oldHead);
- link_head(chunk);
- if (oldHead == NULL) { // only chunk in list
- assert(tail() == NULL, "inconsistent FreeList");
- link_tail(chunk);
- }
- increment_count(); // of # of chunks in list
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
- assert(head() == NULL || head()->size() == size(), "wrong item on list");
- assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
-}
-
-template <class Chunk>
-void FreeList<Chunk>::return_chunk_at_head(Chunk* chunk) {
- assert_proper_lock_protection();
- return_chunk_at_head(chunk, true);
-}
-
-// Add this chunk at the tail of the list.
-template <class Chunk>
-void FreeList<Chunk>::return_chunk_at_tail(Chunk* chunk, bool record_return) {
- assert_proper_lock_protection();
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
- assert(chunk != NULL, "insert a NULL chunk");
- assert(size() == chunk->size(), "wrong size");
-
- Chunk* oldTail = tail();
- assert(chunk != oldTail, "double insertion");
- if (oldTail != NULL) {
- oldTail->link_after(chunk);
- } else { // only chunk in list
- assert(head() == NULL, "inconsistent FreeList");
- link_head(chunk);
- }
- link_tail(chunk);
- increment_count(); // of # of chunks in list
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
- assert(head() == NULL || head()->size() == size(), "wrong item on list");
- assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
-}
-
-template <class Chunk>
-void FreeList<Chunk>::return_chunk_at_tail(Chunk* chunk) {
- return_chunk_at_tail(chunk, true);
-}
-
-template <class Chunk>
-void FreeList<Chunk>::prepend(FreeList<Chunk>* fl) {
- assert_proper_lock_protection();
- if (fl->count() > 0) {
- if (count() == 0) {
- set_head(fl->head());
- set_tail(fl->tail());
- set_count(fl->count());
- } else {
- // Both are non-empty.
- Chunk* fl_tail = fl->tail();
- Chunk* this_head = head();
- assert(fl_tail->next() == NULL, "Well-formedness of fl");
- fl_tail->link_next(this_head);
- this_head->link_prev(fl_tail);
- set_head(fl->head());
- set_count(count() + fl->count());
- }
- fl->set_head(NULL);
- fl->set_tail(NULL);
- fl->set_count(0);
- }
-}
-
-// verify_chunk_in_free_lists() is used to verify that an item is in this free list.
-// It is used as a debugging aid.
-template <class Chunk>
-bool FreeList<Chunk>::verify_chunk_in_free_list(Chunk* fc) const {
- // This is an internal consistency check, not part of the check that the
- // chunk is in the free lists.
- guarantee(fc->size() == size(), "Wrong list is being searched");
- Chunk* curFC = head();
- while (curFC) {
- // This is an internal consistency check.
- guarantee(size() == curFC->size(), "Chunk is in wrong list.");
- if (fc == curFC) {
- return true;
- }
- curFC = curFC->next();
- }
- return false;
-}
-
-#ifdef ASSERT
-template <class Chunk>
-void FreeList<Chunk>::assert_proper_lock_protection_work() const {
- // Nothing to do if the list has no assigned protecting lock
- if (protecting_lock() == NULL) {
- return;
- }
-
- Thread* thr = Thread::current();
- if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) {
- // assert that we are holding the freelist lock
- } else if (thr->is_GC_task_thread()) {
- assert(protecting_lock()->owned_by_self(), "FreeList RACE DETECTED");
- } else if (thr->is_Java_thread()) {
- assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing");
- } else {
- ShouldNotReachHere(); // unaccounted thread type?
- }
-}
-#endif
-
-// Print the "label line" for free list stats.
-template <class Chunk>
-void FreeList<Chunk>::print_labels_on(outputStream* st, const char* c) {
- st->print("%16s\t", c);
- st->print("%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t"
- "%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t" "\n",
- "bfrsurp", "surplus", "desired", "prvSwep", "bfrSwep",
- "count", "cBirths", "cDeaths", "sBirths", "sDeaths");
-}
-
-// Print the AllocationStats for the given free list. If the second argument
-// to the call is a non-null string, it is printed in the first column;
-// otherwise, if the argument is null (the default), then the size of the
-// (free list) block is printed in the first column.
-template <class Chunk_t>
-void FreeList<Chunk_t>::print_on(outputStream* st, const char* c) const {
- if (c != NULL) {
- st->print("%16s", c);
- } else {
- st->print(SIZE_FORMAT_W(16), size());
- }
-}
-
-template class FreeList<Metablock>;
-template class FreeList<Metachunk>;
-#if INCLUDE_ALL_GCS
-template class FreeList<FreeChunk>;
-#endif // INCLUDE_ALL_GCS
--- a/src/hotspot/share/memory/freeList.hpp Fri Apr 06 03:53:28 2018 +0200
+++ b/src/hotspot/share/memory/freeList.hpp Fri Apr 06 11:37:26 2018 +0200
@@ -25,10 +25,6 @@
#ifndef SHARE_VM_MEMORY_FREELIST_HPP
#define SHARE_VM_MEMORY_FREELIST_HPP
-#include "gc/cms/allocationStats.hpp"
-
-class CompactibleFreeListSpace;
-
// A class for maintaining a free list of Chunk's. The FreeList
// maintains a the structure of the list (head, tail, etc.) plus
// statistics for allocations from the list. The links between items
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/memory/freeList.inline.hpp Fri Apr 06 11:37:26 2018 +0200
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_MEMORY_FREELIST_INLINE_HPP
+#define SHARE_MEMORY_FREELIST_INLINE_HPP
+
+#include "gc/shared/collectedHeap.hpp"
+#include "memory/freeList.hpp"
+#include "memory/metachunk.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/mutex.hpp"
+#include "runtime/vmThread.hpp"
+#include "utilities/macros.hpp"
+
+// Free list. A FreeList is used to access a linked list of chunks
+// of space in the heap. The head and tail are maintained so that
+// items can be (as in the current implementation) added at the
+// at the tail of the list and removed from the head of the list to
+// maintain a FIFO queue.
+
+template <class Chunk>
+FreeList<Chunk>::FreeList() :
+ _head(NULL), _tail(NULL)
+#ifdef ASSERT
+ , _protecting_lock(NULL)
+#endif
+{
+ _size = 0;
+ _count = 0;
+}
+
+template <class Chunk>
+void FreeList<Chunk>::link_head(Chunk* v) {
+ assert_proper_lock_protection();
+ set_head(v);
+ // If this method is not used (just set the head instead),
+ // this check can be avoided.
+ if (v != NULL) {
+ v->link_prev(NULL);
+ }
+}
+
+
+
+template <class Chunk>
+void FreeList<Chunk>::reset() {
+ // Don't set the _size to 0 because this method is
+ // used with a existing list that has a size but which has
+ // been emptied.
+ // Don't clear the _protecting_lock of an existing list.
+ set_count(0);
+ set_head(NULL);
+ set_tail(NULL);
+}
+
+template <class Chunk>
+void FreeList<Chunk>::initialize() {
+#ifdef ASSERT
+ // Needed early because it might be checked in other initializing code.
+ set_protecting_lock(NULL);
+#endif
+ reset();
+ set_size(0);
+}
+
+template <class Chunk_t>
+Chunk_t* FreeList<Chunk_t>::get_chunk_at_head() {
+ assert_proper_lock_protection();
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+ Chunk_t* fc = head();
+ if (fc != NULL) {
+ Chunk_t* nextFC = fc->next();
+ if (nextFC != NULL) {
+ // The chunk fc being removed has a "next". Set the "next" to the
+ // "prev" of fc.
+ nextFC->link_prev(NULL);
+ } else { // removed tail of list
+ link_tail(NULL);
+ }
+ link_head(nextFC);
+ decrement_count();
+ }
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+ return fc;
+}
+
+
+template <class Chunk>
+void FreeList<Chunk>::getFirstNChunksFromList(size_t n, FreeList<Chunk>* fl) {
+ assert_proper_lock_protection();
+ assert(fl->count() == 0, "Precondition");
+ if (count() > 0) {
+ int k = 1;
+ fl->set_head(head()); n--;
+ Chunk* tl = head();
+ while (tl->next() != NULL && n > 0) {
+ tl = tl->next(); n--; k++;
+ }
+ assert(tl != NULL, "Loop Inv.");
+
+ // First, fix up the list we took from.
+ Chunk* new_head = tl->next();
+ set_head(new_head);
+ set_count(count() - k);
+ if (new_head == NULL) {
+ set_tail(NULL);
+ } else {
+ new_head->link_prev(NULL);
+ }
+ // Now we can fix up the tail.
+ tl->link_next(NULL);
+ // And return the result.
+ fl->set_tail(tl);
+ fl->set_count(k);
+ }
+}
+
+// Remove this chunk from the list
+template <class Chunk>
+void FreeList<Chunk>::remove_chunk(Chunk*fc) {
+ assert_proper_lock_protection();
+ assert(head() != NULL, "Remove from empty list");
+ assert(fc != NULL, "Remove a NULL chunk");
+ assert(size() == fc->size(), "Wrong list");
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+
+ Chunk* prevFC = fc->prev();
+ Chunk* nextFC = fc->next();
+ if (nextFC != NULL) {
+ // The chunk fc being removed has a "next". Set the "next" to the
+ // "prev" of fc.
+ nextFC->link_prev(prevFC);
+ } else { // removed tail of list
+ link_tail(prevFC);
+ }
+ if (prevFC == NULL) { // removed head of list
+ link_head(nextFC);
+ assert(nextFC == NULL || nextFC->prev() == NULL,
+ "Prev of head should be NULL");
+ } else {
+ prevFC->link_next(nextFC);
+ assert(tail() != prevFC || prevFC->next() == NULL,
+ "Next of tail should be NULL");
+ }
+ decrement_count();
+ assert(((head() == NULL) + (tail() == NULL) + (count() == 0)) % 3 == 0,
+ "H/T/C Inconsistency");
+ // clear next and prev fields of fc, debug only
+ NOT_PRODUCT(
+ fc->link_prev(NULL);
+ fc->link_next(NULL);
+ )
+ assert(fc->is_free(), "Should still be a free chunk");
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+ assert(head() == NULL || head()->size() == size(), "wrong item on list");
+ assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
+}
+
+// Add this chunk at the head of the list.
+template <class Chunk>
+void FreeList<Chunk>::return_chunk_at_head(Chunk* chunk, bool record_return) {
+ assert_proper_lock_protection();
+ assert(chunk != NULL, "insert a NULL chunk");
+ assert(size() == chunk->size(), "Wrong size");
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+
+ Chunk* oldHead = head();
+ assert(chunk != oldHead, "double insertion");
+ chunk->link_after(oldHead);
+ link_head(chunk);
+ if (oldHead == NULL) { // only chunk in list
+ assert(tail() == NULL, "inconsistent FreeList");
+ link_tail(chunk);
+ }
+ increment_count(); // of # of chunks in list
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+ assert(head() == NULL || head()->size() == size(), "wrong item on list");
+ assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
+}
+
+template <class Chunk>
+void FreeList<Chunk>::return_chunk_at_head(Chunk* chunk) {
+ assert_proper_lock_protection();
+ return_chunk_at_head(chunk, true);
+}
+
+// Add this chunk at the tail of the list.
+template <class Chunk>
+void FreeList<Chunk>::return_chunk_at_tail(Chunk* chunk, bool record_return) {
+ assert_proper_lock_protection();
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+ assert(chunk != NULL, "insert a NULL chunk");
+ assert(size() == chunk->size(), "wrong size");
+
+ Chunk* oldTail = tail();
+ assert(chunk != oldTail, "double insertion");
+ if (oldTail != NULL) {
+ oldTail->link_after(chunk);
+ } else { // only chunk in list
+ assert(head() == NULL, "inconsistent FreeList");
+ link_head(chunk);
+ }
+ link_tail(chunk);
+ increment_count(); // of # of chunks in list
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+ assert(head() == NULL || head()->size() == size(), "wrong item on list");
+ assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
+}
+
+template <class Chunk>
+void FreeList<Chunk>::return_chunk_at_tail(Chunk* chunk) {
+ return_chunk_at_tail(chunk, true);
+}
+
+template <class Chunk>
+void FreeList<Chunk>::prepend(FreeList<Chunk>* fl) {
+ assert_proper_lock_protection();
+ if (fl->count() > 0) {
+ if (count() == 0) {
+ set_head(fl->head());
+ set_tail(fl->tail());
+ set_count(fl->count());
+ } else {
+ // Both are non-empty.
+ Chunk* fl_tail = fl->tail();
+ Chunk* this_head = head();
+ assert(fl_tail->next() == NULL, "Well-formedness of fl");
+ fl_tail->link_next(this_head);
+ this_head->link_prev(fl_tail);
+ set_head(fl->head());
+ set_count(count() + fl->count());
+ }
+ fl->set_head(NULL);
+ fl->set_tail(NULL);
+ fl->set_count(0);
+ }
+}
+
+// verify_chunk_in_free_lists() is used to verify that an item is in this free list.
+// It is used as a debugging aid.
+template <class Chunk>
+bool FreeList<Chunk>::verify_chunk_in_free_list(Chunk* fc) const {
+ // This is an internal consistency check, not part of the check that the
+ // chunk is in the free lists.
+ guarantee(fc->size() == size(), "Wrong list is being searched");
+ Chunk* curFC = head();
+ while (curFC) {
+ // This is an internal consistency check.
+ guarantee(size() == curFC->size(), "Chunk is in wrong list.");
+ if (fc == curFC) {
+ return true;
+ }
+ curFC = curFC->next();
+ }
+ return false;
+}
+
+#ifdef ASSERT
+template <class Chunk>
+void FreeList<Chunk>::assert_proper_lock_protection_work() const {
+ // Nothing to do if the list has no assigned protecting lock
+ if (protecting_lock() == NULL) {
+ return;
+ }
+
+ Thread* thr = Thread::current();
+ if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) {
+ // assert that we are holding the freelist lock
+ } else if (thr->is_GC_task_thread()) {
+ assert(protecting_lock()->owned_by_self(), "FreeList RACE DETECTED");
+ } else if (thr->is_Java_thread()) {
+ assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing");
+ } else {
+ ShouldNotReachHere(); // unaccounted thread type?
+ }
+}
+#endif
+
+// Print the "label line" for free list stats.
+template <class Chunk>
+void FreeList<Chunk>::print_labels_on(outputStream* st, const char* c) {
+ st->print("%16s\t", c);
+ st->print("%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t"
+ "%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t" "\n",
+ "bfrsurp", "surplus", "desired", "prvSwep", "bfrSwep",
+ "count", "cBirths", "cDeaths", "sBirths", "sDeaths");
+}
+
+// Print the AllocationStats for the given free list. If the second argument
+// to the call is a non-null string, it is printed in the first column;
+// otherwise, if the argument is null (the default), then the size of the
+// (free list) block is printed in the first column.
+template <class Chunk_t>
+void FreeList<Chunk_t>::print_on(outputStream* st, const char* c) const {
+ if (c != NULL) {
+ st->print("%16s", c);
+ } else {
+ st->print(SIZE_FORMAT_W(16), size());
+ }
+}
+
+#endif // SHARE_MEMORY_FREELIST_INLINE_HPP
--- a/src/hotspot/share/memory/metaspace.cpp Fri Apr 06 03:53:28 2018 +0200
+++ b/src/hotspot/share/memory/metaspace.cpp Fri Apr 06 11:37:26 2018 +0200
@@ -28,9 +28,9 @@
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.hpp"
-#include "memory/binaryTreeDictionary.hpp"
+#include "memory/binaryTreeDictionary.inline.hpp"
#include "memory/filemap.hpp"
-#include "memory/freeList.hpp"
+#include "memory/freeList.inline.hpp"
#include "memory/metachunk.hpp"
#include "memory/metaspace.hpp"
#include "memory/metaspaceGCThresholdUpdater.hpp"
@@ -5342,4 +5342,3 @@
out->medium_chunk_word_size = ClassMediumChunk;
}
}
-