1 /*
   2  * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #ifndef SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP
  26 #define SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP
  27 
  28 #include "memory/freeList.hpp"
  29 #include "memory/memRegion.hpp"
  30 
  31 class Mutex;
  32 
  33 /*
  34  * A binary tree based search structure for free blocks.
  35  * This is currently used in the Concurrent Mark&Sweep implementation, but
  36  * will be used for free block management for metadata.
  37  */
  38 
  39 // A TreeList is a FreeList which can be used to maintain a
  40 // binary tree of free lists.
  41 
  42 template <class Chunk_t, class FreeList_t> class TreeChunk;
  43 template <class Chunk_t, class FreeList_t> class BinaryTreeDictionary;
  44 template <class Chunk_t, class FreeList_t> class AscendTreeCensusClosure;
  45 template <class Chunk_t, class FreeList_t> class DescendTreeCensusClosure;
  46 template <class Chunk_t, class FreeList_t> class DescendTreeSearchClosure;
  47 
  48 template <class Chunk_t, class FreeList_t>
  49 class TreeList : public FreeList_t {
  50   friend class TreeChunk<Chunk_t, FreeList_t>;
  51   friend class BinaryTreeDictionary<Chunk_t, FreeList_t>;
  52   friend class AscendTreeCensusClosure<Chunk_t, FreeList_t>;
  53   friend class DescendTreeCensusClosure<Chunk_t, FreeList_t>;
  54   friend class DescendTreeSearchClosure<Chunk_t, FreeList_t>;
  55 
  56   TreeList<Chunk_t, FreeList_t>* _parent;
  57   TreeList<Chunk_t, FreeList_t>* _left;
  58   TreeList<Chunk_t, FreeList_t>* _right;
  59 
  60  protected:
  61 
  62   TreeList<Chunk_t, FreeList_t>* parent() const { return _parent; }
  63   TreeList<Chunk_t, FreeList_t>* left()   const { return _left;   }
  64   TreeList<Chunk_t, FreeList_t>* right()  const { return _right;  }
  65 
  66   // Wrapper on call to base class, to get the template to compile.
  67   Chunk_t* head() const { return FreeList_t::head(); }
  68   Chunk_t* tail() const { return FreeList_t::tail(); }
  69   void set_head(Chunk_t* head) { FreeList_t::set_head(head); }
  70   void set_tail(Chunk_t* tail) { FreeList_t::set_tail(tail); }
  71 
  72   size_t size() const { return FreeList_t::size(); }
  73 
  74   // Accessors for links in tree.
  75 
  76   void set_left(TreeList<Chunk_t, FreeList_t>* tl) {
  77     _left   = tl;
  78     if (tl != NULL)
  79       tl->set_parent(this);
  80   }
  81   void set_right(TreeList<Chunk_t, FreeList_t>* tl) {
  82     _right  = tl;
  83     if (tl != NULL)
  84       tl->set_parent(this);
  85   }
  86   void set_parent(TreeList<Chunk_t, FreeList_t>* tl)  { _parent = tl;   }
  87 
  88   void clear_left()               { _left = NULL;   }
  89   void clear_right()              { _right = NULL;  }
  90   void clear_parent()             { _parent = NULL; }
  91   void initialize()               { clear_left(); clear_right(), clear_parent(); FreeList_t::initialize(); }
  92 
  93   // For constructing a TreeList from a Tree chunk or
  94   // address and size.
  95   TreeList();
  96   static TreeList<Chunk_t, FreeList_t>*
  97           as_TreeList(TreeChunk<Chunk_t, FreeList_t>* tc);
  98   static TreeList<Chunk_t, FreeList_t>* as_TreeList(HeapWord* addr, size_t size);
  99 
 100   // Returns the head of the free list as a pointer to a TreeChunk.
 101   TreeChunk<Chunk_t, FreeList_t>* head_as_TreeChunk();
 102 
 103   // Returns the first available chunk in the free list as a pointer
 104   // to a TreeChunk.
 105   TreeChunk<Chunk_t, FreeList_t>* first_available();
 106 
 107   // Returns the block with the largest heap address amongst
 108   // those in the list for this size; potentially slow and expensive,
 109   // use with caution!
 110   TreeChunk<Chunk_t, FreeList_t>* largest_address();
 111 
 112   TreeList<Chunk_t, FreeList_t>* get_better_list(
 113     BinaryTreeDictionary<Chunk_t, FreeList_t>* dictionary);
 114 
 115   // remove_chunk_replace_if_needed() removes the given "tc" from the TreeList.
 116   // If "tc" is the first chunk in the list, it is also the
 117   // TreeList that is the node in the tree.  remove_chunk_replace_if_needed()
 118   // returns the possibly replaced TreeList* for the node in
 119   // the tree.  It also updates the parent of the original
 120   // node to point to the new node.
 121   TreeList<Chunk_t, FreeList_t>* remove_chunk_replace_if_needed(TreeChunk<Chunk_t, FreeList_t>* tc);
 122   // See FreeList.
 123   void return_chunk_at_head(TreeChunk<Chunk_t, FreeList_t>* tc);
 124   void return_chunk_at_tail(TreeChunk<Chunk_t, FreeList_t>* tc);
 125 };
 126 
 127 // A TreeChunk is a subclass of a Chunk that additionally
 128 // maintains a pointer to the free list on which it is currently
 129 // linked.
 130 // A TreeChunk is also used as a node in the binary tree.  This
 131 // allows the binary tree to be maintained without any additional
 132 // storage (the free chunks are used).  In a binary tree the first
 133 // chunk in the free list is also the tree node.  Note that the
 134 // TreeChunk has an embedded TreeList for this purpose.  Because
 135 // the first chunk in the list is distinguished in this fashion
 136 // (also is the node in the tree), it is the last chunk to be found
 137 // on the free list for a node in the tree and is only removed if
 138 // it is the last chunk on the free list.
 139 
 140 template <class Chunk_t, class FreeList_t>
 141 class TreeChunk : public Chunk_t {
 142   friend class TreeList<Chunk_t, FreeList_t>;
 143   TreeList<Chunk_t, FreeList_t>* _list;
 144   TreeList<Chunk_t, FreeList_t> _embedded_list;  // if non-null, this chunk is on _list
 145 
 146   static size_t _min_tree_chunk_size;
 147 
 148  protected:
 149   TreeList<Chunk_t, FreeList_t>* embedded_list() const { return (TreeList<Chunk_t, FreeList_t>*) &_embedded_list; }
 150   void set_embedded_list(TreeList<Chunk_t, FreeList_t>* v) { _embedded_list = *v; }
 151  public:
 152   TreeList<Chunk_t, FreeList_t>* list() { return _list; }
 153   void set_list(TreeList<Chunk_t, FreeList_t>* v) { _list = v; }
 154   static TreeChunk<Chunk_t, FreeList_t>* as_TreeChunk(Chunk_t* fc);
 155   // Initialize fields in a TreeChunk that should be
 156   // initialized when the TreeChunk is being added to
 157   // a free list in the tree.
 158   void initialize() { embedded_list()->initialize(); }
 159 
 160   Chunk_t* next() const { return Chunk_t::next(); }
 161   Chunk_t* prev() const { return Chunk_t::prev(); }
 162   size_t size() const volatile { return Chunk_t::size(); }
 163 
 164   static size_t min_size();
 165 
 166   // debugging
 167   void verify_tree_chunk_list() const;
 168   void assert_is_mangled() const;
 169 };
 170 
 171 template <class Chunk_t, class FreeList_t>
 172 size_t TreeChunk<Chunk_t, FreeList_t>::_min_tree_chunk_size = sizeof(TreeChunk<Chunk_t, FreeList_t>)/HeapWordSize;
 173 template <class Chunk_t, class FreeList_t>
 174 size_t TreeChunk<Chunk_t, FreeList_t>::min_size() { return _min_tree_chunk_size; }
 175 
 176 template <class Chunk_t, class FreeList_t>
 177 class BinaryTreeDictionary: public CHeapObj<mtGC> {
 178   friend class VMStructs;
 179 
 180  protected:
 181   size_t     _total_size;
 182   size_t     _total_free_blocks;
 183   TreeList<Chunk_t, FreeList_t>* _root;
 184 
 185   // private accessors
 186   void set_total_size(size_t v) { _total_size = v; }
 187   void inc_total_size(size_t v);
 188   void dec_total_size(size_t v);
 189   void set_total_free_blocks(size_t v) { _total_free_blocks = v; }
 190   TreeList<Chunk_t, FreeList_t>* root() const { return _root; }
 191   void set_root(TreeList<Chunk_t, FreeList_t>* v) { _root = v; }
 192 
 193   // This field is added and can be set to point to the
 194   // the Mutex used to synchronize access to the
 195   // dictionary so that assertion checking can be done.
 196   // For example it is set to point to _parDictionaryAllocLock.
 197   NOT_PRODUCT(Mutex* _lock;)
 198 
 199   // Remove a chunk of size "size" or larger from the tree and
 200   // return it.  If the chunk
 201   // is the last chunk of that size, remove the node for that size
 202   // from the tree.
 203   TreeChunk<Chunk_t, FreeList_t>* get_chunk_from_tree(size_t size);
 204   // Remove this chunk from the tree.  If the removal results
 205   // in an empty list in the tree, remove the empty list.
 206   TreeChunk<Chunk_t, FreeList_t>* remove_chunk_from_tree(TreeChunk<Chunk_t, FreeList_t>* tc);
 207   // Remove the node in the trees starting at tl that has the
 208   // minimum value and return it.  Repair the tree as needed.
 209   TreeList<Chunk_t, FreeList_t>* remove_tree_minimum(TreeList<Chunk_t, FreeList_t>* tl);
 210   // Add this free chunk to the tree.
 211   void       insert_chunk_in_tree(Chunk_t* freeChunk);
 212  public:
 213 
 214   // Return a list of the specified size or NULL from the tree.
 215   // The list is not removed from the tree.
 216   TreeList<Chunk_t, FreeList_t>* find_list (size_t size) const;
 217 
 218   void       verify_tree() const;
 219   // verify that the given chunk is in the tree.
 220   bool       verify_chunk_in_free_list(Chunk_t* tc) const;
 221  private:
 222   void          verify_tree_helper(TreeList<Chunk_t, FreeList_t>* tl) const;
 223   static size_t verify_prev_free_ptrs(TreeList<Chunk_t, FreeList_t>* tl);
 224 
 225   // Returns the total number of chunks in the list.
 226   size_t     total_list_length(TreeList<Chunk_t, FreeList_t>* tl) const;
 227   // Returns the total number of words in the chunks in the tree
 228   // starting at "tl".
 229   size_t     total_size_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const;
 230   // Returns the sum of the square of the size of each block
 231   // in the tree starting at "tl".
 232   double     sum_of_squared_block_sizes(TreeList<Chunk_t, FreeList_t>* const tl) const;
 233   // Returns the total number of free blocks in the tree starting
 234   // at "tl".
 235   size_t     total_free_blocks_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const;
 236   size_t     num_free_blocks()  const;
 237   size_t     tree_height() const;
 238   size_t     tree_height_helper(TreeList<Chunk_t, FreeList_t>* tl) const;
 239   size_t     total_nodes_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const;
 240   size_t     total_nodes_helper(TreeList<Chunk_t, FreeList_t>* tl) const;
 241 
 242  public:
 243   // Constructor
 244   BinaryTreeDictionary() :
 245     _total_size(0), _total_free_blocks(0), _root(0) {}
 246 
 247   BinaryTreeDictionary(MemRegion mr);
 248 
 249   // Public accessors
 250   size_t total_size() const { return _total_size; }
 251   size_t total_free_blocks() const { return _total_free_blocks; }
 252 
 253   // Reset the dictionary to the initial conditions with
 254   // a single free chunk.
 255   void       reset(MemRegion mr);
 256   void       reset(HeapWord* addr, size_t size);
 257   // Reset the dictionary to be empty.
 258   void       reset();
 259 
 260   // Return a chunk of size "size" or greater from
 261   // the tree.
 262   Chunk_t* get_chunk(size_t size) {
 263     verify_par_locked();
 264     Chunk_t* res = get_chunk_from_tree(size);
 265     assert(res == NULL || res->is_free(),
 266            "Should be returning a free chunk");
 267     return res;
 268   }
 269 
 270   void return_chunk(Chunk_t* chunk) {
 271     verify_par_locked();
 272     insert_chunk_in_tree(chunk);
 273   }
 274 
 275   void remove_chunk(Chunk_t* chunk) {
 276     verify_par_locked();
 277     remove_chunk_from_tree((TreeChunk<Chunk_t, FreeList_t>*)chunk);
 278     assert(chunk->is_free(), "Should still be a free chunk");
 279   }
 280 
 281   size_t     max_chunk_size() const;
 282   inline size_t total_chunk_size(debug_only(const Mutex* lock)) const;
 283 
 284   size_t     min_size() const {
 285     return TreeChunk<Chunk_t, FreeList_t>::min_size();
 286   }
 287 
 288   double     sum_of_squared_block_sizes() const {
 289     return sum_of_squared_block_sizes(root());
 290   }
 291 
 292   Chunk_t* find_chunk_ends_at(HeapWord* target) const;
 293 
 294   // Return the largest free chunk in the tree.
 295   Chunk_t* find_largest_dict() const;
 296 
 297   void       print_free_lists(outputStream* st) const;
 298 
 299   // For debugging.  Returns the sum of the _returned_bytes for
 300   // all lists in the tree.
 301   size_t     sum_dict_returned_bytes()     PRODUCT_RETURN0;
 302   // Sets the _returned_bytes for all the lists in the tree to zero.
 303   void       initialize_dict_returned_bytes()      PRODUCT_RETURN;
 304   // For debugging.  Return the total number of chunks in the dictionary.
 305   size_t     total_count()       PRODUCT_RETURN0;
 306 
 307   void       report_statistics(outputStream* st) const;
 308 
 309   void       verify() const;
 310 
 311   Mutex*     par_lock()                const PRODUCT_RETURN0;
 312   void       set_par_lock(Mutex* lock)       PRODUCT_RETURN;
 313   void       verify_par_locked()       const PRODUCT_RETURN;
 314 };
 315 
 316 
 317 // Closures for walking the binary tree.
 318 //   do_list() walks the free list in a node applying the closure
 319 //     to each free chunk in the list
 320 //   do_tree() walks the nodes in the binary tree applying do_list()
 321 //     to each list at each node.
 322 
 323 template <class Chunk_t, class FreeList_t>
 324 class TreeCensusClosure : public StackObj {
 325  protected:
 326   virtual void do_list(FreeList_t* fl) = 0;
 327  public:
 328   virtual void do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
 329 };
 330 
 331 template <class Chunk_t, class FreeList_t>
 332 class AscendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
 333  public:
 334   void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
 335     if (tl != NULL) {
 336       do_tree(tl->left());
 337       this->do_list(tl);
 338       do_tree(tl->right());
 339     }
 340   }
 341 };
 342 
 343 template <class Chunk_t, class FreeList_t>
 344 class DescendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
 345  public:
 346   void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
 347     if (tl != NULL) {
 348       do_tree(tl->right());
 349       this->do_list(tl);
 350       do_tree(tl->left());
 351     }
 352   }
 353 };
 354 
 355 // Used to search the tree until a condition is met.
 356 // Similar to TreeCensusClosure but searches the
 357 // tree and returns promptly when found.
 358 
 359 template <class Chunk_t, class FreeList_t>
 360 class TreeSearchClosure : public StackObj {
 361  protected:
 362   virtual bool do_list(FreeList_t* fl) = 0;
 363  public:
 364   virtual bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
 365 };
 366 
 367 #if 0 //  Don't need this yet but here for symmetry.
 368 template <class Chunk_t, class FreeList_t>
 369 class AscendTreeSearchClosure : public TreeSearchClosure<Chunk_t> {
 370  public:
 371   bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
 372     if (tl != NULL) {
 373       if (do_tree(tl->left())) return true;
 374       if (do_list(tl)) return true;
 375       if (do_tree(tl->right())) return true;
 376     }
 377     return false;
 378   }
 379 };
 380 #endif
 381 
 382 template <class Chunk_t, class FreeList_t>
 383 class DescendTreeSearchClosure : public TreeSearchClosure<Chunk_t, FreeList_t> {
 384  public:
 385   bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
 386     if (tl != NULL) {
 387       if (do_tree(tl->right())) return true;
 388       if (this->do_list(tl)) return true;
 389       if (do_tree(tl->left())) return true;
 390     }
 391     return false;
 392   }
 393 };
 394 
 395 #endif // SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP