1 /* 2 * Copyright (c) 2005, 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_UTILITIES_BITMAP_INLINE_HPP 26 #define SHARE_UTILITIES_BITMAP_INLINE_HPP 27 28 #include "runtime/atomic.hpp" 29 #include "utilities/align.hpp" 30 #include "utilities/bitMap.hpp" 31 #include "utilities/count_trailing_zeros.hpp" 32 33 inline void BitMap::set_bit(idx_t bit) { 34 verify_index(bit); 35 *word_addr(bit) |= bit_mask(bit); 36 } 37 38 inline void BitMap::clear_bit(idx_t bit) { 39 verify_index(bit); 40 *word_addr(bit) &= ~bit_mask(bit); 41 } 42 43 inline bool BitMap::par_set_bit(idx_t bit) { 44 verify_index(bit); 45 volatile bm_word_t* const addr = word_addr(bit); 46 const bm_word_t mask = bit_mask(bit); 47 bm_word_t old_val = *addr; 48 49 do { 50 const bm_word_t new_val = old_val | mask; 51 if (new_val == old_val) { 52 return false; // Someone else beat us to it. 53 } 54 const bm_word_t cur_val = Atomic::cmpxchg(new_val, addr, old_val); 55 if (cur_val == old_val) { 56 return true; // Success. 57 } 58 old_val = cur_val; // The value changed, try again. 59 } while (true); 60 } 61 62 inline bool BitMap::par_clear_bit(idx_t bit) { 63 verify_index(bit); 64 volatile bm_word_t* const addr = word_addr(bit); 65 const bm_word_t mask = ~bit_mask(bit); 66 bm_word_t old_val = *addr; 67 68 do { 69 const bm_word_t new_val = old_val & mask; 70 if (new_val == old_val) { 71 return false; // Someone else beat us to it. 72 } 73 const bm_word_t cur_val = Atomic::cmpxchg(new_val, addr, old_val); 74 if (cur_val == old_val) { 75 return true; // Success. 76 } 77 old_val = cur_val; // The value changed, try again. 78 } while (true); 79 } 80 81 inline void BitMap::set_range(idx_t beg, idx_t end, RangeSizeHint hint) { 82 if (hint == small_range && end - beg == 1) { 83 set_bit(beg); 84 } else { 85 if (hint == large_range) { 86 set_large_range(beg, end); 87 } else { 88 set_range(beg, end); 89 } 90 } 91 } 92 93 inline void BitMap::clear_range(idx_t beg, idx_t end, RangeSizeHint hint) { 94 if (end - beg == 1) { 95 clear_bit(beg); 96 } else { 97 if (hint == large_range) { 98 clear_large_range(beg, end); 99 } else { 100 clear_range(beg, end); 101 } 102 } 103 } 104 105 inline void BitMap::par_set_range(idx_t beg, idx_t end, RangeSizeHint hint) { 106 if (hint == small_range && end - beg == 1) { 107 par_at_put(beg, true); 108 } else { 109 if (hint == large_range) { 110 par_at_put_large_range(beg, end, true); 111 } else { 112 par_at_put_range(beg, end, true); 113 } 114 } 115 } 116 117 inline void BitMap::set_range_of_words(idx_t beg, idx_t end) { 118 bm_word_t* map = _map; 119 for (idx_t i = beg; i < end; ++i) map[i] = ~(bm_word_t)0; 120 } 121 122 inline void BitMap::clear_range_of_words(bm_word_t* map, idx_t beg, idx_t end) { 123 for (idx_t i = beg; i < end; ++i) map[i] = 0; 124 } 125 126 inline void BitMap::clear_range_of_words(idx_t beg, idx_t end) { 127 clear_range_of_words(_map, beg, end); 128 } 129 130 inline void BitMap::clear() { 131 clear_range_of_words(0, size_in_words()); 132 } 133 134 inline void BitMap::par_clear_range(idx_t beg, idx_t end, RangeSizeHint hint) { 135 if (hint == small_range && end - beg == 1) { 136 par_at_put(beg, false); 137 } else { 138 if (hint == large_range) { 139 par_at_put_large_range(beg, end, false); 140 } else { 141 par_at_put_range(beg, end, false); 142 } 143 } 144 } 145 146 template<BitMap::bm_word_t flip, bool aligned_right> 147 inline BitMap::idx_t BitMap::get_next_bit_impl(idx_t l_index, idx_t r_index) const { 148 STATIC_ASSERT(flip == find_ones_flip || flip == find_zeros_flip); 149 verify_range(l_index, r_index); 150 assert(!aligned_right || is_aligned(r_index, BitsPerWord), "r_index not aligned"); 151 152 // The first word often contains an interesting bit, either due to 153 // density or because of features of the calling algorithm. So it's 154 // important to examine that first word with a minimum of fuss, 155 // minimizing setup time for later words that will be wasted if the 156 // first word is indeed interesting. 157 158 // The benefit from aligned_right being true is relatively small. 159 // It saves a couple instructions in the setup for the word search 160 // loop. It also eliminates the range check on the final result. 161 // However, callers often have a comparison with r_index, and 162 // inlining often allows the two comparisons to be combined; it is 163 // important when !aligned_right that return paths either return 164 // r_index or a value dominated by a comparison with r_index. 165 // aligned_right is still helpful when the caller doesn't have a 166 // range check because features of the calling algorithm guarantee 167 // an interesting bit will be present. 168 169 if (l_index < r_index) { 170 // Get the word containing l_index, and shift out low bits. 171 idx_t index = word_index(l_index); 172 bm_word_t cword = (map(index) ^ flip) >> bit_in_word(l_index); 173 if ((cword & 1) != 0) { 174 // The first bit is similarly often interesting. When it matters 175 // (density or features of the calling algorithm make it likely 176 // the first bit is set), going straight to the next clause compares 177 // poorly with doing this check first; count_trailing_zeros can be 178 // relatively expensive, plus there is the additional range check. 179 // But when the first bit isn't set, the cost of having tested for 180 // it is relatively small compared to the rest of the search. 181 return l_index; 182 } else if (cword != 0) { 183 // Flipped and shifted first word is non-zero. 184 idx_t result = l_index + count_trailing_zeros(cword); 185 if (aligned_right || (result < r_index)) return result; 186 // Result is beyond range bound; return r_index. 187 } else { 188 // Flipped and shifted first word is zero. Word search through 189 // aligned up r_index for a non-zero flipped word. 190 idx_t limit = aligned_right 191 ? word_index(r_index) 192 : (word_index(r_index - 1) + 1); // Align up, knowing r_index > 0. 193 while (++index < limit) { 194 cword = map(index) ^ flip; 195 if (cword != 0) { 196 idx_t result = bit_index(index) + count_trailing_zeros(cword); 197 if (aligned_right || (result < r_index)) return result; 198 // Result is beyond range bound; return r_index. 199 assert((index + 1) == limit, "invariant"); 200 break; 201 } 202 } 203 // No bits in range; return r_index. 204 } 205 } 206 return r_index; 207 } 208 209 inline BitMap::idx_t 210 BitMap::get_next_one_offset(idx_t l_offset, idx_t r_offset) const { 211 return get_next_bit_impl<find_ones_flip, false>(l_offset, r_offset); 212 } 213 214 inline BitMap::idx_t 215 BitMap::get_next_zero_offset(idx_t l_offset, idx_t r_offset) const { 216 return get_next_bit_impl<find_zeros_flip, false>(l_offset, r_offset); 217 } 218 219 inline BitMap::idx_t 220 BitMap::get_next_one_offset_aligned_right(idx_t l_offset, idx_t r_offset) const { 221 return get_next_bit_impl<find_ones_flip, true>(l_offset, r_offset); 222 } 223 224 // Returns a bit mask for a range of bits [beg, end) within a single word. Each 225 // bit in the mask is 0 if the bit is in the range, 1 if not in the range. The 226 // returned mask can be used directly to clear the range, or inverted to set the 227 // range. Note: end must not be 0. 228 inline BitMap::bm_word_t 229 BitMap::inverted_bit_mask_for_range(idx_t beg, idx_t end) const { 230 assert(end != 0, "does not work when end == 0"); 231 assert(beg == end || word_index(beg) == word_index(end - 1), 232 "must be a single-word range"); 233 bm_word_t mask = bit_mask(beg) - 1; // low (right) bits 234 if (bit_in_word(end) != 0) { 235 mask |= ~(bit_mask(end) - 1); // high (left) bits 236 } 237 return mask; 238 } 239 240 inline void BitMap::set_large_range_of_words(idx_t beg, idx_t end) { 241 assert(beg <= end, "underflow"); 242 memset(_map + beg, ~(unsigned char)0, (end - beg) * sizeof(bm_word_t)); 243 } 244 245 inline void BitMap::clear_large_range_of_words(idx_t beg, idx_t end) { 246 assert(beg <= end, "underflow"); 247 memset(_map + beg, 0, (end - beg) * sizeof(bm_word_t)); 248 } 249 250 inline BitMap::idx_t BitMap::range_begin_align_up(idx_t bit) { 251 return align_up(bit, BitsPerWord); 252 } 253 254 inline BitMap::idx_t BitMap::range_end_align_down(idx_t bit) { 255 return align_down(bit, BitsPerWord); 256 } 257 258 inline bool BitMap2D::is_valid_index(idx_t slot_index, idx_t bit_within_slot_index) { 259 verify_bit_within_slot_index(bit_within_slot_index); 260 return (bit_index(slot_index, bit_within_slot_index) < size_in_bits()); 261 } 262 263 inline bool BitMap2D::at(idx_t slot_index, idx_t bit_within_slot_index) const { 264 verify_bit_within_slot_index(bit_within_slot_index); 265 return _map.at(bit_index(slot_index, bit_within_slot_index)); 266 } 267 268 inline void BitMap2D::set_bit(idx_t slot_index, idx_t bit_within_slot_index) { 269 verify_bit_within_slot_index(bit_within_slot_index); 270 _map.set_bit(bit_index(slot_index, bit_within_slot_index)); 271 } 272 273 inline void BitMap2D::clear_bit(idx_t slot_index, idx_t bit_within_slot_index) { 274 verify_bit_within_slot_index(bit_within_slot_index); 275 _map.clear_bit(bit_index(slot_index, bit_within_slot_index)); 276 } 277 278 inline void BitMap2D::at_put(idx_t slot_index, idx_t bit_within_slot_index, bool value) { 279 verify_bit_within_slot_index(bit_within_slot_index); 280 _map.at_put(bit_index(slot_index, bit_within_slot_index), value); 281 } 282 283 inline void BitMap2D::at_put_grow(idx_t slot_index, idx_t bit_within_slot_index, bool value) { 284 verify_bit_within_slot_index(bit_within_slot_index); 285 286 idx_t bit = bit_index(slot_index, bit_within_slot_index); 287 if (bit >= _map.size()) { 288 _map.resize(2 * MAX2(_map.size(), bit)); 289 } 290 _map.at_put(bit, value); 291 } 292 293 #endif // SHARE_UTILITIES_BITMAP_INLINE_HPP