#include "partition_alloc/partition_alloc.h"
#include <cstdint>
#include <cstring>
#include <memory>
#include "partition_alloc/address_pool_manager.h"
#include "partition_alloc/buildflags.h"
#include "partition_alloc/memory_reclaimer.h"
#include "partition_alloc/partition_address_space.h"
#include "partition_alloc/partition_alloc_hooks.h"
#include "partition_alloc/partition_direct_map_extent.h"
#include "partition_alloc/partition_oom.h"
#include "partition_alloc/partition_page.h"
#include "partition_alloc/partition_root.h"
#include "partition_alloc/partition_stats.h"
namespace partition_alloc {
void PartitionAllocGlobalInit(OomFunction on_out_of_memory) {
STATIC_ASSERT_OR_PA_CHECK(
(internal::SystemPageSize() & internal::SystemPageOffsetMask()) == 0,
"SystemPageSize() must be power of 2");
STATIC_ASSERT_OR_PA_CHECK(
internal::PartitionPageSize() * 4 <= internal::kSuperPageSize,
"ok super page size");
STATIC_ASSERT_OR_PA_CHECK(
(internal::kSuperPageSize & internal::SystemPageOffsetMask()) == 0,
"ok super page multiple");
STATIC_ASSERT_OR_PA_CHECK(
internal::SystemPageSize() * 4 <= internal::PartitionPageSize(),
"ok partition page size");
STATIC_ASSERT_OR_PA_CHECK(
(internal::PartitionPageSize() & internal::SystemPageOffsetMask()) == 0,
"ok partition page multiple");
static_assert(
sizeof(internal::PartitionPageMetadata) <= internal::kPageMetadataSize,
"PartitionPage should not be too big");
STATIC_ASSERT_OR_PA_CHECK(
internal::kPageMetadataSize * internal::NumPartitionPagesPerSuperPage() <=
internal::SystemPageSize(),
"page metadata fits in hole");
STATIC_ASSERT_OR_PA_CHECK(
internal::MaxDirectMapped() <=
(1UL << 31) + internal::DirectMapAllocationGranularity(),
"maximum direct mapped allocation");
static_assert(BucketIndexLookup::kMinBucketSize == internal::kAlignment,
"generic smallest bucket");
static_assert(BucketIndexLookup::kMaxBucketSize == 983040,
"generic max bucketed");
STATIC_ASSERT_OR_PA_CHECK(
internal::MaxSystemPagesPerRegularSlotSpan() <= 16,
"System pages per slot span must be no greater than 16.");
#if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
STATIC_ASSERT_OR_PA_CHECK(
internal::GetInSlotMetadataIndexMultiplierShift() <
std::numeric_limits<size_t>::max() / 2,
"Calculation in GetInSlotMetadataIndexMultiplierShift() must not "
"underflow.");
STATIC_ASSERT_OR_PA_CHECK(
(1 << internal::GetInSlotMetadataIndexMultiplierShift()) ==
(internal::SystemPageSize() /
(sizeof(internal::InSlotMetadata) *
(internal::kSuperPageSize / internal::SystemPageSize()))),
"Bitshift must match the intended multiplication.");
STATIC_ASSERT_OR_PA_CHECK(
((sizeof(internal::InSlotMetadata) *
(internal::kSuperPageSize / internal::SystemPageSize()))
<< internal::GetInSlotMetadataIndexMultiplierShift()) <=
internal::SystemPageSize(),
"InSlotMetadata table size must be smaller than or equal to "
"<= SystemPageSize().");
#endif
PA_DCHECK(on_out_of_memory);
internal::g_oom_handling_function = on_out_of_memory;
}
void PartitionAllocGlobalUninitForTesting() {
#if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
internal::PartitionAddressSpace::UninitThreadIsolatedPoolForTesting();
#endif
internal::g_oom_handling_function = nullptr;
}
PartitionAllocator::PartitionAllocator() = default;
PartitionAllocator::~PartitionAllocator() {
MemoryReclaimer::Instance()->UnregisterPartition(&partition_root_);
}
void PartitionAllocator::init(PartitionOptions opts) {
#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
PA_CHECK(opts.thread_cache == PartitionOptions::kDisabled ||
opts.thread_cache_index >= kNumPartitions)
<< "Cannot use a thread cache at indices used by default partitions when "
"PartitionAlloc is malloc().";
#endif
PA_CHECK(opts.thread_cache == PartitionOptions::kDisabled ||
opts.thread_cache_index < internal::kMaxThreadCacheIndex)
<< "Thread cache index must be less than kMaxThreadCacheIndex";
partition_root_.Init(opts);
#if PA_BUILDFLAG(ENABLE_THREAD_ISOLATION)
const bool use_memory_reclaimer = !opts.thread_isolation.enabled;
#else
constexpr bool use_memory_reclaimer = true;
#endif
if (use_memory_reclaimer) {
MemoryReclaimer::Instance()->RegisterPartition(&partition_root_);
}
}
}