1 /*
   2  * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2018, 2020 SAP SE. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  *
  24  */
  25 
  26 #ifndef SHARE_MEMORY_METASPACE_MSVIRTUALSPACENODE_HPP
  27 #define SHARE_MEMORY_METASPACE_MSVIRTUALSPACENODE_HPP
  28 
  29 #include "memory/allocation.hpp"
  30 #include "memory/metaspace/msCommitMask.hpp"
  31 #include "memory/metaspace/msCounter.hpp"
  32 #include "memory/metaspace/msRootChunkArea.hpp"
  33 #include "memory/metaspace/msSettings.hpp"
  34 #include "memory/memRegion.hpp"
  35 #include "memory/virtualspace.hpp"
  36 #include "utilities/debug.hpp"
  37 #include "utilities/bitMap.hpp"
  38 #include "utilities/globalDefinitions.hpp"
  39 
  40 class outputStream;
  41 
  42 namespace metaspace {
  43 
  44 class CommitLimiter;
  45 class FreeChunkListVector;
  46 
  47 // VirtualSpaceNode manages a single contiguous address range of metaspace. Logically that memory
  48 //  region is split up into a sequence of "root chunk areas", each one containing one root chunk
  49 //  or splinters of a root chunk.
  50 //
  51 // The underlying memory is also logically divided into a number of "commit granules", units of memory
  52 //  which may be committed or uncommitted independently from each other.
  53 //
  54 // (Both root chunk areas and commit granules have not much to do with each other - one is a way to
  55 //   reserve memory for the upper regions, see ChunkManager. One is a way to manage commited memory.)
  56 //
  57 // VirtualSpaceNode:
  58 //  - exposes a function to allocate a new root chunk (see VirtualSpaceNode::allocate_root_chunk()).
  59 //
  60 //  - knows about the commit state of the memory region - which commit granule are committed, which
  61 //    are not. It exposes functions to commit and uncommit regions (without actively committing
  62 //    itself)
  63 //
  64 //  - It has a reference to a "CommitLimiter", an interface to query whether committing is
  65 //    possible. That interface hides the various ways committing may be limited (GC threshold,
  66 //    MaxMetaspaceSize, ...)
  67 //
  68 //  - It uses ReservedSpace to reserve its memory. It either owns the ReservedSpace or that
  69 //    space got handed in from outside (ccs).
  70 //
  71 //
  72 //
  73 //
  74 // | root chunk area               | root chunk area               | root chunk area               | <-- root chunk areas
  75 //
  76 // +-----------------------------------------------------------------------------------------------+
  77 // |                                                                                               |
  78 // |                                   `VirtualSpaceNode` memory                                   |
  79 // |                                                                                               |
  80 // +-----------------------------------------------------------------------------------------------+
  81 //
  82 // |x| |x|x|x| | | | |x|x|x| | | |x|x| | | |x|x|x|x| | | | | | | | |x| | | |x|x|x|x| | | |x| | | |x| <-- commit granules
  83 //
  84 // (x = committed)
  85 //
  86 
  87 class VirtualSpaceNode : public CHeapObj<mtClass> {
  88 
  89   // Link to next VirtualSpaceNode
  90   VirtualSpaceNode* _next;
  91 
  92   // The underlying space. This has been either created by this node
  93   //  and is owned by it, or has been handed in from outside (e.g. in
  94   //  case of CompressedClassSpace).
  95   ReservedSpace _rs;
  96 
  97   // True if the node owns the reserved space, false if not.
  98   const bool _owns_rs;
  99 
 100   // Start pointer of the area.
 101   MetaWord* const _base;
 102 
 103   // Size, in words, of the whole node
 104   const size_t _word_size;
 105 
 106   // Size, in words, of the range of this node which has been handed out in
 107   // the form of root chunks.
 108   size_t _used_words;
 109 
 110   // The bitmap describing the commit state of the region:
 111   // Each bit covers a region of 64K (see constants::commit_granule_size).
 112   CommitMask _commit_mask;
 113 
 114   // An array/lookup table of RootChunkArea objects. Each one describes a root chunk area.
 115   RootChunkAreaLUT _root_chunk_area_lut;
 116 
 117   // Limiter object to ask before expanding the committed size of this node.
 118   CommitLimiter* const _commit_limiter;
 119 
 120   // Points to outside size counters which we are to increase/decrease when we commit/uncommit
 121   // space from this node.
 122   SizeCounter* const _total_reserved_words_counter;
 123   SizeCounter* const _total_committed_words_counter;
 124 
 125   /// committing, uncommitting ///
 126 
 127   // Given a pointer into this node, calculate the start of the commit granule
 128   // the pointer points into.
 129   MetaWord* calc_start_of_granule(MetaWord* p) const {
 130     DEBUG_ONLY(check_pointer(p));
 131     return align_down(p, Settings::commit_granule_bytes());
 132   }
 133 
 134   // Given an address range, ensure it is committed.
 135   //
 136   // The range has to be aligned to granule size.
 137   //
 138   // Function will:
 139   // - check how many granules in that region are uncommitted; If all are committed, it
 140   //    returns true immediately.
 141   // - check if committing those uncommitted granules would bring us over the commit limit
 142   //    (GC threshold, MaxMetaspaceSize). If true, it returns false.
 143   // - commit the memory.
 144   // - mark the range as committed in the commit mask
 145   //
 146   // Returns true if success, false if it did hit a commit limit.
 147   bool commit_range(MetaWord* p, size_t word_size);
 148 
 149   //// creation ////
 150 
 151   // Create a new empty node spanning the given given reserved space.
 152   VirtualSpaceNode(ReservedSpace rs, bool owns_rs, CommitLimiter* limiter,
 153                    SizeCounter* reserve_counter, SizeCounter* commit_counter);
 154 
 155 public:
 156 
 157   // Create a node of a given size (it will create its own space).
 158   static VirtualSpaceNode* create_node(size_t word_size, CommitLimiter* limiter, SizeCounter* reserve_words_counter,
 159                                        SizeCounter* commit_words_counter);
 160 
 161   // Create a node over an existing space
 162   static VirtualSpaceNode* create_node(ReservedSpace rs, CommitLimiter* limiter, SizeCounter* reserve_words_counter,
 163                                        SizeCounter* commit_words_counter);
 164 
 165   ~VirtualSpaceNode();
 166 
 167   // Note: public for gtests only, could be private.
 168   MetaWord* base() const        { return _base; }
 169 
 170   // Reserved size of the whole node.
 171   size_t word_size() const      { return _word_size; }
 172 
 173   //// Chunk allocation, splitting, merging /////
 174 
 175   // Allocate a root chunk from this node. Will fail and return NULL if the node is full
 176   //  - if we used up the whole address space of this node's memory region.
 177   //    (in case this node backs compressed class space, this is how we hit
 178   //     CompressedClassSpaceSize).
 179   // Note that this just returns reserved memory; caller must take care of committing this
 180   //  chunk before using it.
 181   Metachunk* allocate_root_chunk();
 182 
 183   // Given a chunk c, split it recursively until you get a chunk of the given target_level.
 184   //
 185   // The resulting target chunk resides at the same address as the original chunk.
 186   // The resulting splinters are added to freelists.
 187   void split(chunklevel_t target_level, Metachunk* c, FreeChunkListVector* freelists);
 188 
 189   // Given a chunk, attempt to merge it recursively with its neighboring chunks.
 190   //
 191   // If successful (merged at least once), returns address of
 192   // the merged chunk; NULL otherwise.
 193   //
 194   // The merged chunks are removed from the freelists.
 195   //
 196   // !!! Please note that if this method returns a non-NULL value, the
 197   // original chunk will be invalid and should not be accessed anymore! !!!
 198   Metachunk* merge(Metachunk* c, FreeChunkListVector* freelists);
 199 
 200   // Given a chunk c, which must be "in use" and must not be a root chunk, attempt to
 201   // enlarge it in place by claiming its trailing buddy.
 202   //
 203   // This will only work if c is the leader of the buddy pair and the trailing buddy is free.
 204   //
 205   // If successful, the follower chunk will be removed from the freelists, the leader chunk c will
 206   // double in size (level decreased by one).
 207   //
 208   // On success, true is returned, false otherwise.
 209   bool attempt_enlarge_chunk(Metachunk* c, FreeChunkListVector* freelists);
 210 
 211   // Attempts to purge the node:
 212   //
 213   // If all chunks living in this node are free, they will all be removed from
 214   //  the freelist they currently reside in. Then, the node will be deleted.
 215   //
 216   // Returns true if the node has been deleted, false if not.
 217   // !! If this returns true, do not access the node from this point on. !!
 218   bool attempt_purge(FreeChunkListVector* freelists);
 219 
 220   // Attempts to uncommit free areas according to the rules set in settings.
 221   // Returns number of words uncommitted.
 222   size_t uncommit_free_areas();
 223 
 224   /// misc /////
 225 
 226   // Returns size, in words, of the used space in this node alone.
 227   // (Notes:
 228   //  - This is the space handed out to the ChunkManager, so it is "used" from the viewpoint of this node,
 229   //    but not necessarily used for Metadata.
 230   //  - This may or may not be committed memory.
 231   size_t used_words() const             { return _used_words; }
 232 
 233   // Returns size, in words, of how much space is left in this node alone.
 234   size_t free_words() const             { return _word_size - _used_words; }
 235 
 236   // Returns size, in words, of committed space in this node alone.
 237   // Note: iterates over commit mask and hence may be a tad expensive on large nodes.
 238   size_t committed_words() const;
 239 
 240   //// Committing/uncommitting memory /////
 241 
 242   // Given an address range, ensure it is committed.
 243   //
 244   // The range does not have to be aligned to granule size. However, the function will always commit
 245   // whole granules.
 246   //
 247   // Function will:
 248   // - check how many granules in that region are uncommitted; If all are committed, it
 249   //    returns true immediately.
 250   // - check if committing those uncommitted granules would bring us over the commit limit
 251   //    (GC threshold, MaxMetaspaceSize). If true, it returns false.
 252   // - commit the memory.
 253   // - mark the range as committed in the commit mask
 254   //
 255   // Returns true if success, false if it did hit a commit limit.
 256   bool ensure_range_is_committed(MetaWord* p, size_t word_size);
 257 
 258   // Given an address range (which has to be aligned to commit granule size):
 259   //  - uncommit it
 260   //  - mark it as uncommitted in the commit mask
 261   void uncommit_range(MetaWord* p, size_t word_size);
 262 
 263   //// List stuff ////
 264   VirtualSpaceNode* next() const        { return _next; }
 265   void set_next(VirtualSpaceNode* vsn)  { _next = vsn; }
 266 
 267   /// Debug stuff ////
 268 
 269   // Print a description about this node.
 270   void print_on(outputStream* st) const;
 271 
 272   // Verify counters and basic structure. Slow mode: verify all chunks in depth
 273   bool contains(const MetaWord* p) const {
 274     return p >= _base && p < _base + _used_words;
 275   }
 276 
 277 #ifdef ASSERT
 278   void check_pointer(const MetaWord* p) const {
 279     assert(contains(p), "invalid pointer");
 280   }
 281   void verify() const;
 282   void verify_locked() const;
 283 #endif
 284 
 285 };
 286 
 287 } // namespace metaspace
 288 
 289 #endif // SHARE_MEMORY_METASPACE_MSVIRTUALSPACENODE_HPP