diff options
author | Ian Rogers <irogers@google.com> | 2014-08-20 15:08:45 -0700 |
---|---|---|
committer | Ian Rogers <irogers@google.com> | 2014-08-20 15:09:20 -0700 |
commit | e77493c7217efdd1a0ecef521a6845a13da0305b (patch) | |
tree | 3055cb7aaea8b9edc498b2e209d74af36c32e0fd | |
parent | 41cba7c66cbc441b00fca48dfb2501181b1f2a53 (diff) | |
download | art-e77493c7217efdd1a0ecef521a6845a13da0305b.tar.gz art-e77493c7217efdd1a0ecef521a6845a13da0305b.tar.bz2 art-e77493c7217efdd1a0ecef521a6845a13da0305b.zip |
Make common BitVector operations inline-able.
Change-Id: Ie25de4fae56c6712539f04172c42e3eff57df7ca
-rw-r--r-- | compiler/dex/mir_graph.cc | 1 | ||||
-rw-r--r-- | compiler/dex/mir_optimization.cc | 1 | ||||
-rw-r--r-- | compiler/dex/ssa_transformation.cc | 1 | ||||
-rw-r--r-- | compiler/oat_writer.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/register_allocator.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/ssa_liveness_analysis.cc | 1 | ||||
-rw-r--r-- | compiler/utils/arena_bit_vector.cc | 5 | ||||
-rw-r--r-- | compiler/utils/arena_bit_vector.h | 20 | ||||
-rw-r--r-- | runtime/base/allocator.cc | 4 | ||||
-rw-r--r-- | runtime/base/bit_vector-inl.h | 80 | ||||
-rw-r--r-- | runtime/base/bit_vector.cc | 211 | ||||
-rw-r--r-- | runtime/base/bit_vector.h | 406 | ||||
-rw-r--r-- | runtime/base/bit_vector_test.cc | 3 |
13 files changed, 350 insertions, 385 deletions
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index dee1361a50..16b529a5e6 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -19,6 +19,7 @@ #include <inttypes.h> #include <queue> +#include "base/bit_vector-inl.h" #include "base/stl_util.h" #include "compiler_internals.h" #include "dex_file-inl.h" diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index c7dd85c9c2..6658848570 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "base/bit_vector-inl.h" #include "compiler_internals.h" #include "global_value_numbering.h" #include "local_value_numbering.h" diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc index e26745ad5e..4a55de6891 100644 --- a/compiler/dex/ssa_transformation.cc +++ b/compiler/dex/ssa_transformation.cc @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "base/bit_vector-inl.h" #include "compiler_internals.h" #include "dataflow_iterator-inl.h" #include "utils/scoped_arena_containers.h" diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 0fb1575475..41a91ed9d3 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -18,6 +18,7 @@ #include <zlib.h> +#include "base/allocator.h" #include "base/bit_vector.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc index bd3a7d9767..da13b1ec55 100644 --- a/compiler/optimizing/register_allocator.cc +++ b/compiler/optimizing/register_allocator.cc @@ -16,6 +16,7 @@ #include "register_allocator.h" +#include "base/bit_vector-inl.h" #include "code_generator.h" #include "ssa_liveness_analysis.h" diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc index fbdc0b9593..5de1ab9c31 100644 --- a/compiler/optimizing/ssa_liveness_analysis.cc +++ b/compiler/optimizing/ssa_liveness_analysis.cc @@ -16,6 +16,7 @@ #include "ssa_liveness_analysis.h" +#include "base/bit_vector-inl.h" #include "code_generator.h" #include "nodes.h" diff --git a/compiler/utils/arena_bit_vector.cc b/compiler/utils/arena_bit_vector.cc index 39f7d185a6..de35f3d197 100644 --- a/compiler/utils/arena_bit_vector.cc +++ b/compiler/utils/arena_bit_vector.cc @@ -16,11 +16,12 @@ #include "arena_allocator.h" #include "arena_bit_vector.h" +#include "base/allocator.h" namespace art { template <typename ArenaAlloc> -class ArenaBitVectorAllocator : public Allocator { +class ArenaBitVectorAllocator FINAL : public Allocator { public: explicit ArenaBitVectorAllocator(ArenaAlloc* arena) : arena_(arena) {} ~ArenaBitVectorAllocator() {} @@ -37,7 +38,7 @@ class ArenaBitVectorAllocator : public Allocator { static void operator delete(void* p) {} // Nop. private: - ArenaAlloc* arena_; + ArenaAlloc* const arena_; DISALLOW_COPY_AND_ASSIGN(ArenaBitVectorAllocator); }; diff --git a/compiler/utils/arena_bit_vector.h b/compiler/utils/arena_bit_vector.h index 485ed76d12..c92658f7d6 100644 --- a/compiler/utils/arena_bit_vector.h +++ b/compiler/utils/arena_bit_vector.h @@ -51,23 +51,23 @@ std::ostream& operator<<(std::ostream& os, const OatBitMapKind& kind); * A BitVector implementation that uses Arena allocation. */ class ArenaBitVector : public BitVector { - public: - ArenaBitVector(ArenaAllocator* arena, uint32_t start_bits, bool expandable, - OatBitMapKind kind = kBitMapMisc); - ArenaBitVector(ScopedArenaAllocator* arena, uint32_t start_bits, bool expandable, - OatBitMapKind kind = kBitMapMisc); - ~ArenaBitVector() {} + public: + ArenaBitVector(ArenaAllocator* arena, uint32_t start_bits, bool expandable, + OatBitMapKind kind = kBitMapMisc); + ArenaBitVector(ScopedArenaAllocator* arena, uint32_t start_bits, bool expandable, + OatBitMapKind kind = kBitMapMisc); + ~ArenaBitVector() {} static void* operator new(size_t size, ArenaAllocator* arena) { - return arena->Alloc(sizeof(ArenaBitVector), kArenaAllocGrowableBitMap); + return arena->Alloc(sizeof(ArenaBitVector), kArenaAllocGrowableBitMap); } static void* operator new(size_t size, ScopedArenaAllocator* arena) { - return arena->Alloc(sizeof(ArenaBitVector), kArenaAllocGrowableBitMap); + return arena->Alloc(sizeof(ArenaBitVector), kArenaAllocGrowableBitMap); } static void operator delete(void* p) {} // Nop. - private: - const OatBitMapKind kind_; // for memory use tuning. TODO: currently unused. + private: + const OatBitMapKind kind_; // for memory use tuning. TODO: currently unused. }; diff --git a/runtime/base/allocator.cc b/runtime/base/allocator.cc index 4f7753d476..3469eca8c3 100644 --- a/runtime/base/allocator.cc +++ b/runtime/base/allocator.cc @@ -23,7 +23,7 @@ namespace art { -class MallocAllocator : public Allocator { +class MallocAllocator FINAL : public Allocator { public: explicit MallocAllocator() {} ~MallocAllocator() {} @@ -42,7 +42,7 @@ class MallocAllocator : public Allocator { MallocAllocator g_malloc_allocator; -class NoopAllocator : public Allocator { +class NoopAllocator FINAL : public Allocator { public: explicit NoopAllocator() {} ~NoopAllocator() {} diff --git a/runtime/base/bit_vector-inl.h b/runtime/base/bit_vector-inl.h new file mode 100644 index 0000000000..dc13dd5b9f --- /dev/null +++ b/runtime/base/bit_vector-inl.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_BASE_BIT_VECTOR_INL_H_ +#define ART_RUNTIME_BASE_BIT_VECTOR_INL_H_ + +#include "bit_vector.h" +#include "logging.h" +#include "utils.h" + +namespace art { + +inline bool BitVector::IndexIterator::operator==(const IndexIterator& other) const { + DCHECK(bit_storage_ == other.bit_storage_); + DCHECK_EQ(storage_size_, other.storage_size_); + return bit_index_ == other.bit_index_; +} + +inline int BitVector::IndexIterator::operator*() const { + DCHECK_LT(bit_index_, BitSize()); + return bit_index_; +} + +inline BitVector::IndexIterator& BitVector::IndexIterator::operator++() { + DCHECK_LT(bit_index_, BitSize()); + bit_index_ = FindIndex(bit_index_ + 1u); + return *this; +} + +inline BitVector::IndexIterator BitVector::IndexIterator::operator++(int) { + IndexIterator result(*this); + ++*this; + return result; +} + +inline uint32_t BitVector::IndexIterator::FindIndex(uint32_t start_index) const { + DCHECK_LE(start_index, BitSize()); + uint32_t word_index = start_index / kWordBits; + if (UNLIKELY(word_index == storage_size_)) { + return start_index; + } + uint32_t word = bit_storage_[word_index]; + // Mask out any bits in the first word we've already considered. + word &= static_cast<uint32_t>(-1) << (start_index & 0x1f); + while (word == 0u) { + ++word_index; + if (UNLIKELY(word_index == storage_size_)) { + return BitSize(); + } + word = bit_storage_[word_index]; + } + return word_index * 32u + CTZ(word); +} + +inline void BitVector::ClearAllBits() { + memset(storage_, 0, storage_size_ * kWordBytes); +} + +inline bool BitVector::Equal(const BitVector* src) const { + return (storage_size_ == src->GetStorageSize()) && + (expandable_ == src->IsExpandable()) && + (memcmp(storage_, src->GetRawStorage(), storage_size_ * sizeof(uint32_t)) == 0); +} + +} // namespace art + +#endif // ART_RUNTIME_BASE_BIT_VECTOR_INL_H_ diff --git a/runtime/base/bit_vector.cc b/runtime/base/bit_vector.cc index 1b9022e170..3d2f0deac5 100644 --- a/runtime/base/bit_vector.cc +++ b/runtime/base/bit_vector.cc @@ -16,20 +16,14 @@ #include "bit_vector.h" +#include "allocator.h" +#include "bit_vector-inl.h" + namespace art { -// TODO: profile to make sure this is still a win relative to just using shifted masks. -static uint32_t check_masks[32] = { - 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, - 0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200, - 0x00000400, 0x00000800, 0x00001000, 0x00002000, 0x00004000, - 0x00008000, 0x00010000, 0x00020000, 0x00040000, 0x00080000, - 0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000, - 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, - 0x40000000, 0x80000000 }; - -static inline uint32_t BitsToWords(uint32_t bits) { - return (bits + 31) >> 5; +// The number of words necessary to encode bits. +static constexpr uint32_t BitsToWords(uint32_t bits) { + return RoundUp(bits, 32) / 32; } // TODO: replace excessive argument defaulting when we are at gcc 4.7 @@ -40,10 +34,10 @@ BitVector::BitVector(uint32_t start_bits, Allocator* allocator, uint32_t storage_size, uint32_t* storage) - : allocator_(allocator), - expandable_(expandable), + : storage_(storage), storage_size_(storage_size), - storage_(storage) { + allocator_(allocator), + expandable_(expandable) { COMPILE_ASSERT(sizeof(*storage_) == kWordBytes, check_word_bytes); COMPILE_ASSERT(sizeof(*storage_) * 8u == kWordBits, check_word_bits); if (storage_ == nullptr) { @@ -56,59 +50,7 @@ BitVector::~BitVector() { allocator_->Free(storage_); } -/* - * Determine whether or not the specified bit is set. - */ -bool BitVector::IsBitSet(uint32_t num) const { - // If the index is over the size: - if (num >= storage_size_ * kWordBits) { - // Whether it is expandable or not, this bit does not exist: thus it is not set. - return false; - } - - return IsBitSet(storage_, num); -} - -// Mark all bits bit as "clear". -void BitVector::ClearAllBits() { - memset(storage_, 0, storage_size_ * kWordBytes); -} - -// Mark the specified bit as "set". -/* - * TUNING: this could have pathologically bad growth/expand behavior. Make sure we're - * not using it badly or change resize mechanism. - */ -void BitVector::SetBit(uint32_t num) { - if (num >= storage_size_ * kWordBits) { - DCHECK(expandable_) << "Attempted to expand a non-expandable bitmap to position " << num; - - /* Round up to word boundaries for "num+1" bits */ - uint32_t new_size = BitsToWords(num + 1); - DCHECK_GT(new_size, storage_size_); - uint32_t *new_storage = - static_cast<uint32_t*>(allocator_->Alloc(new_size * kWordBytes)); - memcpy(new_storage, storage_, storage_size_ * kWordBytes); - // Zero out the new storage words. - memset(&new_storage[storage_size_], 0, (new_size - storage_size_) * kWordBytes); - // TOTO: collect stats on space wasted because of resize. - storage_ = new_storage; - storage_size_ = new_size; - } - - storage_[num >> 5] |= check_masks[num & 0x1f]; -} - -// Mark the specified bit as "unset". -void BitVector::ClearBit(uint32_t num) { - // If the index is over the size, we don't have to do anything, it is cleared. - if (num < storage_size_ * kWordBits) { - // Otherwise, go ahead and clear it. - storage_[num >> 5] &= ~check_masks[num & 0x1f]; - } -} - -bool BitVector::SameBitsSet(const BitVector *src) { +bool BitVector::SameBitsSet(const BitVector *src) const { int our_highest = GetHighestBitSet(); int src_highest = src->GetHighestBitSet(); @@ -134,7 +76,6 @@ bool BitVector::SameBitsSet(const BitVector *src) { return (memcmp(storage_, src->GetRawStorage(), our_highest_index * kWordBytes) == 0); } -// Intersect with another bit vector. void BitVector::Intersect(const BitVector* src) { uint32_t src_storage_size = src->storage_size_; @@ -155,9 +96,6 @@ void BitVector::Intersect(const BitVector* src) { } } -/* - * Union with another bit vector. - */ bool BitVector::Union(const BitVector* src) { // Get the highest bit to determine how much we need to expand. int highest_bit = src->GetHighestBitSet(); @@ -175,8 +113,7 @@ bool BitVector::Union(const BitVector* src) { if (storage_size_ < src_size) { changed = true; - // Set it to reallocate. - SetBit(highest_bit); + EnsureSize(highest_bit); // Paranoid: storage size should be big enough to hold this bit now. DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * kWordBits); @@ -242,21 +179,20 @@ bool BitVector::UnionIfNotIn(const BitVector* union_with, const BitVector* not_i } void BitVector::Subtract(const BitVector *src) { - uint32_t src_size = src->storage_size_; + uint32_t src_size = src->storage_size_; - // We only need to operate on bytes up to the smaller of the sizes of the two operands. - unsigned int min_size = (storage_size_ > src_size) ? src_size : storage_size_; + // We only need to operate on bytes up to the smaller of the sizes of the two operands. + unsigned int min_size = (storage_size_ > src_size) ? src_size : storage_size_; - // Difference until max, we know both accept it: - // There is no need to do more: - // If we are bigger than src, the upper bits are unchanged. - // If we are smaller than src, the non-existant upper bits are 0 and thus can't get subtracted. - for (uint32_t idx = 0; idx < min_size; idx++) { - storage_[idx] &= (~(src->GetRawStorageWord(idx))); - } + // Difference until max, we know both accept it: + // There is no need to do more: + // If we are bigger than src, the upper bits are unchanged. + // If we are smaller than src, the non-existant upper bits are 0 and thus can't get subtracted. + for (uint32_t idx = 0; idx < min_size; idx++) { + storage_[idx] &= (~(src->GetRawStorageWord(idx))); + } } -// Count the number of bits that are set. uint32_t BitVector::NumSetBits() const { uint32_t count = 0; for (uint32_t word = 0; word < storage_size_; word++) { @@ -265,17 +201,11 @@ uint32_t BitVector::NumSetBits() const { return count; } -// Count the number of bits that are set in range [0, end). uint32_t BitVector::NumSetBits(uint32_t end) const { DCHECK_LE(end, storage_size_ * kWordBits); return NumSetBits(storage_, end); } -/* - * Mark specified number of bits as "set". Cannot set all bits like ClearAll - * since there might be unused bits - setting those to one will confuse the - * iterator. - */ void BitVector::SetInitialBits(uint32_t num_bits) { // If num_bits is 0, clear everything. if (num_bits == 0) { @@ -288,7 +218,7 @@ void BitVector::SetInitialBits(uint32_t num_bits) { uint32_t idx; // We can set every storage element with -1. - for (idx = 0; idx < (num_bits >> 5); idx++) { + for (idx = 0; idx < WordIndex(num_bits); idx++) { storage_[idx] = -1; } @@ -312,20 +242,8 @@ int BitVector::GetHighestBitSet() const { uint32_t value = storage_[idx]; if (value != 0) { - // Shift right for the counting. - value /= 2; - - int cnt = 0; - - // Count the bits. - while (value > 0) { - value /= 2; - cnt++; - } - - // Return cnt + how many storage units still remain * the number of bits per unit. - int res = cnt + (idx * kWordBits); - return res; + // Return highest bit set in value plus bits from previous storage indexes. + return 31 - CLZ(value) + (idx * kWordBits); } } @@ -333,23 +251,6 @@ int BitVector::GetHighestBitSet() const { return -1; } -bool BitVector::EnsureSizeAndClear(unsigned int num) { - // Check if the bitvector is expandable. - if (IsExpandable() == false) { - return false; - } - - if (num > 0) { - // Now try to expand by setting the last bit. - SetBit(num - 1); - } - - // We must clear all bits as per our specification. - ClearAllBits(); - - return true; -} - void BitVector::Copy(const BitVector *src) { // Get highest bit set, we only need to copy till then. int highest_bit = src->GetHighestBitSet(); @@ -375,13 +276,8 @@ void BitVector::Copy(const BitVector *src) { } } -bool BitVector::IsBitSet(const uint32_t* storage, uint32_t num) { - uint32_t val = storage[num >> 5] & check_masks[num & 0x1f]; - return (val != 0); -} - uint32_t BitVector::NumSetBits(const uint32_t* storage, uint32_t end) { - uint32_t word_end = end >> 5; + uint32_t word_end = WordIndex(end); uint32_t partial_word_bits = end & 0x1f; uint32_t count = 0u; @@ -400,45 +296,6 @@ void BitVector::Dump(std::ostream& os, const char *prefix) const { os << buffer.str() << std::endl; } - -void BitVector::DumpDotHelper(bool last_entry, FILE* file, std::ostringstream& buffer) const { - // Now print it to the file. - fprintf(file, " {%s}", buffer.str().c_str()); - - // If it isn't the last entry, add a |. - if (last_entry == false) { - fprintf(file, "|"); - } - - // Add the \n. - fprintf(file, "\\\n"); -} - -void BitVector::DumpDot(FILE* file, const char* prefix, bool last_entry) const { - std::ostringstream buffer; - DumpHelper(prefix, buffer); - DumpDotHelper(last_entry, file, buffer); -} - -void BitVector::DumpIndicesDot(FILE* file, const char* prefix, bool last_entry) const { - std::ostringstream buffer; - DumpIndicesHelper(prefix, buffer); - DumpDotHelper(last_entry, file, buffer); -} - -void BitVector::DumpIndicesHelper(const char* prefix, std::ostringstream& buffer) const { - // Initialize it. - if (prefix != nullptr) { - buffer << prefix; - } - - for (size_t i = 0; i < storage_size_ * kWordBits; i++) { - if (IsBitSet(i)) { - buffer << i << " "; - } - } -} - void BitVector::DumpHelper(const char* prefix, std::ostringstream& buffer) const { // Initialize it. if (prefix != nullptr) { @@ -452,4 +309,22 @@ void BitVector::DumpHelper(const char* prefix, std::ostringstream& buffer) const buffer << ')'; } +void BitVector::EnsureSize(uint32_t idx) { + if (idx >= storage_size_ * kWordBits) { + DCHECK(expandable_) << "Attempted to expand a non-expandable bitmap to position " << idx; + + /* Round up to word boundaries for "idx+1" bits */ + uint32_t new_size = BitsToWords(idx + 1); + DCHECK_GT(new_size, storage_size_); + uint32_t *new_storage = + static_cast<uint32_t*>(allocator_->Alloc(new_size * kWordBytes)); + memcpy(new_storage, storage_, storage_size_ * kWordBytes); + // Zero out the new storage words. + memset(&new_storage[storage_size_], 0, (new_size - storage_size_) * kWordBytes); + // TOTO: collect stats on space wasted because of resize. + storage_ = new_storage; + storage_size_ = new_size; + } +} + } // namespace art diff --git a/runtime/base/bit_vector.h b/runtime/base/bit_vector.h index fb1646f7fc..1e28a27e94 100644 --- a/runtime/base/bit_vector.h +++ b/runtime/base/bit_vector.h @@ -18,235 +18,237 @@ #define ART_RUNTIME_BASE_BIT_VECTOR_H_ #include <stdint.h> -#include <stddef.h> - -#include "allocator.h" -#include "base/logging.h" -#include "utils.h" +#include <iterator> namespace art { +class Allocator; + /* * Expanding bitmap, used for tracking resources. Bits are numbered starting * from zero. All operations on a BitVector are unsynchronized. */ class BitVector { - public: - class IndexContainer; - - /** - * @brief Convenient iterator across the indexes of the BitVector's set bits. - * - * @details IndexIterator is a Forward iterator (C++11: 24.2.5) from the lowest - * to the highest index of the BitVector's set bits. Instances can be retrieved - * only through BitVector::Indexes() which returns an IndexContainer wrapper - * object with begin() and end() suitable for range-based loops: - * for (uint32_t idx : bit_vector.Indexes()) { - * // Use idx. - * } - */ - class IndexIterator - : std::iterator<std::forward_iterator_tag, uint32_t, ptrdiff_t, void, uint32_t> { - public: - bool operator==(const IndexIterator& other) const { - DCHECK(bit_storage_ == other.bit_storage_); - DCHECK_EQ(storage_size_, other.storage_size_); - return bit_index_ == other.bit_index_; - } - - bool operator!=(const IndexIterator& other) const { - return !(*this == other); - } - - int operator*() const { - DCHECK_LT(bit_index_, BitSize()); - return bit_index_; - } - - IndexIterator& operator++() { - DCHECK_LT(bit_index_, BitSize()); - bit_index_ = FindIndex(bit_index_ + 1u); - return *this; - } - - IndexIterator operator++(int) { - IndexIterator result(*this); - ++*this; - return result; - } - - // Helper function to check for end without comparing with bit_vector.Indexes().end(). - bool Done() const { - return bit_index_ == BitSize(); - } - - private: - struct begin_tag { }; - struct end_tag { }; - - IndexIterator(const BitVector* bit_vector, begin_tag) - : bit_storage_(bit_vector->GetRawStorage()), - storage_size_(bit_vector->storage_size_), - bit_index_(FindIndex(0u)) { } - - IndexIterator(const BitVector* bit_vector, end_tag) - : bit_storage_(bit_vector->GetRawStorage()), - storage_size_(bit_vector->storage_size_), - bit_index_(BitSize()) { } - - uint32_t BitSize() const { - return storage_size_ * kWordBits; - } - - uint32_t FindIndex(uint32_t start_index) const { - DCHECK_LE(start_index, BitSize()); - uint32_t word_index = start_index / kWordBits; - if (UNLIKELY(word_index == storage_size_)) { - return start_index; - } - uint32_t word = bit_storage_[word_index]; - // Mask out any bits in the first word we've already considered. - word &= static_cast<uint32_t>(-1) << (start_index & 0x1f); - while (word == 0u) { - ++word_index; - if (UNLIKELY(word_index == storage_size_)) { - return BitSize(); - } - word = bit_storage_[word_index]; - } - return word_index * 32u + CTZ(word); - } - - const uint32_t* const bit_storage_; - const uint32_t storage_size_; // Size of vector in words. - uint32_t bit_index_; // Current index (size in bits). - - friend class BitVector::IndexContainer; - }; - - /** - * @brief BitVector wrapper class for iteration across indexes of set bits. - */ - class IndexContainer { - public: - explicit IndexContainer(const BitVector* bit_vector) : bit_vector_(bit_vector) { } - - IndexIterator begin() const { - return IndexIterator(bit_vector_, IndexIterator::begin_tag()); - } - - IndexIterator end() const { - return IndexIterator(bit_vector_, IndexIterator::end_tag()); - } - - private: - const BitVector* const bit_vector_; - }; - - BitVector(uint32_t start_bits, - bool expandable, - Allocator* allocator, - uint32_t storage_size = 0, - uint32_t* storage = nullptr); - - virtual ~BitVector(); - - void SetBit(uint32_t num); - void ClearBit(uint32_t num); - bool IsBitSet(uint32_t num) const; - void ClearAllBits(); - void SetInitialBits(uint32_t num_bits); - - void Copy(const BitVector* src); - void Intersect(const BitVector* src2); - bool Union(const BitVector* src); - - // Set bits of union_with that are not in not_in. - bool UnionIfNotIn(const BitVector* union_with, const BitVector* not_in); - - void Subtract(const BitVector* src); - // Are we equal to another bit vector? Note: expandability attributes must also match. - bool Equal(const BitVector* src) { - return (storage_size_ == src->GetStorageSize()) && - (expandable_ == src->IsExpandable()) && - (memcmp(storage_, src->GetRawStorage(), storage_size_ * sizeof(uint32_t)) == 0); + public: + class IndexContainer; + + /** + * @brief Convenient iterator across the indexes of the BitVector's set bits. + * + * @details IndexIterator is a Forward iterator (C++11: 24.2.5) from the lowest + * to the highest index of the BitVector's set bits. Instances can be retrieved + * only through BitVector::Indexes() which returns an IndexContainer wrapper + * object with begin() and end() suitable for range-based loops: + * for (uint32_t idx : bit_vector.Indexes()) { + * // Use idx. + * } + */ + class IndexIterator : + std::iterator<std::forward_iterator_tag, uint32_t, ptrdiff_t, void, uint32_t> { + public: + bool operator==(const IndexIterator& other) const; + + bool operator!=(const IndexIterator& other) const { + return !(*this == other); } - /** - * @brief Are all the bits set the same? - * @details expandability and size can differ as long as the same bits are set. - */ - bool SameBitsSet(const BitVector *src); + int operator*() const; - uint32_t NumSetBits() const; + IndexIterator& operator++(); - // Number of bits set in range [0, end). - uint32_t NumSetBits(uint32_t end) const; + IndexIterator operator++(int); - IndexContainer Indexes() const { - return IndexContainer(this); + // Helper function to check for end without comparing with bit_vector.Indexes().end(). + bool Done() const { + return bit_index_ == BitSize(); } - uint32_t GetStorageSize() const { return storage_size_; } - bool IsExpandable() const { return expandable_; } - uint32_t GetRawStorageWord(size_t idx) const { return storage_[idx]; } - uint32_t* GetRawStorage() { return storage_; } - const uint32_t* GetRawStorage() const { return storage_; } - size_t GetSizeOf() const { return storage_size_ * kWordBytes; } + private: + struct begin_tag { }; + struct end_tag { }; - /** - * @return the highest bit set, -1 if none are set - */ - int GetHighestBitSet() const; + IndexIterator(const BitVector* bit_vector, begin_tag) + : bit_storage_(bit_vector->GetRawStorage()), + storage_size_(bit_vector->storage_size_), + bit_index_(FindIndex(0u)) { } - // Is bit set in storage. (No range check.) - static bool IsBitSet(const uint32_t* storage, uint32_t num); - // Number of bits set in range [0, end) in storage. (No range check.) - static uint32_t NumSetBits(const uint32_t* storage, uint32_t end); + IndexIterator(const BitVector* bit_vector, end_tag) + : bit_storage_(bit_vector->GetRawStorage()), + storage_size_(bit_vector->storage_size_), + bit_index_(BitSize()) { } - bool EnsureSizeAndClear(unsigned int num); + uint32_t BitSize() const { + return storage_size_ * kWordBits; + } - void Dump(std::ostream& os, const char* prefix) const; + uint32_t FindIndex(uint32_t start_index) const; + const uint32_t* const bit_storage_; + const uint32_t storage_size_; // Size of vector in words. + uint32_t bit_index_; // Current index (size in bits). - /** - * @brief last_entry is this the last entry for the dot dumping - * @details if not, a "|" is appended to the dump. - */ - void DumpDot(FILE* file, const char* prefix, bool last_entry = false) const; + friend class BitVector::IndexContainer; + }; - /** - * @brief last_entry is this the last entry for the dot dumping - * @details if not, a "|" is appended to the dump. - */ - void DumpIndicesDot(FILE* file, const char* prefix, bool last_entry = false) const; + /** + * @brief BitVector wrapper class for iteration across indexes of set bits. + */ + class IndexContainer { + public: + explicit IndexContainer(const BitVector* bit_vector) : bit_vector_(bit_vector) { } - protected: - /** - * @brief Dump the bitvector into buffer in a 00101..01 format. - * @param buffer the ostringstream used to dump the bitvector into. - */ - void DumpHelper(const char* prefix, std::ostringstream& buffer) const; + IndexIterator begin() const { + return IndexIterator(bit_vector_, IndexIterator::begin_tag()); + } - /** - * @brief Dump the bitvector in a 1 2 5 8 format, where the numbers are the bit set. - * @param buffer the ostringstream used to dump the bitvector into. - */ - void DumpIndicesHelper(const char* prefix, std::ostringstream& buffer) const; + IndexIterator end() const { + return IndexIterator(bit_vector_, IndexIterator::end_tag()); + } + + private: + const BitVector* const bit_vector_; + }; + + BitVector(uint32_t start_bits, + bool expandable, + Allocator* allocator, + uint32_t storage_size = 0, + uint32_t* storage = nullptr); - /** - * @brief Wrapper to perform the bitvector dumping with the .dot format. - * @param buffer the ostringstream used to dump the bitvector into. + virtual ~BitVector(); + + // Mark the specified bit as "set". + void SetBit(uint32_t idx) { + /* + * TUNING: this could have pathologically bad growth/expand behavior. Make sure we're + * not using it badly or change resize mechanism. */ - void DumpDotHelper(bool last_entry, FILE* file, std::ostringstream& buffer) const; + if (idx >= storage_size_ * kWordBits) { + EnsureSize(idx); + } + storage_[WordIndex(idx)] |= BitMask(idx); + } + + // Mark the specified bit as "unset". + void ClearBit(uint32_t idx) { + // If the index is over the size, we don't have to do anything, it is cleared. + if (idx < storage_size_ * kWordBits) { + // Otherwise, go ahead and clear it. + storage_[WordIndex(idx)] &= ~BitMask(idx); + } + } + + // Determine whether or not the specified bit is set. + bool IsBitSet(uint32_t idx) const { + // If the index is over the size, whether it is expandable or not, this bit does not exist: + // thus it is not set. + return (idx < (storage_size_ * kWordBits)) && IsBitSet(storage_, idx); + } + + // Mark all bits bit as "clear". + void ClearAllBits(); + + // Mark specified number of bits as "set". Cannot set all bits like ClearAll since there might + // be unused bits - setting those to one will confuse the iterator. + void SetInitialBits(uint32_t num_bits); + + void Copy(const BitVector* src); + + // Intersect with another bit vector. + void Intersect(const BitVector* src2); + + // Union with another bit vector. + bool Union(const BitVector* src); + + // Set bits of union_with that are not in not_in. + bool UnionIfNotIn(const BitVector* union_with, const BitVector* not_in); + + void Subtract(const BitVector* src); + + // Are we equal to another bit vector? Note: expandability attributes must also match. + bool Equal(const BitVector* src) const; + + /** + * @brief Are all the bits set the same? + * @details expandability and size can differ as long as the same bits are set. + */ + bool SameBitsSet(const BitVector *src) const; + + // Count the number of bits that are set. + uint32_t NumSetBits() const; + + // Count the number of bits that are set in range [0, end). + uint32_t NumSetBits(uint32_t end) const; + + IndexContainer Indexes() const { + return IndexContainer(this); + } + + uint32_t GetStorageSize() const { + return storage_size_; + } + + bool IsExpandable() const { + return expandable_; + } + + uint32_t GetRawStorageWord(size_t idx) const { + return storage_[idx]; + } + + uint32_t* GetRawStorage() { + return storage_; + } + + const uint32_t* GetRawStorage() const { + return storage_; + } + + size_t GetSizeOf() const { + return storage_size_ * kWordBytes; + } + + /** + * @return the highest bit set, -1 if none are set + */ + int GetHighestBitSet() const; + + // Is bit set in storage. (No range check.) + static bool IsBitSet(const uint32_t* storage, uint32_t idx) { + return (storage[WordIndex(idx)] & BitMask(idx)) != 0; + } + + // Number of bits set in range [0, end) in storage. (No range check.) + static uint32_t NumSetBits(const uint32_t* storage, uint32_t end); + + void Dump(std::ostream& os, const char* prefix) const; + + private: + /** + * @brief Dump the bitvector into buffer in a 00101..01 format. + * @param buffer the ostringstream used to dump the bitvector into. + */ + void DumpHelper(const char* prefix, std::ostringstream& buffer) const; + + // Ensure there is space for a bit at idx. + void EnsureSize(uint32_t idx); + + // The index of the word within storage. + static constexpr uint32_t WordIndex(uint32_t idx) { + return idx >> 5; + } + + // A bit mask to extract the bit for the given index. + static constexpr uint32_t BitMask(uint32_t idx) { + return 1 << (idx & 0x1f); + } - private: - static constexpr uint32_t kWordBytes = sizeof(uint32_t); - static constexpr uint32_t kWordBits = kWordBytes * 8; + static constexpr uint32_t kWordBytes = sizeof(uint32_t); + static constexpr uint32_t kWordBits = kWordBytes * 8; - Allocator* const allocator_; - const bool expandable_; // expand bitmap if we run out? - uint32_t storage_size_; // current size, in 32-bit words. - uint32_t* storage_; + uint32_t* storage_; // The storage for the bit vector. + uint32_t storage_size_; // Current size, in 32-bit words. + Allocator* const allocator_; // Allocator if expandable. + const bool expandable_; // Should the bitmap expand if too small? }; diff --git a/runtime/base/bit_vector_test.cc b/runtime/base/bit_vector_test.cc index 1403f50c04..df5d79d893 100644 --- a/runtime/base/bit_vector_test.cc +++ b/runtime/base/bit_vector_test.cc @@ -16,7 +16,8 @@ #include <memory> -#include "bit_vector.h" +#include "allocator.h" +#include "bit_vector-inl.h" #include "gtest/gtest.h" namespace art { |