1 /* 2 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 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_ROOTCHUNKAREA_HPP 27 #define SHARE_MEMORY_METASPACE_ROOTCHUNKAREA_HPP 28 29 #include "memory/allocation.hpp" 30 #include "memory/metaspace/chunkLevel.hpp" 31 #include "utilities/debug.hpp" 32 #include "utilities/globalDefinitions.hpp" 33 34 class outputStream; 35 36 namespace metaspace { 37 38 class Metachunk; 39 class MetachunkClosure; 40 class FreeChunkListVector; 41 class VirtualSpaceNode; 42 43 44 // RootChunkArea manages a memory area covering a single root chunk. 45 // 46 // Such an area may contain a single root chunk, or a number of chunks the 47 // root chunk was split into. 48 // 49 // RootChunkArea contains the functionality to merge and split chunks in 50 // buddy allocator fashion. 51 // 52 53 class RootChunkArea { 54 55 // The base address of this area. 56 // Todo: this may be somewhat superfluous since RootChunkArea only exist in the 57 // context of a series of chunks, so the address is somewhat implicit. Remove? 58 const MetaWord* const _base; 59 60 // The first chunk in this area; if this area is maximally 61 // folded, this is the root chunk covering the whole area size. 62 Metachunk* _first_chunk; 63 64 public: 65 66 RootChunkArea(const MetaWord* base); 67 ~RootChunkArea(); 68 69 // Initialize: allocate a root node and a root chunk header; return the 70 // root chunk header. It will be partly initialized. 71 // Note: this just allocates a memory-less header; memory itself is allocated inside VirtualSpaceNode. 72 Metachunk* alloc_root_chunk_header(VirtualSpaceNode* node); 73 74 75 // Given a chunk c, split it recursively until you get a chunk of the given target_level. 76 // 77 // The resulting target chunk resides at the same address as the original chunk. 78 // The resulting splinters are added to freelists. 79 // 80 // Returns pointer to the result chunk; the splitted-off chunks are added as 81 // free chunks to the freelists. 82 void split(chunklevel_t target_level, Metachunk* c, FreeChunkListVector* freelists); 83 84 // Given a chunk, attempt to merge it recursively with its neighboring chunks. 85 // 86 // If successful (merged at least once), returns address of 87 // the merged chunk; NULL otherwise. 88 // 89 // The merged chunks are removed from the freelists. 90 // 91 // !!! Please note that if this method returns a non-NULL value, the 92 // original chunk will be invalid and should not be accessed anymore! !!! 93 Metachunk* merge(Metachunk* c, FreeChunkListVector* freelists); 94 95 // Given a chunk c, which must be "in use" and must not be a root chunk, attempt to 96 // enlarge it in place by claiming its trailing buddy. 97 // 98 // This will only work if c is the leader of the buddy pair and the trailing buddy is free. 99 // 100 // If successful, the follower chunk will be removed from the freelists, the leader chunk c will 101 // double in size (level decreased by one). 102 // 103 // On success, true is returned, false otherwise. 104 bool attempt_enlarge_chunk(Metachunk* c, FreeChunkListVector* freelists); 105 106 /// range /// 107 108 const MetaWord* base() const { return _base; } 109 size_t word_size() const { return chunklevel::MAX_CHUNK_WORD_SIZE; } 110 const MetaWord* end() const { return _base + word_size(); } 111 112 // Direct access to the first chunk (use with care) 113 Metachunk* first_chunk() { return _first_chunk; } 114 const Metachunk* first_chunk() const { return _first_chunk; } 115 116 // Returns true if this root chunk area is completely free: 117 // In that case, it should only contain one chunk (maximally merged, so a root chunk) 118 // and it should be free. 119 bool is_free() const; 120 121 //// Debug stuff //// 122 123 #ifdef ASSERT 124 void check_pointer(const MetaWord* p) const { 125 assert(p >= _base && p < _base + word_size(), 126 "pointer " PTR_FORMAT " oob for this root area [" PTR_FORMAT ".." PTR_FORMAT ")", 127 p2i(p), p2i(_base), p2i(_base + word_size())); 128 } 129 void verify(bool slow) const; 130 131 // This is a separate operation from verify(). We should be able to call verify() 132 // from almost anywhere, regardless of state, but verify_area_is_ideally_merged() 133 // can only be called outside split and merge ops. 134 void verify_area_is_ideally_merged() const; 135 #endif // ASSERT 136 137 void print_on(outputStream* st) const; 138 139 }; 140 141 142 // RootChunkAreaLUT (lookup table) manages a series of contiguous root chunk areas 143 // in memory (in the context of a VirtualSpaceNode). It allows finding the containing 144 // root chunk for any given memory address. It allows for easy iteration over all 145 // root chunks. 146 // Beyond that it is unexciting. 147 class RootChunkAreaLUT { 148 149 // Base address of the whole area. 150 const MetaWord* const _base; 151 152 // Number of root chunk areas. 153 const int _num; 154 155 // Array of RootChunkArea objects. 156 RootChunkArea* _arr; 157 158 #ifdef ASSERT 159 void check_pointer(const MetaWord* p) const { 160 assert(p >= base() && p < base() + word_size(), "Invalid pointer"); 161 } 162 #endif 163 164 // Given an address into this range, return the index into the area array for the 165 // area this address falls into. 166 int index_by_address(const MetaWord* p) const { 167 DEBUG_ONLY(check_pointer(p);) 168 int idx = (int)((p - base()) / chunklevel::MAX_CHUNK_WORD_SIZE); 169 assert(idx >= 0 && idx < _num, "Sanity"); 170 return idx; 171 } 172 173 public: 174 175 RootChunkAreaLUT(const MetaWord* base, size_t word_size); 176 ~RootChunkAreaLUT(); 177 178 // Given a memory address into the range this array covers, return the 179 // corresponding area object. If none existed at this position, create it 180 // on demand. 181 RootChunkArea* get_area_by_address(const MetaWord* p) const { 182 const int idx = index_by_address(p); 183 RootChunkArea* ra = _arr + idx; 184 DEBUG_ONLY(ra->check_pointer(p);) 185 return _arr + idx; 186 } 187 188 // Access area by its index 189 int number_of_areas() const { return _num; } 190 RootChunkArea* get_area_by_index(int index) { assert(index >= 0 && index < _num, "oob"); return _arr + index; } 191 const RootChunkArea* get_area_by_index(int index) const { assert(index >= 0 && index < _num, "oob"); return _arr + index; } 192 193 /// range /// 194 195 const MetaWord* base() const { return _base; } 196 size_t word_size() const { return _num * chunklevel::MAX_CHUNK_WORD_SIZE; } 197 const MetaWord* end() const { return _base + word_size(); } 198 199 // Returns true if all areas in this area table are free (only contain free chunks). 200 bool is_free() const; 201 202 DEBUG_ONLY(void verify(bool slow) const;) 203 204 void print_on(outputStream* st) const; 205 206 }; 207 208 209 } // namespace metaspace 210 211 #endif // SHARE_MEMORY_METASPACE_ROOTCHUNKAREA_HPP