1 /*
   2  * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "gc/cms/allocationStats.hpp"
  27 #include "gc/shared/spaceDecorator.hpp"
  28 #include "logging/logStream.inline.hpp"
  29 #include "memory/binaryTreeDictionary.hpp"
  30 #include "memory/freeBlockDictionary.hpp"
  31 #include "memory/freeList.hpp"
  32 #include "memory/metachunk.hpp"
  33 #include "memory/resourceArea.hpp"
  34 #include "runtime/globals.hpp"
  35 #include "utilities/macros.hpp"
  36 #include "utilities/ostream.hpp"
  37 #if INCLUDE_ALL_GCS
  38 #include "gc/cms/adaptiveFreeList.hpp"
  39 #include "gc/cms/freeChunk.hpp"
  40 #endif // INCLUDE_ALL_GCS
  41 
  42 ////////////////////////////////////////////////////////////////////////////////
  43 // A binary tree based search structure for free blocks.
  44 // This is currently used in the Concurrent Mark&Sweep implementation.
  45 ////////////////////////////////////////////////////////////////////////////////
  46 
  47 template <class Chunk_t, class FreeList_t>
  48 TreeChunk<Chunk_t, FreeList_t>* TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(Chunk_t* fc) {
  49   // Do some assertion checking here.
  50   return (TreeChunk<Chunk_t, FreeList_t>*) fc;
  51 }
  52 
  53 template <class Chunk_t, class FreeList_t>
  54 void TreeChunk<Chunk_t, FreeList_t>::verify_tree_chunk_list() const {
  55   TreeChunk<Chunk_t, FreeList_t>* nextTC = (TreeChunk<Chunk_t, FreeList_t>*)next();
  56   if (prev() != NULL) { // interior list node shouldn't have tree fields
  57     guarantee(embedded_list()->parent() == NULL && embedded_list()->left() == NULL &&
  58               embedded_list()->right()  == NULL, "should be clear");
  59   }
  60   if (nextTC != NULL) {
  61     guarantee(as_TreeChunk(nextTC->prev()) == this, "broken chain");
  62     guarantee(nextTC->size() == size(), "wrong size");
  63     nextTC->verify_tree_chunk_list();
  64   }
  65 }
  66 
  67 template <class Chunk_t, class FreeList_t>
  68 TreeList<Chunk_t, FreeList_t>::TreeList() : _parent(NULL),
  69   _left(NULL), _right(NULL) {}
  70 
  71 template <class Chunk_t, class FreeList_t>
  72 TreeList<Chunk_t, FreeList_t>*
  73 TreeList<Chunk_t, FreeList_t>::as_TreeList(TreeChunk<Chunk_t,FreeList_t>* tc) {
  74   // This first free chunk in the list will be the tree list.
  75   assert((tc->size() >= (TreeChunk<Chunk_t, FreeList_t>::min_size())),
  76     "Chunk is too small for a TreeChunk");
  77   TreeList<Chunk_t, FreeList_t>* tl = tc->embedded_list();
  78   tl->initialize();
  79   tc->set_list(tl);
  80   tl->set_size(tc->size());
  81   tl->link_head(tc);
  82   tl->link_tail(tc);
  83   tl->set_count(1);
  84   assert(tl->parent() == NULL, "Should be clear");
  85   return tl;
  86 }
  87 
  88 template <class Chunk_t, class FreeList_t>
  89 TreeList<Chunk_t, FreeList_t>*
  90 TreeList<Chunk_t, FreeList_t>::as_TreeList(HeapWord* addr, size_t size) {
  91   TreeChunk<Chunk_t, FreeList_t>* tc = (TreeChunk<Chunk_t, FreeList_t>*) addr;
  92   assert((size >= TreeChunk<Chunk_t, FreeList_t>::min_size()),
  93     "Chunk is too small for a TreeChunk");
  94   // The space will have been mangled initially but
  95   // is not remangled when a Chunk_t is returned to the free list
  96   // (since it is used to maintain the chunk on the free list).
  97   tc->assert_is_mangled();
  98   tc->set_size(size);
  99   tc->link_prev(NULL);
 100   tc->link_next(NULL);
 101   TreeList<Chunk_t, FreeList_t>* tl = TreeList<Chunk_t, FreeList_t>::as_TreeList(tc);
 102   return tl;
 103 }
 104 
 105 
 106 #if INCLUDE_ALL_GCS
 107 // Specialize for AdaptiveFreeList which tries to avoid
 108 // splitting a chunk of a size that is under populated in favor of
 109 // an over populated size.  The general get_better_list() just returns
 110 // the current list.
 111 template <>
 112 TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >*
 113 TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >::get_better_list(
 114   BinaryTreeDictionary<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* dictionary) {
 115   // A candidate chunk has been found.  If it is already under
 116   // populated, get a chunk associated with the hint for this
 117   // chunk.
 118 
 119   TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* curTL = this;
 120   if (curTL->surplus() <= 0) {
 121     /* Use the hint to find a size with a surplus, and reset the hint. */
 122     TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* hintTL = this;
 123     while (hintTL->hint() != 0) {
 124       assert(hintTL->hint() > hintTL->size(),
 125         "hint points in the wrong direction");
 126       hintTL = dictionary->find_list(hintTL->hint());
 127       assert(curTL != hintTL, "Infinite loop");
 128       if (hintTL == NULL ||
 129           hintTL == curTL /* Should not happen but protect against it */ ) {
 130         // No useful hint.  Set the hint to NULL and go on.
 131         curTL->set_hint(0);
 132         break;
 133       }
 134       assert(hintTL->size() > curTL->size(), "hint is inconsistent");
 135       if (hintTL->surplus() > 0) {
 136         // The hint led to a list that has a surplus.  Use it.
 137         // Set the hint for the candidate to an overpopulated
 138         // size.
 139         curTL->set_hint(hintTL->size());
 140         // Change the candidate.
 141         curTL = hintTL;
 142         break;
 143       }
 144     }
 145   }
 146   return curTL;
 147 }
 148 #endif // INCLUDE_ALL_GCS
 149 
 150 template <class Chunk_t, class FreeList_t>
 151 TreeList<Chunk_t, FreeList_t>*
 152 TreeList<Chunk_t, FreeList_t>::get_better_list(
 153   BinaryTreeDictionary<Chunk_t, FreeList_t>* dictionary) {
 154   return this;
 155 }
 156 
 157 template <class Chunk_t, class FreeList_t>
 158 TreeList<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::remove_chunk_replace_if_needed(TreeChunk<Chunk_t, FreeList_t>* tc) {
 159 
 160   TreeList<Chunk_t, FreeList_t>* retTL = this;
 161   Chunk_t* list = head();
 162   assert(!list || list != list->next(), "Chunk on list twice");
 163   assert(tc != NULL, "Chunk being removed is NULL");
 164   assert(parent() == NULL || this == parent()->left() ||
 165     this == parent()->right(), "list is inconsistent");
 166   assert(tc->is_free(), "Header is not marked correctly");
 167   assert(head() == NULL || head()->prev() == NULL, "list invariant");
 168   assert(tail() == NULL || tail()->next() == NULL, "list invariant");
 169 
 170   Chunk_t* prevFC = tc->prev();
 171   TreeChunk<Chunk_t, FreeList_t>* nextTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(tc->next());
 172   assert(list != NULL, "should have at least the target chunk");
 173 
 174   // Is this the first item on the list?
 175   if (tc == list) {
 176     // The "getChunk..." functions for a TreeList<Chunk_t, FreeList_t> will not return the
 177     // first chunk in the list unless it is the last chunk in the list
 178     // because the first chunk is also acting as the tree node.
 179     // When coalescing happens, however, the first chunk in the a tree
 180     // list can be the start of a free range.  Free ranges are removed
 181     // from the free lists so that they are not available to be
 182     // allocated when the sweeper yields (giving up the free list lock)
 183     // to allow mutator activity.  If this chunk is the first in the
 184     // list and is not the last in the list, do the work to copy the
 185     // TreeList<Chunk_t, FreeList_t> from the first chunk to the next chunk and update all
 186     // the TreeList<Chunk_t, FreeList_t> pointers in the chunks in the list.
 187     if (nextTC == NULL) {
 188       assert(prevFC == NULL, "Not last chunk in the list");
 189       set_tail(NULL);
 190       set_head(NULL);
 191     } else {
 192       // copy embedded list.
 193       nextTC->set_embedded_list(tc->embedded_list());
 194       retTL = nextTC->embedded_list();
 195       // Fix the pointer to the list in each chunk in the list.
 196       // This can be slow for a long list.  Consider having
 197       // an option that does not allow the first chunk on the
 198       // list to be coalesced.
 199       for (TreeChunk<Chunk_t, FreeList_t>* curTC = nextTC; curTC != NULL;
 200           curTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(curTC->next())) {
 201         curTC->set_list(retTL);
 202       }
 203       // Fix the parent to point to the new TreeList<Chunk_t, FreeList_t>.
 204       if (retTL->parent() != NULL) {
 205         if (this == retTL->parent()->left()) {
 206           retTL->parent()->set_left(retTL);
 207         } else {
 208           assert(this == retTL->parent()->right(), "Parent is incorrect");
 209           retTL->parent()->set_right(retTL);
 210         }
 211       }
 212       // Fix the children's parent pointers to point to the
 213       // new list.
 214       assert(right() == retTL->right(), "Should have been copied");
 215       if (retTL->right() != NULL) {
 216         retTL->right()->set_parent(retTL);
 217       }
 218       assert(left() == retTL->left(), "Should have been copied");
 219       if (retTL->left() != NULL) {
 220         retTL->left()->set_parent(retTL);
 221       }
 222       retTL->link_head(nextTC);
 223       assert(nextTC->is_free(), "Should be a free chunk");
 224     }
 225   } else {
 226     if (nextTC == NULL) {
 227       // Removing chunk at tail of list
 228       this->link_tail(prevFC);
 229     }
 230     // Chunk is interior to the list
 231     prevFC->link_after(nextTC);
 232   }
 233 
 234   // Below this point the embedded TreeList<Chunk_t, FreeList_t> being used for the
 235   // tree node may have changed. Don't use "this"
 236   // TreeList<Chunk_t, FreeList_t>*.
 237   // chunk should still be a free chunk (bit set in _prev)
 238   assert(!retTL->head() || retTL->size() == retTL->head()->size(),
 239     "Wrong sized chunk in list");
 240   debug_only(
 241     tc->link_prev(NULL);
 242     tc->link_next(NULL);
 243     tc->set_list(NULL);
 244     bool prev_found = false;
 245     bool next_found = false;
 246     for (Chunk_t* curFC = retTL->head();
 247          curFC != NULL; curFC = curFC->next()) {
 248       assert(curFC != tc, "Chunk is still in list");
 249       if (curFC == prevFC) {
 250         prev_found = true;
 251       }
 252       if (curFC == nextTC) {
 253         next_found = true;
 254       }
 255     }
 256     assert(prevFC == NULL || prev_found, "Chunk was lost from list");
 257     assert(nextTC == NULL || next_found, "Chunk was lost from list");
 258     assert(retTL->parent() == NULL ||
 259            retTL == retTL->parent()->left() ||
 260            retTL == retTL->parent()->right(),
 261            "list is inconsistent");
 262   )
 263   retTL->decrement_count();
 264 
 265   assert(tc->is_free(), "Should still be a free chunk");
 266   assert(retTL->head() == NULL || retTL->head()->prev() == NULL,
 267     "list invariant");
 268   assert(retTL->tail() == NULL || retTL->tail()->next() == NULL,
 269     "list invariant");
 270   return retTL;
 271 }
 272 
 273 template <class Chunk_t, class FreeList_t>
 274 void TreeList<Chunk_t, FreeList_t>::return_chunk_at_tail(TreeChunk<Chunk_t, FreeList_t>* chunk) {
 275   assert(chunk != NULL, "returning NULL chunk");
 276   assert(chunk->list() == this, "list should be set for chunk");
 277   assert(tail() != NULL, "The tree list is embedded in the first chunk");
 278   // which means that the list can never be empty.
 279   assert(!this->verify_chunk_in_free_list(chunk), "Double entry");
 280   assert(head() == NULL || head()->prev() == NULL, "list invariant");
 281   assert(tail() == NULL || tail()->next() == NULL, "list invariant");
 282 
 283   Chunk_t* fc = tail();
 284   fc->link_after(chunk);
 285   this->link_tail(chunk);
 286 
 287   assert(!tail() || size() == tail()->size(), "Wrong sized chunk in list");
 288   FreeList_t::increment_count();
 289   debug_only(this->increment_returned_bytes_by(chunk->size()*sizeof(HeapWord));)
 290   assert(head() == NULL || head()->prev() == NULL, "list invariant");
 291   assert(tail() == NULL || tail()->next() == NULL, "list invariant");
 292 }
 293 
 294 // Add this chunk at the head of the list.  "At the head of the list"
 295 // is defined to be after the chunk pointer to by head().  This is
 296 // because the TreeList<Chunk_t, FreeList_t> is embedded in the first TreeChunk<Chunk_t, FreeList_t> in the
 297 // list.  See the definition of TreeChunk<Chunk_t, FreeList_t>.
 298 template <class Chunk_t, class FreeList_t>
 299 void TreeList<Chunk_t, FreeList_t>::return_chunk_at_head(TreeChunk<Chunk_t, FreeList_t>* chunk) {
 300   assert(chunk->list() == this, "list should be set for chunk");
 301   assert(head() != NULL, "The tree list is embedded in the first chunk");
 302   assert(chunk != NULL, "returning NULL chunk");
 303   assert(!this->verify_chunk_in_free_list(chunk), "Double entry");
 304   assert(head() == NULL || head()->prev() == NULL, "list invariant");
 305   assert(tail() == NULL || tail()->next() == NULL, "list invariant");
 306 
 307   Chunk_t* fc = head()->next();
 308   if (fc != NULL) {
 309     chunk->link_after(fc);
 310   } else {
 311     assert(tail() == NULL, "List is inconsistent");
 312     this->link_tail(chunk);
 313   }
 314   head()->link_after(chunk);
 315   assert(!head() || size() == head()->size(), "Wrong sized chunk in list");
 316   FreeList_t::increment_count();
 317   debug_only(this->increment_returned_bytes_by(chunk->size()*sizeof(HeapWord));)
 318   assert(head() == NULL || head()->prev() == NULL, "list invariant");
 319   assert(tail() == NULL || tail()->next() == NULL, "list invariant");
 320 }
 321 
 322 template <class Chunk_t, class FreeList_t>
 323 void TreeChunk<Chunk_t, FreeList_t>::assert_is_mangled() const {
 324   assert((ZapUnusedHeapArea &&
 325           SpaceMangler::is_mangled((HeapWord*) Chunk_t::size_addr()) &&
 326           SpaceMangler::is_mangled((HeapWord*) Chunk_t::prev_addr()) &&
 327           SpaceMangler::is_mangled((HeapWord*) Chunk_t::next_addr())) ||
 328           (size() == 0 && prev() == NULL && next() == NULL),
 329     "Space should be clear or mangled");
 330 }
 331 
 332 template <class Chunk_t, class FreeList_t>
 333 TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::head_as_TreeChunk() {
 334   assert(head() == NULL || (TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(head())->list() == this),
 335     "Wrong type of chunk?");
 336   return TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(head());
 337 }
 338 
 339 template <class Chunk_t, class FreeList_t>
 340 TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::first_available() {
 341   assert(head() != NULL, "The head of the list cannot be NULL");
 342   Chunk_t* fc = head()->next();
 343   TreeChunk<Chunk_t, FreeList_t>* retTC;
 344   if (fc == NULL) {
 345     retTC = head_as_TreeChunk();
 346   } else {
 347     retTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(fc);
 348   }
 349   assert(retTC->list() == this, "Wrong type of chunk.");
 350   return retTC;
 351 }
 352 
 353 // Returns the block with the largest heap address amongst
 354 // those in the list for this size; potentially slow and expensive,
 355 // use with caution!
 356 template <class Chunk_t, class FreeList_t>
 357 TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::largest_address() {
 358   assert(head() != NULL, "The head of the list cannot be NULL");
 359   Chunk_t* fc = head()->next();
 360   TreeChunk<Chunk_t, FreeList_t>* retTC;
 361   if (fc == NULL) {
 362     retTC = head_as_TreeChunk();
 363   } else {
 364     // walk down the list and return the one with the highest
 365     // heap address among chunks of this size.
 366     Chunk_t* last = fc;
 367     while (fc->next() != NULL) {
 368       if ((HeapWord*)last < (HeapWord*)fc) {
 369         last = fc;
 370       }
 371       fc = fc->next();
 372     }
 373     retTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(last);
 374   }
 375   assert(retTC->list() == this, "Wrong type of chunk.");
 376   return retTC;
 377 }
 378 
 379 template <class Chunk_t, class FreeList_t>
 380 BinaryTreeDictionary<Chunk_t, FreeList_t>::BinaryTreeDictionary(MemRegion mr) {
 381   assert((mr.byte_size() > min_size()), "minimum chunk size");
 382 
 383   reset(mr);
 384   assert(root()->left() == NULL, "reset check failed");
 385   assert(root()->right() == NULL, "reset check failed");
 386   assert(root()->head()->next() == NULL, "reset check failed");
 387   assert(root()->head()->prev() == NULL, "reset check failed");
 388   assert(total_size() == root()->size(), "reset check failed");
 389   assert(total_free_blocks() == 1, "reset check failed");
 390 }
 391 
 392 template <class Chunk_t, class FreeList_t>
 393 void BinaryTreeDictionary<Chunk_t, FreeList_t>::inc_total_size(size_t inc) {
 394   _total_size = _total_size + inc;
 395 }
 396 
 397 template <class Chunk_t, class FreeList_t>
 398 void BinaryTreeDictionary<Chunk_t, FreeList_t>::dec_total_size(size_t dec) {
 399   _total_size = _total_size - dec;
 400 }
 401 
 402 template <class Chunk_t, class FreeList_t>
 403 void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset(MemRegion mr) {
 404   assert((mr.byte_size() > min_size()), "minimum chunk size");
 405   set_root(TreeList<Chunk_t, FreeList_t>::as_TreeList(mr.start(), mr.word_size()));
 406   set_total_size(mr.word_size());
 407   set_total_free_blocks(1);
 408 }
 409 
 410 template <class Chunk_t, class FreeList_t>
 411 void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset(HeapWord* addr, size_t byte_size) {
 412   MemRegion mr(addr, heap_word_size(byte_size));
 413   reset(mr);
 414 }
 415 
 416 template <class Chunk_t, class FreeList_t>
 417 void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset() {
 418   set_root(NULL);
 419   set_total_size(0);
 420   set_total_free_blocks(0);
 421 }
 422 
 423 // Get a free block of size at least size from tree, or NULL.
 424 template <class Chunk_t, class FreeList_t>
 425 TreeChunk<Chunk_t, FreeList_t>*
 426 BinaryTreeDictionary<Chunk_t, FreeList_t>::get_chunk_from_tree(
 427                               size_t size,
 428                               enum FreeBlockDictionary<Chunk_t>::Dither dither)
 429 {
 430   TreeList<Chunk_t, FreeList_t> *curTL, *prevTL;
 431   TreeChunk<Chunk_t, FreeList_t>* retTC = NULL;
 432 
 433   assert((size >= min_size()), "minimum chunk size");
 434   if (FLSVerifyDictionary) {
 435     verify_tree();
 436   }
 437   // starting at the root, work downwards trying to find match.
 438   // Remember the last node of size too great or too small.
 439   for (prevTL = curTL = root(); curTL != NULL;) {
 440     if (curTL->size() == size) {        // exact match
 441       break;
 442     }
 443     prevTL = curTL;
 444     if (curTL->size() < size) {        // proceed to right sub-tree
 445       curTL = curTL->right();
 446     } else {                           // proceed to left sub-tree
 447       assert(curTL->size() > size, "size inconsistency");
 448       curTL = curTL->left();
 449     }
 450   }
 451   if (curTL == NULL) { // couldn't find exact match
 452 
 453     if (dither == FreeBlockDictionary<Chunk_t>::exactly) return NULL;
 454 
 455     // try and find the next larger size by walking back up the search path
 456     for (curTL = prevTL; curTL != NULL;) {
 457       if (curTL->size() >= size) break;
 458       else curTL = curTL->parent();
 459     }
 460     assert(curTL == NULL || curTL->count() > 0,
 461       "An empty list should not be in the tree");
 462   }
 463   if (curTL != NULL) {
 464     assert(curTL->size() >= size, "size inconsistency");
 465 
 466     curTL = curTL->get_better_list(this);
 467 
 468     retTC = curTL->first_available();
 469     assert((retTC != NULL) && (curTL->count() > 0),
 470       "A list in the binary tree should not be NULL");
 471     assert(retTC->size() >= size,
 472       "A chunk of the wrong size was found");
 473     remove_chunk_from_tree(retTC);
 474     assert(retTC->is_free(), "Header is not marked correctly");
 475   }
 476 
 477   if (FLSVerifyDictionary) {
 478     verify();
 479   }
 480   return retTC;
 481 }
 482 
 483 template <class Chunk_t, class FreeList_t>
 484 TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_list(size_t size) const {
 485   TreeList<Chunk_t, FreeList_t>* curTL;
 486   for (curTL = root(); curTL != NULL;) {
 487     if (curTL->size() == size) {        // exact match
 488       break;
 489     }
 490 
 491     if (curTL->size() < size) {        // proceed to right sub-tree
 492       curTL = curTL->right();
 493     } else {                           // proceed to left sub-tree
 494       assert(curTL->size() > size, "size inconsistency");
 495       curTL = curTL->left();
 496     }
 497   }
 498   return curTL;
 499 }
 500 
 501 
 502 template <class Chunk_t, class FreeList_t>
 503 bool BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_chunk_in_free_list(Chunk_t* tc) const {
 504   size_t size = tc->size();
 505   TreeList<Chunk_t, FreeList_t>* tl = find_list(size);
 506   if (tl == NULL) {
 507     return false;
 508   } else {
 509     return tl->verify_chunk_in_free_list(tc);
 510   }
 511 }
 512 
 513 template <class Chunk_t, class FreeList_t>
 514 Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_largest_dict() const {
 515   TreeList<Chunk_t, FreeList_t> *curTL = root();
 516   if (curTL != NULL) {
 517     while(curTL->right() != NULL) curTL = curTL->right();
 518     return curTL->largest_address();
 519   } else {
 520     return NULL;
 521   }
 522 }
 523 
 524 // Remove the current chunk from the tree.  If it is not the last
 525 // chunk in a list on a tree node, just unlink it.
 526 // If it is the last chunk in the list (the next link is NULL),
 527 // remove the node and repair the tree.
 528 template <class Chunk_t, class FreeList_t>
 529 TreeChunk<Chunk_t, FreeList_t>*
 530 BinaryTreeDictionary<Chunk_t, FreeList_t>::remove_chunk_from_tree(TreeChunk<Chunk_t, FreeList_t>* tc) {
 531   assert(tc != NULL, "Should not call with a NULL chunk");
 532   assert(tc->is_free(), "Header is not marked correctly");
 533 
 534   TreeList<Chunk_t, FreeList_t> *newTL, *parentTL;
 535   TreeChunk<Chunk_t, FreeList_t>* retTC;
 536   TreeList<Chunk_t, FreeList_t>* tl = tc->list();
 537   debug_only(
 538     bool removing_only_chunk = false;
 539     if (tl == _root) {
 540       if ((_root->left() == NULL) && (_root->right() == NULL)) {
 541         if (_root->count() == 1) {
 542           assert(_root->head() == tc, "Should only be this one chunk");
 543           removing_only_chunk = true;
 544         }
 545       }
 546     }
 547   )
 548   assert(tl != NULL, "List should be set");
 549   assert(tl->parent() == NULL || tl == tl->parent()->left() ||
 550          tl == tl->parent()->right(), "list is inconsistent");
 551 
 552   bool complicated_splice = false;
 553 
 554   retTC = tc;
 555   // Removing this chunk can have the side effect of changing the node
 556   // (TreeList<Chunk_t, FreeList_t>*) in the tree.  If the node is the root, update it.
 557   TreeList<Chunk_t, FreeList_t>* replacementTL = tl->remove_chunk_replace_if_needed(tc);
 558   assert(tc->is_free(), "Chunk should still be free");
 559   assert(replacementTL->parent() == NULL ||
 560          replacementTL == replacementTL->parent()->left() ||
 561          replacementTL == replacementTL->parent()->right(),
 562          "list is inconsistent");
 563   if (tl == root()) {
 564     assert(replacementTL->parent() == NULL, "Incorrectly replacing root");
 565     set_root(replacementTL);
 566   }
 567 #ifdef ASSERT
 568     if (tl != replacementTL) {
 569       assert(replacementTL->head() != NULL,
 570         "If the tree list was replaced, it should not be a NULL list");
 571       TreeList<Chunk_t, FreeList_t>* rhl = replacementTL->head_as_TreeChunk()->list();
 572       TreeList<Chunk_t, FreeList_t>* rtl =
 573         TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(replacementTL->tail())->list();
 574       assert(rhl == replacementTL, "Broken head");
 575       assert(rtl == replacementTL, "Broken tail");
 576       assert(replacementTL->size() == tc->size(),  "Broken size");
 577     }
 578 #endif
 579 
 580   // Does the tree need to be repaired?
 581   if (replacementTL->count() == 0) {
 582     assert(replacementTL->head() == NULL &&
 583            replacementTL->tail() == NULL, "list count is incorrect");
 584     // Find the replacement node for the (soon to be empty) node being removed.
 585     // if we have a single (or no) child, splice child in our stead
 586     if (replacementTL->left() == NULL) {
 587       // left is NULL so pick right.  right may also be NULL.
 588       newTL = replacementTL->right();
 589       debug_only(replacementTL->clear_right();)
 590     } else if (replacementTL->right() == NULL) {
 591       // right is NULL
 592       newTL = replacementTL->left();
 593       debug_only(replacementTL->clear_left();)
 594     } else {  // we have both children, so, by patriarchal convention,
 595               // my replacement is least node in right sub-tree
 596       complicated_splice = true;
 597       newTL = remove_tree_minimum(replacementTL->right());
 598       assert(newTL != NULL && newTL->left() == NULL &&
 599              newTL->right() == NULL, "sub-tree minimum exists");
 600     }
 601     // newTL is the replacement for the (soon to be empty) node.
 602     // newTL may be NULL.
 603     // should verify; we just cleanly excised our replacement
 604     if (FLSVerifyDictionary) {
 605       verify_tree();
 606     }
 607     // first make newTL my parent's child
 608     if ((parentTL = replacementTL->parent()) == NULL) {
 609       // newTL should be root
 610       assert(tl == root(), "Incorrectly replacing root");
 611       set_root(newTL);
 612       if (newTL != NULL) {
 613         newTL->clear_parent();
 614       }
 615     } else if (parentTL->right() == replacementTL) {
 616       // replacementTL is a right child
 617       parentTL->set_right(newTL);
 618     } else {                                // replacementTL is a left child
 619       assert(parentTL->left() == replacementTL, "should be left child");
 620       parentTL->set_left(newTL);
 621     }
 622     debug_only(replacementTL->clear_parent();)
 623     if (complicated_splice) {  // we need newTL to get replacementTL's
 624                               // two children
 625       assert(newTL != NULL &&
 626              newTL->left() == NULL && newTL->right() == NULL,
 627             "newTL should not have encumbrances from the past");
 628       // we'd like to assert as below:
 629       // assert(replacementTL->left() != NULL && replacementTL->right() != NULL,
 630       //       "else !complicated_splice");
 631       // ... however, the above assertion is too strong because we aren't
 632       // guaranteed that replacementTL->right() is still NULL.
 633       // Recall that we removed
 634       // the right sub-tree minimum from replacementTL.
 635       // That may well have been its right
 636       // child! So we'll just assert half of the above:
 637       assert(replacementTL->left() != NULL, "else !complicated_splice");
 638       newTL->set_left(replacementTL->left());
 639       newTL->set_right(replacementTL->right());
 640       debug_only(
 641         replacementTL->clear_right();
 642         replacementTL->clear_left();
 643       )
 644     }
 645     assert(replacementTL->right() == NULL &&
 646            replacementTL->left() == NULL &&
 647            replacementTL->parent() == NULL,
 648         "delete without encumbrances");
 649   }
 650 
 651   assert(total_size() >= retTC->size(), "Incorrect total size");
 652   dec_total_size(retTC->size());     // size book-keeping
 653   assert(total_free_blocks() > 0, "Incorrect total count");
 654   set_total_free_blocks(total_free_blocks() - 1);
 655 
 656   assert(retTC != NULL, "null chunk?");
 657   assert(retTC->prev() == NULL && retTC->next() == NULL,
 658          "should return without encumbrances");
 659   if (FLSVerifyDictionary) {
 660     verify_tree();
 661   }
 662   assert(!removing_only_chunk || _root == NULL, "root should be NULL");
 663   return TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(retTC);
 664 }
 665 
 666 // Remove the leftmost node (lm) in the tree and return it.
 667 // If lm has a right child, link it to the left node of
 668 // the parent of lm.
 669 template <class Chunk_t, class FreeList_t>
 670 TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::remove_tree_minimum(TreeList<Chunk_t, FreeList_t>* tl) {
 671   assert(tl != NULL && tl->parent() != NULL, "really need a proper sub-tree");
 672   // locate the subtree minimum by walking down left branches
 673   TreeList<Chunk_t, FreeList_t>* curTL = tl;
 674   for (; curTL->left() != NULL; curTL = curTL->left());
 675   // obviously curTL now has at most one child, a right child
 676   if (curTL != root()) {  // Should this test just be removed?
 677     TreeList<Chunk_t, FreeList_t>* parentTL = curTL->parent();
 678     if (parentTL->left() == curTL) { // curTL is a left child
 679       parentTL->set_left(curTL->right());
 680     } else {
 681       // If the list tl has no left child, then curTL may be
 682       // the right child of parentTL.
 683       assert(parentTL->right() == curTL, "should be a right child");
 684       parentTL->set_right(curTL->right());
 685     }
 686   } else {
 687     // The only use of this method would not pass the root of the
 688     // tree (as indicated by the assertion above that the tree list
 689     // has a parent) but the specification does not explicitly exclude the
 690     // passing of the root so accommodate it.
 691     set_root(NULL);
 692   }
 693   debug_only(
 694     curTL->clear_parent();  // Test if this needs to be cleared
 695     curTL->clear_right();    // recall, above, left child is already null
 696   )
 697   // we just excised a (non-root) node, we should still verify all tree invariants
 698   if (FLSVerifyDictionary) {
 699     verify_tree();
 700   }
 701   return curTL;
 702 }
 703 
 704 template <class Chunk_t, class FreeList_t>
 705 void BinaryTreeDictionary<Chunk_t, FreeList_t>::insert_chunk_in_tree(Chunk_t* fc) {
 706   TreeList<Chunk_t, FreeList_t> *curTL, *prevTL;
 707   size_t size = fc->size();
 708 
 709   assert((size >= min_size()),
 710          SIZE_FORMAT " is too small to be a TreeChunk<Chunk_t, FreeList_t> " SIZE_FORMAT,
 711          size, min_size());
 712   if (FLSVerifyDictionary) {
 713     verify_tree();
 714   }
 715 
 716   fc->clear_next();
 717   fc->link_prev(NULL);
 718 
 719   // work down from the _root, looking for insertion point
 720   for (prevTL = curTL = root(); curTL != NULL;) {
 721     if (curTL->size() == size)  // exact match
 722       break;
 723     prevTL = curTL;
 724     if (curTL->size() > size) { // follow left branch
 725       curTL = curTL->left();
 726     } else {                    // follow right branch
 727       assert(curTL->size() < size, "size inconsistency");
 728       curTL = curTL->right();
 729     }
 730   }
 731   TreeChunk<Chunk_t, FreeList_t>* tc = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(fc);
 732   // This chunk is being returned to the binary tree.  Its embedded
 733   // TreeList<Chunk_t, FreeList_t> should be unused at this point.
 734   tc->initialize();
 735   if (curTL != NULL) {          // exact match
 736     tc->set_list(curTL);
 737     curTL->return_chunk_at_tail(tc);
 738   } else {                     // need a new node in tree
 739     tc->clear_next();
 740     tc->link_prev(NULL);
 741     TreeList<Chunk_t, FreeList_t>* newTL = TreeList<Chunk_t, FreeList_t>::as_TreeList(tc);
 742     assert(((TreeChunk<Chunk_t, FreeList_t>*)tc)->list() == newTL,
 743       "List was not initialized correctly");
 744     if (prevTL == NULL) {      // we are the only tree node
 745       assert(root() == NULL, "control point invariant");
 746       set_root(newTL);
 747     } else {                   // insert under prevTL ...
 748       if (prevTL->size() < size) {   // am right child
 749         assert(prevTL->right() == NULL, "control point invariant");
 750         prevTL->set_right(newTL);
 751       } else {                       // am left child
 752         assert(prevTL->size() > size && prevTL->left() == NULL, "cpt pt inv");
 753         prevTL->set_left(newTL);
 754       }
 755     }
 756   }
 757   assert(tc->list() != NULL, "Tree list should be set");
 758 
 759   inc_total_size(size);
 760   // Method 'total_size_in_tree' walks through the every block in the
 761   // tree, so it can cause significant performance loss if there are
 762   // many blocks in the tree
 763   assert(!FLSVerifyDictionary || total_size_in_tree(root()) == total_size(), "_total_size inconsistency");
 764   set_total_free_blocks(total_free_blocks() + 1);
 765   if (FLSVerifyDictionary) {
 766     verify_tree();
 767   }
 768 }
 769 
 770 template <class Chunk_t, class FreeList_t>
 771 size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::max_chunk_size() const {
 772   FreeBlockDictionary<Chunk_t>::verify_par_locked();
 773   TreeList<Chunk_t, FreeList_t>* tc = root();
 774   if (tc == NULL) return 0;
 775   for (; tc->right() != NULL; tc = tc->right());
 776   return tc->size();
 777 }
 778 
 779 template <class Chunk_t, class FreeList_t>
 780 size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_list_length(TreeList<Chunk_t, FreeList_t>* tl) const {
 781   size_t res;
 782   res = tl->count();
 783 #ifdef ASSERT
 784   size_t cnt;
 785   Chunk_t* tc = tl->head();
 786   for (cnt = 0; tc != NULL; tc = tc->next(), cnt++);
 787   assert(res == cnt, "The count is not being maintained correctly");
 788 #endif
 789   return res;
 790 }
 791 
 792 template <class Chunk_t, class FreeList_t>
 793 size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_size_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
 794   if (tl == NULL)
 795     return 0;
 796   return (tl->size() * total_list_length(tl)) +
 797          total_size_in_tree(tl->left())    +
 798          total_size_in_tree(tl->right());
 799 }
 800 
 801 template <class Chunk_t, class FreeList_t>
 802 double BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_of_squared_block_sizes(TreeList<Chunk_t, FreeList_t>* const tl) const {
 803   if (tl == NULL) {
 804     return 0.0;
 805   }
 806   double size = (double)(tl->size());
 807   double curr = size * size * total_list_length(tl);
 808   curr += sum_of_squared_block_sizes(tl->left());
 809   curr += sum_of_squared_block_sizes(tl->right());
 810   return curr;
 811 }
 812 
 813 template <class Chunk_t, class FreeList_t>
 814 size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_free_blocks_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
 815   if (tl == NULL)
 816     return 0;
 817   return total_list_length(tl) +
 818          total_free_blocks_in_tree(tl->left()) +
 819          total_free_blocks_in_tree(tl->right());
 820 }
 821 
 822 template <class Chunk_t, class FreeList_t>
 823 size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::num_free_blocks() const {
 824   assert(total_free_blocks_in_tree(root()) == total_free_blocks(),
 825          "_total_free_blocks inconsistency");
 826   return total_free_blocks();
 827 }
 828 
 829 template <class Chunk_t, class FreeList_t>
 830 size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::tree_height_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
 831   if (tl == NULL)
 832     return 0;
 833   return 1 + MAX2(tree_height_helper(tl->left()),
 834                   tree_height_helper(tl->right()));
 835 }
 836 
 837 template <class Chunk_t, class FreeList_t>
 838 size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::tree_height() const {
 839   return tree_height_helper(root());
 840 }
 841 
 842 template <class Chunk_t, class FreeList_t>
 843 size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
 844   if (tl == NULL) {
 845     return 0;
 846   }
 847   return 1 + total_nodes_helper(tl->left()) +
 848     total_nodes_helper(tl->right());
 849 }
 850 
 851 template <class Chunk_t, class FreeList_t>
 852 size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
 853   return total_nodes_helper(root());
 854 }
 855 
 856 template <class Chunk_t, class FreeList_t>
 857 void BinaryTreeDictionary<Chunk_t, FreeList_t>::dict_census_update(size_t size, bool split, bool birth){}
 858 
 859 #if INCLUDE_ALL_GCS
 860 template <>
 861 void AFLBinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth) {
 862   TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* nd = find_list(size);
 863   if (nd) {
 864     if (split) {
 865       if (birth) {
 866         nd->increment_split_births();
 867         nd->increment_surplus();
 868       }  else {
 869         nd->increment_split_deaths();
 870         nd->decrement_surplus();
 871       }
 872     } else {
 873       if (birth) {
 874         nd->increment_coal_births();
 875         nd->increment_surplus();
 876       } else {
 877         nd->increment_coal_deaths();
 878         nd->decrement_surplus();
 879       }
 880     }
 881   }
 882   // A list for this size may not be found (nd == 0) if
 883   //   This is a death where the appropriate list is now
 884   //     empty and has been removed from the list.
 885   //   This is a birth associated with a LinAB.  The chunk
 886   //     for the LinAB is not in the dictionary.
 887 }
 888 #endif // INCLUDE_ALL_GCS
 889 
 890 template <class Chunk_t, class FreeList_t>
 891 bool BinaryTreeDictionary<Chunk_t, FreeList_t>::coal_dict_over_populated(size_t size) {
 892   // For the general type of freelists, encourage coalescing by
 893   // returning true.
 894   return true;
 895 }
 896 
 897 #if INCLUDE_ALL_GCS
 898 template <>
 899 bool AFLBinaryTreeDictionary::coal_dict_over_populated(size_t size) {
 900   if (FLSAlwaysCoalesceLarge) return true;
 901 
 902   TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* list_of_size = find_list(size);
 903   // None of requested size implies overpopulated.
 904   return list_of_size == NULL || list_of_size->coal_desired() <= 0 ||
 905          list_of_size->count() > list_of_size->coal_desired();
 906 }
 907 #endif // INCLUDE_ALL_GCS
 908 
 909 // Closures for walking the binary tree.
 910 //   do_list() walks the free list in a node applying the closure
 911 //     to each free chunk in the list
 912 //   do_tree() walks the nodes in the binary tree applying do_list()
 913 //     to each list at each node.
 914 
 915 template <class Chunk_t, class FreeList_t>
 916 class TreeCensusClosure : public StackObj {
 917  protected:
 918   virtual void do_list(FreeList_t* fl) = 0;
 919  public:
 920   virtual void do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
 921 };
 922 
 923 template <class Chunk_t, class FreeList_t>
 924 class AscendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
 925  public:
 926   void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
 927     if (tl != NULL) {
 928       do_tree(tl->left());
 929       this->do_list(tl);
 930       do_tree(tl->right());
 931     }
 932   }
 933 };
 934 
 935 template <class Chunk_t, class FreeList_t>
 936 class DescendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
 937  public:
 938   void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
 939     if (tl != NULL) {
 940       do_tree(tl->right());
 941       this->do_list(tl);
 942       do_tree(tl->left());
 943     }
 944   }
 945 };
 946 
 947 // For each list in the tree, calculate the desired, desired
 948 // coalesce, count before sweep, and surplus before sweep.
 949 template <class Chunk_t, class FreeList_t>
 950 class BeginSweepClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
 951   double _percentage;
 952   float _inter_sweep_current;
 953   float _inter_sweep_estimate;
 954   float _intra_sweep_estimate;
 955 
 956  public:
 957   BeginSweepClosure(double p, float inter_sweep_current,
 958                               float inter_sweep_estimate,
 959                               float intra_sweep_estimate) :
 960    _percentage(p),
 961    _inter_sweep_current(inter_sweep_current),
 962    _inter_sweep_estimate(inter_sweep_estimate),
 963    _intra_sweep_estimate(intra_sweep_estimate) { }
 964 
 965   void do_list(FreeList<Chunk_t>* fl) {}
 966 
 967 #if INCLUDE_ALL_GCS
 968   void do_list(AdaptiveFreeList<Chunk_t>* fl) {
 969     double coalSurplusPercent = _percentage;
 970     fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate);
 971     fl->set_coal_desired((ssize_t)((double)fl->desired() * coalSurplusPercent));
 972     fl->set_before_sweep(fl->count());
 973     fl->set_bfr_surp(fl->surplus());
 974   }
 975 #endif // INCLUDE_ALL_GCS
 976 };
 977 
 978 // Used to search the tree until a condition is met.
 979 // Similar to TreeCensusClosure but searches the
 980 // tree and returns promptly when found.
 981 
 982 template <class Chunk_t, class FreeList_t>
 983 class TreeSearchClosure : public StackObj {
 984  protected:
 985   virtual bool do_list(FreeList_t* fl) = 0;
 986  public:
 987   virtual bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
 988 };
 989 
 990 #if 0 //  Don't need this yet but here for symmetry.
 991 template <class Chunk_t, class FreeList_t>
 992 class AscendTreeSearchClosure : public TreeSearchClosure<Chunk_t> {
 993  public:
 994   bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
 995     if (tl != NULL) {
 996       if (do_tree(tl->left())) return true;
 997       if (do_list(tl)) return true;
 998       if (do_tree(tl->right())) return true;
 999     }
1000     return false;
1001   }
1002 };
1003 #endif
1004 
1005 template <class Chunk_t, class FreeList_t>
1006 class DescendTreeSearchClosure : public TreeSearchClosure<Chunk_t, FreeList_t> {
1007  public:
1008   bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
1009     if (tl != NULL) {
1010       if (do_tree(tl->right())) return true;
1011       if (this->do_list(tl)) return true;
1012       if (do_tree(tl->left())) return true;
1013     }
1014     return false;
1015   }
1016 };
1017 
1018 // Searches the tree for a chunk that ends at the
1019 // specified address.
1020 template <class Chunk_t, class FreeList_t>
1021 class EndTreeSearchClosure : public DescendTreeSearchClosure<Chunk_t, FreeList_t> {
1022   HeapWord* _target;
1023   Chunk_t* _found;
1024 
1025  public:
1026   EndTreeSearchClosure(HeapWord* target) : _target(target), _found(NULL) {}
1027   bool do_list(FreeList_t* fl) {
1028     Chunk_t* item = fl->head();
1029     while (item != NULL) {
1030       if (item->end() == (uintptr_t*) _target) {
1031         _found = item;
1032         return true;
1033       }
1034       item = item->next();
1035     }
1036     return false;
1037   }
1038   Chunk_t* found() { return _found; }
1039 };
1040 
1041 template <class Chunk_t, class FreeList_t>
1042 Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_chunk_ends_at(HeapWord* target) const {
1043   EndTreeSearchClosure<Chunk_t, FreeList_t> etsc(target);
1044   bool found_target = etsc.do_tree(root());
1045   assert(found_target || etsc.found() == NULL, "Consistency check");
1046   assert(!found_target || etsc.found() != NULL, "Consistency check");
1047   return etsc.found();
1048 }
1049 
1050 template <class Chunk_t, class FreeList_t>
1051 void BinaryTreeDictionary<Chunk_t, FreeList_t>::begin_sweep_dict_census(double coalSurplusPercent,
1052   float inter_sweep_current, float inter_sweep_estimate, float intra_sweep_estimate) {
1053   BeginSweepClosure<Chunk_t, FreeList_t> bsc(coalSurplusPercent, inter_sweep_current,
1054                                             inter_sweep_estimate,
1055                                             intra_sweep_estimate);
1056   bsc.do_tree(root());
1057 }
1058 
1059 // Closures and methods for calculating total bytes returned to the
1060 // free lists in the tree.
1061 #ifndef PRODUCT
1062 template <class Chunk_t, class FreeList_t>
1063 class InitializeDictReturnedBytesClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
1064    public:
1065   void do_list(FreeList_t* fl) {
1066     fl->set_returned_bytes(0);
1067   }
1068 };
1069 
1070 template <class Chunk_t, class FreeList_t>
1071 void BinaryTreeDictionary<Chunk_t, FreeList_t>::initialize_dict_returned_bytes() {
1072   InitializeDictReturnedBytesClosure<Chunk_t, FreeList_t> idrb;
1073   idrb.do_tree(root());
1074 }
1075 
1076 template <class Chunk_t, class FreeList_t>
1077 class ReturnedBytesClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
1078   size_t _dict_returned_bytes;
1079  public:
1080   ReturnedBytesClosure() { _dict_returned_bytes = 0; }
1081   void do_list(FreeList_t* fl) {
1082     _dict_returned_bytes += fl->returned_bytes();
1083   }
1084   size_t dict_returned_bytes() { return _dict_returned_bytes; }
1085 };
1086 
1087 template <class Chunk_t, class FreeList_t>
1088 size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_dict_returned_bytes() {
1089   ReturnedBytesClosure<Chunk_t, FreeList_t> rbc;
1090   rbc.do_tree(root());
1091 
1092   return rbc.dict_returned_bytes();
1093 }
1094 
1095 // Count the number of entries in the tree.
1096 template <class Chunk_t, class FreeList_t>
1097 class treeCountClosure : public DescendTreeCensusClosure<Chunk_t, FreeList_t> {
1098  public:
1099   uint count;
1100   treeCountClosure(uint c) { count = c; }
1101   void do_list(FreeList_t* fl) {
1102     count++;
1103   }
1104 };
1105 
1106 template <class Chunk_t, class FreeList_t>
1107 size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_count() {
1108   treeCountClosure<Chunk_t, FreeList_t> ctc(0);
1109   ctc.do_tree(root());
1110   return ctc.count;
1111 }
1112 #endif // PRODUCT
1113 
1114 // Calculate surpluses for the lists in the tree.
1115 template <class Chunk_t, class FreeList_t>
1116 class setTreeSurplusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
1117   double percentage;
1118  public:
1119   setTreeSurplusClosure(double v) { percentage = v; }
1120   void do_list(FreeList<Chunk_t>* fl) {}
1121 
1122 #if INCLUDE_ALL_GCS
1123   void do_list(AdaptiveFreeList<Chunk_t>* fl) {
1124     double splitSurplusPercent = percentage;
1125     fl->set_surplus(fl->count() -
1126                    (ssize_t)((double)fl->desired() * splitSurplusPercent));
1127   }
1128 #endif // INCLUDE_ALL_GCS
1129 };
1130 
1131 template <class Chunk_t, class FreeList_t>
1132 void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_tree_surplus(double splitSurplusPercent) {
1133   setTreeSurplusClosure<Chunk_t, FreeList_t> sts(splitSurplusPercent);
1134   sts.do_tree(root());
1135 }
1136 
1137 // Set hints for the lists in the tree.
1138 template <class Chunk_t, class FreeList_t>
1139 class setTreeHintsClosure : public DescendTreeCensusClosure<Chunk_t, FreeList_t> {
1140   size_t hint;
1141  public:
1142   setTreeHintsClosure(size_t v) { hint = v; }
1143   void do_list(FreeList<Chunk_t>* fl) {}
1144 
1145 #if INCLUDE_ALL_GCS
1146   void do_list(AdaptiveFreeList<Chunk_t>* fl) {
1147     fl->set_hint(hint);
1148     assert(fl->hint() == 0 || fl->hint() > fl->size(),
1149       "Current hint is inconsistent");
1150     if (fl->surplus() > 0) {
1151       hint = fl->size();
1152     }
1153   }
1154 #endif // INCLUDE_ALL_GCS
1155 };
1156 
1157 template <class Chunk_t, class FreeList_t>
1158 void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_tree_hints(void) {
1159   setTreeHintsClosure<Chunk_t, FreeList_t> sth(0);
1160   sth.do_tree(root());
1161 }
1162 
1163 // Save count before previous sweep and splits and coalesces.
1164 template <class Chunk_t, class FreeList_t>
1165 class clearTreeCensusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
1166   void do_list(FreeList<Chunk_t>* fl) {}
1167 
1168 #if INCLUDE_ALL_GCS
1169   void do_list(AdaptiveFreeList<Chunk_t>* fl) {
1170     fl->set_prev_sweep(fl->count());
1171     fl->set_coal_births(0);
1172     fl->set_coal_deaths(0);
1173     fl->set_split_births(0);
1174     fl->set_split_deaths(0);
1175   }
1176 #endif // INCLUDE_ALL_GCS
1177 };
1178 
1179 template <class Chunk_t, class FreeList_t>
1180 void BinaryTreeDictionary<Chunk_t, FreeList_t>::clear_tree_census(void) {
1181   clearTreeCensusClosure<Chunk_t, FreeList_t> ctc;
1182   ctc.do_tree(root());
1183 }
1184 
1185 // Do reporting and post sweep clean up.
1186 template <class Chunk_t, class FreeList_t>
1187 void BinaryTreeDictionary<Chunk_t, FreeList_t>::end_sweep_dict_census(double splitSurplusPercent) {
1188   // Does walking the tree 3 times hurt?
1189   set_tree_surplus(splitSurplusPercent);
1190   set_tree_hints();
1191   LogTarget(Trace, gc, freelist, stats) log;
1192   if (log.is_enabled()) {
1193     LogStream out(log);
1194     report_statistics(&out);
1195   }
1196   clear_tree_census();
1197 }
1198 
1199 // Print summary statistics
1200 template <class Chunk_t, class FreeList_t>
1201 void BinaryTreeDictionary<Chunk_t, FreeList_t>::report_statistics(outputStream* st) const {
1202   FreeBlockDictionary<Chunk_t>::verify_par_locked();
1203   st->print_cr("Statistics for BinaryTreeDictionary:");
1204   st->print_cr("------------------------------------");
1205   size_t total_size = total_chunk_size(debug_only(NULL));
1206   size_t free_blocks = num_free_blocks();
1207   st->print_cr("Total Free Space: " SIZE_FORMAT, total_size);
1208   st->print_cr("Max   Chunk Size: " SIZE_FORMAT, max_chunk_size());
1209   st->print_cr("Number of Blocks: " SIZE_FORMAT, free_blocks);
1210   if (free_blocks > 0) {
1211     st->print_cr("Av.  Block  Size: " SIZE_FORMAT, total_size/free_blocks);
1212   }
1213   st->print_cr("Tree      Height: " SIZE_FORMAT, tree_height());
1214 }
1215 
1216 // Print census information - counts, births, deaths, etc.
1217 // for each list in the tree.  Also print some summary
1218 // information.
1219 template <class Chunk_t, class FreeList_t>
1220 class PrintTreeCensusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
1221   int _print_line;
1222   size_t _total_free;
1223   FreeList_t _total;
1224 
1225  public:
1226   PrintTreeCensusClosure() {
1227     _print_line = 0;
1228     _total_free = 0;
1229   }
1230   FreeList_t* total() { return &_total; }
1231   size_t total_free() { return _total_free; }
1232   void do_list(FreeList<Chunk_t>* fl) {
1233     LogStreamHandle(Debug, gc, freelist, census) out;
1234 
1235     if (++_print_line >= 40) {
1236       FreeList_t::print_labels_on(&out, "size");
1237       _print_line = 0;
1238     }
1239     fl->print_on(&out);
1240     _total_free += fl->count() * fl->size();
1241     total()->set_count(total()->count() + fl->count());
1242   }
1243 
1244 #if INCLUDE_ALL_GCS
1245   void do_list(AdaptiveFreeList<Chunk_t>* fl) {
1246     LogStreamHandle(Debug, gc, freelist, census) out;
1247 
1248     if (++_print_line >= 40) {
1249       FreeList_t::print_labels_on(&out, "size");
1250       _print_line = 0;
1251     }
1252     fl->print_on(&out);
1253     _total_free +=           fl->count()             * fl->size()        ;
1254     total()->set_count(      total()->count()        + fl->count()      );
1255     total()->set_bfr_surp(   total()->bfr_surp()     + fl->bfr_surp()    );
1256     total()->set_surplus(    total()->split_deaths() + fl->surplus()    );
1257     total()->set_desired(    total()->desired()      + fl->desired()    );
1258     total()->set_prev_sweep(  total()->prev_sweep()   + fl->prev_sweep()  );
1259     total()->set_before_sweep(total()->before_sweep() + fl->before_sweep());
1260     total()->set_coal_births( total()->coal_births()  + fl->coal_births() );
1261     total()->set_coal_deaths( total()->coal_deaths()  + fl->coal_deaths() );
1262     total()->set_split_births(total()->split_births() + fl->split_births());
1263     total()->set_split_deaths(total()->split_deaths() + fl->split_deaths());
1264   }
1265 #endif // INCLUDE_ALL_GCS
1266 };
1267 
1268 template <class Chunk_t, class FreeList_t>
1269 void BinaryTreeDictionary<Chunk_t, FreeList_t>::print_dict_census(outputStream* st) const {
1270 
1271   st->print("BinaryTree");
1272   FreeList_t::print_labels_on(st, "size");
1273   PrintTreeCensusClosure<Chunk_t, FreeList_t> ptc;
1274   ptc.do_tree(root());
1275 
1276   FreeList_t* total = ptc.total();
1277   FreeList_t::print_labels_on(st, " ");
1278 }
1279 
1280 #if INCLUDE_ALL_GCS
1281 template <>
1282 void AFLBinaryTreeDictionary::print_dict_census(outputStream* st) const {
1283 
1284   st->print_cr("BinaryTree");
1285   AdaptiveFreeList<FreeChunk>::print_labels_on(st, "size");
1286   PrintTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > ptc;
1287   ptc.do_tree(root());
1288 
1289   AdaptiveFreeList<FreeChunk>* total = ptc.total();
1290   AdaptiveFreeList<FreeChunk>::print_labels_on(st, " ");
1291   total->print_on(st, "TOTAL\t");
1292   st->print_cr("total_free(words): " SIZE_FORMAT_W(16) " growth: %8.5f  deficit: %8.5f",
1293                ptc.total_free(),
1294                (double)(total->split_births() + total->coal_births()
1295                       - total->split_deaths() - total->coal_deaths())
1296                /(total->prev_sweep() != 0 ? (double)total->prev_sweep() : 1.0),
1297               (double)(total->desired() - total->count())
1298               /(total->desired() != 0 ? (double)total->desired() : 1.0));
1299 }
1300 #endif // INCLUDE_ALL_GCS
1301 
1302 template <class Chunk_t, class FreeList_t>
1303 class PrintFreeListsClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
1304   outputStream* _st;
1305   int _print_line;
1306 
1307  public:
1308   PrintFreeListsClosure(outputStream* st) {
1309     _st = st;
1310     _print_line = 0;
1311   }
1312   void do_list(FreeList_t* fl) {
1313     if (++_print_line >= 40) {
1314       FreeList_t::print_labels_on(_st, "size");
1315       _print_line = 0;
1316     }
1317     fl->print_on(_st);
1318     size_t sz = fl->size();
1319     for (Chunk_t* fc = fl->head(); fc != NULL;
1320          fc = fc->next()) {
1321       _st->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ")  %s",
1322                     p2i(fc), p2i((HeapWord*)fc + sz),
1323                     fc->cantCoalesce() ? "\t CC" : "");
1324     }
1325   }
1326 };
1327 
1328 template <class Chunk_t, class FreeList_t>
1329 void BinaryTreeDictionary<Chunk_t, FreeList_t>::print_free_lists(outputStream* st) const {
1330 
1331   FreeList_t::print_labels_on(st, "size");
1332   PrintFreeListsClosure<Chunk_t, FreeList_t> pflc(st);
1333   pflc.do_tree(root());
1334 }
1335 
1336 // Verify the following tree invariants:
1337 // . _root has no parent
1338 // . parent and child point to each other
1339 // . each node's key correctly related to that of its child(ren)
1340 template <class Chunk_t, class FreeList_t>
1341 void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree() const {
1342   guarantee(root() == NULL || total_free_blocks() == 0 ||
1343     total_size() != 0, "_total_size shouldn't be 0?");
1344   guarantee(root() == NULL || root()->parent() == NULL, "_root shouldn't have parent");
1345   verify_tree_helper(root());
1346 }
1347 
1348 template <class Chunk_t, class FreeList_t>
1349 size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_prev_free_ptrs(TreeList<Chunk_t, FreeList_t>* tl) {
1350   size_t ct = 0;
1351   for (Chunk_t* curFC = tl->head(); curFC != NULL; curFC = curFC->next()) {
1352     ct++;
1353     assert(curFC->prev() == NULL || curFC->prev()->is_free(),
1354       "Chunk should be free");
1355   }
1356   return ct;
1357 }
1358 
1359 // Note: this helper is recursive rather than iterative, so use with
1360 // caution on very deep trees; and watch out for stack overflow errors;
1361 // In general, to be used only for debugging.
1362 template <class Chunk_t, class FreeList_t>
1363 void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
1364   if (tl == NULL)
1365     return;
1366   guarantee(tl->size() != 0, "A list must has a size");
1367   guarantee(tl->left()  == NULL || tl->left()->parent()  == tl,
1368          "parent<-/->left");
1369   guarantee(tl->right() == NULL || tl->right()->parent() == tl,
1370          "parent<-/->right");;
1371   guarantee(tl->left() == NULL  || tl->left()->size()    <  tl->size(),
1372          "parent !> left");
1373   guarantee(tl->right() == NULL || tl->right()->size()   >  tl->size(),
1374          "parent !< left");
1375   guarantee(tl->head() == NULL || tl->head()->is_free(), "!Free");
1376   guarantee(tl->head() == NULL || tl->head_as_TreeChunk()->list() == tl,
1377     "list inconsistency");
1378   guarantee(tl->count() > 0 || (tl->head() == NULL && tl->tail() == NULL),
1379     "list count is inconsistent");
1380   guarantee(tl->count() > 1 || tl->head() == tl->tail(),
1381     "list is incorrectly constructed");
1382   size_t count = verify_prev_free_ptrs(tl);
1383   guarantee(count == (size_t)tl->count(), "Node count is incorrect");
1384   if (tl->head() != NULL) {
1385     tl->head_as_TreeChunk()->verify_tree_chunk_list();
1386   }
1387   verify_tree_helper(tl->left());
1388   verify_tree_helper(tl->right());
1389 }
1390 
1391 template <class Chunk_t, class FreeList_t>
1392 void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify() const {
1393   verify_tree();
1394   guarantee(total_size() == total_size_in_tree(root()), "Total Size inconsistency");
1395 }
1396 
1397 template class TreeList<Metablock, FreeList<Metablock> >;
1398 template class BinaryTreeDictionary<Metablock, FreeList<Metablock> >;
1399 template class TreeChunk<Metablock, FreeList<Metablock> >;
1400 
1401 template class TreeList<Metachunk, FreeList<Metachunk> >;
1402 template class BinaryTreeDictionary<Metachunk, FreeList<Metachunk> >;
1403 template class TreeChunk<Metachunk, FreeList<Metachunk> >;
1404 
1405 
1406 #if INCLUDE_ALL_GCS
1407 // Explicitly instantiate these types for FreeChunk.
1408 template class TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >;
1409 template class BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> >;
1410 template class TreeChunk<FreeChunk, AdaptiveFreeList<FreeChunk> >;
1411 
1412 #endif // INCLUDE_ALL_GCS