#ifndef PARTITION_ALLOC_FREESLOT_BITMAP_H_
#define PARTITION_ALLOC_FREESLOT_BITMAP_H_
#include <climits>
#include <cstdint>
#include <utility>
#include "partition_alloc/buildflags.h"
#include "partition_alloc/freeslot_bitmap_constants.h"
#include "partition_alloc/partition_alloc_base/bits.h"
#include "partition_alloc/partition_alloc_base/compiler_specific.h"
#include "partition_alloc/partition_alloc_constants.h"
#if PA_BUILDFLAG(USE_FREESLOT_BITMAP)
namespace partition_alloc::internal {
PA_ALWAYS_INLINE uintptr_t GetFreeSlotBitmapAddressForPointer(uintptr_t ptr) {
uintptr_t super_page = ptr & kSuperPageBaseMask;
return SuperPageFreeSlotBitmapAddr(super_page);
}
PA_ALWAYS_INLINE std::pair<FreeSlotBitmapCellType*, size_t>
GetFreeSlotBitmapCellPtrAndBitIndex(uintptr_t slot_start) {
uintptr_t slot_superpage_offset = slot_start & kSuperPageOffsetMask;
uintptr_t superpage_bitmap_start =
GetFreeSlotBitmapAddressForPointer(slot_start);
uintptr_t cell_addr = base::bits::AlignDown(
superpage_bitmap_start +
(slot_superpage_offset / kSmallestBucket) / CHAR_BIT,
sizeof(FreeSlotBitmapCellType));
PA_DCHECK(cell_addr < superpage_bitmap_start + kFreeSlotBitmapSize);
size_t bit_index =
(slot_superpage_offset / kSmallestBucket) & kFreeSlotBitmapOffsetMask;
PA_DCHECK(bit_index < kFreeSlotBitmapBitsPerCell);
return {reinterpret_cast<FreeSlotBitmapCellType*>(cell_addr), bit_index};
}
PA_ALWAYS_INLINE FreeSlotBitmapCellType CellWithAOne(size_t n) {
return static_cast<FreeSlotBitmapCellType>(1) << n;
}
PA_ALWAYS_INLINE FreeSlotBitmapCellType CellWithTrailingOnes(size_t n) {
return (static_cast<FreeSlotBitmapCellType>(1) << n) -
static_cast<FreeSlotBitmapCellType>(1);
}
PA_ALWAYS_INLINE bool FreeSlotBitmapSlotIsUsed(uintptr_t slot_start) {
auto [cell, bit_index] = GetFreeSlotBitmapCellPtrAndBitIndex(slot_start);
return (*cell & CellWithAOne(bit_index)) == 0;
}
PA_ALWAYS_INLINE void FreeSlotBitmapMarkSlotAsUsed(uintptr_t slot_start) {
PA_CHECK(!FreeSlotBitmapSlotIsUsed(slot_start));
auto [cell, bit_index] = GetFreeSlotBitmapCellPtrAndBitIndex(slot_start);
*cell &= ~CellWithAOne(bit_index);
}
PA_ALWAYS_INLINE void FreeSlotBitmapMarkSlotAsFree(uintptr_t slot_start) {
PA_CHECK(FreeSlotBitmapSlotIsUsed(slot_start));
auto [cell, bit_index] = GetFreeSlotBitmapCellPtrAndBitIndex(slot_start);
*cell |= CellWithAOne(bit_index);
}
PA_ALWAYS_INLINE void FreeSlotBitmapReset(uintptr_t begin_addr,
uintptr_t end_addr,
uintptr_t slot_size) {
PA_DCHECK(begin_addr <= end_addr);
PA_DCHECK((end_addr & (kSmallestBucket - 1)) == 0u);
for (uintptr_t slot_start = begin_addr; slot_start < end_addr;
slot_start += slot_size) {
auto [cell, bit_index] = GetFreeSlotBitmapCellPtrAndBitIndex(slot_start);
*cell &= ~CellWithAOne(bit_index);
}
#if PA_BUILDFLAG(DCHECKS_ARE_ON)
auto [begin_cell, begin_bit_index] =
GetFreeSlotBitmapCellPtrAndBitIndex(begin_addr);
auto [end_cell, end_bit_index] =
GetFreeSlotBitmapCellPtrAndBitIndex(end_addr);
if (begin_cell == end_cell) {
PA_DCHECK((*begin_cell & (~CellWithTrailingOnes(begin_bit_index) &
CellWithTrailingOnes(end_bit_index))) == 0u);
return;
}
if (begin_bit_index != 0) {
PA_DCHECK((*begin_cell & ~CellWithTrailingOnes(begin_bit_index)) == 0u);
++begin_cell;
}
if (end_bit_index != 0) {
PA_DCHECK((*end_cell & CellWithTrailingOnes(end_bit_index)) == 0u);
}
for (FreeSlotBitmapCellType* cell = begin_cell; cell < end_cell; ++cell) {
PA_DCHECK(*cell == 0u);
}
#endif
}
}
#endif
#endif