src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp

changeset 435
a61af66fc99e
child 447
6432c3bb6240
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/binaryTreeDictionary.cpp	Sat Dec 01 00:00:00 2007 +0000
     1.3 @@ -0,0 +1,1210 @@
     1.4 +/*
     1.5 + * Copyright 2001-2006 Sun Microsystems, Inc.  All Rights Reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
    1.24 + * have any questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +# include "incls/_precompiled.incl"
    1.29 +# include "incls/_binaryTreeDictionary.cpp.incl"
    1.30 +
    1.31 +////////////////////////////////////////////////////////////////////////////////
    1.32 +// A binary tree based search structure for free blocks.
    1.33 +// This is currently used in the Concurrent Mark&Sweep implementation.
    1.34 +////////////////////////////////////////////////////////////////////////////////
    1.35 +
    1.36 +TreeChunk* TreeChunk::as_TreeChunk(FreeChunk* fc) {
    1.37 +  // Do some assertion checking here.
    1.38 +  return (TreeChunk*) fc;
    1.39 +}
    1.40 +
    1.41 +void TreeChunk::verifyTreeChunkList() const {
    1.42 +  TreeChunk* nextTC = (TreeChunk*)next();
    1.43 +  if (prev() != NULL) { // interior list node shouldn'r have tree fields
    1.44 +    guarantee(embedded_list()->parent() == NULL && embedded_list()->left() == NULL &&
    1.45 +              embedded_list()->right()  == NULL, "should be clear");
    1.46 +  }
    1.47 +  if (nextTC != NULL) {
    1.48 +    guarantee(as_TreeChunk(nextTC->prev()) == this, "broken chain");
    1.49 +    guarantee(nextTC->size() == size(), "wrong size");
    1.50 +    nextTC->verifyTreeChunkList();
    1.51 +  }
    1.52 +}
    1.53 +
    1.54 +
    1.55 +TreeList* TreeList::as_TreeList(TreeChunk* tc) {
    1.56 +  // This first free chunk in the list will be the tree list.
    1.57 +  assert(tc->size() >= sizeof(TreeChunk), "Chunk is too small for a TreeChunk");
    1.58 +  TreeList* tl = tc->embedded_list();
    1.59 +  tc->set_list(tl);
    1.60 +#ifdef ASSERT
    1.61 +  tl->set_protecting_lock(NULL);
    1.62 +#endif
    1.63 +  tl->set_hint(0);
    1.64 +  tl->set_size(tc->size());
    1.65 +  tl->link_head(tc);
    1.66 +  tl->link_tail(tc);
    1.67 +  tl->set_count(1);
    1.68 +  tl->init_statistics();
    1.69 +  tl->setParent(NULL);
    1.70 +  tl->setLeft(NULL);
    1.71 +  tl->setRight(NULL);
    1.72 +  return tl;
    1.73 +}
    1.74 +TreeList* TreeList::as_TreeList(HeapWord* addr, size_t size) {
    1.75 +  TreeChunk* tc = (TreeChunk*) addr;
    1.76 +  assert(size >= sizeof(TreeChunk), "Chunk is too small for a TreeChunk");
    1.77 +  assert(tc->size() == 0 && tc->prev() == NULL && tc->next() == NULL,
    1.78 +    "Space should be clear");
    1.79 +  tc->setSize(size);
    1.80 +  tc->linkPrev(NULL);
    1.81 +  tc->linkNext(NULL);
    1.82 +  TreeList* tl = TreeList::as_TreeList(tc);
    1.83 +  return tl;
    1.84 +}
    1.85 +
    1.86 +TreeList* TreeList::removeChunkReplaceIfNeeded(TreeChunk* tc) {
    1.87 +
    1.88 +  TreeList* retTL = this;
    1.89 +  FreeChunk* list = head();
    1.90 +  assert(!list || list != list->next(), "Chunk on list twice");
    1.91 +  assert(tc != NULL, "Chunk being removed is NULL");
    1.92 +  assert(parent() == NULL || this == parent()->left() ||
    1.93 +    this == parent()->right(), "list is inconsistent");
    1.94 +  assert(tc->isFree(), "Header is not marked correctly");
    1.95 +  assert(head() == NULL || head()->prev() == NULL, "list invariant");
    1.96 +  assert(tail() == NULL || tail()->next() == NULL, "list invariant");
    1.97 +
    1.98 +  FreeChunk* prevFC = tc->prev();
    1.99 +  TreeChunk* nextTC = TreeChunk::as_TreeChunk(tc->next());
   1.100 +  assert(list != NULL, "should have at least the target chunk");
   1.101 +
   1.102 +  // Is this the first item on the list?
   1.103 +  if (tc == list) {
   1.104 +    // The "getChunk..." functions for a TreeList will not return the
   1.105 +    // first chunk in the list unless it is the last chunk in the list
   1.106 +    // because the first chunk is also acting as the tree node.
   1.107 +    // When coalescing happens, however, the first chunk in the a tree
   1.108 +    // list can be the start of a free range.  Free ranges are removed
   1.109 +    // from the free lists so that they are not available to be
   1.110 +    // allocated when the sweeper yields (giving up the free list lock)
   1.111 +    // to allow mutator activity.  If this chunk is the first in the
   1.112 +    // list and is not the last in the list, do the work to copy the
   1.113 +    // TreeList from the first chunk to the next chunk and update all
   1.114 +    // the TreeList pointers in the chunks in the list.
   1.115 +    if (nextTC == NULL) {
   1.116 +      assert(prevFC == NULL, "Not last chunk in the list")
   1.117 +      set_tail(NULL);
   1.118 +      set_head(NULL);
   1.119 +    } else {
   1.120 +      // copy embedded list.
   1.121 +      nextTC->set_embedded_list(tc->embedded_list());
   1.122 +      retTL = nextTC->embedded_list();
   1.123 +      // Fix the pointer to the list in each chunk in the list.
   1.124 +      // This can be slow for a long list.  Consider having
   1.125 +      // an option that does not allow the first chunk on the
   1.126 +      // list to be coalesced.
   1.127 +      for (TreeChunk* curTC = nextTC; curTC != NULL;
   1.128 +          curTC = TreeChunk::as_TreeChunk(curTC->next())) {
   1.129 +        curTC->set_list(retTL);
   1.130 +      }
   1.131 +      // Fix the parent to point to the new TreeList.
   1.132 +      if (retTL->parent() != NULL) {
   1.133 +        if (this == retTL->parent()->left()) {
   1.134 +          retTL->parent()->setLeft(retTL);
   1.135 +        } else {
   1.136 +          assert(this == retTL->parent()->right(), "Parent is incorrect");
   1.137 +          retTL->parent()->setRight(retTL);
   1.138 +        }
   1.139 +      }
   1.140 +      // Fix the children's parent pointers to point to the
   1.141 +      // new list.
   1.142 +      assert(right() == retTL->right(), "Should have been copied");
   1.143 +      if (retTL->right() != NULL) {
   1.144 +        retTL->right()->setParent(retTL);
   1.145 +      }
   1.146 +      assert(left() == retTL->left(), "Should have been copied");
   1.147 +      if (retTL->left() != NULL) {
   1.148 +        retTL->left()->setParent(retTL);
   1.149 +      }
   1.150 +      retTL->link_head(nextTC);
   1.151 +      assert(nextTC->isFree(), "Should be a free chunk");
   1.152 +    }
   1.153 +  } else {
   1.154 +    if (nextTC == NULL) {
   1.155 +      // Removing chunk at tail of list
   1.156 +      link_tail(prevFC);
   1.157 +    }
   1.158 +    // Chunk is interior to the list
   1.159 +    prevFC->linkAfter(nextTC);
   1.160 +  }
   1.161 +
   1.162 +  // Below this point the embeded TreeList being used for the
   1.163 +  // tree node may have changed. Don't use "this"
   1.164 +  // TreeList*.
   1.165 +  // chunk should still be a free chunk (bit set in _prev)
   1.166 +  assert(!retTL->head() || retTL->size() == retTL->head()->size(),
   1.167 +    "Wrong sized chunk in list");
   1.168 +  debug_only(
   1.169 +    tc->linkPrev(NULL);
   1.170 +    tc->linkNext(NULL);
   1.171 +    tc->set_list(NULL);
   1.172 +    bool prev_found = false;
   1.173 +    bool next_found = false;
   1.174 +    for (FreeChunk* curFC = retTL->head();
   1.175 +         curFC != NULL; curFC = curFC->next()) {
   1.176 +      assert(curFC != tc, "Chunk is still in list");
   1.177 +      if (curFC == prevFC) {
   1.178 +        prev_found = true;
   1.179 +      }
   1.180 +      if (curFC == nextTC) {
   1.181 +        next_found = true;
   1.182 +      }
   1.183 +    }
   1.184 +    assert(prevFC == NULL || prev_found, "Chunk was lost from list");
   1.185 +    assert(nextTC == NULL || next_found, "Chunk was lost from list");
   1.186 +    assert(retTL->parent() == NULL ||
   1.187 +           retTL == retTL->parent()->left() ||
   1.188 +           retTL == retTL->parent()->right(),
   1.189 +           "list is inconsistent");
   1.190 +  )
   1.191 +  retTL->decrement_count();
   1.192 +
   1.193 +  assert(tc->isFree(), "Should still be a free chunk");
   1.194 +  assert(retTL->head() == NULL || retTL->head()->prev() == NULL,
   1.195 +    "list invariant");
   1.196 +  assert(retTL->tail() == NULL || retTL->tail()->next() == NULL,
   1.197 +    "list invariant");
   1.198 +  return retTL;
   1.199 +}
   1.200 +void TreeList::returnChunkAtTail(TreeChunk* chunk) {
   1.201 +  assert(chunk != NULL, "returning NULL chunk");
   1.202 +  assert(chunk->list() == this, "list should be set for chunk");
   1.203 +  assert(tail() != NULL, "The tree list is embedded in the first chunk");
   1.204 +  // which means that the list can never be empty.
   1.205 +  assert(!verifyChunkInFreeLists(chunk), "Double entry");
   1.206 +  assert(head() == NULL || head()->prev() == NULL, "list invariant");
   1.207 +  assert(tail() == NULL || tail()->next() == NULL, "list invariant");
   1.208 +
   1.209 +  FreeChunk* fc = tail();
   1.210 +  fc->linkAfter(chunk);
   1.211 +  link_tail(chunk);
   1.212 +
   1.213 +  assert(!tail() || size() == tail()->size(), "Wrong sized chunk in list");
   1.214 +  increment_count();
   1.215 +  debug_only(increment_returnedBytes_by(chunk->size()*sizeof(HeapWord));)
   1.216 +  assert(head() == NULL || head()->prev() == NULL, "list invariant");
   1.217 +  assert(tail() == NULL || tail()->next() == NULL, "list invariant");
   1.218 +}
   1.219 +
   1.220 +// Add this chunk at the head of the list.  "At the head of the list"
   1.221 +// is defined to be after the chunk pointer to by head().  This is
   1.222 +// because the TreeList is embedded in the first TreeChunk in the
   1.223 +// list.  See the definition of TreeChunk.
   1.224 +void TreeList::returnChunkAtHead(TreeChunk* chunk) {
   1.225 +  assert(chunk->list() == this, "list should be set for chunk");
   1.226 +  assert(head() != NULL, "The tree list is embedded in the first chunk");
   1.227 +  assert(chunk != NULL, "returning NULL chunk");
   1.228 +  assert(!verifyChunkInFreeLists(chunk), "Double entry");
   1.229 +  assert(head() == NULL || head()->prev() == NULL, "list invariant");
   1.230 +  assert(tail() == NULL || tail()->next() == NULL, "list invariant");
   1.231 +
   1.232 +  FreeChunk* fc = head()->next();
   1.233 +  if (fc != NULL) {
   1.234 +    chunk->linkAfter(fc);
   1.235 +  } else {
   1.236 +    assert(tail() == NULL, "List is inconsistent");
   1.237 +    link_tail(chunk);
   1.238 +  }
   1.239 +  head()->linkAfter(chunk);
   1.240 +  assert(!head() || size() == head()->size(), "Wrong sized chunk in list");
   1.241 +  increment_count();
   1.242 +  debug_only(increment_returnedBytes_by(chunk->size()*sizeof(HeapWord));)
   1.243 +  assert(head() == NULL || head()->prev() == NULL, "list invariant");
   1.244 +  assert(tail() == NULL || tail()->next() == NULL, "list invariant");
   1.245 +}
   1.246 +
   1.247 +TreeChunk* TreeList::head_as_TreeChunk() {
   1.248 +  assert(head() == NULL || TreeChunk::as_TreeChunk(head())->list() == this,
   1.249 +    "Wrong type of chunk?");
   1.250 +  return TreeChunk::as_TreeChunk(head());
   1.251 +}
   1.252 +
   1.253 +TreeChunk* TreeList::first_available() {
   1.254 +  guarantee(head() != NULL, "The head of the list cannot be NULL");
   1.255 +  FreeChunk* fc = head()->next();
   1.256 +  TreeChunk* retTC;
   1.257 +  if (fc == NULL) {
   1.258 +    retTC = head_as_TreeChunk();
   1.259 +  } else {
   1.260 +    retTC = TreeChunk::as_TreeChunk(fc);
   1.261 +  }
   1.262 +  assert(retTC->list() == this, "Wrong type of chunk.");
   1.263 +  return retTC;
   1.264 +}
   1.265 +
   1.266 +BinaryTreeDictionary::BinaryTreeDictionary(MemRegion mr, bool splay):
   1.267 +  _splay(splay)
   1.268 +{
   1.269 +  assert(mr.byte_size() > MIN_TREE_CHUNK_SIZE, "minimum chunk size");
   1.270 +
   1.271 +  reset(mr);
   1.272 +  assert(root()->left() == NULL, "reset check failed");
   1.273 +  assert(root()->right() == NULL, "reset check failed");
   1.274 +  assert(root()->head()->next() == NULL, "reset check failed");
   1.275 +  assert(root()->head()->prev() == NULL, "reset check failed");
   1.276 +  assert(totalSize() == root()->size(), "reset check failed");
   1.277 +  assert(totalFreeBlocks() == 1, "reset check failed");
   1.278 +}
   1.279 +
   1.280 +void BinaryTreeDictionary::inc_totalSize(size_t inc) {
   1.281 +  _totalSize = _totalSize + inc;
   1.282 +}
   1.283 +
   1.284 +void BinaryTreeDictionary::dec_totalSize(size_t dec) {
   1.285 +  _totalSize = _totalSize - dec;
   1.286 +}
   1.287 +
   1.288 +void BinaryTreeDictionary::reset(MemRegion mr) {
   1.289 +  assert(mr.byte_size() > MIN_TREE_CHUNK_SIZE, "minimum chunk size");
   1.290 +  set_root(TreeList::as_TreeList(mr.start(), mr.word_size()));
   1.291 +  set_totalSize(mr.word_size());
   1.292 +  set_totalFreeBlocks(1);
   1.293 +}
   1.294 +
   1.295 +void BinaryTreeDictionary::reset(HeapWord* addr, size_t byte_size) {
   1.296 +  MemRegion mr(addr, heap_word_size(byte_size));
   1.297 +  reset(mr);
   1.298 +}
   1.299 +
   1.300 +void BinaryTreeDictionary::reset() {
   1.301 +  set_root(NULL);
   1.302 +  set_totalSize(0);
   1.303 +  set_totalFreeBlocks(0);
   1.304 +}
   1.305 +
   1.306 +// Get a free block of size at least size from tree, or NULL.
   1.307 +// If a splay step is requested, the removal algorithm (only) incorporates
   1.308 +// a splay step as follows:
   1.309 +// . the search proceeds down the tree looking for a possible
   1.310 +//   match. At the (closest) matching location, an appropriate splay step is applied
   1.311 +//   (zig, zig-zig or zig-zag). A chunk of the appropriate size is then returned
   1.312 +//   if available, and if it's the last chunk, the node is deleted. A deteleted
   1.313 +//   node is replaced in place by its tree successor.
   1.314 +TreeChunk*
   1.315 +BinaryTreeDictionary::getChunkFromTree(size_t size, Dither dither, bool splay)
   1.316 +{
   1.317 +  TreeList *curTL, *prevTL;
   1.318 +  TreeChunk* retTC = NULL;
   1.319 +  assert(size >= MIN_TREE_CHUNK_SIZE, "minimum chunk size");
   1.320 +  if (FLSVerifyDictionary) {
   1.321 +    verifyTree();
   1.322 +  }
   1.323 +  // starting at the root, work downwards trying to find match.
   1.324 +  // Remember the last node of size too great or too small.
   1.325 +  for (prevTL = curTL = root(); curTL != NULL;) {
   1.326 +    if (curTL->size() == size) {        // exact match
   1.327 +      break;
   1.328 +    }
   1.329 +    prevTL = curTL;
   1.330 +    if (curTL->size() < size) {        // proceed to right sub-tree
   1.331 +      curTL = curTL->right();
   1.332 +    } else {                           // proceed to left sub-tree
   1.333 +      assert(curTL->size() > size, "size inconsistency");
   1.334 +      curTL = curTL->left();
   1.335 +    }
   1.336 +  }
   1.337 +  if (curTL == NULL) { // couldn't find exact match
   1.338 +    // try and find the next larger size by walking back up the search path
   1.339 +    for (curTL = prevTL; curTL != NULL;) {
   1.340 +      if (curTL->size() >= size) break;
   1.341 +      else curTL = curTL->parent();
   1.342 +    }
   1.343 +    assert(curTL == NULL || curTL->count() > 0,
   1.344 +      "An empty list should not be in the tree");
   1.345 +  }
   1.346 +  if (curTL != NULL) {
   1.347 +    assert(curTL->size() >= size, "size inconsistency");
   1.348 +    if (UseCMSAdaptiveFreeLists) {
   1.349 +
   1.350 +      // A candidate chunk has been found.  If it is already under
   1.351 +      // populated, get a chunk associated with the hint for this
   1.352 +      // chunk.
   1.353 +      if (curTL->surplus() <= 0) {
   1.354 +        /* Use the hint to find a size with a surplus, and reset the hint. */
   1.355 +        TreeList* hintTL = curTL;
   1.356 +        while (hintTL->hint() != 0) {
   1.357 +          assert(hintTL->hint() == 0 || hintTL->hint() > hintTL->size(),
   1.358 +            "hint points in the wrong direction");
   1.359 +          hintTL = findList(hintTL->hint());
   1.360 +          assert(curTL != hintTL, "Infinite loop");
   1.361 +          if (hintTL == NULL ||
   1.362 +              hintTL == curTL /* Should not happen but protect against it */ ) {
   1.363 +            // No useful hint.  Set the hint to NULL and go on.
   1.364 +            curTL->set_hint(0);
   1.365 +            break;
   1.366 +          }
   1.367 +          assert(hintTL->size() > size, "hint is inconsistent");
   1.368 +          if (hintTL->surplus() > 0) {
   1.369 +            // The hint led to a list that has a surplus.  Use it.
   1.370 +            // Set the hint for the candidate to an overpopulated
   1.371 +            // size.
   1.372 +            curTL->set_hint(hintTL->size());
   1.373 +            // Change the candidate.
   1.374 +            curTL = hintTL;
   1.375 +            break;
   1.376 +          }
   1.377 +          // The evm code reset the hint of the candidate as
   1.378 +          // at an interrim point.  Why?  Seems like this leaves
   1.379 +          // the hint pointing to a list that didn't work.
   1.380 +          // curTL->set_hint(hintTL->size());
   1.381 +        }
   1.382 +      }
   1.383 +    }
   1.384 +    // don't waste time splaying if chunk's singleton
   1.385 +    if (splay && curTL->head()->next() != NULL) {
   1.386 +      semiSplayStep(curTL);
   1.387 +    }
   1.388 +    retTC = curTL->first_available();
   1.389 +    assert((retTC != NULL) && (curTL->count() > 0),
   1.390 +      "A list in the binary tree should not be NULL");
   1.391 +    assert(retTC->size() >= size,
   1.392 +      "A chunk of the wrong size was found");
   1.393 +    removeChunkFromTree(retTC);
   1.394 +    assert(retTC->isFree(), "Header is not marked correctly");
   1.395 +  }
   1.396 +
   1.397 +  if (FLSVerifyDictionary) {
   1.398 +    verify();
   1.399 +  }
   1.400 +  return retTC;
   1.401 +}
   1.402 +
   1.403 +TreeList* BinaryTreeDictionary::findList(size_t size) const {
   1.404 +  TreeList* curTL;
   1.405 +  for (curTL = root(); curTL != NULL;) {
   1.406 +    if (curTL->size() == size) {        // exact match
   1.407 +      break;
   1.408 +    }
   1.409 +
   1.410 +    if (curTL->size() < size) {        // proceed to right sub-tree
   1.411 +      curTL = curTL->right();
   1.412 +    } else {                           // proceed to left sub-tree
   1.413 +      assert(curTL->size() > size, "size inconsistency");
   1.414 +      curTL = curTL->left();
   1.415 +    }
   1.416 +  }
   1.417 +  return curTL;
   1.418 +}
   1.419 +
   1.420 +
   1.421 +bool BinaryTreeDictionary::verifyChunkInFreeLists(FreeChunk* tc) const {
   1.422 +  size_t size = tc->size();
   1.423 +  TreeList* tl = findList(size);
   1.424 +  if (tl == NULL) {
   1.425 +    return false;
   1.426 +  } else {
   1.427 +    return tl->verifyChunkInFreeLists(tc);
   1.428 +  }
   1.429 +}
   1.430 +
   1.431 +FreeChunk* BinaryTreeDictionary::findLargestDict() const {
   1.432 +  TreeList *curTL = root();
   1.433 +  if (curTL != NULL) {
   1.434 +    while(curTL->right() != NULL) curTL = curTL->right();
   1.435 +    return curTL->first_available();
   1.436 +  } else {
   1.437 +    return NULL;
   1.438 +  }
   1.439 +}
   1.440 +
   1.441 +// Remove the current chunk from the tree.  If it is not the last
   1.442 +// chunk in a list on a tree node, just unlink it.
   1.443 +// If it is the last chunk in the list (the next link is NULL),
   1.444 +// remove the node and repair the tree.
   1.445 +TreeChunk*
   1.446 +BinaryTreeDictionary::removeChunkFromTree(TreeChunk* tc) {
   1.447 +  assert(tc != NULL, "Should not call with a NULL chunk");
   1.448 +  assert(tc->isFree(), "Header is not marked correctly");
   1.449 +
   1.450 +  TreeList *newTL, *parentTL;
   1.451 +  TreeChunk* retTC;
   1.452 +  TreeList* tl = tc->list();
   1.453 +  debug_only(
   1.454 +    bool removing_only_chunk = false;
   1.455 +    if (tl == _root) {
   1.456 +      if ((_root->left() == NULL) && (_root->right() == NULL)) {
   1.457 +        if (_root->count() == 1) {
   1.458 +          assert(_root->head() == tc, "Should only be this one chunk");
   1.459 +          removing_only_chunk = true;
   1.460 +        }
   1.461 +      }
   1.462 +    }
   1.463 +  )
   1.464 +  assert(tl != NULL, "List should be set");
   1.465 +  assert(tl->parent() == NULL || tl == tl->parent()->left() ||
   1.466 +         tl == tl->parent()->right(), "list is inconsistent");
   1.467 +
   1.468 +  bool complicatedSplice = false;
   1.469 +
   1.470 +  retTC = tc;
   1.471 +  // Removing this chunk can have the side effect of changing the node
   1.472 +  // (TreeList*) in the tree.  If the node is the root, update it.
   1.473 +  TreeList* replacementTL = tl->removeChunkReplaceIfNeeded(tc);
   1.474 +  assert(tc->isFree(), "Chunk should still be free");
   1.475 +  assert(replacementTL->parent() == NULL ||
   1.476 +         replacementTL == replacementTL->parent()->left() ||
   1.477 +         replacementTL == replacementTL->parent()->right(),
   1.478 +         "list is inconsistent");
   1.479 +  if (tl == root()) {
   1.480 +    assert(replacementTL->parent() == NULL, "Incorrectly replacing root");
   1.481 +    set_root(replacementTL);
   1.482 +  }
   1.483 +  debug_only(
   1.484 +    if (tl != replacementTL) {
   1.485 +      assert(replacementTL->head() != NULL,
   1.486 +        "If the tree list was replaced, it should not be a NULL list");
   1.487 +      TreeList* rhl = replacementTL->head_as_TreeChunk()->list();
   1.488 +      TreeList* rtl = TreeChunk::as_TreeChunk(replacementTL->tail())->list();
   1.489 +      assert(rhl == replacementTL, "Broken head");
   1.490 +      assert(rtl == replacementTL, "Broken tail");
   1.491 +      assert(replacementTL->size() == tc->size(),  "Broken size");
   1.492 +    }
   1.493 +  )
   1.494 +
   1.495 +  // Does the tree need to be repaired?
   1.496 +  if (replacementTL->count() == 0) {
   1.497 +    assert(replacementTL->head() == NULL &&
   1.498 +           replacementTL->tail() == NULL, "list count is incorrect");
   1.499 +    // Find the replacement node for the (soon to be empty) node being removed.
   1.500 +    // if we have a single (or no) child, splice child in our stead
   1.501 +    if (replacementTL->left() == NULL) {
   1.502 +      // left is NULL so pick right.  right may also be NULL.
   1.503 +      newTL = replacementTL->right();
   1.504 +      debug_only(replacementTL->clearRight();)
   1.505 +    } else if (replacementTL->right() == NULL) {
   1.506 +      // right is NULL
   1.507 +      newTL = replacementTL->left();
   1.508 +      debug_only(replacementTL->clearLeft();)
   1.509 +    } else {  // we have both children, so, by patriarchal convention,
   1.510 +              // my replacement is least node in right sub-tree
   1.511 +      complicatedSplice = true;
   1.512 +      newTL = removeTreeMinimum(replacementTL->right());
   1.513 +      assert(newTL != NULL && newTL->left() == NULL &&
   1.514 +             newTL->right() == NULL, "sub-tree minimum exists");
   1.515 +    }
   1.516 +    // newTL is the replacement for the (soon to be empty) node.
   1.517 +    // newTL may be NULL.
   1.518 +    // should verify; we just cleanly excised our replacement
   1.519 +    if (FLSVerifyDictionary) {
   1.520 +      verifyTree();
   1.521 +    }
   1.522 +    // first make newTL my parent's child
   1.523 +    if ((parentTL = replacementTL->parent()) == NULL) {
   1.524 +      // newTL should be root
   1.525 +      assert(tl == root(), "Incorrectly replacing root");
   1.526 +      set_root(newTL);
   1.527 +      if (newTL != NULL) {
   1.528 +        newTL->clearParent();
   1.529 +      }
   1.530 +    } else if (parentTL->right() == replacementTL) {
   1.531 +      // replacementTL is a right child
   1.532 +      parentTL->setRight(newTL);
   1.533 +    } else {                                // replacementTL is a left child
   1.534 +      assert(parentTL->left() == replacementTL, "should be left child");
   1.535 +      parentTL->setLeft(newTL);
   1.536 +    }
   1.537 +    debug_only(replacementTL->clearParent();)
   1.538 +    if (complicatedSplice) {  // we need newTL to get replacementTL's
   1.539 +                              // two children
   1.540 +      assert(newTL != NULL &&
   1.541 +             newTL->left() == NULL && newTL->right() == NULL,
   1.542 +            "newTL should not have encumbrances from the past");
   1.543 +      // we'd like to assert as below:
   1.544 +      // assert(replacementTL->left() != NULL && replacementTL->right() != NULL,
   1.545 +      //       "else !complicatedSplice");
   1.546 +      // ... however, the above assertion is too strong because we aren't
   1.547 +      // guaranteed that replacementTL->right() is still NULL.
   1.548 +      // Recall that we removed
   1.549 +      // the right sub-tree minimum from replacementTL.
   1.550 +      // That may well have been its right
   1.551 +      // child! So we'll just assert half of the above:
   1.552 +      assert(replacementTL->left() != NULL, "else !complicatedSplice");
   1.553 +      newTL->setLeft(replacementTL->left());
   1.554 +      newTL->setRight(replacementTL->right());
   1.555 +      debug_only(
   1.556 +        replacementTL->clearRight();
   1.557 +        replacementTL->clearLeft();
   1.558 +      )
   1.559 +    }
   1.560 +    assert(replacementTL->right() == NULL &&
   1.561 +           replacementTL->left() == NULL &&
   1.562 +           replacementTL->parent() == NULL,
   1.563 +        "delete without encumbrances");
   1.564 +  }
   1.565 +
   1.566 +  assert(totalSize() >= retTC->size(), "Incorrect total size");
   1.567 +  dec_totalSize(retTC->size());     // size book-keeping
   1.568 +  assert(totalFreeBlocks() > 0, "Incorrect total count");
   1.569 +  set_totalFreeBlocks(totalFreeBlocks() - 1);
   1.570 +
   1.571 +  assert(retTC != NULL, "null chunk?");
   1.572 +  assert(retTC->prev() == NULL && retTC->next() == NULL,
   1.573 +         "should return without encumbrances");
   1.574 +  if (FLSVerifyDictionary) {
   1.575 +    verifyTree();
   1.576 +  }
   1.577 +  assert(!removing_only_chunk || _root == NULL, "root should be NULL");
   1.578 +  return TreeChunk::as_TreeChunk(retTC);
   1.579 +}
   1.580 +
   1.581 +// Remove the leftmost node (lm) in the tree and return it.
   1.582 +// If lm has a right child, link it to the left node of
   1.583 +// the parent of lm.
   1.584 +TreeList* BinaryTreeDictionary::removeTreeMinimum(TreeList* tl) {
   1.585 +  assert(tl != NULL && tl->parent() != NULL, "really need a proper sub-tree");
   1.586 +  // locate the subtree minimum by walking down left branches
   1.587 +  TreeList* curTL = tl;
   1.588 +  for (; curTL->left() != NULL; curTL = curTL->left());
   1.589 +  // obviously curTL now has at most one child, a right child
   1.590 +  if (curTL != root()) {  // Should this test just be removed?
   1.591 +    TreeList* parentTL = curTL->parent();
   1.592 +    if (parentTL->left() == curTL) { // curTL is a left child
   1.593 +      parentTL->setLeft(curTL->right());
   1.594 +    } else {
   1.595 +      // If the list tl has no left child, then curTL may be
   1.596 +      // the right child of parentTL.
   1.597 +      assert(parentTL->right() == curTL, "should be a right child");
   1.598 +      parentTL->setRight(curTL->right());
   1.599 +    }
   1.600 +  } else {
   1.601 +    // The only use of this method would not pass the root of the
   1.602 +    // tree (as indicated by the assertion above that the tree list
   1.603 +    // has a parent) but the specification does not explicitly exclude the
   1.604 +    // passing of the root so accomodate it.
   1.605 +    set_root(NULL);
   1.606 +  }
   1.607 +  debug_only(
   1.608 +    curTL->clearParent();  // Test if this needs to be cleared
   1.609 +    curTL->clearRight();    // recall, above, left child is already null
   1.610 +  )
   1.611 +  // we just excised a (non-root) node, we should still verify all tree invariants
   1.612 +  if (FLSVerifyDictionary) {
   1.613 +    verifyTree();
   1.614 +  }
   1.615 +  return curTL;
   1.616 +}
   1.617 +
   1.618 +// Based on a simplification of the algorithm by Sleator and Tarjan (JACM 1985).
   1.619 +// The simplifications are the following:
   1.620 +// . we splay only when we delete (not when we insert)
   1.621 +// . we apply a single spay step per deletion/access
   1.622 +// By doing such partial splaying, we reduce the amount of restructuring,
   1.623 +// while getting a reasonably efficient search tree (we think).
   1.624 +// [Measurements will be needed to (in)validate this expectation.]
   1.625 +
   1.626 +void BinaryTreeDictionary::semiSplayStep(TreeList* tc) {
   1.627 +  // apply a semi-splay step at the given node:
   1.628 +  // . if root, norting needs to be done
   1.629 +  // . if child of root, splay once
   1.630 +  // . else zig-zig or sig-zag depending on path from grandparent
   1.631 +  if (root() == tc) return;
   1.632 +  warning("*** Splaying not yet implemented; "
   1.633 +          "tree operations may be inefficient ***");
   1.634 +}
   1.635 +
   1.636 +void BinaryTreeDictionary::insertChunkInTree(FreeChunk* fc) {
   1.637 +  TreeList *curTL, *prevTL;
   1.638 +  size_t size = fc->size();
   1.639 +
   1.640 +  assert(size >= MIN_TREE_CHUNK_SIZE, "too small to be a TreeList");
   1.641 +  if (FLSVerifyDictionary) {
   1.642 +    verifyTree();
   1.643 +  }
   1.644 +  // XXX: do i need to clear the FreeChunk fields, let me do it just in case
   1.645 +  // Revisit this later
   1.646 +
   1.647 +  fc->clearNext();
   1.648 +  fc->linkPrev(NULL);
   1.649 +
   1.650 +  // work down from the _root, looking for insertion point
   1.651 +  for (prevTL = curTL = root(); curTL != NULL;) {
   1.652 +    if (curTL->size() == size)  // exact match
   1.653 +      break;
   1.654 +    prevTL = curTL;
   1.655 +    if (curTL->size() > size) { // follow left branch
   1.656 +      curTL = curTL->left();
   1.657 +    } else {                    // follow right branch
   1.658 +      assert(curTL->size() < size, "size inconsistency");
   1.659 +      curTL = curTL->right();
   1.660 +    }
   1.661 +  }
   1.662 +  TreeChunk* tc = TreeChunk::as_TreeChunk(fc);
   1.663 +  // This chunk is being returned to the binary try.  It's embedded
   1.664 +  // TreeList should be unused at this point.
   1.665 +  tc->initialize();
   1.666 +  if (curTL != NULL) {          // exact match
   1.667 +    tc->set_list(curTL);
   1.668 +    curTL->returnChunkAtTail(tc);
   1.669 +  } else {                     // need a new node in tree
   1.670 +    tc->clearNext();
   1.671 +    tc->linkPrev(NULL);
   1.672 +    TreeList* newTL = TreeList::as_TreeList(tc);
   1.673 +    assert(((TreeChunk*)tc)->list() == newTL,
   1.674 +      "List was not initialized correctly");
   1.675 +    if (prevTL == NULL) {      // we are the only tree node
   1.676 +      assert(root() == NULL, "control point invariant");
   1.677 +      set_root(newTL);
   1.678 +    } else {                   // insert under prevTL ...
   1.679 +      if (prevTL->size() < size) {   // am right child
   1.680 +        assert(prevTL->right() == NULL, "control point invariant");
   1.681 +        prevTL->setRight(newTL);
   1.682 +      } else {                       // am left child
   1.683 +        assert(prevTL->size() > size && prevTL->left() == NULL, "cpt pt inv");
   1.684 +        prevTL->setLeft(newTL);
   1.685 +      }
   1.686 +    }
   1.687 +  }
   1.688 +  assert(tc->list() != NULL, "Tree list should be set");
   1.689 +
   1.690 +  inc_totalSize(size);
   1.691 +  // Method 'totalSizeInTree' walks through the every block in the
   1.692 +  // tree, so it can cause significant performance loss if there are
   1.693 +  // many blocks in the tree
   1.694 +  assert(!FLSVerifyDictionary || totalSizeInTree(root()) == totalSize(), "_totalSize inconsistency");
   1.695 +  set_totalFreeBlocks(totalFreeBlocks() + 1);
   1.696 +  if (FLSVerifyDictionary) {
   1.697 +    verifyTree();
   1.698 +  }
   1.699 +}
   1.700 +
   1.701 +size_t BinaryTreeDictionary::maxChunkSize() const {
   1.702 +  verify_par_locked();
   1.703 +  TreeList* tc = root();
   1.704 +  if (tc == NULL) return 0;
   1.705 +  for (; tc->right() != NULL; tc = tc->right());
   1.706 +  return tc->size();
   1.707 +}
   1.708 +
   1.709 +size_t BinaryTreeDictionary::totalListLength(TreeList* tl) const {
   1.710 +  size_t res;
   1.711 +  res = tl->count();
   1.712 +#ifdef ASSERT
   1.713 +  size_t cnt;
   1.714 +  FreeChunk* tc = tl->head();
   1.715 +  for (cnt = 0; tc != NULL; tc = tc->next(), cnt++);
   1.716 +  assert(res == cnt, "The count is not being maintained correctly");
   1.717 +#endif
   1.718 +  return res;
   1.719 +}
   1.720 +
   1.721 +size_t BinaryTreeDictionary::totalSizeInTree(TreeList* tl) const {
   1.722 +  if (tl == NULL)
   1.723 +    return 0;
   1.724 +  return (tl->size() * totalListLength(tl)) +
   1.725 +         totalSizeInTree(tl->left())    +
   1.726 +         totalSizeInTree(tl->right());
   1.727 +}
   1.728 +
   1.729 +double BinaryTreeDictionary::sum_of_squared_block_sizes(TreeList* const tl) const {
   1.730 +  if (tl == NULL) {
   1.731 +    return 0.0;
   1.732 +  }
   1.733 +  double size = (double)(tl->size());
   1.734 +  double curr = size * size * totalListLength(tl);
   1.735 +  curr += sum_of_squared_block_sizes(tl->left());
   1.736 +  curr += sum_of_squared_block_sizes(tl->right());
   1.737 +  return curr;
   1.738 +}
   1.739 +
   1.740 +size_t BinaryTreeDictionary::totalFreeBlocksInTree(TreeList* tl) const {
   1.741 +  if (tl == NULL)
   1.742 +    return 0;
   1.743 +  return totalListLength(tl) +
   1.744 +         totalFreeBlocksInTree(tl->left()) +
   1.745 +         totalFreeBlocksInTree(tl->right());
   1.746 +}
   1.747 +
   1.748 +size_t BinaryTreeDictionary::numFreeBlocks() const {
   1.749 +  assert(totalFreeBlocksInTree(root()) == totalFreeBlocks(),
   1.750 +         "_totalFreeBlocks inconsistency");
   1.751 +  return totalFreeBlocks();
   1.752 +}
   1.753 +
   1.754 +size_t BinaryTreeDictionary::treeHeightHelper(TreeList* tl) const {
   1.755 +  if (tl == NULL)
   1.756 +    return 0;
   1.757 +  return 1 + MAX2(treeHeightHelper(tl->left()),
   1.758 +                  treeHeightHelper(tl->right()));
   1.759 +}
   1.760 +
   1.761 +size_t BinaryTreeDictionary::treeHeight() const {
   1.762 +  return treeHeightHelper(root());
   1.763 +}
   1.764 +
   1.765 +size_t BinaryTreeDictionary::totalNodesHelper(TreeList* tl) const {
   1.766 +  if (tl == NULL) {
   1.767 +    return 0;
   1.768 +  }
   1.769 +  return 1 + totalNodesHelper(tl->left()) +
   1.770 +    totalNodesHelper(tl->right());
   1.771 +}
   1.772 +
   1.773 +size_t BinaryTreeDictionary::totalNodesInTree(TreeList* tl) const {
   1.774 +  return totalNodesHelper(root());
   1.775 +}
   1.776 +
   1.777 +void BinaryTreeDictionary::dictCensusUpdate(size_t size, bool split, bool birth){
   1.778 +  TreeList* nd = findList(size);
   1.779 +  if (nd) {
   1.780 +    if (split) {
   1.781 +      if (birth) {
   1.782 +        nd->increment_splitBirths();
   1.783 +        nd->increment_surplus();
   1.784 +      }  else {
   1.785 +        nd->increment_splitDeaths();
   1.786 +        nd->decrement_surplus();
   1.787 +      }
   1.788 +    } else {
   1.789 +      if (birth) {
   1.790 +        nd->increment_coalBirths();
   1.791 +        nd->increment_surplus();
   1.792 +      } else {
   1.793 +        nd->increment_coalDeaths();
   1.794 +        nd->decrement_surplus();
   1.795 +      }
   1.796 +    }
   1.797 +  }
   1.798 +  // A list for this size may not be found (nd == 0) if
   1.799 +  //   This is a death where the appropriate list is now
   1.800 +  //     empty and has been removed from the list.
   1.801 +  //   This is a birth associated with a LinAB.  The chunk
   1.802 +  //     for the LinAB is not in the dictionary.
   1.803 +}
   1.804 +
   1.805 +bool BinaryTreeDictionary::coalDictOverPopulated(size_t size) {
   1.806 +  TreeList* list_of_size = findList(size);
   1.807 +  // None of requested size implies overpopulated.
   1.808 +  return list_of_size == NULL || list_of_size->coalDesired() <= 0 ||
   1.809 +         list_of_size->count() > list_of_size->coalDesired();
   1.810 +}
   1.811 +
   1.812 +// Closures for walking the binary tree.
   1.813 +//   do_list() walks the free list in a node applying the closure
   1.814 +//     to each free chunk in the list
   1.815 +//   do_tree() walks the nodes in the binary tree applying do_list()
   1.816 +//     to each list at each node.
   1.817 +
   1.818 +class TreeCensusClosure : public StackObj {
   1.819 + protected:
   1.820 +  virtual void do_list(FreeList* fl) = 0;
   1.821 + public:
   1.822 +  virtual void do_tree(TreeList* tl) = 0;
   1.823 +};
   1.824 +
   1.825 +class AscendTreeCensusClosure : public TreeCensusClosure {
   1.826 + public:
   1.827 +  void do_tree(TreeList* tl) {
   1.828 +    if (tl != NULL) {
   1.829 +      do_tree(tl->left());
   1.830 +      do_list(tl);
   1.831 +      do_tree(tl->right());
   1.832 +    }
   1.833 +  }
   1.834 +};
   1.835 +
   1.836 +class DescendTreeCensusClosure : public TreeCensusClosure {
   1.837 + public:
   1.838 +  void do_tree(TreeList* tl) {
   1.839 +    if (tl != NULL) {
   1.840 +      do_tree(tl->right());
   1.841 +      do_list(tl);
   1.842 +      do_tree(tl->left());
   1.843 +    }
   1.844 +  }
   1.845 +};
   1.846 +
   1.847 +// For each list in the tree, calculate the desired, desired
   1.848 +// coalesce, count before sweep, and surplus before sweep.
   1.849 +class BeginSweepClosure : public AscendTreeCensusClosure {
   1.850 +  double _percentage;
   1.851 +  float _inter_sweep_current;
   1.852 +  float _inter_sweep_estimate;
   1.853 +
   1.854 + public:
   1.855 +  BeginSweepClosure(double p, float inter_sweep_current,
   1.856 +                              float inter_sweep_estimate) :
   1.857 +   _percentage(p),
   1.858 +   _inter_sweep_current(inter_sweep_current),
   1.859 +   _inter_sweep_estimate(inter_sweep_estimate) { }
   1.860 +
   1.861 +  void do_list(FreeList* fl) {
   1.862 +    double coalSurplusPercent = _percentage;
   1.863 +    fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate);
   1.864 +    fl->set_coalDesired((ssize_t)((double)fl->desired() * coalSurplusPercent));
   1.865 +    fl->set_beforeSweep(fl->count());
   1.866 +    fl->set_bfrSurp(fl->surplus());
   1.867 +  }
   1.868 +};
   1.869 +
   1.870 +// Used to search the tree until a condition is met.
   1.871 +// Similar to TreeCensusClosure but searches the
   1.872 +// tree and returns promptly when found.
   1.873 +
   1.874 +class TreeSearchClosure : public StackObj {
   1.875 + protected:
   1.876 +  virtual bool do_list(FreeList* fl) = 0;
   1.877 + public:
   1.878 +  virtual bool do_tree(TreeList* tl) = 0;
   1.879 +};
   1.880 +
   1.881 +#if 0 //  Don't need this yet but here for symmetry.
   1.882 +class AscendTreeSearchClosure : public TreeSearchClosure {
   1.883 + public:
   1.884 +  bool do_tree(TreeList* tl) {
   1.885 +    if (tl != NULL) {
   1.886 +      if (do_tree(tl->left())) return true;
   1.887 +      if (do_list(tl)) return true;
   1.888 +      if (do_tree(tl->right())) return true;
   1.889 +    }
   1.890 +    return false;
   1.891 +  }
   1.892 +};
   1.893 +#endif
   1.894 +
   1.895 +class DescendTreeSearchClosure : public TreeSearchClosure {
   1.896 + public:
   1.897 +  bool do_tree(TreeList* tl) {
   1.898 +    if (tl != NULL) {
   1.899 +      if (do_tree(tl->right())) return true;
   1.900 +      if (do_list(tl)) return true;
   1.901 +      if (do_tree(tl->left())) return true;
   1.902 +    }
   1.903 +    return false;
   1.904 +  }
   1.905 +};
   1.906 +
   1.907 +// Searches the tree for a chunk that ends at the
   1.908 +// specified address.
   1.909 +class EndTreeSearchClosure : public DescendTreeSearchClosure {
   1.910 +  HeapWord* _target;
   1.911 +  FreeChunk* _found;
   1.912 +
   1.913 + public:
   1.914 +  EndTreeSearchClosure(HeapWord* target) : _target(target), _found(NULL) {}
   1.915 +  bool do_list(FreeList* fl) {
   1.916 +    FreeChunk* item = fl->head();
   1.917 +    while (item != NULL) {
   1.918 +      if (item->end() == _target) {
   1.919 +        _found = item;
   1.920 +        return true;
   1.921 +      }
   1.922 +      item = item->next();
   1.923 +    }
   1.924 +    return false;
   1.925 +  }
   1.926 +  FreeChunk* found() { return _found; }
   1.927 +};
   1.928 +
   1.929 +FreeChunk* BinaryTreeDictionary::find_chunk_ends_at(HeapWord* target) const {
   1.930 +  EndTreeSearchClosure etsc(target);
   1.931 +  bool found_target = etsc.do_tree(root());
   1.932 +  assert(found_target || etsc.found() == NULL, "Consistency check");
   1.933 +  assert(!found_target || etsc.found() != NULL, "Consistency check");
   1.934 +  return etsc.found();
   1.935 +}
   1.936 +
   1.937 +void BinaryTreeDictionary::beginSweepDictCensus(double coalSurplusPercent,
   1.938 +  float inter_sweep_current, float inter_sweep_estimate) {
   1.939 +  BeginSweepClosure bsc(coalSurplusPercent, inter_sweep_current,
   1.940 +                                            inter_sweep_estimate);
   1.941 +  bsc.do_tree(root());
   1.942 +}
   1.943 +
   1.944 +// Closures and methods for calculating total bytes returned to the
   1.945 +// free lists in the tree.
   1.946 +NOT_PRODUCT(
   1.947 +  class InitializeDictReturnedBytesClosure : public AscendTreeCensusClosure {
   1.948 +   public:
   1.949 +    void do_list(FreeList* fl) {
   1.950 +      fl->set_returnedBytes(0);
   1.951 +    }
   1.952 +  };
   1.953 +
   1.954 +  void BinaryTreeDictionary::initializeDictReturnedBytes() {
   1.955 +    InitializeDictReturnedBytesClosure idrb;
   1.956 +    idrb.do_tree(root());
   1.957 +  }
   1.958 +
   1.959 +  class ReturnedBytesClosure : public AscendTreeCensusClosure {
   1.960 +    size_t _dictReturnedBytes;
   1.961 +   public:
   1.962 +    ReturnedBytesClosure() { _dictReturnedBytes = 0; }
   1.963 +    void do_list(FreeList* fl) {
   1.964 +      _dictReturnedBytes += fl->returnedBytes();
   1.965 +    }
   1.966 +    size_t dictReturnedBytes() { return _dictReturnedBytes; }
   1.967 +  };
   1.968 +
   1.969 +  size_t BinaryTreeDictionary::sumDictReturnedBytes() {
   1.970 +    ReturnedBytesClosure rbc;
   1.971 +    rbc.do_tree(root());
   1.972 +
   1.973 +    return rbc.dictReturnedBytes();
   1.974 +  }
   1.975 +
   1.976 +  // Count the number of entries in the tree.
   1.977 +  class treeCountClosure : public DescendTreeCensusClosure {
   1.978 +   public:
   1.979 +    uint count;
   1.980 +    treeCountClosure(uint c) { count = c; }
   1.981 +    void do_list(FreeList* fl) {
   1.982 +      count++;
   1.983 +    }
   1.984 +  };
   1.985 +
   1.986 +  size_t BinaryTreeDictionary::totalCount() {
   1.987 +    treeCountClosure ctc(0);
   1.988 +    ctc.do_tree(root());
   1.989 +    return ctc.count;
   1.990 +  }
   1.991 +)
   1.992 +
   1.993 +// Calculate surpluses for the lists in the tree.
   1.994 +class setTreeSurplusClosure : public AscendTreeCensusClosure {
   1.995 +  double percentage;
   1.996 + public:
   1.997 +  setTreeSurplusClosure(double v) { percentage = v; }
   1.998 +  void do_list(FreeList* fl) {
   1.999 +    double splitSurplusPercent = percentage;
  1.1000 +    fl->set_surplus(fl->count() -
  1.1001 +                   (ssize_t)((double)fl->desired() * splitSurplusPercent));
  1.1002 +  }
  1.1003 +};
  1.1004 +
  1.1005 +void BinaryTreeDictionary::setTreeSurplus(double splitSurplusPercent) {
  1.1006 +  setTreeSurplusClosure sts(splitSurplusPercent);
  1.1007 +  sts.do_tree(root());
  1.1008 +}
  1.1009 +
  1.1010 +// Set hints for the lists in the tree.
  1.1011 +class setTreeHintsClosure : public DescendTreeCensusClosure {
  1.1012 +  size_t hint;
  1.1013 + public:
  1.1014 +  setTreeHintsClosure(size_t v) { hint = v; }
  1.1015 +  void do_list(FreeList* fl) {
  1.1016 +    fl->set_hint(hint);
  1.1017 +    assert(fl->hint() == 0 || fl->hint() > fl->size(),
  1.1018 +      "Current hint is inconsistent");
  1.1019 +    if (fl->surplus() > 0) {
  1.1020 +      hint = fl->size();
  1.1021 +    }
  1.1022 +  }
  1.1023 +};
  1.1024 +
  1.1025 +void BinaryTreeDictionary::setTreeHints(void) {
  1.1026 +  setTreeHintsClosure sth(0);
  1.1027 +  sth.do_tree(root());
  1.1028 +}
  1.1029 +
  1.1030 +// Save count before previous sweep and splits and coalesces.
  1.1031 +class clearTreeCensusClosure : public AscendTreeCensusClosure {
  1.1032 +  void do_list(FreeList* fl) {
  1.1033 +    fl->set_prevSweep(fl->count());
  1.1034 +    fl->set_coalBirths(0);
  1.1035 +    fl->set_coalDeaths(0);
  1.1036 +    fl->set_splitBirths(0);
  1.1037 +    fl->set_splitDeaths(0);
  1.1038 +  }
  1.1039 +};
  1.1040 +
  1.1041 +void BinaryTreeDictionary::clearTreeCensus(void) {
  1.1042 +  clearTreeCensusClosure ctc;
  1.1043 +  ctc.do_tree(root());
  1.1044 +}
  1.1045 +
  1.1046 +// Do reporting and post sweep clean up.
  1.1047 +void BinaryTreeDictionary::endSweepDictCensus(double splitSurplusPercent) {
  1.1048 +  // Does walking the tree 3 times hurt?
  1.1049 +  setTreeSurplus(splitSurplusPercent);
  1.1050 +  setTreeHints();
  1.1051 +  if (PrintGC && Verbose) {
  1.1052 +    reportStatistics();
  1.1053 +  }
  1.1054 +  clearTreeCensus();
  1.1055 +}
  1.1056 +
  1.1057 +// Print summary statistics
  1.1058 +void BinaryTreeDictionary::reportStatistics() const {
  1.1059 +  verify_par_locked();
  1.1060 +  gclog_or_tty->print("Statistics for BinaryTreeDictionary:\n"
  1.1061 +         "------------------------------------\n");
  1.1062 +  size_t totalSize = totalChunkSize(debug_only(NULL));
  1.1063 +  size_t    freeBlocks = numFreeBlocks();
  1.1064 +  gclog_or_tty->print("Total Free Space: %d\n", totalSize);
  1.1065 +  gclog_or_tty->print("Max   Chunk Size: %d\n", maxChunkSize());
  1.1066 +  gclog_or_tty->print("Number of Blocks: %d\n", freeBlocks);
  1.1067 +  if (freeBlocks > 0) {
  1.1068 +    gclog_or_tty->print("Av.  Block  Size: %d\n", totalSize/freeBlocks);
  1.1069 +  }
  1.1070 +  gclog_or_tty->print("Tree      Height: %d\n", treeHeight());
  1.1071 +}
  1.1072 +
  1.1073 +// Print census information - counts, births, deaths, etc.
  1.1074 +// for each list in the tree.  Also print some summary
  1.1075 +// information.
  1.1076 +class printTreeCensusClosure : public AscendTreeCensusClosure {
  1.1077 +  size_t _totalFree;
  1.1078 +  AllocationStats _totals;
  1.1079 +  size_t _count;
  1.1080 +
  1.1081 + public:
  1.1082 +  printTreeCensusClosure() {
  1.1083 +    _totalFree = 0;
  1.1084 +    _count = 0;
  1.1085 +    _totals.initialize();
  1.1086 +  }
  1.1087 +  AllocationStats* totals() { return &_totals; }
  1.1088 +  size_t count() { return _count; }
  1.1089 +  void increment_count_by(size_t v) { _count += v; }
  1.1090 +  size_t totalFree() { return _totalFree; }
  1.1091 +  void increment_totalFree_by(size_t v) { _totalFree += v; }
  1.1092 +  void do_list(FreeList* fl) {
  1.1093 +    bool nl = false; // "maybe this is not needed" isNearLargestChunk(fl->head());
  1.1094 +
  1.1095 +    gclog_or_tty->print("%c %4d\t\t" "%7d\t" "%7d\t"
  1.1096 +               "%7d\t"      "%7d\t" "%7d\t" "%7d\t"
  1.1097 +               "%7d\t"      "%7d\t" "%7d\t"
  1.1098 +               "%7d\t" "\n",
  1.1099 +               " n"[nl], fl->size(), fl->bfrSurp(), fl->surplus(),
  1.1100 +               fl->desired(), fl->prevSweep(), fl->beforeSweep(), fl->count(),
  1.1101 +               fl->coalBirths(), fl->coalDeaths(), fl->splitBirths(),
  1.1102 +               fl->splitDeaths());
  1.1103 +
  1.1104 +    increment_totalFree_by(fl->count() * fl->size());
  1.1105 +    increment_count_by(fl->count());
  1.1106 +    totals()->set_bfrSurp(totals()->bfrSurp() + fl->bfrSurp());
  1.1107 +    totals()->set_surplus(totals()->splitDeaths()     + fl->surplus());
  1.1108 +    totals()->set_prevSweep(totals()->prevSweep()   + fl->prevSweep());
  1.1109 +    totals()->set_beforeSweep(totals()->beforeSweep() + fl->beforeSweep());
  1.1110 +    totals()->set_coalBirths(totals()->coalBirths()  + fl->coalBirths());
  1.1111 +    totals()->set_coalDeaths(totals()->coalDeaths()  + fl->coalDeaths());
  1.1112 +    totals()->set_splitBirths(totals()->splitBirths() + fl->splitBirths());
  1.1113 +    totals()->set_splitDeaths(totals()->splitDeaths() + fl->splitDeaths());
  1.1114 +  }
  1.1115 +};
  1.1116 +
  1.1117 +void BinaryTreeDictionary::printDictCensus(void) const {
  1.1118 +
  1.1119 +  gclog_or_tty->print("\nBinaryTree\n");
  1.1120 +  gclog_or_tty->print(
  1.1121 +             "%4s\t\t" "%7s\t"   "%7s\t"    "%7s\t"    "%7s\t"    "%7s\t"
  1.1122 +             "%7s\t"   "%7s\t"   "%7s\t"    "%7s\t"    "%7s\t"     "\n",
  1.1123 +             "size",  "bfrsurp", "surplus", "desired", "prvSwep", "bfrSwep",
  1.1124 +             "count", "cBirths", "cDeaths", "sBirths", "sDeaths");
  1.1125 +
  1.1126 +  printTreeCensusClosure ptc;
  1.1127 +  ptc.do_tree(root());
  1.1128 +
  1.1129 +  gclog_or_tty->print(
  1.1130 +             "\t\t"    "%7s\t"    "%7s\t"    "%7s\t"    "%7s\t"
  1.1131 +             "%7s\t"   "%7s\t"    "%7s\t"    "%7s\t"    "%7s\t"     "\n",
  1.1132 +                       "bfrsurp", "surplus", "prvSwep", "bfrSwep",
  1.1133 +             "count",  "cBirths", "cDeaths", "sBirths", "sDeaths");
  1.1134 +  gclog_or_tty->print(
  1.1135 +             "%s\t\t"  "%7d\t"    "%7d\t"     "%7d\t"    "%7d\t"
  1.1136 +             "%7d\t"   "%7d\t"    "%7d\t"     "%7d\t"    "%7d\t"    "\n",
  1.1137 +             "totl",
  1.1138 +             ptc.totals()->bfrSurp(),
  1.1139 +             ptc.totals()->surplus(),
  1.1140 +             ptc.totals()->prevSweep(),
  1.1141 +             ptc.totals()->beforeSweep(),
  1.1142 +             ptc.count(),
  1.1143 +             ptc.totals()->coalBirths(),
  1.1144 +             ptc.totals()->coalDeaths(),
  1.1145 +             ptc.totals()->splitBirths(),
  1.1146 +             ptc.totals()->splitDeaths());
  1.1147 +  gclog_or_tty->print("totalFree(words): %7d growth: %8.5f  deficit: %8.5f\n",
  1.1148 +              ptc.totalFree(),
  1.1149 +              (double)(ptc.totals()->splitBirths()+ptc.totals()->coalBirths()
  1.1150 +                       -ptc.totals()->splitDeaths()-ptc.totals()->coalDeaths())
  1.1151 +              /(ptc.totals()->prevSweep() != 0 ?
  1.1152 +                (double)ptc.totals()->prevSweep() : 1.0),
  1.1153 +             (double)(ptc.totals()->desired() - ptc.count())
  1.1154 +             /(ptc.totals()->desired() != 0 ?
  1.1155 +               (double)ptc.totals()->desired() : 1.0));
  1.1156 +}
  1.1157 +
  1.1158 +// Verify the following tree invariants:
  1.1159 +// . _root has no parent
  1.1160 +// . parent and child point to each other
  1.1161 +// . each node's key correctly related to that of its child(ren)
  1.1162 +void BinaryTreeDictionary::verifyTree() const {
  1.1163 +  guarantee(root() == NULL || totalFreeBlocks() == 0 ||
  1.1164 +    totalSize() != 0, "_totalSize should't be 0?");
  1.1165 +  guarantee(root() == NULL || root()->parent() == NULL, "_root shouldn't have parent");
  1.1166 +  verifyTreeHelper(root());
  1.1167 +}
  1.1168 +
  1.1169 +size_t BinaryTreeDictionary::verifyPrevFreePtrs(TreeList* tl) {
  1.1170 +  size_t ct = 0;
  1.1171 +  for (FreeChunk* curFC = tl->head(); curFC != NULL; curFC = curFC->next()) {
  1.1172 +    ct++;
  1.1173 +    assert(curFC->prev() == NULL || curFC->prev()->isFree(),
  1.1174 +      "Chunk should be free");
  1.1175 +  }
  1.1176 +  return ct;
  1.1177 +}
  1.1178 +
  1.1179 +// Note: this helper is recursive rather than iterative, so use with
  1.1180 +// caution on very deep trees; and watch out for stack overflow errors;
  1.1181 +// In general, to be used only for debugging.
  1.1182 +void BinaryTreeDictionary::verifyTreeHelper(TreeList* tl) const {
  1.1183 +  if (tl == NULL)
  1.1184 +    return;
  1.1185 +  guarantee(tl->size() != 0, "A list must has a size");
  1.1186 +  guarantee(tl->left()  == NULL || tl->left()->parent()  == tl,
  1.1187 +         "parent<-/->left");
  1.1188 +  guarantee(tl->right() == NULL || tl->right()->parent() == tl,
  1.1189 +         "parent<-/->right");;
  1.1190 +  guarantee(tl->left() == NULL  || tl->left()->size()    <  tl->size(),
  1.1191 +         "parent !> left");
  1.1192 +  guarantee(tl->right() == NULL || tl->right()->size()   >  tl->size(),
  1.1193 +         "parent !< left");
  1.1194 +  guarantee(tl->head() == NULL || tl->head()->isFree(), "!Free");
  1.1195 +  guarantee(tl->head() == NULL || tl->head_as_TreeChunk()->list() == tl,
  1.1196 +    "list inconsistency");
  1.1197 +  guarantee(tl->count() > 0 || (tl->head() == NULL && tl->tail() == NULL),
  1.1198 +    "list count is inconsistent");
  1.1199 +  guarantee(tl->count() > 1 || tl->head() == tl->tail(),
  1.1200 +    "list is incorrectly constructed");
  1.1201 +  size_t count = verifyPrevFreePtrs(tl);
  1.1202 +  guarantee(count == (size_t)tl->count(), "Node count is incorrect");
  1.1203 +  if (tl->head() != NULL) {
  1.1204 +    tl->head_as_TreeChunk()->verifyTreeChunkList();
  1.1205 +  }
  1.1206 +  verifyTreeHelper(tl->left());
  1.1207 +  verifyTreeHelper(tl->right());
  1.1208 +}
  1.1209 +
  1.1210 +void BinaryTreeDictionary::verify() const {
  1.1211 +  verifyTree();
  1.1212 +  guarantee(totalSize() == totalSizeInTree(root()), "Total Size inconsistency");
  1.1213 +}

mercurial