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