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