8213415: BitMap::word_index_round_up overflow problems

Limit BitMap sizes so to-word round-up can't overflow.

Reviewed-by: tschatzl, stuefe
This commit is contained in:
Kim Barrett 2019-12-03 15:12:56 -05:00
parent 7204086e7e
commit e70386f23a
8 changed files with 149 additions and 101 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2019, 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
@ -39,7 +39,7 @@ ParMarkBitMap::initialize(MemRegion covered_region)
const idx_t bits = bits_required(covered_region);
// The bits will be divided evenly between two bitmaps; each of them should be
// an integral number of words.
assert(bits % (BitsPerWord * 2) == 0, "region size unaligned");
assert(is_aligned(bits, (BitsPerWord * 2)), "region size unaligned");
const size_t words = bits / BitsPerWord;
const size_t raw_bytes = words * sizeof(idx_t);
@ -118,7 +118,7 @@ ParMarkBitMap::live_words_in_range_helper(HeapWord* beg_addr, oop end_obj) const
// The bitmap routines require the right boundary to be word-aligned.
const idx_t end_bit = addr_to_bit((HeapWord*)end_obj);
const idx_t range_end = BitMap::word_align_up(end_bit);
const idx_t range_end = align_range_end(end_bit);
idx_t beg_bit = find_obj_beg(addr_to_bit(beg_addr), range_end);
while (beg_bit < end_bit) {
@ -177,7 +177,7 @@ ParMarkBitMap::iterate(ParMarkBitMapClosure* live_closure,
assert(range_beg <= range_end, "live range invalid");
// The bitmap routines require the right boundary to be word-aligned.
const idx_t search_end = BitMap::word_align_up(range_end);
const idx_t search_end = align_range_end(range_end);
idx_t cur_beg = find_obj_beg(range_beg, search_end);
while (cur_beg < range_end) {
@ -216,8 +216,8 @@ ParMarkBitMap::iterate(ParMarkBitMapClosure* live_closure,
assert(range_end <= dead_range_end, "dead range invalid");
// The bitmap routines require the right boundary to be word-aligned.
const idx_t live_search_end = BitMap::word_align_up(range_end);
const idx_t dead_search_end = BitMap::word_align_up(dead_range_end);
const idx_t live_search_end = align_range_end(range_end);
const idx_t dead_search_end = align_range_end(dead_range_end);
idx_t cur_beg = range_beg;
if (range_beg < range_end && is_unmarked(range_beg)) {

View File

@ -138,8 +138,12 @@ public:
inline idx_t addr_to_bit(HeapWord* addr) const;
inline HeapWord* bit_to_addr(idx_t bit) const;
// Return word-aligned up range_end, which must not be greater than size().
inline idx_t align_range_end(idx_t range_end) const;
// Return the bit index of the first marked object that begins (or ends,
// respectively) in the range [beg, end). If no object is found, return end.
// end must be word-aligned.
inline idx_t find_obj_beg(idx_t beg, idx_t end) const;
inline idx_t find_obj_end(idx_t beg, idx_t end) const;

View File

@ -26,6 +26,7 @@
#define SHARE_GC_PARALLEL_PARMARKBITMAP_INLINE_HPP
#include "gc/parallel/parMarkBitMap.hpp"
#include "utilities/align.hpp"
#include "utilities/bitMap.inline.hpp"
inline ParMarkBitMap::ParMarkBitMap():
@ -146,7 +147,7 @@ inline bool ParMarkBitMap::mark_obj(oop obj, int size) {
return mark_obj((HeapWord*)obj, (size_t)size);
}
inline BitMap::idx_t ParMarkBitMap::addr_to_bit(HeapWord* addr) const {
inline ParMarkBitMap::idx_t ParMarkBitMap::addr_to_bit(HeapWord* addr) const {
DEBUG_ONLY(verify_addr(addr);)
return words_to_bits(pointer_delta(addr, region_start()));
}
@ -156,6 +157,12 @@ inline HeapWord* ParMarkBitMap::bit_to_addr(idx_t bit) const {
return region_start() + bits_to_words(bit);
}
inline ParMarkBitMap::idx_t ParMarkBitMap::align_range_end(idx_t range_end) const {
// size is aligned, so if range_end <= size then so is aligned result.
assert(range_end <= size(), "range end out of range");
return align_up(range_end, BitsPerWord);
}
inline ParMarkBitMap::idx_t ParMarkBitMap::find_obj_beg(idx_t beg, idx_t end) const {
return _beg_bits.get_next_one_offset_aligned_right(beg, end);
}
@ -167,7 +174,7 @@ inline ParMarkBitMap::idx_t ParMarkBitMap::find_obj_end(idx_t beg, idx_t end) co
inline HeapWord* ParMarkBitMap::find_obj_beg(HeapWord* beg, HeapWord* end) const {
const idx_t beg_bit = addr_to_bit(beg);
const idx_t end_bit = addr_to_bit(end);
const idx_t search_end = BitMap::word_align_up(end_bit);
const idx_t search_end = align_range_end(end_bit);
const idx_t res_bit = MIN2(find_obj_beg(beg_bit, search_end), end_bit);
return bit_to_addr(res_bit);
}
@ -175,7 +182,7 @@ inline HeapWord* ParMarkBitMap::find_obj_beg(HeapWord* beg, HeapWord* end) const
inline HeapWord* ParMarkBitMap::find_obj_end(HeapWord* beg, HeapWord* end) const {
const idx_t beg_bit = addr_to_bit(beg);
const idx_t end_bit = addr_to_bit(end);
const idx_t search_end = BitMap::word_align_up(end_bit);
const idx_t search_end = align_range_end(end_bit);
const idx_t res_bit = MIN2(find_obj_end(beg_bit, search_end), end_bit);
return bit_to_addr(res_bit);
}

View File

@ -961,7 +961,7 @@ PSParallelCompact::clear_data_covering_space(SpaceId id)
HeapWord* const max_top = MAX2(top, _space_info[id].new_top());
const idx_t beg_bit = _mark_bitmap.addr_to_bit(bot);
const idx_t end_bit = BitMap::word_align_up(_mark_bitmap.addr_to_bit(top));
const idx_t end_bit = _mark_bitmap.align_range_end(_mark_bitmap.addr_to_bit(top));
_mark_bitmap.clear_range(beg_bit, end_bit);
const size_t beg_region = _summary_data.addr_to_region_idx(bot);
@ -2849,7 +2849,7 @@ PSParallelCompact::skip_live_words(HeapWord* beg, HeapWord* end, size_t count)
ParMarkBitMap* m = mark_bitmap();
idx_t bits_to_skip = m->words_to_bits(count);
idx_t cur_beg = m->addr_to_bit(beg);
const idx_t search_end = BitMap::word_align_up(m->addr_to_bit(end));
const idx_t search_end = m->align_range_end(m->addr_to_bit(end));
do {
cur_beg = m->find_obj_beg(cur_beg, search_end);

View File

@ -174,14 +174,27 @@ void CHeapBitMap::reinitialize(idx_t size_in_bits, bool clear) {
}
#ifdef ASSERT
void BitMap::verify_index(idx_t index) const {
assert(index < _size, "BitMap index out of bounds");
void BitMap::verify_size(idx_t size_in_bits) {
assert(size_in_bits <= max_size_in_bits(),
"out of bounds: " SIZE_FORMAT, size_in_bits);
}
void BitMap::verify_range(idx_t beg_index, idx_t end_index) const {
assert(beg_index <= end_index, "BitMap range error");
// Note that [0,0) and [size,size) are both valid ranges.
if (end_index != _size) verify_index(end_index);
void BitMap::verify_index(idx_t bit) const {
assert(bit < _size,
"BitMap index out of bounds: " SIZE_FORMAT " >= " SIZE_FORMAT,
bit, _size);
}
void BitMap::verify_limit(idx_t bit) const {
assert(bit <= _size,
"BitMap limit out of bounds: " SIZE_FORMAT " > " SIZE_FORMAT,
bit, _size);
}
void BitMap::verify_range(idx_t beg, idx_t end) const {
assert(beg <= end,
"BitMap range error: " SIZE_FORMAT " > " SIZE_FORMAT, beg, end);
verify_limit(end);
}
#endif // #ifdef ASSERT
@ -228,8 +241,8 @@ void BitMap::par_put_range_within_word(idx_t beg, idx_t end, bool value) {
void BitMap::set_range(idx_t beg, idx_t end) {
verify_range(beg, end);
idx_t beg_full_word = word_index_round_up(beg);
idx_t end_full_word = word_index(end);
idx_t beg_full_word = to_words_align_up(beg);
idx_t end_full_word = to_words_align_down(end);
if (beg_full_word < end_full_word) {
// The range includes at least one full word.
@ -247,8 +260,8 @@ void BitMap::set_range(idx_t beg, idx_t end) {
void BitMap::clear_range(idx_t beg, idx_t end) {
verify_range(beg, end);
idx_t beg_full_word = word_index_round_up(beg);
idx_t end_full_word = word_index(end);
idx_t beg_full_word = to_words_align_up(beg);
idx_t end_full_word = to_words_align_down(end);
if (beg_full_word < end_full_word) {
// The range includes at least one full word.
@ -265,17 +278,19 @@ void BitMap::clear_range(idx_t beg, idx_t end) {
bool BitMap::is_small_range_of_words(idx_t beg_full_word, idx_t end_full_word) {
// There is little point to call large version on small ranges.
// Need to check carefully, keeping potential idx_t underflow in mind.
// Need to check carefully, keeping potential idx_t over/underflow in mind,
// because beg_full_word > end_full_word can occur when beg and end are in
// the same word.
// The threshold should be at least one word.
STATIC_ASSERT(small_range_words >= 1);
return (beg_full_word + small_range_words >= end_full_word);
return beg_full_word + small_range_words >= end_full_word;
}
void BitMap::set_large_range(idx_t beg, idx_t end) {
verify_range(beg, end);
idx_t beg_full_word = word_index_round_up(beg);
idx_t end_full_word = word_index(end);
idx_t beg_full_word = to_words_align_up(beg);
idx_t end_full_word = to_words_align_down(end);
if (is_small_range_of_words(beg_full_word, end_full_word)) {
set_range(beg, end);
@ -291,8 +306,8 @@ void BitMap::set_large_range(idx_t beg, idx_t end) {
void BitMap::clear_large_range(idx_t beg, idx_t end) {
verify_range(beg, end);
idx_t beg_full_word = word_index_round_up(beg);
idx_t end_full_word = word_index(end);
idx_t beg_full_word = to_words_align_up(beg);
idx_t end_full_word = to_words_align_down(end);
if (is_small_range_of_words(beg_full_word, end_full_word)) {
clear_range(beg, end);
@ -343,8 +358,8 @@ void BitMap::at_put_range(idx_t start_offset, idx_t end_offset, bool value) {
void BitMap::par_at_put_range(idx_t beg, idx_t end, bool value) {
verify_range(beg, end);
idx_t beg_full_word = word_index_round_up(beg);
idx_t end_full_word = word_index(end);
idx_t beg_full_word = to_words_align_up(beg);
idx_t end_full_word = to_words_align_down(end);
if (beg_full_word < end_full_word) {
// The range includes at least one full word.
@ -375,8 +390,8 @@ void BitMap::at_put_large_range(idx_t beg, idx_t end, bool value) {
void BitMap::par_at_put_large_range(idx_t beg, idx_t end, bool value) {
verify_range(beg, end);
idx_t beg_full_word = word_index_round_up(beg);
idx_t end_full_word = word_index(end);
idx_t beg_full_word = to_words_align_up(beg);
idx_t end_full_word = to_words_align_down(end);
if (is_small_range_of_words(beg_full_word, end_full_word)) {
par_at_put_range(beg, end, value);
@ -420,7 +435,7 @@ bool BitMap::contains(const BitMap& other) const {
assert(size() == other.size(), "must have same size");
const bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
idx_t limit = word_index(size());
idx_t limit = to_words_align_down(size());
for (idx_t index = 0; index < limit; ++index) {
// false if other bitmap has bits set which are clear in this bitmap.
if ((~dest_map[index] & other_map[index]) != 0) return false;
@ -435,7 +450,7 @@ bool BitMap::intersects(const BitMap& other) const {
assert(size() == other.size(), "must have same size");
const bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
idx_t limit = word_index(size());
idx_t limit = to_words_align_down(size());
for (idx_t index = 0; index < limit; ++index) {
if ((dest_map[index] & other_map[index]) != 0) return true;
}
@ -448,7 +463,7 @@ void BitMap::set_union(const BitMap& other) {
assert(size() == other.size(), "must have same size");
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
idx_t limit = word_index(size());
idx_t limit = to_words_align_down(size());
for (idx_t index = 0; index < limit; ++index) {
dest_map[index] |= other_map[index];
}
@ -463,7 +478,7 @@ void BitMap::set_difference(const BitMap& other) {
assert(size() == other.size(), "must have same size");
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
idx_t limit = word_index(size());
idx_t limit = to_words_align_down(size());
for (idx_t index = 0; index < limit; ++index) {
dest_map[index] &= ~other_map[index];
}
@ -478,7 +493,7 @@ void BitMap::set_intersection(const BitMap& other) {
assert(size() == other.size(), "must have same size");
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
idx_t limit = word_index(size());
idx_t limit = to_words_align_down(size());
for (idx_t index = 0; index < limit; ++index) {
dest_map[index] &= other_map[index];
}
@ -494,7 +509,7 @@ bool BitMap::set_union_with_result(const BitMap& other) {
bool changed = false;
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
idx_t limit = word_index(size());
idx_t limit = to_words_align_down(size());
for (idx_t index = 0; index < limit; ++index) {
bm_word_t orig = dest_map[index];
bm_word_t temp = orig | other_map[index];
@ -516,7 +531,7 @@ bool BitMap::set_difference_with_result(const BitMap& other) {
bool changed = false;
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
idx_t limit = word_index(size());
idx_t limit = to_words_align_down(size());
for (idx_t index = 0; index < limit; ++index) {
bm_word_t orig = dest_map[index];
bm_word_t temp = orig & ~other_map[index];
@ -538,7 +553,7 @@ bool BitMap::set_intersection_with_result(const BitMap& other) {
bool changed = false;
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
idx_t limit = word_index(size());
idx_t limit = to_words_align_down(size());
for (idx_t index = 0; index < limit; ++index) {
bm_word_t orig = dest_map[index];
bm_word_t temp = orig & other_map[index];
@ -559,7 +574,7 @@ void BitMap::set_from(const BitMap& other) {
assert(size() == other.size(), "must have same size");
bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
idx_t copy_words = word_index(size());
idx_t copy_words = to_words_align_down(size());
Copy::disjoint_words((HeapWord*)other_map, (HeapWord*)dest_map, copy_words);
idx_t rest = bit_in_word(size());
if (rest > 0) {
@ -573,7 +588,7 @@ bool BitMap::is_same(const BitMap& other) const {
assert(size() == other.size(), "must have same size");
const bm_word_t* dest_map = map();
const bm_word_t* other_map = other.map();
idx_t limit = word_index(size());
idx_t limit = to_words_align_down(size());
for (idx_t index = 0; index < limit; ++index) {
if (dest_map[index] != other_map[index]) return false;
}
@ -583,7 +598,7 @@ bool BitMap::is_same(const BitMap& other) const {
bool BitMap::is_full() const {
const bm_word_t* words = map();
idx_t limit = word_index(size());
idx_t limit = to_words_align_down(size());
for (idx_t index = 0; index < limit; ++index) {
if (~words[index] != 0) return false;
}
@ -593,7 +608,7 @@ bool BitMap::is_full() const {
bool BitMap::is_empty() const {
const bm_word_t* words = map();
idx_t limit = word_index(size());
idx_t limit = to_words_align_down(size());
for (idx_t index = 0; index < limit; ++index) {
if (words[index] != 0) return false;
}
@ -612,8 +627,8 @@ void BitMap::clear_large() {
bool BitMap::iterate(BitMapClosure* blk, idx_t leftOffset, idx_t rightOffset) {
verify_range(leftOffset, rightOffset);
idx_t startIndex = word_index(leftOffset);
idx_t endIndex = MIN2(word_index(rightOffset) + 1, size_in_words());
idx_t startIndex = to_words_align_down(leftOffset);
idx_t endIndex = to_words_align_up(rightOffset);
for (idx_t index = startIndex, offset = leftOffset;
offset < rightOffset && index < endIndex;
offset = (++index) << LogBitsPerWord) {

View File

@ -27,13 +27,12 @@
#include "memory/allocation.hpp"
#include "runtime/atomic.hpp"
#include "utilities/align.hpp"
// Forward decl;
class BitMapClosure;
// Operations for bitmaps represented as arrays of unsigned integers.
// Bit offsets are numbered from 0 to size-1.
// Bits are numbered from 0 to size-1.
// The "abstract" base BitMap class.
//
@ -50,8 +49,10 @@ class BitMap {
public:
typedef size_t idx_t; // Type used for bit and word indices.
typedef uintptr_t bm_word_t; // Element type of array that represents
// the bitmap.
typedef uintptr_t bm_word_t; // Element type of array that represents the
// bitmap, with BitsPerWord bits per element.
// If this were to fail, there are lots of places that would need repair.
STATIC_ASSERT((sizeof(bm_word_t) * BitsPerByte) == BitsPerWord);
// Hints for range sizes.
typedef enum {
@ -62,6 +63,35 @@ class BitMap {
bm_word_t* _map; // First word in bitmap
idx_t _size; // Size of bitmap (in bits)
// The maximum allowable size of a bitmap, in words or bits.
// Limit max_size_in_bits so aligning up to a word boundary never overflows.
static idx_t max_size_in_words() { return raw_to_words_align_down(~idx_t(0)); }
static idx_t max_size_in_bits() { return max_size_in_words() * BitsPerWord; }
// Assumes relevant validity checking for bit has already been done.
static idx_t raw_to_words_align_up(idx_t bit) {
return raw_to_words_align_down(bit + (BitsPerWord - 1));
}
// Assumes relevant validity checking for bit has already been done.
static idx_t raw_to_words_align_down(idx_t bit) {
return bit >> LogBitsPerWord;
}
// Word-aligns bit and converts it to a word offset.
// precondition: bit <= size()
idx_t to_words_align_up(idx_t bit) const {
verify_limit(bit);
return raw_to_words_align_up(bit);
}
// Word-aligns bit and converts it to a word offset.
// precondition: bit <= size()
inline idx_t to_words_align_down(idx_t bit) const {
verify_limit(bit);
return raw_to_words_align_down(bit);
}
// Helper for get_next_{zero,one}_bit variants.
// - flip designates whether searching for 1s or 0s. Must be one of
// find_{zeros,ones}_flip.
@ -77,6 +107,8 @@ class BitMap {
// operation was requested. Measured in words.
static const size_t small_range_words = 32;
static bool is_small_range_of_words(idx_t beg_full_word, idx_t end_full_word);
protected:
// Return the position of bit within the word that contains it (e.g., if
// bitmap words are 32 bits, return a number 0 <= n <= 31).
@ -86,9 +118,6 @@ class BitMap {
// containing the bit.
static bm_word_t bit_mask(idx_t bit) { return (bm_word_t)1 << bit_in_word(bit); }
// Return the index of the word containing the specified bit.
static idx_t word_index(idx_t bit) { return bit >> LogBitsPerWord; }
// Return the bit number of the first bit in the specified word.
static idx_t bit_index(idx_t word) { return word << LogBitsPerWord; }
@ -98,8 +127,12 @@ class BitMap {
bm_word_t map(idx_t word) const { return _map[word]; }
// Return a pointer to the word containing the specified bit.
bm_word_t* word_addr(idx_t bit) { return map() + word_index(bit); }
const bm_word_t* word_addr(idx_t bit) const { return map() + word_index(bit); }
bm_word_t* word_addr(idx_t bit) {
return map() + to_words_align_down(bit);
}
const bm_word_t* word_addr(idx_t bit) const {
return map() + to_words_align_down(bit);
}
// Set a word to a specified value or to all ones; clear a word.
void set_word (idx_t word, bm_word_t val) { _map[word] = val; }
@ -124,14 +157,16 @@ class BitMap {
static void clear_range_of_words(bm_word_t* map, idx_t beg, idx_t end);
static bool is_small_range_of_words(idx_t beg_full_word, idx_t end_full_word);
// The index of the first full word in a range.
idx_t word_index_round_up(idx_t bit) const;
// Verification.
void verify_index(idx_t index) const NOT_DEBUG_RETURN;
void verify_range(idx_t beg_index, idx_t end_index) const NOT_DEBUG_RETURN;
// Verify size_in_bits does not exceed max_size_in_bits().
static void verify_size(idx_t size_in_bits) NOT_DEBUG_RETURN;
// Verify bit is less than size().
void verify_index(idx_t bit) const NOT_DEBUG_RETURN;
// Verify bit is not greater than size().
void verify_limit(idx_t bit) const NOT_DEBUG_RETURN;
// Verify [beg,end) is a valid range, e.g. beg <= end <= size().
void verify_range(idx_t beg, idx_t end) const NOT_DEBUG_RETURN;
// Statistics.
static const idx_t* _pop_count_table;
@ -182,7 +217,9 @@ class BitMap {
}
// Protected constructor and destructor.
BitMap(bm_word_t* map, idx_t size_in_bits) : _map(map), _size(size_in_bits) {}
BitMap(bm_word_t* map, idx_t size_in_bits) : _map(map), _size(size_in_bits) {
verify_size(size_in_bits);
}
~BitMap() {}
public:
@ -191,16 +228,13 @@ class BitMap {
// Accessing
static idx_t calc_size_in_words(size_t size_in_bits) {
return word_index(size_in_bits + BitsPerWord - 1);
}
static idx_t calc_size_in_bytes(size_t size_in_bits) {
return calc_size_in_words(size_in_bits) * BytesPerWord;
verify_size(size_in_bits);
return raw_to_words_align_up(size_in_bits);
}
idx_t size() const { return _size; }
idx_t size_in_words() const { return calc_size_in_words(size()); }
idx_t size_in_bytes() const { return calc_size_in_bytes(size()); }
idx_t size_in_bytes() const { return size_in_words() * BytesPerWord; }
bool at(idx_t index) const {
verify_index(index);
@ -210,18 +244,6 @@ class BitMap {
// memory_order must be memory_order_relaxed or memory_order_acquire.
bool par_at(idx_t index, atomic_memory_order memory_order = memory_order_acquire) const;
// Align bit index up or down to the next bitmap word boundary, or check
// alignment.
static idx_t word_align_up(idx_t bit) {
return align_up(bit, BitsPerWord);
}
static idx_t word_align_down(idx_t bit) {
return align_down(bit, BitsPerWord);
}
static bool is_word_aligned(idx_t bit) {
return word_align_up(bit) == bit;
}
// Set or clear the specified bit.
inline void set_bit(idx_t bit);
inline void clear_bit(idx_t bit);
@ -235,7 +257,7 @@ class BitMap {
inline bool par_set_bit(idx_t bit, atomic_memory_order memory_order = memory_order_conservative);
inline bool par_clear_bit(idx_t bit, atomic_memory_order memory_order = memory_order_conservative);
// Put the given value at the given offset. The parallel version
// Put the given value at the given index. The parallel version
// will CAS the value into the bitmap and is quite a bit slower.
// The parallel version also returns a value indicating if the
// calling thread was the one that changed the value of the bit.
@ -454,7 +476,7 @@ class BitMapClosure {
public:
// Callback when bit in map is set. Should normally return "true";
// return of false indicates that the bitmap iteration should terminate.
virtual bool do_bit(BitMap::idx_t offset) = 0;
virtual bool do_bit(BitMap::idx_t index) = 0;
};
#endif // SHARE_UTILITIES_BITMAP_HPP

View File

@ -26,6 +26,7 @@
#define SHARE_UTILITIES_BITMAP_INLINE_HPP
#include "runtime/atomic.hpp"
#include "utilities/align.hpp"
#include "utilities/bitMap.hpp"
#include "utilities/count_trailing_zeros.hpp"
@ -167,7 +168,7 @@ template<BitMap::bm_word_t flip, bool aligned_right>
inline BitMap::idx_t BitMap::get_next_bit_impl(idx_t l_index, idx_t r_index) const {
STATIC_ASSERT(flip == find_ones_flip || flip == find_zeros_flip);
verify_range(l_index, r_index);
assert(!aligned_right || is_word_aligned(r_index), "r_index not aligned");
assert(!aligned_right || is_aligned(r_index, BitsPerWord), "r_index not aligned");
// The first word often contains an interesting bit, either due to
// density or because of features of the calling algorithm. So it's
@ -176,8 +177,8 @@ inline BitMap::idx_t BitMap::get_next_bit_impl(idx_t l_index, idx_t r_index) con
// first word is indeed interesting.
// The benefit from aligned_right being true is relatively small.
// It saves a couple instructions in the setup for the word search
// loop. It also eliminates the range check on the final result.
// It saves an operation in the setup for the word search loop.
// It also eliminates the range check on the final result.
// However, callers often have a comparison with r_index, and
// inlining often allows the two comparisons to be combined; it is
// important when !aligned_right that return paths either return
@ -188,7 +189,7 @@ inline BitMap::idx_t BitMap::get_next_bit_impl(idx_t l_index, idx_t r_index) con
if (l_index < r_index) {
// Get the word containing l_index, and shift out low bits.
idx_t index = word_index(l_index);
idx_t index = to_words_align_down(l_index);
bm_word_t cword = (map(index) ^ flip) >> bit_in_word(l_index);
if ((cword & 1) != 0) {
// The first bit is similarly often interesting. When it matters
@ -208,8 +209,8 @@ inline BitMap::idx_t BitMap::get_next_bit_impl(idx_t l_index, idx_t r_index) con
// Flipped and shifted first word is zero. Word search through
// aligned up r_index for a non-zero flipped word.
idx_t limit = aligned_right
? word_index(r_index)
: (word_index(r_index - 1) + 1); // Align up, knowing r_index > 0.
? to_words_align_down(r_index) // Miniscule savings when aligned.
: to_words_align_up(r_index);
while (++index < limit) {
cword = map(index) ^ flip;
if (cword != 0) {
@ -248,7 +249,7 @@ BitMap::get_next_one_offset_aligned_right(idx_t l_offset, idx_t r_offset) const
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 || word_index(beg) == word_index(end - 1),
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) {
@ -267,12 +268,6 @@ inline void BitMap::clear_large_range_of_words(idx_t beg, idx_t end) {
memset(_map + beg, 0, (end - beg) * sizeof(bm_word_t));
}
inline BitMap::idx_t BitMap::word_index_round_up(idx_t bit) const {
idx_t bit_rounded_up = bit + (BitsPerWord - 1);
// Check for integer arithmetic overflow.
return bit_rounded_up > bit ? word_index(bit_rounded_up) : size_in_words();
}
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());

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2019, 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
@ -22,6 +22,7 @@
*/
#include "precompiled.hpp"
#include "utilities/align.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/copy.hpp"
#include "utilities/debug.hpp"
@ -32,6 +33,10 @@
typedef BitMap::idx_t idx_t;
typedef BitMap::bm_word_t bm_word_t;
inline idx_t word_align_down(idx_t bit) {
return align_down(bit, BitsPerWord);
}
class BitMapMemory {
private:
idx_t _words;
@ -147,7 +152,7 @@ TEST(BitMap, is_same__unaligned) {
// Check that a difference in the final partial word does count.
{
idx_t index = unaligned_size - 2;
ASSERT_LE(BitMap::word_align_down(unaligned_size), index);
ASSERT_LE(word_align_down(unaligned_size), index);
WithBitClear wbc(y, index);
EXPECT_FALSE(x.is_same(y));
@ -261,7 +266,7 @@ TEST(BitMap, contains__unaligned) {
// Check that a missing bit in the final partial word does count.
{
idx_t index = unaligned_size - 2;
ASSERT_LE(BitMap::word_align_down(unaligned_size), index);
ASSERT_LE(word_align_down(unaligned_size), index);
WithBitClear wbc(x, index);
EXPECT_FALSE(x.contains(y));
@ -307,7 +312,7 @@ TEST(BitMap, intersects__unaligned) {
// Check that adding a bit in the final partial word does count.
{
idx_t index = unaligned_size - 2;
ASSERT_LE(BitMap::word_align_down(unaligned_size), index);
ASSERT_LE(word_align_down(unaligned_size), index);
ASSERT_TRUE(x.at(index));
WithBitSet wbs(y, index);
@ -328,8 +333,8 @@ TEST(BitMap, intersects__unaligned) {
static void check_tail_unmodified(BitMapMemory& mem,
idx_t bits,
bm_word_t fill_word) {
if (!BitMap::is_word_aligned(bits)) {
idx_t last_word_bit_index = BitMap::word_align_down(bits);
if (!is_aligned(bits, BitsPerWord)) {
idx_t last_word_bit_index = word_align_down(bits);
idx_t last_word_index = BitMap::calc_size_in_words(last_word_bit_index);
bm_word_t last_word = mem.memory()[last_word_index];
idx_t shift = bits - last_word_bit_index;