%PDF- <> %âãÏÓ endobj 2 0 obj <> endobj 3 0 obj <>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 28 0 R 29 0 R] /MediaBox[ 0 0 595.5 842.25] /Contents 4 0 R/Group<>/Tabs/S>> endobj ºaâÚÎΞ-ÌE1ÍØÄ÷{òò2ÿ ÛÖ^ÔÀá TÎ{¦?§®¥kuµùÕ5sLOšuY>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<>endobj 2 0 obj<> endobj 2 0 obj<>endobj 2 0 obj<>es 3 0 R>> endobj 2 0 obj<> ox[ 0.000000 0.000000 609.600000 935.600000]/Fi endobj 3 0 obj<> endobj 7 1 obj<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI]>>/Subtype/Form>> stream
// Copyright 2020 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_HEAP_CPPGC_OBJECT_START_BITMAP_H_ #define V8_HEAP_CPPGC_OBJECT_START_BITMAP_H_ #include <limits.h> #include <stdint.h> #include <array> #include "include/cppgc/internal/write-barrier.h" #include "src/base/atomic-utils.h" #include "src/base/bits.h" #include "src/base/macros.h" #include "src/heap/cppgc/globals.h" #include "src/heap/cppgc/heap-object-header.h" namespace cppgc { namespace internal { // A bitmap for recording object starts. Objects have to be allocated at // minimum granularity of kGranularity. // // Depends on internals such as: // - kBlinkPageSize // - kAllocationGranularity // // ObjectStartBitmap supports concurrent reads from multiple threads but // only a single mutator thread can write to it. class V8_EXPORT_PRIVATE ObjectStartBitmap { public: // Granularity of addresses added to the bitmap. static constexpr size_t Granularity() { return kAllocationGranularity; } // Maximum number of entries in the bitmap. static constexpr size_t MaxEntries() { return kReservedForBitmap * kBitsPerCell; } explicit inline ObjectStartBitmap(Address offset); // Finds an object header based on a // address_maybe_pointing_to_the_middle_of_object. Will search for an object // start in decreasing address order. template <AccessMode = AccessMode::kNonAtomic> inline HeapObjectHeader* FindHeader( ConstAddress address_maybe_pointing_to_the_middle_of_object) const; template <AccessMode = AccessMode::kNonAtomic> inline void SetBit(ConstAddress); template <AccessMode = AccessMode::kNonAtomic> inline void ClearBit(ConstAddress); template <AccessMode = AccessMode::kNonAtomic> inline bool CheckBit(ConstAddress) const; // Iterates all object starts recorded in the bitmap. // // The callback is of type // void(Address) // and is passed the object start address as parameter. template <typename Callback> inline void Iterate(Callback) const; // Clear the object start bitmap. inline void Clear(); private: template <AccessMode = AccessMode::kNonAtomic> inline void store(size_t cell_index, uint8_t value); template <AccessMode = AccessMode::kNonAtomic> inline uint8_t load(size_t cell_index) const; static constexpr size_t kBitsPerCell = sizeof(uint8_t) * CHAR_BIT; static constexpr size_t kCellMask = kBitsPerCell - 1; static constexpr size_t kBitmapSize = (kPageSize + ((kBitsPerCell * kAllocationGranularity) - 1)) / (kBitsPerCell * kAllocationGranularity); static constexpr size_t kReservedForBitmap = ((kBitmapSize + kAllocationMask) & ~kAllocationMask); inline void ObjectStartIndexAndBit(ConstAddress, size_t*, size_t*) const; const Address offset_; // The bitmap contains a bit for every kGranularity aligned address on a // a NormalPage, i.e., for a page of size kBlinkPageSize. std::array<uint8_t, kReservedForBitmap> object_start_bit_map_; }; ObjectStartBitmap::ObjectStartBitmap(Address offset) : offset_(offset) { Clear(); } template <AccessMode mode> HeapObjectHeader* ObjectStartBitmap::FindHeader( ConstAddress address_maybe_pointing_to_the_middle_of_object) const { DCHECK_LE(offset_, address_maybe_pointing_to_the_middle_of_object); size_t object_offset = address_maybe_pointing_to_the_middle_of_object - offset_; size_t object_start_number = object_offset / kAllocationGranularity; size_t cell_index = object_start_number / kBitsPerCell; DCHECK_GT(object_start_bit_map_.size(), cell_index); const size_t bit = object_start_number & kCellMask; uint8_t byte = load<mode>(cell_index) & ((1 << (bit + 1)) - 1); while (!byte && cell_index) { DCHECK_LT(0u, cell_index); byte = load<mode>(--cell_index); } const int leading_zeroes = v8::base::bits::CountLeadingZeros(byte); object_start_number = (cell_index * kBitsPerCell) + (kBitsPerCell - 1) - leading_zeroes; object_offset = object_start_number * kAllocationGranularity; return reinterpret_cast<HeapObjectHeader*>(object_offset + offset_); } template <AccessMode mode> void ObjectStartBitmap::SetBit(ConstAddress header_address) { size_t cell_index, object_bit; ObjectStartIndexAndBit(header_address, &cell_index, &object_bit); // Only a single mutator thread can write to the bitmap, so no need for CAS. store<mode>(cell_index, static_cast<uint8_t>(load(cell_index) | (1 << object_bit))); } template <AccessMode mode> void ObjectStartBitmap::ClearBit(ConstAddress header_address) { size_t cell_index, object_bit; ObjectStartIndexAndBit(header_address, &cell_index, &object_bit); store<mode>(cell_index, static_cast<uint8_t>(load(cell_index) & ~(1 << object_bit))); } template <AccessMode mode> bool ObjectStartBitmap::CheckBit(ConstAddress header_address) const { size_t cell_index, object_bit; ObjectStartIndexAndBit(header_address, &cell_index, &object_bit); return load<mode>(cell_index) & (1 << object_bit); } template <AccessMode mode> void ObjectStartBitmap::store(size_t cell_index, uint8_t value) { if (mode == AccessMode::kNonAtomic) { object_start_bit_map_[cell_index] = value; return; } v8::base::AsAtomicPtr(&object_start_bit_map_[cell_index]) ->store(value, std::memory_order_release); } template <AccessMode mode> uint8_t ObjectStartBitmap::load(size_t cell_index) const { if (mode == AccessMode::kNonAtomic) { return object_start_bit_map_[cell_index]; } return v8::base::AsAtomicPtr(&object_start_bit_map_[cell_index]) ->load(std::memory_order_acquire); } void ObjectStartBitmap::ObjectStartIndexAndBit(ConstAddress header_address, size_t* cell_index, size_t* bit) const { const size_t object_offset = header_address - offset_; DCHECK(!(object_offset & kAllocationMask)); const size_t object_start_number = object_offset / kAllocationGranularity; *cell_index = object_start_number / kBitsPerCell; DCHECK_GT(kBitmapSize, *cell_index); *bit = object_start_number & kCellMask; } template <typename Callback> inline void ObjectStartBitmap::Iterate(Callback callback) const { for (size_t cell_index = 0; cell_index < kReservedForBitmap; cell_index++) { if (!object_start_bit_map_[cell_index]) continue; uint8_t value = object_start_bit_map_[cell_index]; while (value) { const int trailing_zeroes = v8::base::bits::CountTrailingZeros(value); const size_t object_start_number = (cell_index * kBitsPerCell) + trailing_zeroes; const Address object_address = offset_ + (kAllocationGranularity * object_start_number); callback(object_address); // Clear current object bit in temporary value to advance iteration. value &= ~(1 << (object_start_number & kCellMask)); } } } void ObjectStartBitmap::Clear() { std::fill(object_start_bit_map_.begin(), object_start_bit_map_.end(), 0); } // A platform aware version of ObjectStartBitmap to provide platform specific // optimizations (e.g. Use non-atomic stores on ARMv7 when not marking). class V8_EXPORT_PRIVATE PlatformAwareObjectStartBitmap : public ObjectStartBitmap { public: explicit inline PlatformAwareObjectStartBitmap(Address offset); template <AccessMode = AccessMode::kNonAtomic> inline void SetBit(ConstAddress); template <AccessMode = AccessMode::kNonAtomic> inline void ClearBit(ConstAddress); private: template <AccessMode> static bool ShouldForceNonAtomic(); }; PlatformAwareObjectStartBitmap::PlatformAwareObjectStartBitmap(Address offset) : ObjectStartBitmap(offset) {} // static template <AccessMode mode> bool PlatformAwareObjectStartBitmap::ShouldForceNonAtomic() { #if defined(V8_TARGET_ARCH_ARM) // Use non-atomic accesses on ARMv7 when marking is not active. if (mode == AccessMode::kAtomic) { if (V8_LIKELY(!WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) return true; } #endif // defined(V8_TARGET_ARCH_ARM) return false; } template <AccessMode mode> void PlatformAwareObjectStartBitmap::SetBit(ConstAddress header_address) { if (ShouldForceNonAtomic<mode>()) { ObjectStartBitmap::SetBit<AccessMode::kNonAtomic>(header_address); return; } ObjectStartBitmap::SetBit<mode>(header_address); } template <AccessMode mode> void PlatformAwareObjectStartBitmap::ClearBit(ConstAddress header_address) { if (ShouldForceNonAtomic<mode>()) { ObjectStartBitmap::ClearBit<AccessMode::kNonAtomic>(header_address); return; } ObjectStartBitmap::ClearBit<mode>(header_address); } } // namespace internal } // namespace cppgc #endif // V8_HEAP_CPPGC_OBJECT_START_BITMAP_H_