#ifndef PARTITION_ALLOC_PARTITION_ROOT_H_
#define PARTITION_ALLOC_PARTITION_ROOT_H_
#include <algorithm>
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <optional>
#include <utility>
#include "partition_alloc/address_pool_manager_types.h"
#include "partition_alloc/allocation_guard.h"
#include "partition_alloc/build_config.h"
#include "partition_alloc/buildflags.h"
#include "partition_alloc/freeslot_bitmap.h"
#include "partition_alloc/in_slot_metadata.h"
#include "partition_alloc/lightweight_quarantine.h"
#include "partition_alloc/page_allocator.h"
#include "partition_alloc/partition_address_space.h"
#include "partition_alloc/partition_alloc-inl.h"
#include "partition_alloc/partition_alloc_allocation_data.h"
#include "partition_alloc/partition_alloc_base/bits.h"
#include "partition_alloc/partition_alloc_base/compiler_specific.h"
#include "partition_alloc/partition_alloc_base/component_export.h"
#include "partition_alloc/partition_alloc_base/export_template.h"
#include "partition_alloc/partition_alloc_base/no_destructor.h"
#include "partition_alloc/partition_alloc_base/notreached.h"
#include "partition_alloc/partition_alloc_base/thread_annotations.h"
#include "partition_alloc/partition_alloc_base/time/time.h"
#include "partition_alloc/partition_alloc_check.h"
#include "partition_alloc/partition_alloc_config.h"
#include "partition_alloc/partition_alloc_constants.h"
#include "partition_alloc/partition_alloc_forward.h"
#include "partition_alloc/partition_alloc_hooks.h"
#include "partition_alloc/partition_bucket.h"
#include "partition_alloc/partition_bucket_lookup.h"
#include "partition_alloc/partition_cookie.h"
#include "partition_alloc/partition_dcheck_helper.h"
#include "partition_alloc/partition_direct_map_extent.h"
#include "partition_alloc/partition_freelist_entry.h"
#include "partition_alloc/partition_lock.h"
#include "partition_alloc/partition_oom.h"
#include "partition_alloc/partition_page.h"
#include "partition_alloc/reservation_offset_table.h"
#include "partition_alloc/tagging.h"
#include "partition_alloc/thread_cache.h"
#include "partition_alloc/thread_isolation/thread_isolation.h"
namespace partition_alloc::internal {
static constexpr size_t kAllocInfoSize = …;
struct AllocInfo { … };
#if PA_BUILDFLAG(RECORD_ALLOC_INFO)
extern AllocInfo g_allocs;
void RecordAllocOrFree(uintptr_t addr, size_t size);
#endif
}
namespace partition_alloc {
internal
struct PurgeFlags { … };
struct PartitionOptions { … };
constexpr PartitionOptions::PartitionOptions() = default;
constexpr PartitionOptions::PartitionOptions(const PartitionOptions& other) =
default;
PA_CONSTEXPR_DTOR PartitionOptions::~PartitionOptions() = default;
enum class StraightenLargerSlotSpanFreeListsMode { … };
struct alignas(64) PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionRoot { … };
internal
template <AllocFlags flags>
PA_ALWAYS_INLINE uintptr_t
PartitionRoot::AllocFromBucket(Bucket* bucket,
size_t raw_size,
size_t slot_span_alignment,
size_t* usable_size,
size_t* slot_size,
bool* is_already_zeroed) { … }
AllocationNotificationData PartitionRoot::CreateAllocationNotificationData(
void* object,
size_t size,
const char* type_name) const { … }
FreeNotificationData PartitionRoot::CreateDefaultFreeNotificationData(
void* address) { … }
FreeNotificationData PartitionRoot::CreateFreeNotificationData(
void* address) const { … }
template <FreeFlags flags>
PA_ALWAYS_INLINE bool PartitionRoot::FreeProlog(void* object,
const PartitionRoot* root) { … }
PA_ALWAYS_INLINE bool PartitionRoot::IsMemoryTaggingEnabled() const { … }
PA_ALWAYS_INLINE bool PartitionRoot::UseRandomMemoryTagging() const { … }
PA_ALWAYS_INLINE TagViolationReportingMode
PartitionRoot::memory_tagging_reporting_mode() const { … }
template <FreeFlags flags>
PA_ALWAYS_INLINE void PartitionRoot::FreeInlineInUnknownRoot(void* object) { … }
template <FreeFlags flags>
PA_ALWAYS_INLINE void PartitionRoot::FreeInline(void* object) { … }
PA_ALWAYS_INLINE void PartitionRoot::FreeNoHooksImmediate(
void* object,
SlotSpanMetadata* slot_span,
uintptr_t slot_start) { … }
PA_ALWAYS_INLINE void PartitionRoot::FreeInSlotSpan(
uintptr_t slot_start,
SlotSpanMetadata* slot_span) { … }
PA_ALWAYS_INLINE void PartitionRoot::RawFree(uintptr_t slot_start) { … }
#if PA_CONFIG(IS_NONCLANG_MSVC)
#pragma optimize("", off)
#endif
PA_ALWAYS_INLINE void PartitionRoot::RawFree(uintptr_t slot_start,
SlotSpanMetadata* slot_span) { … }
#if PA_CONFIG(IS_NONCLANG_MSVC)
#pragma optimize("", on)
#endif
PA_ALWAYS_INLINE void PartitionRoot::RawFreeBatch(FreeListEntry* head,
FreeListEntry* tail,
size_t size,
SlotSpanMetadata* slot_span) { … }
#if PA_BUILDFLAG(HAS_MEMORY_TAGGING)
PA_ALWAYS_INLINE void PartitionRoot::RetagSlotIfNeeded(void* slot_start_ptr,
size_t slot_size) {
if (!IsMemoryTaggingEnabled()) [[likely]] {
return;
}
if (slot_size <= internal::kMaxMemoryTaggingSize) [[likely]] {
if (UseRandomMemoryTagging()) {
uint8_t previous_tag = internal::ExtractTagFromPtr(slot_start_ptr);
internal::TagMemoryRangeRandomly(slot_start_ptr, slot_size,
1 << previous_tag);
} else {
internal::TagMemoryRangeIncrement(slot_start_ptr, slot_size);
}
}
}
#endif
PA_ALWAYS_INLINE void PartitionRoot::RawFreeWithThreadCache(
uintptr_t slot_start,
void* slot_start_ptr,
SlotSpanMetadata* slot_span) { … }
PA_ALWAYS_INLINE void PartitionRoot::RawFreeLocked(uintptr_t slot_start) { … }
PA_ALWAYS_INLINE PartitionRoot* PartitionRoot::FromSlotSpanMetadata(
SlotSpanMetadata* slot_span) { … }
PA_ALWAYS_INLINE PartitionRoot* PartitionRoot::FromFirstSuperPage(
uintptr_t super_page) { … }
PA_ALWAYS_INLINE PartitionRoot* PartitionRoot::FromAddrInFirstSuperpage(
uintptr_t address) { … }
PA_ALWAYS_INLINE void PartitionRoot::IncreaseTotalSizeOfAllocatedBytes(
uintptr_t addr,
size_t len,
size_t raw_size) { … }
PA_ALWAYS_INLINE void PartitionRoot::DecreaseTotalSizeOfAllocatedBytes(
uintptr_t addr,
size_t len) { … }
PA_ALWAYS_INLINE void PartitionRoot::IncreaseCommittedPages(size_t len) { … }
PA_ALWAYS_INLINE void PartitionRoot::DecreaseCommittedPages(size_t len) { … }
PA_ALWAYS_INLINE void PartitionRoot::DecommitSystemPagesForData(
uintptr_t address,
size_t length,
PageAccessibilityDisposition accessibility_disposition) { … }
PA_ALWAYS_INLINE void PartitionRoot::RecommitSystemPagesForData(
uintptr_t address,
size_t length,
PageAccessibilityDisposition accessibility_disposition,
bool request_tagging) { … }
template <bool already_locked>
PA_ALWAYS_INLINE bool PartitionRoot::TryRecommitSystemPagesForDataInternal(
uintptr_t address,
size_t length,
PageAccessibilityDisposition accessibility_disposition,
bool request_tagging) { … }
PA_ALWAYS_INLINE bool
PartitionRoot::TryRecommitSystemPagesForDataWithAcquiringLock(
uintptr_t address,
size_t length,
PageAccessibilityDisposition accessibility_disposition,
bool request_tagging) { … }
PA_ALWAYS_INLINE
bool PartitionRoot::TryRecommitSystemPagesForDataLocked(
uintptr_t address,
size_t length,
PageAccessibilityDisposition accessibility_disposition,
bool request_tagging) { … }
PA_ALWAYS_INLINE size_t PartitionRoot::GetUsableSize(void* ptr) { … }
PA_ALWAYS_INLINE size_t
PartitionRoot::GetUsableSizeWithMac11MallocSizeHack(void* ptr) { … }
PA_ALWAYS_INLINE PageAccessibilityConfiguration
PartitionRoot::GetPageAccessibility(bool request_tagging) const { … }
PA_ALWAYS_INLINE PageAccessibilityConfiguration
PartitionRoot::PageAccessibilityWithThreadIsolationIfEnabled(
PageAccessibilityConfiguration::Permissions permissions) const { … }
PA_ALWAYS_INLINE size_t
PartitionRoot::AllocationCapacityFromSlotStart(uintptr_t slot_start) const { … }
#if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
PA_ALWAYS_INLINE internal::InSlotMetadata*
PartitionRoot::InSlotMetadataPointerFromSlotStartAndSize(uintptr_t slot_start,
size_t slot_size) { … }
PA_ALWAYS_INLINE internal::InSlotMetadata*
PartitionRoot::InSlotMetadataPointerFromObjectForTesting(void* object) const { … }
#endif
PA_ALWAYS_INLINE uint16_t
PartitionRoot::SizeToBucketIndex(size_t size,
BucketDistribution bucket_distribution) { … }
template <AllocFlags flags>
PA_ALWAYS_INLINE void* PartitionRoot::AllocInternal(size_t requested_size,
size_t slot_span_alignment,
const char* type_name) { … }
template <AllocFlags flags>
PA_ALWAYS_INLINE void* PartitionRoot::AllocInternalNoHooks(
size_t requested_size,
size_t slot_span_alignment) { … }
template <AllocFlags flags>
PA_ALWAYS_INLINE uintptr_t PartitionRoot::RawAlloc(Bucket* bucket,
size_t raw_size,
size_t slot_span_alignment,
size_t* usable_size,
size_t* slot_size,
bool* is_already_zeroed) { … }
template <AllocFlags flags>
PA_ALWAYS_INLINE void* PartitionRoot::AlignedAllocInline(
size_t alignment,
size_t requested_size) { … }
template <AllocFlags alloc_flags, FreeFlags free_flags>
void* PartitionRoot::ReallocInline(void* ptr,
size_t new_size,
const char* type_name) { … }
PA_ALWAYS_INLINE size_t
PartitionRoot::AllocationCapacityFromRequestedSize(size_t size) const { … }
ThreadCache* PartitionRoot::GetOrCreateThreadCache() { … }
ThreadCache* PartitionRoot::GetThreadCache() { … }
internal::LightweightQuarantineBranch&
PartitionRoot::GetSchedulerLoopQuarantineBranch() { … }
internal::LightweightQuarantineRoot&
PartitionRoot::GetSchedulerLoopQuarantineRoot() { … }
#define EXPORT_TEMPLATE …
EXPORT_TEMPLATE void* PartitionRoot::Alloc<AllocFlags::kNone>(size_t,
const char*);
EXPORT_TEMPLATE void* PartitionRoot::Alloc<AllocFlags::kReturnNull>(
size_t,
const char*);
EXPORT_TEMPLATE void*
PartitionRoot::Realloc<AllocFlags::kNone, FreeFlags::kNone>(void*,
size_t,
const char*);
EXPORT_TEMPLATE void*
PartitionRoot::Realloc<AllocFlags::kReturnNull, FreeFlags::kNone>(void*,
size_t,
const char*);
EXPORT_TEMPLATE void* PartitionRoot::AlignedAlloc<AllocFlags::kNone>(size_t,
size_t);
#undef EXPORT_TEMPLATE
#if PA_BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
PartitionAllocGetSlotStartAndSizeInBRPPool;
#endif
#if PA_BUILDFLAG(IS_APPLE) && PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
PA_COMPONENT_EXPORT(PARTITION_ALLOC)
void PartitionAllocMallocHookOnBeforeForkInParent();
PA_COMPONENT_EXPORT(PARTITION_ALLOC)
void PartitionAllocMallocHookOnAfterForkInParent();
PA_COMPONENT_EXPORT(PARTITION_ALLOC)
void PartitionAllocMallocHookOnAfterForkInChild();
#endif
}
#endif