1 /* 2 * Copyright (c) 2018, 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 25 #ifndef SHARE_MEMORY_METASPACE_ABSTRACTPOOL_HPP 26 #define SHARE_MEMORY_METASPACE_ABSTRACTPOOL_HPP 27 28 #include "memory/allocation.hpp" 29 #include "utilities/debug.hpp" 30 #include "utilities/globalDefinitions.hpp" 31 32 namespace metaspace { 33 34 // A simple helper class; 35 // 36 // Holds a linear array of elements of type E. Array lives in C heap and 37 // expands automatically. Free elements can be returned, will be kept in 38 // a freelist. Elements can be retrieved by their index (index type I). 39 // Index 0 will never be allocated and can be relied upon as being invalid. 40 // 41 // E must be of at least sizeof(I), and I must be an integral size. 42 // 43 template <class E, class I> 44 class AbstractPool { 45 public: 46 47 typedef I size_type_t; 48 49 private: 50 51 E* _arr; 52 size_type_t _capacity; 53 size_type_t _top; 54 55 I _freelist; 56 size_type_t _num_in_freelist; 57 58 const size_type_t _max_capacity; 59 const size_type_t _capacity_increase; 60 const char* const _name; 61 62 // Enlarge internal array if needed. Zero out new portion of array. 63 void enlarge_to(size_type_t new_len) { 64 E* p = REALLOC_C_HEAP_ARRAY(E, _arr, new_len, mtInternal); 65 _arr = p; 66 _capacity = new_len; 67 } 68 69 //// freelist handling //// 70 71 struct free_elem_t { 72 I next_idx; 73 }; 74 75 // free_elem_t must fit into an E, and sizeof(E) must be aligned such that 76 // one can write free_elem_t at &E. 77 STATIC_ASSERT(sizeof(E) >= sizeof(free_elem_t)); 78 STATIC_ASSERT(sizeof(E) % sizeof(free_elem_t) == 0); 79 80 E* take_from_freelist() { 81 I idx = _freelist; 82 if (0 == idx) { 83 assert(_num_in_freelist == 0, "counter mismatch"); 84 return NULL; 85 } 86 E* p = elem_at_index(idx); 87 _freelist = ((free_elem_t*)p)->next_idx; 88 assert(_num_in_freelist > 0, "counter underflow"); 89 _num_in_freelist --; 90 return p; 91 } 92 93 void add_to_freelist(E* p) { 94 ((free_elem_t*)p)->next_idx = _freelist; 95 _freelist = index_for_elem(p); 96 _num_in_freelist ++; 97 } 98 99 public: 100 101 AbstractPool(const char* name, size_type_t max_capacity, size_type_t capacity_increase) 102 : _arr(NULL), _capacity(0), 103 _top(0), 104 _freelist((I)0), _num_in_freelist(0), 105 _max_capacity(max_capacity), _capacity_increase(capacity_increase), 106 _name(name) 107 {} 108 109 ~AbstractPool() { FREE_C_HEAP_ARRAY(E, _arr); } 110 111 I index_for_elem(const E* p) const { 112 DEBUG_ONLY(check_elem(p)); 113 return p - _arr; 114 } 115 116 E* elem_at_index(I i) const { 117 DEBUG_ONLY(check_idx(i)); 118 return _arr + i; 119 } 120 121 // Allocate a new element. Enlarge internal array if needed. 122 // Will return NULL if max_size is reached. 123 E* allocate_element() { 124 125 DEBUG_ONLY(verify(false)); 126 127 E* p = take_from_freelist(); 128 if (p != NULL) { 129 return p; 130 } 131 132 if (_capacity == _top) { // Need to enlarge. 133 size_type_t new_cap = MIN2((size_type_t)(_capacity + _capacity_increase), _max_capacity); 134 if (new_cap == _capacity) { 135 return NULL; // capped out. 136 } 137 enlarge_to(new_cap); 138 } 139 140 // Avoid handing out anything at index 0. 141 // This allows callers to use "I index == 0" as "invalid ref". 142 if (_top == 0) { 143 _top ++; 144 } 145 146 p = _arr + _top; 147 _top ++; 148 149 return p; 150 151 } 152 153 void return_element(E* p) { 154 DEBUG_ONLY(check_elem(p)); 155 add_to_freelist(p); 156 } 157 158 // Returns number of allocated elements. 159 size_type_t used() const { return _top - _num_in_freelist; } 160 161 // True if pool is full. 162 bool is_full() const { return used() == max_capacity(); } 163 164 // True if pool is empty. 165 bool is_empty() const { return used() == 0; } 166 167 // Returns number of elements in free list. 168 size_type_t free_elements() const { return _num_in_freelist; } 169 170 // Returns max. capacity of this pool. 171 size_type_t max_capacity() const { return _max_capacity; } 172 173 // Returns size of memory used. 174 size_t memory_footprint_words() const { return _capacity * sizeof(E); } 175 176 // Returns true if p was allocated from this pool. 177 bool is_valid_elem(const E* p) const { return p >= _arr && p < _arr + _top; } 178 179 // Returns true if the index points into the allocated portion of the pool. 180 // Note: may point to an allocated element or one in the freelist. 181 bool is_valid_index(I idx) const { return idx > 0 && idx < _top; } 182 183 #ifdef ASSERT 184 void check_elem(const E* p) const { assert(is_valid_elem(p), "invalid pointer"); } 185 void check_idx(I i) const { assert(i > 0 && i <= _top, "invalid index"); } 186 void verify(bool slow) const { 187 assert(_top <= _capacity && _capacity <= _max_capacity, "Sanity"); 188 assert(used() <= _capacity, "Sanity"); 189 if (slow) { 190 // check freelist. 191 I idx = _freelist; 192 size_type_t num = 0; 193 while (idx != 0) { 194 num ++; 195 idx = ((free_elem_t*)elem_at_index(idx))->next_idx; 196 } 197 assert(num == _num_in_freelist, "counter mismatch"); 198 } 199 } 200 #endif // ASSERT 201 202 }; 203 204 205 } // namespace metaspace 206 207 208 209 210 #endif // SHARE_MEMORY_METASPACE_ABSTRACTPOOL_HPP