11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#ifndef V8_HEAP_CPPGC_OBJECT_START_BITMAP_H_ 61cb0ef41Sopenharmony_ci#define V8_HEAP_CPPGC_OBJECT_START_BITMAP_H_ 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci#include <limits.h> 91cb0ef41Sopenharmony_ci#include <stdint.h> 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ci#include <array> 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_ci#include "include/cppgc/internal/write-barrier.h" 141cb0ef41Sopenharmony_ci#include "src/base/atomic-utils.h" 151cb0ef41Sopenharmony_ci#include "src/base/bits.h" 161cb0ef41Sopenharmony_ci#include "src/base/macros.h" 171cb0ef41Sopenharmony_ci#include "src/heap/cppgc/globals.h" 181cb0ef41Sopenharmony_ci#include "src/heap/cppgc/heap-object-header.h" 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_cinamespace cppgc { 211cb0ef41Sopenharmony_cinamespace internal { 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ci// A bitmap for recording object starts. Objects have to be allocated at 241cb0ef41Sopenharmony_ci// minimum granularity of kGranularity. 251cb0ef41Sopenharmony_ci// 261cb0ef41Sopenharmony_ci// Depends on internals such as: 271cb0ef41Sopenharmony_ci// - kBlinkPageSize 281cb0ef41Sopenharmony_ci// - kAllocationGranularity 291cb0ef41Sopenharmony_ci// 301cb0ef41Sopenharmony_ci// ObjectStartBitmap supports concurrent reads from multiple threads but 311cb0ef41Sopenharmony_ci// only a single mutator thread can write to it. 321cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE ObjectStartBitmap { 331cb0ef41Sopenharmony_ci public: 341cb0ef41Sopenharmony_ci // Granularity of addresses added to the bitmap. 351cb0ef41Sopenharmony_ci static constexpr size_t Granularity() { return kAllocationGranularity; } 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci // Maximum number of entries in the bitmap. 381cb0ef41Sopenharmony_ci static constexpr size_t MaxEntries() { 391cb0ef41Sopenharmony_ci return kReservedForBitmap * kBitsPerCell; 401cb0ef41Sopenharmony_ci } 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci explicit inline ObjectStartBitmap(Address offset); 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci // Finds an object header based on a 451cb0ef41Sopenharmony_ci // address_maybe_pointing_to_the_middle_of_object. Will search for an object 461cb0ef41Sopenharmony_ci // start in decreasing address order. 471cb0ef41Sopenharmony_ci template <AccessMode = AccessMode::kNonAtomic> 481cb0ef41Sopenharmony_ci inline HeapObjectHeader* FindHeader( 491cb0ef41Sopenharmony_ci ConstAddress address_maybe_pointing_to_the_middle_of_object) const; 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ci template <AccessMode = AccessMode::kNonAtomic> 521cb0ef41Sopenharmony_ci inline void SetBit(ConstAddress); 531cb0ef41Sopenharmony_ci template <AccessMode = AccessMode::kNonAtomic> 541cb0ef41Sopenharmony_ci inline void ClearBit(ConstAddress); 551cb0ef41Sopenharmony_ci template <AccessMode = AccessMode::kNonAtomic> 561cb0ef41Sopenharmony_ci inline bool CheckBit(ConstAddress) const; 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci // Iterates all object starts recorded in the bitmap. 591cb0ef41Sopenharmony_ci // 601cb0ef41Sopenharmony_ci // The callback is of type 611cb0ef41Sopenharmony_ci // void(Address) 621cb0ef41Sopenharmony_ci // and is passed the object start address as parameter. 631cb0ef41Sopenharmony_ci template <typename Callback> 641cb0ef41Sopenharmony_ci inline void Iterate(Callback) const; 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci // Clear the object start bitmap. 671cb0ef41Sopenharmony_ci inline void Clear(); 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci // Marks the bitmap as fully populated. Unpopulated bitmaps are in an 701cb0ef41Sopenharmony_ci // inconsistent state and must be populated before they can be used to find 711cb0ef41Sopenharmony_ci // object headers. 721cb0ef41Sopenharmony_ci inline void MarkAsFullyPopulated(); 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ci private: 751cb0ef41Sopenharmony_ci template <AccessMode = AccessMode::kNonAtomic> 761cb0ef41Sopenharmony_ci inline void store(size_t cell_index, uint8_t value); 771cb0ef41Sopenharmony_ci template <AccessMode = AccessMode::kNonAtomic> 781cb0ef41Sopenharmony_ci inline uint8_t load(size_t cell_index) const; 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ci static constexpr size_t kBitsPerCell = sizeof(uint8_t) * CHAR_BIT; 811cb0ef41Sopenharmony_ci static constexpr size_t kCellMask = kBitsPerCell - 1; 821cb0ef41Sopenharmony_ci static constexpr size_t kBitmapSize = 831cb0ef41Sopenharmony_ci (kPageSize + ((kBitsPerCell * kAllocationGranularity) - 1)) / 841cb0ef41Sopenharmony_ci (kBitsPerCell * kAllocationGranularity); 851cb0ef41Sopenharmony_ci static constexpr size_t kReservedForBitmap = 861cb0ef41Sopenharmony_ci ((kBitmapSize + kAllocationMask) & ~kAllocationMask); 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci inline void ObjectStartIndexAndBit(ConstAddress, size_t*, size_t*) const; 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci const Address offset_; 911cb0ef41Sopenharmony_ci // `fully_populated_` is used to denote that the bitmap is popluated with all 921cb0ef41Sopenharmony_ci // currently allocated objects on the page and is in a consistent state. It is 931cb0ef41Sopenharmony_ci // used to guard against using the bitmap for finding headers during 941cb0ef41Sopenharmony_ci // concurrent sweeping. 951cb0ef41Sopenharmony_ci // 961cb0ef41Sopenharmony_ci // Although this flag can be used by both the main thread and concurrent 971cb0ef41Sopenharmony_ci // sweeping threads, it is not atomic. The flag should never be accessed by 981cb0ef41Sopenharmony_ci // multiple threads at the same time. If data races are observed on this flag, 991cb0ef41Sopenharmony_ci // it likely means that the bitmap is queried while concurrent sweeping is 1001cb0ef41Sopenharmony_ci // active, which is not supported and should be avoided. 1011cb0ef41Sopenharmony_ci bool fully_populated_ = false; 1021cb0ef41Sopenharmony_ci // The bitmap contains a bit for every kGranularity aligned address on a 1031cb0ef41Sopenharmony_ci // a NormalPage, i.e., for a page of size kBlinkPageSize. 1041cb0ef41Sopenharmony_ci std::array<uint8_t, kReservedForBitmap> object_start_bit_map_; 1051cb0ef41Sopenharmony_ci}; 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ciObjectStartBitmap::ObjectStartBitmap(Address offset) : offset_(offset) { 1081cb0ef41Sopenharmony_ci Clear(); 1091cb0ef41Sopenharmony_ci MarkAsFullyPopulated(); 1101cb0ef41Sopenharmony_ci} 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_citemplate <AccessMode mode> 1131cb0ef41Sopenharmony_ciHeapObjectHeader* ObjectStartBitmap::FindHeader( 1141cb0ef41Sopenharmony_ci ConstAddress address_maybe_pointing_to_the_middle_of_object) const { 1151cb0ef41Sopenharmony_ci DCHECK(fully_populated_); 1161cb0ef41Sopenharmony_ci DCHECK_LE(offset_, address_maybe_pointing_to_the_middle_of_object); 1171cb0ef41Sopenharmony_ci size_t object_offset = 1181cb0ef41Sopenharmony_ci address_maybe_pointing_to_the_middle_of_object - offset_; 1191cb0ef41Sopenharmony_ci size_t object_start_number = object_offset / kAllocationGranularity; 1201cb0ef41Sopenharmony_ci size_t cell_index = object_start_number / kBitsPerCell; 1211cb0ef41Sopenharmony_ci DCHECK_GT(object_start_bit_map_.size(), cell_index); 1221cb0ef41Sopenharmony_ci const size_t bit = object_start_number & kCellMask; 1231cb0ef41Sopenharmony_ci uint8_t byte = load<mode>(cell_index) & ((1 << (bit + 1)) - 1); 1241cb0ef41Sopenharmony_ci while (!byte && cell_index) { 1251cb0ef41Sopenharmony_ci DCHECK_LT(0u, cell_index); 1261cb0ef41Sopenharmony_ci byte = load<mode>(--cell_index); 1271cb0ef41Sopenharmony_ci } 1281cb0ef41Sopenharmony_ci const int leading_zeroes = v8::base::bits::CountLeadingZeros(byte); 1291cb0ef41Sopenharmony_ci object_start_number = 1301cb0ef41Sopenharmony_ci (cell_index * kBitsPerCell) + (kBitsPerCell - 1) - leading_zeroes; 1311cb0ef41Sopenharmony_ci object_offset = object_start_number * kAllocationGranularity; 1321cb0ef41Sopenharmony_ci return reinterpret_cast<HeapObjectHeader*>(object_offset + offset_); 1331cb0ef41Sopenharmony_ci} 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_citemplate <AccessMode mode> 1361cb0ef41Sopenharmony_civoid ObjectStartBitmap::SetBit(ConstAddress header_address) { 1371cb0ef41Sopenharmony_ci size_t cell_index, object_bit; 1381cb0ef41Sopenharmony_ci ObjectStartIndexAndBit(header_address, &cell_index, &object_bit); 1391cb0ef41Sopenharmony_ci // Only a single mutator thread can write to the bitmap, so no need for CAS. 1401cb0ef41Sopenharmony_ci store<mode>(cell_index, 1411cb0ef41Sopenharmony_ci static_cast<uint8_t>(load(cell_index) | (1 << object_bit))); 1421cb0ef41Sopenharmony_ci} 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_citemplate <AccessMode mode> 1451cb0ef41Sopenharmony_civoid ObjectStartBitmap::ClearBit(ConstAddress header_address) { 1461cb0ef41Sopenharmony_ci size_t cell_index, object_bit; 1471cb0ef41Sopenharmony_ci ObjectStartIndexAndBit(header_address, &cell_index, &object_bit); 1481cb0ef41Sopenharmony_ci store<mode>(cell_index, 1491cb0ef41Sopenharmony_ci static_cast<uint8_t>(load(cell_index) & ~(1 << object_bit))); 1501cb0ef41Sopenharmony_ci} 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_citemplate <AccessMode mode> 1531cb0ef41Sopenharmony_cibool ObjectStartBitmap::CheckBit(ConstAddress header_address) const { 1541cb0ef41Sopenharmony_ci size_t cell_index, object_bit; 1551cb0ef41Sopenharmony_ci ObjectStartIndexAndBit(header_address, &cell_index, &object_bit); 1561cb0ef41Sopenharmony_ci return load<mode>(cell_index) & (1 << object_bit); 1571cb0ef41Sopenharmony_ci} 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_citemplate <AccessMode mode> 1601cb0ef41Sopenharmony_civoid ObjectStartBitmap::store(size_t cell_index, uint8_t value) { 1611cb0ef41Sopenharmony_ci if (mode == AccessMode::kNonAtomic) { 1621cb0ef41Sopenharmony_ci object_start_bit_map_[cell_index] = value; 1631cb0ef41Sopenharmony_ci return; 1641cb0ef41Sopenharmony_ci } 1651cb0ef41Sopenharmony_ci v8::base::AsAtomicPtr(&object_start_bit_map_[cell_index]) 1661cb0ef41Sopenharmony_ci ->store(value, std::memory_order_release); 1671cb0ef41Sopenharmony_ci} 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_citemplate <AccessMode mode> 1701cb0ef41Sopenharmony_ciuint8_t ObjectStartBitmap::load(size_t cell_index) const { 1711cb0ef41Sopenharmony_ci if (mode == AccessMode::kNonAtomic) { 1721cb0ef41Sopenharmony_ci return object_start_bit_map_[cell_index]; 1731cb0ef41Sopenharmony_ci } 1741cb0ef41Sopenharmony_ci return v8::base::AsAtomicPtr(&object_start_bit_map_[cell_index]) 1751cb0ef41Sopenharmony_ci ->load(std::memory_order_acquire); 1761cb0ef41Sopenharmony_ci} 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_civoid ObjectStartBitmap::ObjectStartIndexAndBit(ConstAddress header_address, 1791cb0ef41Sopenharmony_ci size_t* cell_index, 1801cb0ef41Sopenharmony_ci size_t* bit) const { 1811cb0ef41Sopenharmony_ci const size_t object_offset = header_address - offset_; 1821cb0ef41Sopenharmony_ci DCHECK(!(object_offset & kAllocationMask)); 1831cb0ef41Sopenharmony_ci const size_t object_start_number = object_offset / kAllocationGranularity; 1841cb0ef41Sopenharmony_ci *cell_index = object_start_number / kBitsPerCell; 1851cb0ef41Sopenharmony_ci DCHECK_GT(kBitmapSize, *cell_index); 1861cb0ef41Sopenharmony_ci *bit = object_start_number & kCellMask; 1871cb0ef41Sopenharmony_ci} 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_citemplate <typename Callback> 1901cb0ef41Sopenharmony_ciinline void ObjectStartBitmap::Iterate(Callback callback) const { 1911cb0ef41Sopenharmony_ci for (size_t cell_index = 0; cell_index < kReservedForBitmap; cell_index++) { 1921cb0ef41Sopenharmony_ci if (!object_start_bit_map_[cell_index]) continue; 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci uint8_t value = object_start_bit_map_[cell_index]; 1951cb0ef41Sopenharmony_ci while (value) { 1961cb0ef41Sopenharmony_ci const int trailing_zeroes = v8::base::bits::CountTrailingZeros(value); 1971cb0ef41Sopenharmony_ci const size_t object_start_number = 1981cb0ef41Sopenharmony_ci (cell_index * kBitsPerCell) + trailing_zeroes; 1991cb0ef41Sopenharmony_ci const Address object_address = 2001cb0ef41Sopenharmony_ci offset_ + (kAllocationGranularity * object_start_number); 2011cb0ef41Sopenharmony_ci callback(object_address); 2021cb0ef41Sopenharmony_ci // Clear current object bit in temporary value to advance iteration. 2031cb0ef41Sopenharmony_ci value &= ~(1 << (object_start_number & kCellMask)); 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci } 2061cb0ef41Sopenharmony_ci} 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_civoid ObjectStartBitmap::MarkAsFullyPopulated() { 2091cb0ef41Sopenharmony_ci DCHECK(!fully_populated_); 2101cb0ef41Sopenharmony_ci fully_populated_ = true; 2111cb0ef41Sopenharmony_ci} 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_civoid ObjectStartBitmap::Clear() { 2141cb0ef41Sopenharmony_ci fully_populated_ = false; 2151cb0ef41Sopenharmony_ci std::fill(object_start_bit_map_.begin(), object_start_bit_map_.end(), 0); 2161cb0ef41Sopenharmony_ci} 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_ci// A platform aware version of ObjectStartBitmap to provide platform specific 2191cb0ef41Sopenharmony_ci// optimizations (e.g. Use non-atomic stores on ARMv7 when not marking). 2201cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE PlatformAwareObjectStartBitmap 2211cb0ef41Sopenharmony_ci : public ObjectStartBitmap { 2221cb0ef41Sopenharmony_ci public: 2231cb0ef41Sopenharmony_ci explicit inline PlatformAwareObjectStartBitmap(Address offset); 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci template <AccessMode = AccessMode::kNonAtomic> 2261cb0ef41Sopenharmony_ci inline void SetBit(ConstAddress); 2271cb0ef41Sopenharmony_ci template <AccessMode = AccessMode::kNonAtomic> 2281cb0ef41Sopenharmony_ci inline void ClearBit(ConstAddress); 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_ci private: 2311cb0ef41Sopenharmony_ci template <AccessMode> 2321cb0ef41Sopenharmony_ci static bool ShouldForceNonAtomic(); 2331cb0ef41Sopenharmony_ci}; 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ciPlatformAwareObjectStartBitmap::PlatformAwareObjectStartBitmap(Address offset) 2361cb0ef41Sopenharmony_ci : ObjectStartBitmap(offset) {} 2371cb0ef41Sopenharmony_ci 2381cb0ef41Sopenharmony_ci// static 2391cb0ef41Sopenharmony_citemplate <AccessMode mode> 2401cb0ef41Sopenharmony_cibool PlatformAwareObjectStartBitmap::ShouldForceNonAtomic() { 2411cb0ef41Sopenharmony_ci#if defined(V8_TARGET_ARCH_ARM) 2421cb0ef41Sopenharmony_ci // Use non-atomic accesses on ARMv7 when marking is not active. 2431cb0ef41Sopenharmony_ci if (mode == AccessMode::kAtomic) { 2441cb0ef41Sopenharmony_ci if (V8_LIKELY(!WriteBarrier::IsAnyIncrementalOrConcurrentMarking())) 2451cb0ef41Sopenharmony_ci return true; 2461cb0ef41Sopenharmony_ci } 2471cb0ef41Sopenharmony_ci#endif // defined(V8_TARGET_ARCH_ARM) 2481cb0ef41Sopenharmony_ci return false; 2491cb0ef41Sopenharmony_ci} 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_citemplate <AccessMode mode> 2521cb0ef41Sopenharmony_civoid PlatformAwareObjectStartBitmap::SetBit(ConstAddress header_address) { 2531cb0ef41Sopenharmony_ci if (ShouldForceNonAtomic<mode>()) { 2541cb0ef41Sopenharmony_ci ObjectStartBitmap::SetBit<AccessMode::kNonAtomic>(header_address); 2551cb0ef41Sopenharmony_ci return; 2561cb0ef41Sopenharmony_ci } 2571cb0ef41Sopenharmony_ci ObjectStartBitmap::SetBit<mode>(header_address); 2581cb0ef41Sopenharmony_ci} 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_citemplate <AccessMode mode> 2611cb0ef41Sopenharmony_civoid PlatformAwareObjectStartBitmap::ClearBit(ConstAddress header_address) { 2621cb0ef41Sopenharmony_ci if (ShouldForceNonAtomic<mode>()) { 2631cb0ef41Sopenharmony_ci ObjectStartBitmap::ClearBit<AccessMode::kNonAtomic>(header_address); 2641cb0ef41Sopenharmony_ci return; 2651cb0ef41Sopenharmony_ci } 2661cb0ef41Sopenharmony_ci ObjectStartBitmap::ClearBit<mode>(header_address); 2671cb0ef41Sopenharmony_ci} 2681cb0ef41Sopenharmony_ci 2691cb0ef41Sopenharmony_ci} // namespace internal 2701cb0ef41Sopenharmony_ci} // namespace cppgc 2711cb0ef41Sopenharmony_ci 2721cb0ef41Sopenharmony_ci#endif // V8_HEAP_CPPGC_OBJECT_START_BITMAP_H_ 273