1 /* 2 * Copyright (c) 2012, 2019, 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 #ifndef SHARE_MEMORY_METASPACE_METACHUNK_HPP 25 #define SHARE_MEMORY_METASPACE_METACHUNK_HPP 26 27 28 #include "memory/metaspace/counter.hpp" 29 #include "memory/metaspace/abstractPool.hpp" 30 #include "memory/metaspace/chunkLevel.hpp" 31 #include "utilities/debug.hpp" 32 #include "utilities/globalDefinitions.hpp" 33 34 35 36 namespace metaspace { 37 38 class VirtualSpaceNode; 39 40 // Metachunk - Quantum of allocation from a Virtualspace 41 // Metachunks are reused (when freed are put on a global freelist) and 42 // have no permanent association to a SpaceManager. 43 44 // +--------------+ <- end ----+ --+ 45 // | | | | 46 // | | | free | 47 // | | | 48 // | | | | size (aka capacity) 49 // | | | | 50 // | ----------- | <- top -- + | 51 // | | | | 52 // | | | used | 53 // +--------------+ <- start -- + -- + 54 55 // Note: this is a chunk **descriptor**. The real Payload area lives in metaspace, 56 // this class lives somewhere else. 57 class Metachunk { 58 59 // Todo: compact this node. A lot of things can be expressed more tighter. 60 61 // A chunk header is kept in a list: 62 // - in the list of used chunks inside a SpaceManager, if it is in use 63 // - in the list of free chunks inside a ChunkManager, if it is free 64 // - in the freelist of dead headers inside the MetaChunkHeaderPool, 65 // if it is dead (e.g. result of chunk merging). 66 Metachunk* _prev; 67 Metachunk* _next; 68 69 chklvl_t _level; // aka size. 70 71 // true: free, owned by ChunkManager 72 // false: in-use, owned by SpaceManager 73 // if dead, meaningless 74 bool _is_free; 75 76 // start of chunk memory; NULL if dead. 77 MetaWord* _base; 78 79 // Used words. 80 size_t _used_words; 81 82 // Guaranteed-to-be-committed-words, counted from base 83 // (This is a performance optimization. The underlying VirtualSpaceNode knows 84 // which granules are committed; but we want to avoid asking it unnecessarily 85 // in Metachunk::allocate(), so we keep a limit until which we are guaranteed 86 // to have committed memory under us.) 87 size_t _committed_words; 88 89 // the chunk tree node this header is hanging under; NULL if dead. 90 u2 _tree_node_ref; 91 92 // We need unfortunately a back link to the virtual space node 93 // for splitting and merging nodes. 94 VirtualSpaceNode* _vsnode; 95 96 MetaWord* top() const { return base() + _used_words; } 97 98 public: 99 100 Metachunk() 101 : _prev(NULL), _next(NULL), 102 _level(chklvl::ROOT_CHUNK_LEVEL), 103 _is_free(true), 104 _base(NULL), 105 _used_words(0), 106 _committed_words(0), 107 _tree_node_ref(0), 108 _vsnode(NULL) 109 {} 110 111 size_t word_size() const { return chklvl::word_size_for_level(_level); } 112 113 MetaWord* base() const { return _base; } 114 void set_base(MetaWord* p) { _base = p; } 115 MetaWord* end() const { return base() + word_size(); } 116 117 void set_prev(Metachunk* c) { _prev = c; } 118 Metachunk* prev() const { return _prev; } 119 void set_next(Metachunk* c) { _next = c; } 120 Metachunk* next() const { return _next; } 121 // Remove chunk from whatever list it lives in by wiring next with previous. 122 void remove_from_list(); 123 124 bool is_free() const { return _is_free; } 125 bool is_in_use() const { return !_is_free; } 126 void set_free(bool v) { _is_free = v; } 127 128 129 void inc_level() { _level ++; DEBUG_ONLY(chklvl::is_valid_level(_level);) } 130 void dec_level() { _level --; DEBUG_ONLY(chklvl::is_valid_level(_level);) } 131 void set_level(chklvl_t v) { _level = v; DEBUG_ONLY(chklvl::is_valid_level(_level);) } 132 chklvl_t level() const { return _level; } 133 134 void set_tree_node_ref(u2 v) { _tree_node_ref = v; } 135 u2 tree_node_ref() const { return _tree_node_ref; } 136 137 VirtualSpaceNode* vsnode() const { return _vsnode; } 138 void set_vsnode(VirtualSpaceNode* n) { _vsnode = n; } 139 140 size_t used_words() const { return _used_words; } 141 size_t free_words() const { return word_size() - used_words(); } 142 size_t free_below_committed_words() const { return committed_words() - used_words(); } 143 void reset_used_words() { _used_words = 0; } 144 145 size_t committed_words() const { return _committed_words; } 146 void set_committed_words(size_t v) { _committed_words = v; } 147 bool is_fully_committed() const { return committed_words() == word_size(); } 148 149 // Ensure that chunk is committed up to at least word_size words. 150 // Fails if we hit a commit limit. 151 bool ensure_committed(size_t word_size); 152 153 // Alignment of an allocation. 154 static const size_t allocation_alignment_bytes = 8; 155 static const size_t allocation_alignment_words = allocation_alignment_bytes / BytesPerWord; 156 157 // Allocation from a chunk 158 159 // Allocate word_size words from this chunk. 160 // 161 // May cause memory to be committed. That may fail if we hit a commit limit. In that case, 162 // NULL is returned and p_did_hit_commit_limit will be set to true. 163 // If the remainder portion of the chunk was too small to hold the allocation, 164 // NULL is returned and p_did_hit_commit_limit will be set to false. 165 MetaWord* allocate(size_t word_size, bool* p_did_hit_commit_limit); 166 167 // Wipe this object to look as if it were default constructed. 168 void wipe() { 169 _prev = NULL; _next = NULL; 170 _level = chklvl::ROOT_CHUNK_LEVEL; 171 _is_free = true; 172 _base = NULL; 173 _used_words = 0; 174 _committed_words = 0; 175 _tree_node_ref = 0; 176 _vsnode = NULL; 177 } 178 179 //// Debug stuff //// 180 DEBUG_ONLY(void verify(bool slow) const;) 181 182 }; 183 184 185 class MetachunkList { 186 187 Metachunk* _first; 188 IntCounter _num; 189 190 public: 191 192 MetachunkList() : _first(NULL), _num() {} 193 194 Metachunk* first() const { return _first; } 195 int size() const { return _num.get(); } 196 197 void add(Metachunk* c) { 198 c->set_next(_first); 199 _first = c; 200 _num.increment(); 201 } 202 203 // Remove first node unless empty. Returns node or NULL. 204 Metachunk* remove_first() { 205 Metachunk* c = _first; 206 if (c != NULL) { 207 _first = c->next(); 208 _num.decrement(); 209 } 210 return c; 211 } 212 213 // Remove given chunk from list. List must contain that chunk. 214 void remove(Metachunk* c) { 215 assert(contains(c), "Does not contain this chunk"); 216 c->remove_from_list(); 217 _num.decrement(); 218 } 219 220 // Manually decrement counter; needed for cases where chunks 221 // have been manually removed from the list without informing 222 // the list, e.g. chunk merging, see chunkManager::return_chunk(). 223 void dec_counter_by(int v) { 224 _num.decrement_by(v); 225 } 226 227 #ifdef ASSERT 228 bool contains(const Metachunk* c) const; 229 void verify(bool slow) const; 230 #endif 231 232 }; 233 234 } // namespace metaspace 235 236 #endif // SHARE_MEMORY_METASPACE_METACHUNK_HPP