Path: blob/master/src/hotspot/share/utilities/bitMap.inline.hpp
40949 views
/*1* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#ifndef SHARE_UTILITIES_BITMAP_INLINE_HPP25#define SHARE_UTILITIES_BITMAP_INLINE_HPP2627#include "utilities/bitMap.hpp"2829#include "runtime/atomic.hpp"30#include "utilities/align.hpp"31#include "utilities/count_trailing_zeros.hpp"3233inline void BitMap::set_bit(idx_t bit) {34verify_index(bit);35*word_addr(bit) |= bit_mask(bit);36}3738inline void BitMap::clear_bit(idx_t bit) {39verify_index(bit);40*word_addr(bit) &= ~bit_mask(bit);41}4243inline const BitMap::bm_word_t BitMap::load_word_ordered(const volatile bm_word_t* const addr, atomic_memory_order memory_order) {44if (memory_order == memory_order_relaxed || memory_order == memory_order_release) {45return Atomic::load(addr);46} else {47assert(memory_order == memory_order_acq_rel ||48memory_order == memory_order_acquire ||49memory_order == memory_order_conservative,50"unexpected memory ordering");51return Atomic::load_acquire(addr);52}53}5455inline bool BitMap::par_at(idx_t index, atomic_memory_order memory_order) const {56verify_index(index);57assert(memory_order == memory_order_acquire ||58memory_order == memory_order_relaxed,59"unexpected memory ordering");60const volatile bm_word_t* const addr = word_addr(index);61return (load_word_ordered(addr, memory_order) & bit_mask(index)) != 0;62}6364inline bool BitMap::par_set_bit(idx_t bit, atomic_memory_order memory_order) {65verify_index(bit);66volatile bm_word_t* const addr = word_addr(bit);67const bm_word_t mask = bit_mask(bit);68bm_word_t old_val = load_word_ordered(addr, memory_order);6970do {71const bm_word_t new_val = old_val | mask;72if (new_val == old_val) {73return false; // Someone else beat us to it.74}75const bm_word_t cur_val = Atomic::cmpxchg(addr, old_val, new_val, memory_order);76if (cur_val == old_val) {77return true; // Success.78}79old_val = cur_val; // The value changed, try again.80} while (true);81}8283inline bool BitMap::par_clear_bit(idx_t bit, atomic_memory_order memory_order) {84verify_index(bit);85volatile bm_word_t* const addr = word_addr(bit);86const bm_word_t mask = ~bit_mask(bit);87bm_word_t old_val = load_word_ordered(addr, memory_order);8889do {90const bm_word_t new_val = old_val & mask;91if (new_val == old_val) {92return false; // Someone else beat us to it.93}94const bm_word_t cur_val = Atomic::cmpxchg(addr, old_val, new_val, memory_order);95if (cur_val == old_val) {96return true; // Success.97}98old_val = cur_val; // The value changed, try again.99} while (true);100}101102inline void BitMap::set_range(idx_t beg, idx_t end, RangeSizeHint hint) {103if (hint == small_range && end - beg == 1) {104set_bit(beg);105} else {106if (hint == large_range) {107set_large_range(beg, end);108} else {109set_range(beg, end);110}111}112}113114inline void BitMap::clear_range(idx_t beg, idx_t end, RangeSizeHint hint) {115if (end - beg == 1) {116clear_bit(beg);117} else {118if (hint == large_range) {119clear_large_range(beg, end);120} else {121clear_range(beg, end);122}123}124}125126inline void BitMap::par_set_range(idx_t beg, idx_t end, RangeSizeHint hint) {127if (hint == small_range && end - beg == 1) {128par_at_put(beg, true);129} else {130if (hint == large_range) {131par_at_put_large_range(beg, end, true);132} else {133par_at_put_range(beg, end, true);134}135}136}137138inline void BitMap::set_range_of_words(idx_t beg, idx_t end) {139bm_word_t* map = _map;140for (idx_t i = beg; i < end; ++i) map[i] = ~(bm_word_t)0;141}142143inline void BitMap::clear_range_of_words(bm_word_t* map, idx_t beg, idx_t end) {144for (idx_t i = beg; i < end; ++i) map[i] = 0;145}146147inline void BitMap::clear_range_of_words(idx_t beg, idx_t end) {148clear_range_of_words(_map, beg, end);149}150151inline void BitMap::clear() {152clear_range_of_words(0, size_in_words());153}154155inline void BitMap::par_clear_range(idx_t beg, idx_t end, RangeSizeHint hint) {156if (hint == small_range && end - beg == 1) {157par_at_put(beg, false);158} else {159if (hint == large_range) {160par_at_put_large_range(beg, end, false);161} else {162par_at_put_range(beg, end, false);163}164}165}166167template<BitMap::bm_word_t flip, bool aligned_right>168inline BitMap::idx_t BitMap::get_next_bit_impl(idx_t l_index, idx_t r_index) const {169STATIC_ASSERT(flip == find_ones_flip || flip == find_zeros_flip);170verify_range(l_index, r_index);171assert(!aligned_right || is_aligned(r_index, BitsPerWord), "r_index not aligned");172173// The first word often contains an interesting bit, either due to174// density or because of features of the calling algorithm. So it's175// important to examine that first word with a minimum of fuss,176// minimizing setup time for later words that will be wasted if the177// first word is indeed interesting.178179// The benefit from aligned_right being true is relatively small.180// It saves an operation in the setup for the word search loop.181// It also eliminates the range check on the final result.182// However, callers often have a comparison with r_index, and183// inlining often allows the two comparisons to be combined; it is184// important when !aligned_right that return paths either return185// r_index or a value dominated by a comparison with r_index.186// aligned_right is still helpful when the caller doesn't have a187// range check because features of the calling algorithm guarantee188// an interesting bit will be present.189190if (l_index < r_index) {191// Get the word containing l_index, and shift out low bits.192idx_t index = to_words_align_down(l_index);193bm_word_t cword = (map(index) ^ flip) >> bit_in_word(l_index);194if ((cword & 1) != 0) {195// The first bit is similarly often interesting. When it matters196// (density or features of the calling algorithm make it likely197// the first bit is set), going straight to the next clause compares198// poorly with doing this check first; count_trailing_zeros can be199// relatively expensive, plus there is the additional range check.200// But when the first bit isn't set, the cost of having tested for201// it is relatively small compared to the rest of the search.202return l_index;203} else if (cword != 0) {204// Flipped and shifted first word is non-zero.205idx_t result = l_index + count_trailing_zeros(cword);206if (aligned_right || (result < r_index)) return result;207// Result is beyond range bound; return r_index.208} else {209// Flipped and shifted first word is zero. Word search through210// aligned up r_index for a non-zero flipped word.211idx_t limit = aligned_right212? to_words_align_down(r_index) // Miniscule savings when aligned.213: to_words_align_up(r_index);214while (++index < limit) {215cword = map(index) ^ flip;216if (cword != 0) {217idx_t result = bit_index(index) + count_trailing_zeros(cword);218if (aligned_right || (result < r_index)) return result;219// Result is beyond range bound; return r_index.220assert((index + 1) == limit, "invariant");221break;222}223}224// No bits in range; return r_index.225}226}227return r_index;228}229230inline BitMap::idx_t231BitMap::get_next_one_offset(idx_t l_offset, idx_t r_offset) const {232return get_next_bit_impl<find_ones_flip, false>(l_offset, r_offset);233}234235inline BitMap::idx_t236BitMap::get_next_zero_offset(idx_t l_offset, idx_t r_offset) const {237return get_next_bit_impl<find_zeros_flip, false>(l_offset, r_offset);238}239240inline BitMap::idx_t241BitMap::get_next_one_offset_aligned_right(idx_t l_offset, idx_t r_offset) const {242return get_next_bit_impl<find_ones_flip, true>(l_offset, r_offset);243}244245inline bool BitMap::iterate(BitMapClosure* cl, idx_t beg, idx_t end) {246for (idx_t index = beg; true; ++index) {247index = get_next_one_offset(index, end);248if (index >= end) {249return true;250} else if (!cl->do_bit(index)) {251return false;252}253}254}255256inline bool BitMap::iterate(BitMapClosure* cl) {257return iterate(cl, 0, size());258}259260// Returns a bit mask for a range of bits [beg, end) within a single word. Each261// bit in the mask is 0 if the bit is in the range, 1 if not in the range. The262// returned mask can be used directly to clear the range, or inverted to set the263// range. Note: end must not be 0.264inline BitMap::bm_word_t265BitMap::inverted_bit_mask_for_range(idx_t beg, idx_t end) const {266assert(end != 0, "does not work when end == 0");267assert(beg == end || to_words_align_down(beg) == to_words_align_down(end - 1),268"must be a single-word range");269bm_word_t mask = bit_mask(beg) - 1; // low (right) bits270if (bit_in_word(end) != 0) {271mask |= ~(bit_mask(end) - 1); // high (left) bits272}273return mask;274}275276inline void BitMap::set_large_range_of_words(idx_t beg, idx_t end) {277assert(beg <= end, "underflow");278memset(_map + beg, ~(unsigned char)0, (end - beg) * sizeof(bm_word_t));279}280281inline void BitMap::clear_large_range_of_words(idx_t beg, idx_t end) {282assert(beg <= end, "underflow");283memset(_map + beg, 0, (end - beg) * sizeof(bm_word_t));284}285286inline bool BitMap2D::is_valid_index(idx_t slot_index, idx_t bit_within_slot_index) {287verify_bit_within_slot_index(bit_within_slot_index);288return (bit_index(slot_index, bit_within_slot_index) < size_in_bits());289}290291inline bool BitMap2D::at(idx_t slot_index, idx_t bit_within_slot_index) const {292verify_bit_within_slot_index(bit_within_slot_index);293return _map.at(bit_index(slot_index, bit_within_slot_index));294}295296inline void BitMap2D::set_bit(idx_t slot_index, idx_t bit_within_slot_index) {297verify_bit_within_slot_index(bit_within_slot_index);298_map.set_bit(bit_index(slot_index, bit_within_slot_index));299}300301inline void BitMap2D::clear_bit(idx_t slot_index, idx_t bit_within_slot_index) {302verify_bit_within_slot_index(bit_within_slot_index);303_map.clear_bit(bit_index(slot_index, bit_within_slot_index));304}305306inline void BitMap2D::at_put(idx_t slot_index, idx_t bit_within_slot_index, bool value) {307verify_bit_within_slot_index(bit_within_slot_index);308_map.at_put(bit_index(slot_index, bit_within_slot_index), value);309}310311inline void BitMap2D::at_put_grow(idx_t slot_index, idx_t bit_within_slot_index, bool value) {312verify_bit_within_slot_index(bit_within_slot_index);313314idx_t bit = bit_index(slot_index, bit_within_slot_index);315if (bit >= _map.size()) {316_map.resize(2 * MAX2(_map.size(), bit));317}318_map.at_put(bit, value);319}320321#endif // SHARE_UTILITIES_BITMAP_INLINE_HPP322323324