#include "partition_alloc/address_pool_manager.h"
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <limits>
#include "partition_alloc/address_space_stats.h"
#include "partition_alloc/build_config.h"
#include "partition_alloc/buildflags.h"
#include "partition_alloc/page_allocator.h"
#include "partition_alloc/page_allocator_constants.h"
#include "partition_alloc/partition_alloc_base/notreached.h"
#include "partition_alloc/partition_alloc_check.h"
#include "partition_alloc/partition_alloc_constants.h"
#include "partition_alloc/reservation_offset_table.h"
#include "partition_alloc/thread_isolation/alignment.h"
#if PA_BUILDFLAG(IS_APPLE) || PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
#include <sys/mman.h>
#endif
namespace partition_alloc::internal {
AddressPoolManager AddressPoolManager::singleton_;
AddressPoolManager& AddressPoolManager::GetInstance() { … }
namespace {
constexpr PageTag kPageTag = …;
}
#if PA_BUILDFLAG(HAS_64_BIT_POINTERS)
namespace {
void DecommitPages(uintptr_t address, size_t size) { … }
}
void AddressPoolManager::Add(pool_handle handle, uintptr_t ptr, size_t length) { … }
void AddressPoolManager::GetPoolUsedSuperPages(
pool_handle handle,
std::bitset<kMaxSuperPagesInPool>& used) { … }
uintptr_t AddressPoolManager::GetPoolBaseAddress(pool_handle handle) { … }
void AddressPoolManager::ResetForTesting() { … }
void AddressPoolManager::Remove(pool_handle handle) { … }
uintptr_t AddressPoolManager::Reserve(pool_handle handle,
uintptr_t requested_address,
size_t length) { … }
void AddressPoolManager::UnreserveAndDecommit(pool_handle handle,
uintptr_t address,
size_t length) { … }
void AddressPoolManager::Pool::Initialize(uintptr_t ptr, size_t length) { … }
bool AddressPoolManager::Pool::IsInitialized() { … }
void AddressPoolManager::Pool::Reset() { … }
void AddressPoolManager::Pool::GetUsedSuperPages(
std::bitset<kMaxSuperPagesInPool>& used) { … }
uintptr_t AddressPoolManager::Pool::GetBaseAddress() { … }
uintptr_t AddressPoolManager::Pool::FindChunk(size_t requested_size) { … }
bool AddressPoolManager::Pool::TryReserveChunk(uintptr_t address,
size_t requested_size) { … }
void AddressPoolManager::Pool::FreeChunk(uintptr_t address, size_t free_size) { … }
void AddressPoolManager::Pool::GetStats(PoolStats* stats) { … }
void AddressPoolManager::GetPoolStats(const pool_handle handle,
PoolStats* stats) { … }
bool AddressPoolManager::GetStats(AddressSpaceStats* stats) { … }
#else
static_assert(
kSuperPageSize % AddressPoolManagerBitmap::kBytesPer1BitOfBRPPoolBitmap ==
0,
"kSuperPageSize must be a multiple of kBytesPer1BitOfBRPPoolBitmap.");
static_assert(
kSuperPageSize / AddressPoolManagerBitmap::kBytesPer1BitOfBRPPoolBitmap > 0,
"kSuperPageSize must be larger than kBytesPer1BitOfBRPPoolBitmap.");
static_assert(AddressPoolManagerBitmap::kGuardBitsOfBRPPoolBitmap >=
AddressPoolManagerBitmap::kGuardOffsetOfBRPPoolBitmap,
"kGuardBitsOfBRPPoolBitmap must be larger than or equal to "
"kGuardOffsetOfBRPPoolBitmap.");
template <size_t bitsize>
void SetBitmap(std::bitset<bitsize>& bitmap,
size_t start_bit,
size_t bit_length) {
const size_t end_bit = start_bit + bit_length;
PA_DCHECK(start_bit <= bitsize);
PA_DCHECK(end_bit <= bitsize);
for (size_t i = start_bit; i < end_bit; ++i) {
PA_DCHECK(!bitmap.test(i));
bitmap.set(i);
}
}
template <size_t bitsize>
void ResetBitmap(std::bitset<bitsize>& bitmap,
size_t start_bit,
size_t bit_length) {
const size_t end_bit = start_bit + bit_length;
PA_DCHECK(start_bit <= bitsize);
PA_DCHECK(end_bit <= bitsize);
for (size_t i = start_bit; i < end_bit; ++i) {
PA_DCHECK(bitmap.test(i));
bitmap.reset(i);
}
}
uintptr_t AddressPoolManager::Reserve(pool_handle handle,
uintptr_t requested_address,
size_t length) {
PA_DCHECK(!(length & DirectMapAllocationGranularityOffsetMask()));
uintptr_t address =
AllocPages(requested_address, length, kSuperPageSize,
PageAccessibilityConfiguration(
PageAccessibilityConfiguration::kInaccessible),
kPageTag);
return address;
}
void AddressPoolManager::UnreserveAndDecommit(pool_handle handle,
uintptr_t address,
size_t length) {
PA_DCHECK(!(address & kSuperPageOffsetMask));
PA_DCHECK(!(length & DirectMapAllocationGranularityOffsetMask()));
FreePages(address, length);
}
void AddressPoolManager::MarkUsed(pool_handle handle,
uintptr_t address,
size_t length) {
ScopedGuard scoped_lock(AddressPoolManagerBitmap::GetLock());
#if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
if (handle == kBRPPoolHandle) {
PA_DCHECK(
(length % AddressPoolManagerBitmap::kBytesPer1BitOfBRPPoolBitmap) == 0);
SetBitmap(AddressPoolManagerBitmap::brp_pool_bits_,
(address >> AddressPoolManagerBitmap::kBitShiftOfBRPPoolBitmap) +
AddressPoolManagerBitmap::kGuardOffsetOfBRPPoolBitmap,
(length >> AddressPoolManagerBitmap::kBitShiftOfBRPPoolBitmap) -
AddressPoolManagerBitmap::kGuardBitsOfBRPPoolBitmap);
} else
#endif
{
PA_DCHECK(handle == kRegularPoolHandle);
PA_DCHECK(
(length % AddressPoolManagerBitmap::kBytesPer1BitOfRegularPoolBitmap) ==
0);
SetBitmap(AddressPoolManagerBitmap::regular_pool_bits_,
address >> AddressPoolManagerBitmap::kBitShiftOfRegularPoolBitmap,
length >> AddressPoolManagerBitmap::kBitShiftOfRegularPoolBitmap);
}
}
void AddressPoolManager::MarkUnused(pool_handle handle,
uintptr_t address,
size_t length) {
ScopedGuard scoped_lock(AddressPoolManagerBitmap::GetLock());
#if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
if (handle == kBRPPoolHandle) {
PA_DCHECK(
(length % AddressPoolManagerBitmap::kBytesPer1BitOfBRPPoolBitmap) == 0);
ResetBitmap(
AddressPoolManagerBitmap::brp_pool_bits_,
(address >> AddressPoolManagerBitmap::kBitShiftOfBRPPoolBitmap) +
AddressPoolManagerBitmap::kGuardOffsetOfBRPPoolBitmap,
(length >> AddressPoolManagerBitmap::kBitShiftOfBRPPoolBitmap) -
AddressPoolManagerBitmap::kGuardBitsOfBRPPoolBitmap);
} else
#endif
{
PA_DCHECK(handle == kRegularPoolHandle);
PA_DCHECK(
(length % AddressPoolManagerBitmap::kBytesPer1BitOfRegularPoolBitmap) ==
0);
ResetBitmap(
AddressPoolManagerBitmap::regular_pool_bits_,
address >> AddressPoolManagerBitmap::kBitShiftOfRegularPoolBitmap,
length >> AddressPoolManagerBitmap::kBitShiftOfRegularPoolBitmap);
}
}
void AddressPoolManager::ResetForTesting() {
ScopedGuard guard(AddressPoolManagerBitmap::GetLock());
AddressPoolManagerBitmap::regular_pool_bits_.reset();
AddressPoolManagerBitmap::brp_pool_bits_.reset();
}
namespace {
template <size_t bitsize>
size_t CountUsedSuperPages(const std::bitset<bitsize>& bitmap,
const size_t bits_per_super_page) {
size_t count = 0;
size_t bit_index = 0;
for (size_t super_page_index = 0; bit_index < bitsize; ++super_page_index) {
for (bit_index = super_page_index * bits_per_super_page;
bit_index < (super_page_index + 1) * bits_per_super_page &&
bit_index < bitsize;
++bit_index) {
if (bitmap[bit_index]) {
count += 1;
break;
}
}
}
return count;
}
}
bool AddressPoolManager::GetStats(AddressSpaceStats* stats) {
std::bitset<AddressPoolManagerBitmap::kRegularPoolBits> regular_pool_bits;
std::bitset<AddressPoolManagerBitmap::kBRPPoolBits> brp_pool_bits;
{
ScopedGuard scoped_lock(AddressPoolManagerBitmap::GetLock());
regular_pool_bits = AddressPoolManagerBitmap::regular_pool_bits_;
brp_pool_bits = AddressPoolManagerBitmap::brp_pool_bits_;
}
static_assert(
kSuperPageSize %
AddressPoolManagerBitmap::kBytesPer1BitOfRegularPoolBitmap ==
0,
"information loss when calculating metrics");
constexpr size_t kRegularPoolBitsPerSuperPage =
kSuperPageSize /
AddressPoolManagerBitmap::kBytesPer1BitOfRegularPoolBitmap;
stats->regular_pool_stats.usage =
CountUsedSuperPages(regular_pool_bits, kRegularPoolBitsPerSuperPage);
#if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
static_assert(
kSuperPageSize % AddressPoolManagerBitmap::kBytesPer1BitOfBRPPoolBitmap ==
0,
"information loss when calculating metrics");
constexpr size_t kBRPPoolBitsPerSuperPage =
kSuperPageSize / AddressPoolManagerBitmap::kBytesPer1BitOfBRPPoolBitmap;
stats->brp_pool_stats.usage =
CountUsedSuperPages(brp_pool_bits, kBRPPoolBitsPerSuperPage);
for (const auto& blocked :
AddressPoolManagerBitmap::brp_forbidden_super_page_map_) {
if (blocked.load(std::memory_order_relaxed)) {
stats->blocklist_size += 1;
}
}
stats->blocklist_hit_count =
AddressPoolManagerBitmap::blocklist_hit_count_.load(
std::memory_order_relaxed);
#endif
return true;
}
#endif
void AddressPoolManager::DumpStats(AddressSpaceStatsDumper* dumper) { … }
#if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
void AddressPoolManager::AssertThreadIsolatedLayout() { … }
#endif
}