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