/
githubmirror
/
jdk22
Обзор
Документация
Войти
/
githubmirror
/
jdk22
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/hotspot/share/utilities/bitMap.inline.hpp
589 строк
20 KB
Daniel Jeliński
8310948: Fix ignored-qualifiers warning in Hotspot
03 июл 2023, 10:51
03 июл 2023, 10:51
055b4b4
Код
Авторство
О чём код?
/* * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #ifndef SHARE_UTILITIES_BITMAP_INLINE_HPP #define SHARE_UTILITIES_BITMAP_INLINE_HPP #include "utilities/bitMap.hpp" #include "runtime/atomic.hpp" #include "utilities/align.hpp" #include "utilities/count_trailing_zeros.hpp" #include "utilities/powerOfTwo.hpp" inline void BitMap::set_bit(idx_t bit) { verify_index(bit); *word_addr(bit) |= bit_mask(bit); } inline void BitMap::clear_bit(idx_t bit) { verify_index(bit); *word_addr(bit) &= ~bit_mask(bit); } inline BitMap::bm_word_t BitMap::load_word_ordered(const volatile bm_word_t* const addr, atomic_memory_order memory_order) { if (memory_order == memory_order_relaxed || memory_order == memory_order_release) { return Atomic::load(addr); } else { assert(memory_order == memory_order_acq_rel || memory_order == memory_order_acquire || memory_order == memory_order_conservative, "unexpected memory ordering"); return Atomic::load_acquire(addr); } } inline bool BitMap::par_at(idx_t bit, atomic_memory_order memory_order) const { verify_index(bit); assert(memory_order == memory_order_acquire || memory_order == memory_order_relaxed, "unexpected memory ordering"); const volatile bm_word_t* const addr = word_addr(bit); return (load_word_ordered(addr, memory_order) & bit_mask(bit)) != 0; } inline bool BitMap::par_set_bit(idx_t bit, atomic_memory_order memory_order) { verify_index(bit); volatile bm_word_t* const addr = word_addr(bit); const bm_word_t mask = bit_mask(bit); bm_word_t old_val = load_word_ordered(addr, memory_order); do { const bm_word_t new_val = old_val | mask; if (new_val == old_val) { return false; // Someone else beat us to it. } const bm_word_t cur_val = Atomic::cmpxchg(addr, old_val, new_val, memory_order); if (cur_val == old_val) { return true; // Success. } old_val = cur_val; // The value changed, try again. } while (true); } inline bool BitMap::par_clear_bit(idx_t bit, atomic_memory_order memory_order) { verify_index(bit); volatile bm_word_t* const addr = word_addr(bit); const bm_word_t mask = ~bit_mask(bit); bm_word_t old_val = load_word_ordered(addr, memory_order); do { const bm_word_t new_val = old_val & mask; if (new_val == old_val) { return false; // Someone else beat us to it. } const bm_word_t cur_val = Atomic::cmpxchg(addr, old_val, new_val, memory_order); if (cur_val == old_val) { return true; // Success. } old_val = cur_val; // The value changed, try again. } while (true); } inline void BitMap::set_range(idx_t beg, idx_t end, RangeSizeHint hint) { if (hint == small_range && end - beg == 1) { set_bit(beg); } else { if (hint == large_range) { set_large_range(beg, end); } else { set_range(beg, end); } } } inline void BitMap::clear_range(idx_t beg, idx_t end, RangeSizeHint hint) { if (end - beg == 1) { clear_bit(beg); } else { if (hint == large_range) { clear_large_range(beg, end); } else { clear_range(beg, end); } } } inline void BitMap::par_set_range(idx_t beg, idx_t end, RangeSizeHint hint) { if (hint == small_range && end - beg == 1) { par_at_put(beg, true); } else { if (hint == large_range) { par_at_put_large_range(beg, end, true); } else { par_at_put_range(beg, end, true); } } } inline void BitMap::set_range_of_words(idx_t beg, idx_t end) { bm_word_t* map = _map; for (idx_t i = beg; i < end; ++i) map[i] = ~(bm_word_t)0; } inline void BitMap::clear_range_of_words(bm_word_t* map, idx_t beg, idx_t end) { for (idx_t i = beg; i < end; ++i) map[i] = 0; } inline void BitMap::clear_range_of_words(idx_t beg, idx_t end) { clear_range_of_words(_map, beg, end); } inline void BitMap::clear() { clear_range_of_words(0, size_in_words()); } inline void BitMap::par_clear_range(idx_t beg, idx_t end, RangeSizeHint hint) { if (hint == small_range && end - beg == 1) { par_at_put(beg, false); } else { if (hint == large_range) { par_at_put_large_range(beg, end, false); } else { par_at_put_range(beg, end, false); } } } // General notes regarding find_{first,last}_bit_impl. // // The first (last) word often contains an interesting bit, either due to // density or because of features of the calling algorithm. So it's important // to examine that word with a minimum of fuss, minimizing setup time for // additional words that will be wasted if the that word is indeed // interesting. // // The first (last) bit is similarly often interesting. When it matters // (density or features of the calling algorithm make it likely that bit is // set), going straight to counting bits compares poorly to examining that bit // first; the counting operations can be relatively expensive, plus there is // the additional range check (unless aligned). But when that bit isn't set, // the cost of having tested for it is relatively small compared to the rest // of the search. // // The benefit from aligned_right being true is relatively small. It saves an // operation in the setup of the word search loop. It also eliminates the // range check on the final result. However, callers often have a comparison // with end, and inlining may allow the two comparisons to be combined. It is // important when !aligned_right that return paths either return end or a // value dominated by a comparison with end. aligned_right is still helpful // when the caller doesn't have a range check because features of the calling // algorithm guarantee an interesting bit will be present. // // The benefit from aligned_left is even smaller, as there is no savings in // the setup of the word search loop. template<BitMap::bm_word_t flip, bool aligned_right> inline BitMap::idx_t BitMap::find_first_bit_impl(idx_t beg, idx_t end) const { STATIC_ASSERT(flip == find_ones_flip || flip == find_zeros_flip); verify_range(beg, end); assert(!aligned_right || is_aligned(end, BitsPerWord), "end not aligned"); if (beg < end) { // Get the word containing beg, and shift out low bits. idx_t word_index = to_words_align_down(beg); bm_word_t cword = flipped_word(word_index, flip) >> bit_in_word(beg); if ((cword & 1) != 0) { // Test the beg bit. return beg; } // Position of bit0 of cword in the bitmap. Initially for shifted first word. idx_t cword_pos = beg; if (cword == 0) { // Test other bits in the first word. // First word had no interesting bits. Word search through // aligned up end for a non-zero flipped word. idx_t word_limit = aligned_right ? to_words_align_down(end) // Minuscule savings when aligned. : to_words_align_up(end); while (++word_index < word_limit) { cword = flipped_word(word_index, flip); if (cword != 0) { // Update for found non-zero word, and join common tail to compute // result from cword_pos and non-zero cword. cword_pos = bit_index(word_index); break; } } } // For all paths reaching here, (cword != 0) is already known, so we // expect the compiler to not generate any code for it. Either first word // was non-zero, or found a non-zero word in range, or fully scanned range // (so cword is zero). if (cword != 0) { idx_t result = cword_pos + count_trailing_zeros(cword); if (aligned_right || (result < end)) return result; // Result is beyond range bound; return end. } } return end; } template<BitMap::bm_word_t flip, bool aligned_left> inline BitMap::idx_t BitMap::find_last_bit_impl(idx_t beg, idx_t end) const { STATIC_ASSERT(flip == find_ones_flip || flip == find_zeros_flip); verify_range(beg, end); assert(!aligned_left || is_aligned(beg, BitsPerWord), "beg not aligned"); if (beg < end) { // Get the last partial and flipped word in the range. idx_t last_bit_index = end - 1; idx_t word_index = to_words_align_down(last_bit_index); bm_word_t cword = flipped_word(word_index, flip); // Mask for extracting and testing bits of last word. bm_word_t last_bit_mask = bm_word_t(1) << bit_in_word(last_bit_index); if ((cword & last_bit_mask) != 0) { // Test last bit. return last_bit_index; } // Extract prior bits, clearing those above last_bit_index. cword &= (last_bit_mask - 1); if (cword == 0) { // Test other bits in the last word. // Last word had no interesting bits. Word search through // aligned down beg for a non-zero flipped word. idx_t word_limit = to_words_align_down(beg); while (word_index-- > word_limit) { cword = flipped_word(word_index, flip); if (cword != 0) break; } } // For all paths reaching here, (cword != 0) is already known, so we // expect the compiler to not generate any code for it. Either last word // was non-zero, or found a non-zero word in range, or fully scanned range // (so cword is zero). if (cword != 0) { idx_t result = bit_index(word_index) + log2i(cword); if (aligned_left || (result >= beg)) return result; // Result is below range bound; return end. } } return end; } inline BitMap::idx_t BitMap::find_first_set_bit(idx_t beg, idx_t end) const { return find_first_bit_impl<find_ones_flip, false>(beg, end); } inline BitMap::idx_t BitMap::find_first_clear_bit(idx_t beg, idx_t end) const { return find_first_bit_impl<find_zeros_flip, false>(beg, end); } inline BitMap::idx_t BitMap::find_first_set_bit_aligned_right(idx_t beg, idx_t end) const { return find_first_bit_impl<find_ones_flip, true>(beg, end); } inline BitMap::idx_t BitMap::find_last_set_bit(idx_t beg, idx_t end) const { return find_last_bit_impl<find_ones_flip, false>(beg, end); } inline BitMap::idx_t BitMap::find_last_clear_bit(idx_t beg, idx_t end) const { return find_last_bit_impl<find_zeros_flip, false>(beg, end); } inline BitMap::idx_t BitMap::find_last_set_bit_aligned_left(idx_t beg, idx_t end) const { return find_last_bit_impl<find_ones_flip, true>(beg, end); } // IterateInvoker supports conditionally stopping iteration early. The // invoker is called with the function to apply to each set index, along with // the current index. If the function returns void then the invoker always // returns true, so no early stopping. Otherwise, the result of the function // is returned by the invoker. Iteration stops early if conversion of that // result to bool is false. template<typename ReturnType> struct BitMap::IterateInvoker { template<typename Function> bool operator()(Function function, idx_t index) const { return function(index); // Stop early if converting to bool is false. } }; template<> struct BitMap::IterateInvoker<void> { template<typename Function> bool operator()(Function function, idx_t index) const { function(index); // Result is void. return true; // Never stop early. } }; template <typename Function> inline bool BitMap::iterate(Function function, idx_t beg, idx_t end) const { auto invoke = IterateInvoker<decltype(function(beg))>(); for (idx_t index = beg; true; ++index) { index = find_first_set_bit(index, end); if (index >= end) { return true; } else if (!invoke(function, index)) { return false; } } } template <typename BitMapClosureType> inline bool BitMap::iterate(BitMapClosureType* cl, idx_t beg, idx_t end) const { auto function = [&](idx_t index) { return cl->do_bit(index); }; return iterate(function, beg, end); } template <typename Function> inline bool BitMap::reverse_iterate(Function function, idx_t beg, idx_t end) const { auto invoke = IterateInvoker<decltype(function(beg))>(); for (idx_t index; true; end = index) { index = find_last_set_bit(beg, end); if (index >= end) { return true; } else if (!invoke(function, index)) { return false; } } } template <typename BitMapClosureType> inline bool BitMap::reverse_iterate(BitMapClosureType* cl, idx_t beg, idx_t end) const { auto function = [&](idx_t index) { return cl->do_bit(index); }; return reverse_iterate(function, beg, end); } /// BitMap::IteratorImpl inline BitMap::IteratorImpl::IteratorImpl() : _map(nullptr), _cur_beg(0), _cur_end(0) {} inline BitMap::IteratorImpl::IteratorImpl(const BitMap* map, idx_t beg, idx_t end) : _map(map), _cur_beg(beg), _cur_end(end) {} inline bool BitMap::IteratorImpl::is_empty() const { return _cur_beg == _cur_end; } inline BitMap::idx_t BitMap::IteratorImpl::first() const { assert_not_empty(); return _cur_beg; } inline BitMap::idx_t BitMap::IteratorImpl::last() const { assert_not_empty(); return _cur_end - 1; } inline void BitMap::IteratorImpl::step_first() { assert_not_empty(); _cur_beg = _map->find_first_set_bit(_cur_beg + 1, _cur_end); } inline void BitMap::IteratorImpl::step_last() { assert_not_empty(); idx_t lastpos = last(); idx_t pos = _map->find_last_set_bit(_cur_beg, lastpos); _cur_end = (pos < lastpos) ? (pos + 1) : _cur_beg; } /// BitMap::Iterator inline BitMap::Iterator::Iterator() : _impl() {} inline BitMap::Iterator::Iterator(const BitMap& map) : Iterator(map, 0, map.size()) {} inline BitMap::Iterator::Iterator(const BitMap& map, idx_t beg, idx_t end) : _impl(&map, map.find_first_set_bit(beg, end), end) {} inline bool BitMap::Iterator::is_empty() const { return _impl.is_empty(); } inline BitMap::idx_t BitMap::Iterator::index() const { return _impl.first(); } inline void BitMap::Iterator::step() { _impl.step_first(); } inline BitMap::RBFIterator BitMap::Iterator::begin() const { return RBFIterator(_impl._map, _impl._cur_beg, _impl._cur_end); } inline BitMap::RBFIterator BitMap::Iterator::end() const { return RBFIterator(_impl._map, _impl._cur_end, _impl._cur_end); } /// BitMap::ReverseIterator inline BitMap::idx_t BitMap::ReverseIterator::initial_end(const BitMap& map, idx_t beg, idx_t end) { idx_t pos = map.find_last_set_bit(beg, end); return (pos < end) ? (pos + 1) : beg; } inline BitMap::ReverseIterator::ReverseIterator() : _impl() {} inline BitMap::ReverseIterator::ReverseIterator(const BitMap& map) : ReverseIterator(map, 0, map.size()) {} inline BitMap::ReverseIterator::ReverseIterator(const BitMap& map, idx_t beg, idx_t end) : _impl(&map, beg, initial_end(map, beg, end)) {} inline bool BitMap::ReverseIterator::is_empty() const { return _impl.is_empty(); } inline BitMap::idx_t BitMap::ReverseIterator::index() const { return _impl.last(); } inline void BitMap::ReverseIterator::step() { _impl.step_last(); } inline BitMap::ReverseRBFIterator BitMap::ReverseIterator::begin() const { return ReverseRBFIterator(_impl._map, _impl._cur_beg, _impl._cur_end); } inline BitMap::ReverseRBFIterator BitMap::ReverseIterator::end() const { return ReverseRBFIterator(_impl._map, _impl._cur_beg, _impl._cur_beg); } /// BitMap::RBFIterator inline BitMap::RBFIterator::RBFIterator(const BitMap* map, idx_t beg, idx_t end) : _impl(map, beg, end) {} inline bool BitMap::RBFIterator::operator!=(const RBFIterator& i) const { // Shouldn't be comparing RBF iterators from different contexts. assert(_impl._map == i._impl._map, "mismatched range-based for iterators"); assert(_impl._cur_end == i._impl._cur_end, "mismatched range-based for iterators"); return _impl._cur_beg != i._impl._cur_beg; } inline BitMap::idx_t BitMap::RBFIterator::operator*() const { return _impl.first(); } inline BitMap::RBFIterator& BitMap::RBFIterator::operator++() { _impl.step_first(); return *this; } /// BitMap::ReverseRBFIterator inline BitMap::ReverseRBFIterator::ReverseRBFIterator(const BitMap* map, idx_t beg, idx_t end) : _impl(map, beg, end) {} inline bool BitMap::ReverseRBFIterator::operator!=(const ReverseRBFIterator& i) const { // Shouldn't be comparing RBF iterators from different contexts. assert(_impl._map == i._impl._map, "mismatched range-based for iterators"); assert(_impl._cur_beg == i._impl._cur_beg, "mismatched range-based for iterators"); return _impl._cur_end != i._impl._cur_end; } inline BitMap::idx_t BitMap::ReverseRBFIterator::operator*() const { return _impl.last(); } inline BitMap::ReverseRBFIterator& BitMap::ReverseRBFIterator::operator++() { _impl.step_last(); return *this; } // Returns a bit mask for a range of bits [beg, end) within a single word. Each // bit in the mask is 0 if the bit is in the range, 1 if not in the range. The // returned mask can be used directly to clear the range, or inverted to set the // range. Note: end must not be 0. inline BitMap::bm_word_t BitMap::inverted_bit_mask_for_range(idx_t beg, idx_t end) const { assert(end != 0, "does not work when end == 0"); assert(beg == end || to_words_align_down(beg) == to_words_align_down(end - 1), "must be a single-word range"); bm_word_t mask = bit_mask(beg) - 1; // low (right) bits if (bit_in_word(end) != 0) { mask |= ~(bit_mask(end) - 1); // high (left) bits } return mask; } inline void BitMap::set_large_range_of_words(idx_t beg, idx_t end) { assert(beg <= end, "underflow"); memset(_map + beg, ~(unsigned char)0, (end - beg) * sizeof(bm_word_t)); } inline void BitMap::clear_large_range_of_words(idx_t beg, idx_t end) { assert(beg <= end, "underflow"); memset(_map + beg, 0, (end - beg) * sizeof(bm_word_t)); } inline bool BitMap2D::is_valid_index(idx_t slot_index, idx_t bit_within_slot_index) { verify_bit_within_slot_index(bit_within_slot_index); return (bit_index(slot_index, bit_within_slot_index) < size_in_bits()); } inline bool BitMap2D::at(idx_t slot_index, idx_t bit_within_slot_index) const { verify_bit_within_slot_index(bit_within_slot_index); return _map.at(bit_index(slot_index, bit_within_slot_index)); } inline void BitMap2D::set_bit(idx_t slot_index, idx_t bit_within_slot_index) { verify_bit_within_slot_index(bit_within_slot_index); _map.set_bit(bit_index(slot_index, bit_within_slot_index)); } inline void BitMap2D::clear_bit(idx_t slot_index, idx_t bit_within_slot_index) { verify_bit_within_slot_index(bit_within_slot_index); _map.clear_bit(bit_index(slot_index, bit_within_slot_index)); } inline void BitMap2D::at_put(idx_t slot_index, idx_t bit_within_slot_index, bool value) { verify_bit_within_slot_index(bit_within_slot_index); _map.at_put(bit_index(slot_index, bit_within_slot_index), value); } inline void BitMap2D::at_put_grow(idx_t slot_index, idx_t bit_within_slot_index, bool value) { verify_bit_within_slot_index(bit_within_slot_index); idx_t bit = bit_index(slot_index, bit_within_slot_index); if (bit >= _map.size()) { _map.resize(2 * MAX2(_map.size(), bit)); } _map.at_put(bit, value); } #endif // SHARE_UTILITIES_BITMAP_INLINE_HPP