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_COMMITMASK_HPP 26 #define SHARE_MEMORY_METASPACE_COMMITMASK_HPP 27 28 #include "memory/metaspace/constants.hpp" 29 #include "utilities/debug.hpp" 30 #include "utilities/bitMap.hpp" 31 #include "utilities/globalDefinitions.hpp" 32 33 namespace metaspace { 34 35 // A bitmap covering a range of metaspace; each bit in this mask corresponds to 36 // 37 class CommitMask : private CHeapBitMap { 38 39 const MetaWord* const _base; 40 const size_t _word_size; 41 42 // Given an offset, in words, into the area, return the number of the bit 43 // covering it. 44 static idx_t bitno_for_word_offset(size_t offset) { 45 return offset / constants::commit_granule_words; 46 } 47 48 idx_t bitno_for_address(const MetaWord* p) const { 49 assert(p >= _base && p < _base + _word_size, "Invalid address"); 50 const size_t off = p - _base; 51 return bitno_for_word_offset(off); 52 } 53 54 static idx_t mask_size(size_t word_size) { 55 assert(is_aligned(word_size, constants::commit_granule_words), "size not aligned correctly."); 56 return bitno_for_word_offset(word_size) + 1; 57 } 58 59 struct BitCounterClosure : public BitMapClosure { 60 idx_t cnt; 61 bool do_bit(BitMap::idx_t offset) { cnt ++; return true; } 62 }; 63 64 // Missing from BitMap. 65 // Count 1 bits in range [start, end). 66 idx_t count_one_bits_in_range(idx_t start, idx_t end) const { 67 if (start == end) { 68 return at(start) ? 1 : 0; 69 } 70 // TODO: This can be done more efficiently. 71 BitCounterClosure bcc; 72 bcc.cnt = 0; 73 iterate(&bcc, start, end + 1); 74 return bcc.cnt; 75 } 76 77 #ifdef ASSERT 78 // Given a pointer, check if it points into the range this bitmap covers. 79 bool is_pointer_valid(const MetaWord* p) const { 80 return p >= _base && p < _base + _word_size; 81 } 82 // Given a pointer, check if it points into the range this bitmap covers, 83 // and if it is aligned to commit granule border. 84 bool is_pointer_valid_and_aligned(const MetaWord* p) const { 85 return is_pointer_valid(p) && is_aligned(p, constants::commit_granule_bytes); 86 } 87 // Given a pointer, check if it points into the range this bitmap covers. 88 void check_pointer(const MetaWord* p) const { 89 assert(is_pointer_valid(p), 90 "Pointer " PTR_FORMAT " not in range of this bitmap [" PTR_FORMAT ", " PTR_FORMAT ").", 91 p2i(p), p2i(_base), p2i(_base + _word_size)); 92 } 93 // Given a pointer, check if it points into the range this bitmap covers, 94 // and if it is aligned to commit granule border. 95 void check_pointer_aligned(const MetaWord* p) const { 96 check_pointer(p); 97 assert(is_aligned(p, constants::commit_granule_bytes), 98 "Pointer " PTR_FORMAT " should be aligned to commit granule size " SIZE_FORMAT ".", p2i(p), constants::commit_granule_bytes); 99 } 100 // Given a range, check if it points into the range this bitmap covers, 101 // and if its borders are aligned to commit granule border. 102 void check_range(const MetaWord* start, size_t word_size) const { 103 check_pointer_aligned(start); 104 check_pointer_aligned(start + word_size); 105 } 106 #endif 107 108 // Marks a single commit granule as committed or uncomitted and returns 109 // its prior state. 110 bool mark_granule(idx_t bitno, bool value) { 111 bool b = at(bitno); 112 at_put(bitno, value); 113 return b; 114 } 115 116 public: 117 118 CommitMask(const MetaWord* start, size_t word_size) 119 : CHeapBitMap(mask_size(word_size)) 120 , _base(start) 121 , _word_size(word_size) 122 {} 123 124 virtual ~CommitMask() {} 125 126 // Given an address, returns true if the address is committed, false if not. 127 bool is_committed_address(const MetaWord* p) const { 128 DEBUG_ONLY(check_pointer(p)); 129 const idx_t bitno = bitno_for_address(p); 130 return at(bitno); 131 } 132 133 // Given an address range [start, end), returns true if area is fully committed through. 134 bool is_fully_committed_range(const MetaWord* start, size_t word_size) const { 135 DEBUG_ONLY(check_range(start, word_size)); 136 const idx_t b1 = bitno_for_address(start); 137 const idx_t b2 = bitno_for_address(start + word_size); 138 return get_next_zero_offset(b1, b2) == b2; 139 } 140 141 // Given an address range, return size, in number of words, of committed area within that range. 142 size_t get_committed_size_in_range(const MetaWord* start, size_t word_size) const { 143 DEBUG_ONLY(check_range(start, word_size)); 144 const idx_t b1 = bitno_for_address(start); 145 const idx_t b2 = bitno_for_address(start + word_size); 146 const idx_t num_bits = count_one_bits_in_range(b1, b2); 147 return num_bits * constants::commit_granule_words; 148 } 149 150 // Return total committed size, in number of words. 151 size_t get_committed_size() const { 152 return count_one_bits() * constants::commit_granule_words; 153 } 154 155 // Mark a whole address range [start, end) as committed. 156 // Return the number of words which had already been committed before this operation. 157 size_t mark_range_as_committed(const MetaWord* start, size_t word_size) { 158 DEBUG_ONLY(check_range(start, word_size)); 159 const idx_t b1 = bitno_for_address(start); 160 const idx_t b2 = bitno_for_address(start + word_size); 161 if (b1 == b2) { // Simple case, 1 granule 162 return mark_granule(b1, true) ? constants::commit_granule_words : 0; 163 } 164 const idx_t bits_set_before = count_one_bits_in_range(bitno_for_address(start), word_size); 165 set_range(b1, b2); 166 return bits_set_before * constants::commit_granule_words; 167 } 168 169 // Mark a whole address range [start, end) as uncommitted. 170 // Return the number of words which had already been uncommitted before this operation. 171 size_t mark_range_as_uncommitted(const MetaWord* start, size_t word_size) { 172 DEBUG_ONLY(check_range(start, word_size)); 173 const idx_t b1 = bitno_for_address(start); 174 const idx_t b2 = bitno_for_address(start + word_size); 175 if (b1 == b2) { // Simple case, 1 granule 176 return mark_granule(b1, true) ? constants::commit_granule_words : 0; 177 } 178 const idx_t bits_set_before = count_one_bits_in_range(bitno_for_address(start), word_size); 179 clear_range(b1, b2); 180 return ((b2 - b1) - bits_set_before) * constants::commit_granule_words; 181 } 182 183 184 //// Debug stuff //// 185 DEBUG_ONLY(void verify(bool slow) const;) 186 187 }; 188 189 } // namespace metaspace 190 191 #endif // SHARE_MEMORY_METASPACE_COMMITMASK_HPP