#ifndef PARTITION_ALLOC_ADDRESS_POOL_MANAGER_BITMAP_H_
#define PARTITION_ALLOC_ADDRESS_POOL_MANAGER_BITMAP_H_
#include <array>
#include <atomic>
#include <bitset>
#include <limits>
#include "partition_alloc/build_config.h"
#include "partition_alloc/buildflags.h"
#include "partition_alloc/partition_alloc_base/compiler_specific.h"
#include "partition_alloc/partition_alloc_base/component_export.h"
#include "partition_alloc/partition_alloc_check.h"
#include "partition_alloc/partition_alloc_constants.h"
#include "partition_alloc/partition_lock.h"
#if !PA_BUILDFLAG(HAS_64_BIT_POINTERS)
namespace partition_alloc {
namespace internal {
class PA_COMPONENT_EXPORT(PARTITION_ALLOC) AddressPoolManagerBitmap {
public:
static constexpr uint64_t kGiB = 1024 * 1024 * 1024ull;
static constexpr uint64_t kAddressSpaceSize = 4ull * kGiB;
static constexpr size_t kBitShiftOfBRPPoolBitmap = PartitionPageShift();
static constexpr size_t kBytesPer1BitOfBRPPoolBitmap = PartitionPageSize();
static_assert(kBytesPer1BitOfBRPPoolBitmap == 1 << kBitShiftOfBRPPoolBitmap,
"");
static constexpr size_t kGuardOffsetOfBRPPoolBitmap = 1;
static constexpr size_t kGuardBitsOfBRPPoolBitmap = 2;
static constexpr size_t kBRPPoolBits =
kAddressSpaceSize / kBytesPer1BitOfBRPPoolBitmap;
static constexpr size_t kBitShiftOfRegularPoolBitmap =
DirectMapAllocationGranularityShift();
static constexpr size_t kBytesPer1BitOfRegularPoolBitmap =
DirectMapAllocationGranularity();
static_assert(kBytesPer1BitOfRegularPoolBitmap ==
1 << kBitShiftOfRegularPoolBitmap,
"");
static constexpr size_t kRegularPoolBits =
kAddressSpaceSize / kBytesPer1BitOfRegularPoolBitmap;
static bool IsManagedByRegularPool(uintptr_t address) {
static_assert(
std::numeric_limits<uintptr_t>::max() >> kBitShiftOfRegularPoolBitmap <
regular_pool_bits_.size(),
"The bitmap is too small, will result in unchecked out of bounds "
"accesses.");
return PA_TS_UNCHECKED_READ(
regular_pool_bits_)[address >> kBitShiftOfRegularPoolBitmap];
}
static bool IsManagedByBRPPool(uintptr_t address) {
static_assert(std::numeric_limits<uintptr_t>::max() >>
kBitShiftOfBRPPoolBitmap < brp_pool_bits_.size(),
"The bitmap is too small, will result in unchecked out of "
"bounds accesses.");
return PA_TS_UNCHECKED_READ(
brp_pool_bits_)[address >> kBitShiftOfBRPPoolBitmap];
}
#if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
static void BanSuperPageFromBRPPool(uintptr_t address) {
brp_forbidden_super_page_map_[address >> kSuperPageShift].store(
true, std::memory_order_relaxed);
}
static bool IsAllowedSuperPageForBRPPool(uintptr_t address) {
return !brp_forbidden_super_page_map_[address >> kSuperPageShift].load(
std::memory_order_relaxed);
}
static void IncrementBlocklistHitCount() { ++blocklist_hit_count_; }
#endif
private:
friend class AddressPoolManager;
static Lock& GetLock();
static std::bitset<kRegularPoolBits> regular_pool_bits_
PA_GUARDED_BY(GetLock());
static std::bitset<kBRPPoolBits> brp_pool_bits_ PA_GUARDED_BY(GetLock());
#if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
static std::array<std::atomic_bool, kAddressSpaceSize / kSuperPageSize>
brp_forbidden_super_page_map_;
static std::atomic_size_t blocklist_hit_count_;
#endif
};
}
PA_ALWAYS_INLINE bool IsManagedByPartitionAlloc(uintptr_t address) {
#if !PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
PA_DCHECK(!internal::AddressPoolManagerBitmap::IsManagedByBRPPool(address));
#endif
return internal::AddressPoolManagerBitmap::IsManagedByRegularPool(address)
#if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
|| internal::AddressPoolManagerBitmap::IsManagedByBRPPool(address)
#endif
;
}
PA_ALWAYS_INLINE bool IsManagedByPartitionAllocRegularPool(uintptr_t address) {
return internal::AddressPoolManagerBitmap::IsManagedByRegularPool(address);
}
PA_ALWAYS_INLINE bool IsManagedByPartitionAllocBRPPool(uintptr_t address) {
return internal::AddressPoolManagerBitmap::IsManagedByBRPPool(address);
}
PA_ALWAYS_INLINE bool IsManagedByPartitionAllocConfigurablePool(
uintptr_t address) {
return false;
}
PA_ALWAYS_INLINE bool IsConfigurablePoolAvailable() {
return false;
}
}
#endif
#endif