| /* |
| * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. |
| * Copyright (c) 2025, 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. |
| * |
| */ |
| |
| #include "gc/shenandoah/shenandoahSimpleBitMap.inline.hpp" |
| |
| ShenandoahSimpleBitMap::ShenandoahSimpleBitMap(size_t num_bits) : |
| _num_bits(num_bits), |
| _num_words(align_up(num_bits, BitsPerWord) / BitsPerWord), |
| _bitmap(NEW_C_HEAP_ARRAY(uintx, _num_words, mtGC)) |
| { |
| clear_all(); |
| } |
| |
| ShenandoahSimpleBitMap::~ShenandoahSimpleBitMap() { |
| if (_bitmap != nullptr) { |
| FREE_C_HEAP_ARRAY(uintx, _bitmap); |
| } |
| } |
| |
| size_t ShenandoahSimpleBitMap::count_leading_ones(idx_t start_idx) const { |
| assert((start_idx >= 0) && (start_idx < _num_bits), "precondition"); |
| size_t array_idx = start_idx >> LogBitsPerWord; |
| uintx element_bits = _bitmap[array_idx]; |
| uintx bit_number = start_idx & (BitsPerWord - 1); |
| uintx mask = ~tail_mask(bit_number); |
| size_t counted_ones = 0; |
| while ((element_bits & mask) == mask) { |
| // All bits numbered >= bit_number are set |
| size_t found_ones = BitsPerWord - bit_number; |
| counted_ones += found_ones; |
| // Dead code: do not need to compute: start_idx += found_ones; |
| // Strength reduction: array_idx = (start_idx >> LogBitsPerWord) |
| array_idx++; |
| element_bits = _bitmap[array_idx]; |
| // Constant folding: bit_number = start_idx & (BitsPerWord - 1); |
| bit_number = 0; |
| // Constant folding: mask = ~right_n_bits(bit_number); |
| mask = ~0; |
| } |
| |
| // Add in number of consecutive ones starting with the_bit and including more significant bits and return result |
| uintx aligned = element_bits >> bit_number; |
| uintx complement = ~aligned; |
| return counted_ones + count_trailing_zeros<uintx>(complement); |
| } |
| |
| size_t ShenandoahSimpleBitMap::count_trailing_ones(idx_t last_idx) const { |
| assert((last_idx >= 0) && (last_idx < _num_bits), "precondition"); |
| size_t array_idx = last_idx >> LogBitsPerWord; |
| uintx element_bits = _bitmap[array_idx]; |
| uintx bit_number = last_idx & (BitsPerWord - 1); |
| // All ones from bit 0 to the_bit |
| uintx mask = tail_mask(bit_number + 1); |
| size_t counted_ones = 0; |
| while ((element_bits & mask) == mask) { |
| // All bits numbered <= bit_number are set |
| size_t found_ones = bit_number + 1; |
| counted_ones += found_ones; |
| // Dead code: do not need to compute: last_idx -= found_ones; |
| array_idx--; |
| element_bits = _bitmap[array_idx]; |
| // Constant folding: bit_number = last_idx & (BitsPerWord - 1); |
| bit_number = BitsPerWord - 1; |
| // Constant folding: mask = right_n_bits(bit_number + 1); |
| mask = ~0; |
| } |
| |
| // Add in number of consecutive ones starting with the_bit and including less significant bits and return result |
| uintx aligned = element_bits << (BitsPerWord - (bit_number + 1)); |
| uintx complement = ~aligned; |
| return counted_ones + count_leading_zeros<uintx>(complement); |
| } |
| |
| bool ShenandoahSimpleBitMap::is_forward_consecutive_ones(idx_t start_idx, idx_t count) const { |
| while (count > 0) { |
| assert((start_idx >= 0) && (start_idx < _num_bits), "precondition: start_idx: %zd, count: %zd", |
| start_idx, count); |
| assert(start_idx + count <= (idx_t) _num_bits, "precondition"); |
| size_t array_idx = start_idx >> LogBitsPerWord; |
| uintx bit_number = start_idx & (BitsPerWord - 1); |
| uintx element_bits = _bitmap[array_idx]; |
| uintx bits_to_examine = BitsPerWord - bit_number; |
| element_bits >>= bit_number; |
| uintx complement = ~element_bits; |
| uintx trailing_ones; |
| if (complement != 0) { |
| trailing_ones = count_trailing_zeros<uintx>(complement); |
| } else { |
| trailing_ones = bits_to_examine; |
| } |
| if (trailing_ones >= (uintx) count) { |
| return true; |
| } else if (trailing_ones == bits_to_examine) { |
| start_idx += bits_to_examine; |
| count -= bits_to_examine; |
| // Repeat search with smaller goal |
| } else { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool ShenandoahSimpleBitMap::is_backward_consecutive_ones(idx_t last_idx, idx_t count) const { |
| while (count > 0) { |
| assert((last_idx >= 0) && (last_idx < _num_bits), "precondition"); |
| assert(last_idx - count >= -1, "precondition"); |
| size_t array_idx = last_idx >> LogBitsPerWord; |
| uintx bit_number = last_idx & (BitsPerWord - 1); |
| uintx element_bits = _bitmap[array_idx]; |
| uintx bits_to_examine = bit_number + 1; |
| element_bits <<= (BitsPerWord - bits_to_examine); |
| uintx complement = ~element_bits; |
| uintx leading_ones; |
| if (complement != 0) { |
| leading_ones = count_leading_zeros<uintx>(complement); |
| } else { |
| leading_ones = bits_to_examine; |
| } |
| if (leading_ones >= (uintx) count) { |
| return true; |
| } else if (leading_ones == bits_to_examine) { |
| last_idx -= leading_ones; |
| count -= leading_ones; |
| // Repeat search with smaller goal |
| } else { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| idx_t ShenandoahSimpleBitMap::find_first_consecutive_set_bits(idx_t beg, idx_t end, size_t num_bits) const { |
| assert((beg >= 0) && (beg < _num_bits), "precondition"); |
| |
| // Stop looking if there are not num_bits remaining in probe space. |
| idx_t start_boundary = end - num_bits; |
| if (beg > start_boundary) { |
| return end; |
| } |
| uintx array_idx = beg >> LogBitsPerWord; |
| uintx bit_number = beg & (BitsPerWord - 1); |
| uintx element_bits = _bitmap[array_idx]; |
| if (bit_number > 0) { |
| uintx mask_out = tail_mask(bit_number); |
| element_bits &= ~mask_out; |
| } |
| |
| // The following loop minimizes the number of spans probed in order to find num_bits consecutive bits. |
| // For example, if bit_number = beg = 0, num_bits = 8, and element bits equals 00111111_11000000_00000000_10011000B, |
| // we need only 3 probes to find the match at bit offset 22. |
| // |
| // Let beg = 0 |
| // element_bits = 00111111_11000000_00000000_10011000B; |
| // ________ (the searched span) |
| // ^ ^ ^- bit_number = beg = 0 |
| // | +-- next_start_candidate_1 (where next 1 is found) |
| // +------ next_start_candidate_2 (start of the trailing 1s within span) |
| // Let beg = 7 |
| // element_bits = 00111111_11000000_00000000_10011000B; |
| // ^ ^_________ (the searched span) |
| // | | ^- bit_number = beg = 7 |
| // | +---------- next_start_candidate_2 (there are no trailing 1s within span) |
| // +------------------ next_start_candidate_1 (where next 1 is found) |
| // Let beg = 22 |
| // Let beg = 22 |
| // element_bits = 00111111_11000001_11111100_10011000B; |
| // _________ (the searched span) |
| // ^- bit_number = beg = 18 |
| // Here, is_forward_consecutive_ones(22, 8) succeeds and we report the match |
| |
| while (true) { |
| if (element_bits == 0) { |
| // move to the next element |
| beg += BitsPerWord - bit_number; |
| if (beg > start_boundary) { |
| // No match found. |
| return end; |
| } |
| array_idx++; |
| bit_number = 0; |
| element_bits = _bitmap[array_idx]; |
| } else if (is_forward_consecutive_ones(beg, num_bits)) { |
| return beg; |
| } else { |
| // There is at least one non-zero bit within the masked element_bits. Arrange to skip over bits that |
| // cannot be part of a consecutive-ones match. |
| uintx next_set_bit = count_trailing_zeros<uintx>(element_bits); |
| uintx next_start_candidate_1 = (array_idx << LogBitsPerWord) + next_set_bit; |
| |
| // There is at least one zero bit in this span. Align the next probe at the start of trailing ones for probed span, |
| // or align at end of span if this span has no trailing ones. |
| size_t trailing_ones = count_trailing_ones(beg + num_bits - 1); |
| uintx next_start_candidate_2 = beg + num_bits - trailing_ones; |
| |
| beg = MAX2(next_start_candidate_1, next_start_candidate_2); |
| if (beg > start_boundary) { |
| // No match found. |
| return end; |
| } |
| array_idx = beg >> LogBitsPerWord; |
| element_bits = _bitmap[array_idx]; |
| bit_number = beg & (BitsPerWord - 1); |
| if (bit_number > 0) { |
| size_t mask_out = tail_mask(bit_number); |
| element_bits &= ~mask_out; |
| } |
| } |
| } |
| } |
| |
| idx_t ShenandoahSimpleBitMap::find_last_consecutive_set_bits(const idx_t beg, idx_t end, const size_t num_bits) const { |
| |
| assert((end >= 0) && (end < _num_bits), "precondition"); |
| |
| // Stop looking if there are not num_bits remaining in probe space. |
| idx_t last_boundary = beg + num_bits; |
| if (end < last_boundary) { |
| return beg; |
| } |
| |
| size_t array_idx = end >> LogBitsPerWord; |
| uintx bit_number = end & (BitsPerWord - 1); |
| uintx element_bits = _bitmap[array_idx]; |
| if (bit_number < BitsPerWord - 1) { |
| uintx mask_in = tail_mask(bit_number + 1); |
| element_bits &= mask_in; |
| } |
| |
| // See comment in find_first_consecutive_set_bits to understand how this loop works. |
| while (true) { |
| if (element_bits == 0) { |
| // move to the previous element |
| end -= bit_number + 1; |
| if (end < last_boundary) { |
| // No match found. |
| return beg; |
| } |
| array_idx--; |
| bit_number = BitsPerWord - 1; |
| element_bits = _bitmap[array_idx]; |
| } else if (is_backward_consecutive_ones(end, num_bits)) { |
| return end + 1 - num_bits; |
| } else { |
| // There is at least one non-zero bit within the masked element_bits. Arrange to skip over bits that |
| // cannot be part of a consecutive-ones match. |
| uintx next_set_bit = BitsPerWord - (1 + count_leading_zeros<uintx>(element_bits)); |
| uintx next_last_candidate_1 = (array_idx << LogBitsPerWord) + next_set_bit; |
| |
| // There is at least one zero bit in this span. Align the next probe at the end of leading ones for probed span, |
| // or align before start of span if this span has no leading ones. |
| size_t leading_ones = count_leading_ones(end - (num_bits - 1)); |
| uintx next_last_candidate_2 = end - (num_bits - leading_ones); |
| |
| end = MIN2(next_last_candidate_1, next_last_candidate_2); |
| if (end < last_boundary) { |
| // No match found. |
| return beg; |
| } |
| array_idx = end >> LogBitsPerWord; |
| bit_number = end & (BitsPerWord - 1); |
| element_bits = _bitmap[array_idx]; |
| if (bit_number < BitsPerWord - 1){ |
| size_t mask_in = tail_mask(bit_number + 1); |
| element_bits &= mask_in; |
| } |
| } |
| } |
| } |