1 /*
   2  * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2017, 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_MSMETACHUNK_HPP
  27 #define SHARE_MEMORY_METASPACE_MSMETACHUNK_HPP
  28 
  29 #include "memory/metaspace/msChunklevel.hpp"
  30 #include "memory/metaspace/msCounter.hpp"
  31 #include "utilities/debug.hpp"
  32 #include "utilities/globalDefinitions.hpp"
  33 
  34 class outputStream;
  35 
  36 namespace metaspace {
  37 
  38 class VirtualSpaceNode;
  39 
  40 // A Metachunk is a contiguous metaspace memory region. It is part of
  41 // a MetaspaceArena, which keeps a list of MetaChunk and allocates via
  42 // pointer bump from the top element in the list.
  43 //
  44 // The Metachunk object itself (the "chunk header") is separated from
  45 //  the memory region (the chunk payload) it describes. It also can have
  46 //  no payload (a "dead" chunk). In itself it lives in C-heap, managed
  47 //  as part of a pool of Metachunk headers (ChunkHeaderPool).
  48 //
  49 // -- Metachunk state --
  50 //
  51 // A Metachunk is "in-use" if it is part of a MetaspaceArena. That means
  52 //  its memory is used - or will be used shortly - to hold VM metadata
  53 //  on behalf of a class loader.
  54 //
  55 // A Metachunk is "free" if its payload is currently unused. In that
  56 //  case it is managed by a chunk freelist (the ChunkManager).
  57 // 
  58 // A Metachunk is "dead" if it does not have a corresponding payload.
  59 //  In that case it lives as part of a freelist-of-dead-chunk-headers
  60 //  in the ChunkHeaderPool.
  61 //
  62 // -- Level --
  63 //
  64 // Metachunks are managed as part of a buddy style allocation scheme.
  65 // Sized always in steps of power-of-2, ranging from the smallest chunk size
  66 // (1Kb) to the largest (4Mb) (see chunklevel.hpp).
  67 // Its size is encoded as level, with level 0 being the largest chunk
  68 // size ("root chunk").
  69 //
  70 // -- Payload commit state --
  71 //
  72 // A Metachunk payload may be committed, partly committed or completely
  73 // uncommitted. Technically, a payload may be committed "checkered" -
  74 // i.e. committed and uncommitted parts may interleave - but the
  75 // important part is how much contiguous space is committed starting
  76 // at the base of the payload (since that's where we allocate). 
  77 // 
  78 // The Metachunk keeps track of how much space is committed starting
  79 //  at the base of the payload - which is a performace optimization - 
  80 //  while underlying layers (VirtualSpaceNode->commitmask) keep track
  81 //  of the "real" commit state, aka which granules are committed,
  82 //  independent on what chunks reside above those granules.
  83 
  84 //            +--------------+ <- end    -----------+ ----------+
  85 //            |              |                      |           |
  86 //            |              |                      |           |
  87 //            |              |                      |           |
  88 //            |              |                      |           |
  89 //            |              |                      |           |
  90 //            | -----------  | <- committed_top  -- +           |
  91 //            |              |                      |           |
  92 //            |              |                      | "free"    |
  93 //            |              |                      |           | size 
  94 //            |              |     "free_below_     |           |
  95 //            |              |        committed"    |           |
  96 //            |              |                      |           |
  97 //            |              |                      |           |
  98 //            | -----------  | <- top     --------- + --------  |
  99 //            |              |                      |           |
 100 //            |              |     "used"           |           |
 101 //            |              |                      |           |
 102 //            +--------------+ <- start   ----------+ ----------+
 103 
 104 // Note: this is a chunk **descriptor**. The real Payload area lives in metaspace,
 105 // this class lives somewhere else.
 106 class Metachunk {
 107 
 108   // start of chunk memory; NULL if dead.
 109   MetaWord* _base;
 110 
 111   // Used words.
 112   size_t _used_words;
 113 
 114   // Size of the region, starting from base, which is guaranteed to be committed. In words.
 115   //  The actual size of committed regions may actually be larger.
 116   //
 117   //  (This is a performance optimization. The underlying VirtualSpaceNode knows
 118   //   which granules are committed; but we want to avoid having to ask.)
 119   size_t _committed_words;
 120 
 121   chunklevel_t _level; // aka size.
 122 
 123   // state_free:    free, owned by a ChunkManager
 124   // state_in_use:  in-use, owned by a MetaspaceArena
 125   // dead:          just a hollow chunk header without associated memory, owned
 126   //                 by chunk header pool.
 127   enum class State : uint8_t {
 128     Free = 0,
 129     InUse = 1,
 130     Dead = 2
 131   };
 132   State _state;
 133 
 134   // We need unfortunately a back link to the virtual space node
 135   // for splitting and merging nodes.
 136   VirtualSpaceNode* _vsnode;
 137 
 138   // A chunk header is kept in a list:
 139   // 1 in the list of used chunks inside a MetaspaceArena, if it is in use
 140   // 2 in the list of free chunks inside a ChunkManager, if it is free
 141   // 3 in the freelist of unused headers inside the ChunkHeaderPool,
 142   //   if it is unused (e.g. result of chunk merging) and has no associated
 143   //   memory area.
 144   Metachunk* _prev;
 145   Metachunk* _next;
 146 
 147   // Furthermore, we keep, per chunk, information about the neighboring chunks.
 148   // This is needed to split and merge chunks.
 149   //
 150   // Note: These members can be modified concurrently while a chunk is alive and in use.
 151   // This can happen if a neighboring chunk is added or removed.
 152   // This means only read or modify these members under expand lock protection.
 153   Metachunk* _prev_in_vs;
 154   Metachunk* _next_in_vs;
 155 
 156   // Commit uncommitted section of the chunk.
 157   // Fails if we hit a commit limit.
 158   bool commit_up_to(size_t new_committed_words);
 159 
 160   DEBUG_ONLY(static void assert_have_expand_lock();)
 161 
 162 public:
 163 
 164   Metachunk()
 165     : _base(NULL),
 166       _used_words(0),
 167       _committed_words(0),
 168       _level(chunklevel::ROOT_CHUNK_LEVEL),
 169       _state(State::Free),
 170       _vsnode(NULL),
 171       _prev(NULL), _next(NULL),
 172       _prev_in_vs(NULL), _next_in_vs(NULL)
 173   {}
 174 
 175  void clear() {
 176    _base = NULL;
 177    _used_words = 0;
 178    _committed_words = 0;
 179    _level = chunklevel::ROOT_CHUNK_LEVEL;
 180    _state = State::Free;
 181    _vsnode = NULL;
 182    _prev = NULL;
 183    _next = NULL;
 184    _prev_in_vs = NULL;
 185    _next_in_vs = NULL;
 186   }
 187 
 188   size_t word_size() const        { return chunklevel::word_size_for_level(_level); }
 189 
 190   MetaWord* base() const          { return _base; }
 191   MetaWord* top() const           { return base() + _used_words; }
 192   MetaWord* committed_top() const { return base() + _committed_words; }
 193   MetaWord* end() const           { return base() + word_size(); }
 194 
 195   // Chunk list wiring
 196   void set_prev(Metachunk* c)     { _prev = c; }
 197   Metachunk* prev() const         { return _prev; }
 198   void set_next(Metachunk* c)     { _next = c; }
 199   Metachunk* next() const         { return _next; }
 200 
 201   DEBUG_ONLY(bool in_list() const { return _prev != NULL || _next != NULL; })
 202 
 203   // Physical neighbors wiring
 204   void set_prev_in_vs(Metachunk* c) { DEBUG_ONLY(assert_have_expand_lock()); _prev_in_vs = c; }
 205   Metachunk* prev_in_vs() const     { DEBUG_ONLY(assert_have_expand_lock()); return _prev_in_vs; }
 206   void set_next_in_vs(Metachunk* c) { DEBUG_ONLY(assert_have_expand_lock()); _next_in_vs = c; }
 207   Metachunk* next_in_vs() const     { DEBUG_ONLY(assert_have_expand_lock()); return _next_in_vs; }
 208 
 209   bool is_free() const            { return _state == State::Free; }
 210   bool is_in_use() const          { return _state == State::InUse; }
 211   bool is_dead() const            { return _state == State::Dead; }
 212   void set_free()                 { _state = State::Free; }
 213   void set_in_use()               { _state = State::InUse; }
 214   void set_dead()                 { _state = State::Dead; }
 215 
 216   // Return a single char presentation of the state ('f', 'u', 'd')
 217   char get_state_char() const;
 218 
 219   void inc_level()                { _level++; DEBUG_ONLY(chunklevel::is_valid_level(_level);) }
 220   void dec_level()                { _level --; DEBUG_ONLY(chunklevel::is_valid_level(_level);) }
 221   chunklevel_t level() const          { return _level; }
 222 
 223   // Convenience functions for extreme levels.
 224   bool is_root_chunk() const      { return chunklevel::ROOT_CHUNK_LEVEL == _level; }
 225   bool is_leaf_chunk() const      { return chunklevel::HIGHEST_CHUNK_LEVEL == _level; }
 226 
 227   VirtualSpaceNode* vsnode() const        { return _vsnode; }
 228 
 229   size_t used_words() const                   { return _used_words; }
 230   size_t free_words() const                   { return word_size() - used_words(); }
 231   size_t free_below_committed_words() const   { return committed_words() - used_words(); }
 232   void reset_used_words()                     { _used_words = 0; }
 233 
 234   size_t committed_words() const      { return _committed_words; }
 235   void set_committed_words(size_t v);
 236   bool is_fully_committed() const     { return committed_words() == word_size(); }
 237   bool is_fully_uncommitted() const   { return committed_words() == 0; }
 238 
 239   // Ensure that chunk is committed up to at least new_committed_words words.
 240   // Fails if we hit a commit limit.
 241   bool ensure_committed(size_t new_committed_words);
 242   bool ensure_committed_locked(size_t new_committed_words);
 243 
 244   bool ensure_fully_committed()           { return ensure_committed(word_size()); }
 245   bool ensure_fully_committed_locked()    { return ensure_committed_locked(word_size()); }
 246 
 247   // Ensure that the chunk is committed far enough to serve an additional allocation of word_size.
 248   bool ensure_committed_additional(size_t additional_word_size)   {
 249     return ensure_committed(used_words() + additional_word_size);
 250   }
 251 
 252   // Uncommit chunk area. The area must be a common multiple of the
 253   // commit granule size (in other words, we cannot uncommit chunks smaller than
 254   // a commit granule size).
 255   void uncommit();
 256   void uncommit_locked();
 257 
 258   // Allocation from a chunk
 259 
 260   // Allocate word_size words from this chunk (word_size must be aligned to
 261   //  allocation_alignment_words).
 262   //
 263   // Caller must make sure the chunk is both large enough and committed far enough
 264   // to hold the allocation. Will always work.
 265   //
 266   MetaWord* allocate(size_t request_word_size);
 267 
 268   // Initialize structure for reuse.
 269   void initialize(VirtualSpaceNode* node, MetaWord* base, chunklevel_t lvl) {
 270     _vsnode = node; _base = base; _level = lvl;
 271     _used_words = _committed_words = 0; _state = State::Free;
 272     _next = _prev = _next_in_vs = _prev_in_vs = NULL;
 273   }
 274 
 275   // Returns true if this chunk is the leader in its buddy pair, false if not.
 276   // Do not call for root chunks.
 277   bool is_leader() const {
 278     assert(!is_root_chunk(), "Root chunks have no buddy."); // Bit harsh?
 279     return is_aligned(base(), chunklevel::word_size_for_level(level() - 1) * BytesPerWord);
 280   }
 281 
 282   //// Debug stuff ////
 283 #ifdef ASSERT
 284   void verify() const;
 285   // Verifies linking with neighbors in virtual space. Needs expand lock protection.
 286   void verify_neighborhood() const;
 287   void zap_header(uint8_t c = 0x17);
 288 
 289   // Returns true if given pointer points into the payload area of this chunk.
 290   bool is_valid_pointer(const MetaWord* p) const {
 291     return base() <= p && p < top();
 292   }
 293 
 294   // Returns true if given pointer points into the commmitted payload area of this chunk.
 295   bool is_valid_committed_pointer(const MetaWord* p) const {
 296     return base() <= p && p < committed_top();
 297   }
 298 
 299 #endif // ASSERT
 300 
 301   void print_on(outputStream* st) const;
 302 
 303 };
 304 
 305 // Little print helpers: since we often print out chunks, here some convenience macros
 306 #define METACHUNK_FORMAT                "@" PTR_FORMAT ", %c, base " PTR_FORMAT ", level " CHKLVL_FORMAT
 307 #define METACHUNK_FORMAT_ARGS(chunk)    p2i(chunk), chunk->get_state_char(), p2i(chunk->base()), chunk->level()
 308 
 309 #define METACHUNK_FULL_FORMAT                "@" PTR_FORMAT ", %c, base " PTR_FORMAT ", level " CHKLVL_FORMAT " (" SIZE_FORMAT "), used: " SIZE_FORMAT ", committed: " SIZE_FORMAT ", committed-free: " SIZE_FORMAT
 310 #define METACHUNK_FULL_FORMAT_ARGS(chunk)    p2i(chunk), chunk->get_state_char(), p2i(chunk->base()), chunk->level(), chunk->word_size(), chunk->used_words(), chunk->committed_words(), chunk->free_below_committed_words()
 311 
 312 } // namespace metaspace
 313 
 314 #endif // SHARE_MEMORY_METASPACE_MSMETACHUNK_HPP