| /* |
| * Copyright (C) 2015 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_GC_ACCOUNTING_BITMAP_H_ |
| #define ART_RUNTIME_GC_ACCOUNTING_BITMAP_H_ |
| |
| #include <limits.h> |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <set> |
| #include <vector> |
| |
| #include "base/bit_utils.h" |
| #include "base/locks.h" |
| #include "base/mem_map.h" |
| #include "runtime_globals.h" |
| |
| namespace art { |
| |
| namespace gc { |
| namespace accounting { |
| |
| // TODO: Use this code to implement SpaceBitmap. |
| class Bitmap { |
| public: |
| // Create and initialize a bitmap with size num_bits. Storage is allocated with a MemMap. |
| static Bitmap* Create(const std::string& name, size_t num_bits); |
| |
| // Initialize a space bitmap using the provided mem_map as the live bits. Takes ownership of the |
| // mem map. The address range covered starts at heap_begin and is of size equal to heap_capacity. |
| // Objects are kAlignement-aligned. |
| static Bitmap* CreateFromMemMap(MemMap&& mem_map, size_t num_bits); |
| |
| // offset is the difference from base to a index. |
| static ALWAYS_INLINE constexpr size_t BitIndexToWordIndex(uintptr_t offset) { |
| return offset / kBitsPerBitmapWord; |
| } |
| |
| template<typename T> |
| static ALWAYS_INLINE constexpr T WordIndexToBitIndex(T word_index) { |
| return static_cast<T>(word_index * kBitsPerBitmapWord); |
| } |
| |
| static ALWAYS_INLINE constexpr uintptr_t BitIndexToMask(uintptr_t bit_index) { |
| return static_cast<uintptr_t>(1) << (bit_index % kBitsPerBitmapWord); |
| } |
| |
| ALWAYS_INLINE bool SetBit(size_t bit_index) { |
| return ModifyBit<true>(bit_index); |
| } |
| |
| ALWAYS_INLINE bool ClearBit(size_t bit_index) { |
| return ModifyBit<false>(bit_index); |
| } |
| |
| ALWAYS_INLINE bool TestBit(size_t bit_index) const; |
| |
| // Returns true if the bit_index was previously set. |
| ALWAYS_INLINE bool AtomicTestAndSetBit(size_t bit_index); |
| |
| // Fill the bitmap with zeroes. Returns the bitmap's memory to the system as a side-effect. |
| void Clear(); |
| |
| // Visit the all the set bits range [visit_begin, visit_end) where visit_begin and visit_end are |
| // bit indices visitor is called with the index of each set bit. |
| template <typename Visitor> |
| void VisitSetBits(uintptr_t visit_begin, size_t visit_end, const Visitor& visitor) const; |
| |
| void CopyFrom(Bitmap* source_bitmap); |
| |
| // Starting address of our internal storage. |
| uintptr_t* Begin() const { |
| return bitmap_begin_; |
| } |
| |
| // Size of our bitmap in bits. |
| size_t BitmapSize() const { return bitmap_numbits_; } |
| |
| // Check that a bit index is valid with a DCHECK. |
| ALWAYS_INLINE void CheckValidBitIndex(size_t bit_index) const { |
| DCHECK_LT(bit_index, BitmapSize()); |
| } |
| |
| std::string Dump() const; |
| |
| protected: |
| static constexpr size_t kBitsPerBitmapWord = kBitsPerIntPtrT; |
| |
| Bitmap(MemMap&& mem_map, size_t bitmap_size); |
| ~Bitmap(); |
| |
| // Allocate the mem-map for a bitmap based on how many bits are required. |
| static MemMap AllocateMemMap(const std::string& name, size_t num_bits); |
| |
| template<bool kSetBit> |
| ALWAYS_INLINE bool ModifyBit(uintptr_t bit_index); |
| |
| // Backing storage for bitmap. This is interpreted as an array of |
| // kBitsPerBitmapWord-sized integers, with bits assigned in each word little |
| // endian first. |
| MemMap mem_map_; |
| |
| // This bitmap itself, word sized for efficiency in scanning. |
| uintptr_t* const bitmap_begin_; |
| |
| // Number of bits in the bitmap. |
| size_t bitmap_numbits_; |
| |
| private: |
| DISALLOW_IMPLICIT_CONSTRUCTORS(Bitmap); |
| }; |
| |
| // One bit per kAlignment in range [start, end) |
| template<size_t kAlignment> |
| class MemoryRangeBitmap : public Bitmap { |
| public: |
| static MemoryRangeBitmap* Create( |
| const std::string& name, uintptr_t cover_begin, uintptr_t cover_end); |
| static MemoryRangeBitmap* CreateFromMemMap( |
| MemMap&& mem_map, uintptr_t cover_begin, size_t num_bits); |
| |
| void SetBitmapSize(size_t bytes) { |
| CHECK_ALIGNED(bytes, kAlignment); |
| bitmap_numbits_ = bytes / kAlignment; |
| size_t rounded_size = |
| RoundUp(bitmap_numbits_, kBitsPerBitmapWord) / kBitsPerBitmapWord * sizeof(uintptr_t); |
| mem_map_.SetSize(rounded_size); |
| } |
| |
| // Beginning of the memory range that the bitmap covers. |
| ALWAYS_INLINE uintptr_t CoverBegin() const { |
| return cover_begin_; |
| } |
| |
| // End of the memory range that the bitmap covers. |
| ALWAYS_INLINE uintptr_t CoverEnd() const { |
| return cover_begin_ + kAlignment * BitmapSize(); |
| } |
| |
| // Return the address associated with a bit index. |
| ALWAYS_INLINE uintptr_t AddrFromBitIndex(size_t bit_index) const { |
| const uintptr_t addr = CoverBegin() + bit_index * kAlignment; |
| DCHECK_EQ(BitIndexFromAddr(addr), bit_index); |
| return addr; |
| } |
| |
| // Return the bit index associated with an address . |
| ALWAYS_INLINE uintptr_t BitIndexFromAddr(uintptr_t addr) const { |
| uintptr_t result = (addr - CoverBegin()) / kAlignment; |
| DCHECK(result < BitmapSize()) << CoverBegin() << " <= " << addr << " < " << CoverEnd(); |
| return result; |
| } |
| |
| ALWAYS_INLINE bool HasAddress(const uintptr_t addr) const { |
| // Don't use BitIndexFromAddr() here as the addr passed to this function |
| // could be outside the range. If addr < cover_begin_, then the result |
| // underflows to some very large value past the end of the bitmap. |
| // Therefore, all operations are unsigned here. |
| bool ret = (addr - CoverBegin()) / kAlignment < BitmapSize(); |
| if (ret) { |
| DCHECK(CoverBegin() <= addr && addr < CoverEnd()) |
| << CoverBegin() << " <= " << addr << " < " << CoverEnd(); |
| } |
| return ret; |
| } |
| |
| ALWAYS_INLINE bool Set(uintptr_t addr) { |
| return SetBit(BitIndexFromAddr(addr)); |
| } |
| |
| ALWAYS_INLINE bool Clear(uintptr_t addr) { |
| return ClearBit(BitIndexFromAddr(addr)); |
| } |
| |
| ALWAYS_INLINE bool Test(uintptr_t addr) const { |
| return TestBit(BitIndexFromAddr(addr)); |
| } |
| |
| // Returns true if the object was previously set. |
| ALWAYS_INLINE bool AtomicTestAndSet(uintptr_t addr) { |
| return AtomicTestAndSetBit(BitIndexFromAddr(addr)); |
| } |
| |
| private: |
| MemoryRangeBitmap(MemMap&& mem_map, uintptr_t begin, size_t num_bits) |
| : Bitmap(std::move(mem_map), num_bits), |
| cover_begin_(begin) {} |
| |
| uintptr_t const cover_begin_; |
| |
| DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryRangeBitmap); |
| }; |
| |
| } // namespace accounting |
| } // namespace gc |
| } // namespace art |
| |
| #endif // ART_RUNTIME_GC_ACCOUNTING_BITMAP_H_ |