#include "base/allocator/partition_allocator/partition_bucket.h"
#include <algorithm>
#include <cstdint>
#include <tuple>
#include "base/allocator/partition_allocator/address_pool_manager.h"
#include "base/allocator/partition_allocator/freeslot_bitmap.h"
#include "base/allocator/partition_allocator/freeslot_bitmap_constants.h"
#include "base/allocator/partition_allocator/oom.h"
#include "base/allocator/partition_allocator/page_allocator.h"
#include "base/allocator/partition_allocator/page_allocator_constants.h"
#include "base/allocator/partition_allocator/partition_address_space.h"
#include "base/allocator/partition_allocator/partition_alloc.h"
#include "base/allocator/partition_allocator/partition_alloc_base/bits.h"
#include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
#include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
#include "base/allocator/partition_allocator/partition_alloc_base/debug/alias.h"
#include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
#include "base/allocator/partition_allocator/partition_alloc_base/immediate_crash.h"
#include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
#include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
#include "base/allocator/partition_allocator/partition_alloc_check.h"
#include "base/allocator/partition_allocator/partition_alloc_config.h"
#include "base/allocator/partition_allocator/partition_alloc_constants.h"
#include "base/allocator/partition_allocator/partition_alloc_forward.h"
#include "base/allocator/partition_allocator/partition_direct_map_extent.h"
#include "base/allocator/partition_allocator/partition_oom.h"
#include "base/allocator/partition_allocator/partition_page.h"
#include "base/allocator/partition_allocator/reservation_offset_table.h"
#include "base/allocator/partition_allocator/tagging.h"
#include "build/build_config.h"
#if BUILDFLAG(USE_STARSCAN)
#include "base/allocator/partition_allocator/starscan/pcscan.h"
#endif
uintptr_t g_bucket_cookie = 0;
namespace partition_alloc::internal {
namespace {
#if PA_CONFIG(ENABLE_SHADOW_METADATA)
PA_ALWAYS_INLINE uintptr_t ShadowMetadataStart(uintptr_t super_page,
pool_handle pool) {
uintptr_t shadow_metadata_start =
super_page + SystemPageSize() + ShadowPoolOffset(pool);
PA_DCHECK(!PartitionAddressSpace::IsInRegularPool(shadow_metadata_start));
PA_DCHECK(!PartitionAddressSpace::IsInBRPPool(shadow_metadata_start));
return shadow_metadata_start;
}
#endif
template <bool thread_safe>
[[noreturn]] PA_NOINLINE void PartitionOutOfMemoryMappingFailure(
PartitionRoot<thread_safe>* root,
size_t size) PA_LOCKS_EXCLUDED(root->lock_) {
PA_NO_CODE_FOLDING();
root->OutOfMemory(size);
PA_IMMEDIATE_CRASH();
}
template <bool thread_safe>
[[noreturn]] PA_NOINLINE void PartitionOutOfMemoryCommitFailure(
PartitionRoot<thread_safe>* root,
size_t size) PA_LOCKS_EXCLUDED(root->lock_) {
PA_NO_CODE_FOLDING();
root->OutOfMemory(size);
PA_IMMEDIATE_CRASH();
}
#if !BUILDFLAG(HAS_64_BIT_POINTERS) && BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
bool AreAllowedSuperPagesForBRPPool(uintptr_t start, uintptr_t end) {
PA_DCHECK(!(start % kSuperPageSize));
for (uintptr_t super_page = start; super_page < end;
super_page += kSuperPageSize) {
if (!AddressPoolManagerBitmap::IsAllowedSuperPageForBRPPool(super_page)) {
AddressPoolManagerBitmap::IncrementBlocklistHitCount();
return false;
}
}
return true;
}
#endif
uintptr_t ReserveMemoryFromPool(pool_handle pool,
uintptr_t requested_address,
size_t requested_size) {
PA_DCHECK(!(requested_address % kSuperPageSize));
uintptr_t reserved_address = AddressPoolManager::GetInstance().Reserve(
pool, requested_address, requested_size);
#if !BUILDFLAG(HAS_64_BIT_POINTERS) && BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
if (pool == kBRPPoolHandle) {
constexpr int kMaxRandomAddressTries = 10;
for (int i = 0; i < kMaxRandomAddressTries; ++i) {
if (!reserved_address ||
AreAllowedSuperPagesForBRPPool(reserved_address,
reserved_address + requested_size)) {
break;
}
AddressPoolManager::GetInstance().UnreserveAndDecommit(
pool, reserved_address, requested_size);
reserved_address =
AddressPoolManager::GetInstance().Reserve(pool, 0, requested_size);
}
for (uintptr_t address_to_try = kSuperPageSize; address_to_try != 0;
address_to_try += kSuperPageSize) {
if (!reserved_address ||
AreAllowedSuperPagesForBRPPool(reserved_address,
reserved_address + requested_size)) {
break;
}
AddressPoolManager::GetInstance().UnreserveAndDecommit(
pool, reserved_address, requested_size);
reserved_address = AddressPoolManager::GetInstance().Reserve(
pool, address_to_try, requested_size);
}
if (reserved_address &&
!AreAllowedSuperPagesForBRPPool(reserved_address,
reserved_address + requested_size)) {
AddressPoolManager::GetInstance().UnreserveAndDecommit(
pool, reserved_address, requested_size);
reserved_address = 0;
}
}
#endif
#if !BUILDFLAG(HAS_64_BIT_POINTERS)
if (reserved_address) {
AddressPoolManager::GetInstance().MarkUsed(pool, reserved_address,
requested_size);
}
#endif
PA_DCHECK(!(reserved_address % kSuperPageSize));
return reserved_address;
}
template <bool thread_safe>
SlotSpanMetadata<thread_safe>* PartitionDirectMap(
PartitionRoot<thread_safe>* root,
unsigned int flags,
size_t raw_size,
size_t slot_span_alignment) {
PA_DCHECK((slot_span_alignment >= PartitionPageSize()) &&
base::bits::IsPowerOfTwo(slot_span_alignment));
root->lock_.AssertAcquired();
const bool return_null = flags & AllocFlags::kReturnNull;
if (PA_UNLIKELY(raw_size > MaxDirectMapped())) {
if (return_null) {
return nullptr;
}
ScopedUnlockGuard unlock{root->lock_};
PartitionExcessiveAllocationSize(raw_size);
}
PartitionDirectMapExtent<thread_safe>* map_extent = nullptr;
PartitionPage<thread_safe>* page = nullptr;
{
ScopedUnlockGuard scoped_unlock{root->lock_};
const size_t slot_size =
PartitionRoot<thread_safe>::GetDirectMapSlotSize(raw_size);
const size_t padding_for_alignment =
slot_span_alignment - PartitionPageSize();
const size_t reservation_size =
PartitionRoot<thread_safe>::GetDirectMapReservationSize(
raw_size + padding_for_alignment);
#if BUILDFLAG(PA_DCHECK_IS_ON)
const size_t available_reservation_size =
reservation_size - padding_for_alignment -
PartitionRoot<thread_safe>::GetDirectMapMetadataAndGuardPagesSize();
PA_DCHECK(slot_size <= available_reservation_size);
#endif
pool_handle pool = root->ChoosePool();
uintptr_t reservation_start;
{
#if !BUILDFLAG(HAS_64_BIT_POINTERS)
ScopedSyscallTimer timer{root};
#endif
reservation_start = ReserveMemoryFromPool(pool, 0, reservation_size);
}
if (PA_UNLIKELY(!reservation_start)) {
if (return_null) {
return nullptr;
}
PartitionOutOfMemoryMappingFailure(root, reservation_size);
}
root->total_size_of_direct_mapped_pages.fetch_add(
reservation_size, std::memory_order_relaxed);
const uintptr_t slot_start =
reservation_start + PartitionPageSize() + padding_for_alignment;
{
ScopedSyscallTimer timer{root};
RecommitSystemPages(reservation_start + SystemPageSize(),
SystemPageSize(),
#if PA_CONFIG(ENABLE_SHADOW_METADATA)
root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kRead),
#else
root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
#endif
PageAccessibilityDisposition::kRequireUpdate);
}
#if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
if (pool == kBRPPoolHandle) {
ScopedSyscallTimer timer{root};
RecommitSystemPages(reservation_start + SystemPageSize() * 2,
SystemPageSize(),
root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate);
}
#endif
#if PA_CONFIG(ENABLE_SHADOW_METADATA)
{
ScopedSyscallTimer timer{root};
RecommitSystemPages(ShadowMetadataStart(reservation_start, pool),
SystemPageSize(),
root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate);
}
#endif
uintptr_t address_start = reservation_start;
uintptr_t address_end = address_start + reservation_size;
auto* offset_ptr = ReservationOffsetPointer(address_start);
uint16_t offset = 0;
while (address_start < address_end) {
PA_DCHECK(offset_ptr < GetReservationOffsetTableEnd(address_start));
PA_DCHECK(offset < kOffsetTagNormalBuckets);
*offset_ptr++ = offset++;
address_start += kSuperPageSize;
}
auto* super_page_extent =
PartitionSuperPageToExtent<thread_safe>(reservation_start);
#if defined(OHOS_ENABLE_POINTER_HARDENED)
super_page_extent->root = (PartitionRoot<thread_safe>*)EncodeRoot((void*)root);
#else
super_page_extent->root = root;
#endif
PA_DCHECK(!super_page_extent->number_of_consecutive_super_pages);
PA_DCHECK(!super_page_extent->next);
PartitionPage<thread_safe>* first_page =
reinterpret_cast<PartitionPage<thread_safe>*>(super_page_extent) + 1;
page = PartitionPage<thread_safe>::FromAddr(slot_start);
if (page != first_page) {
PA_DCHECK(page > first_page);
PA_DCHECK(page - first_page <=
PartitionPage<thread_safe>::kMaxSlotSpanMetadataOffset);
PA_CHECK(!first_page->is_valid);
first_page->has_valid_span_after_this = true;
first_page->slot_span_metadata_offset = page - first_page;
}
auto* metadata =
reinterpret_cast<PartitionDirectMapMetadata<thread_safe>*>(page);
PA_DCHECK(base::bits::AlignDown(reinterpret_cast<uintptr_t>(metadata),
SystemPageSize()) ==
base::bits::AlignDown(
reinterpret_cast<uintptr_t>(metadata) +
sizeof(PartitionDirectMapMetadata<thread_safe>) - 1,
SystemPageSize()));
PA_DCHECK(page == &metadata->page);
page->is_valid = true;
PA_DCHECK(!page->has_valid_span_after_this);
PA_DCHECK(!page->slot_span_metadata_offset);
PA_DCHECK(!page->slot_span_metadata.next_slot_span);
PA_DCHECK(!page->slot_span_metadata.marked_full);
PA_DCHECK(!page->slot_span_metadata.num_allocated_slots);
PA_DCHECK(!page->slot_span_metadata.num_unprovisioned_slots);
PA_DCHECK(!page->slot_span_metadata.in_empty_cache());
PA_DCHECK(!metadata->subsequent_page.subsequent_page_metadata.raw_size);
metadata->subsequent_page.slot_span_metadata_offset = 1;
PA_DCHECK(!metadata->bucket.active_slot_spans_head);
PA_DCHECK(!metadata->bucket.empty_slot_spans_head);
PA_DCHECK(!metadata->bucket.decommitted_slot_spans_head);
PA_DCHECK(!metadata->bucket.num_system_pages_per_slot_span);
PA_DCHECK(!metadata->bucket.num_full_slot_spans);
metadata->bucket.slot_size = slot_size;
new (&page->slot_span_metadata)
SlotSpanMetadata<thread_safe>(&metadata->bucket);
const bool ok = root->TryRecommitSystemPagesForData(
slot_start, slot_size, PageAccessibilityDisposition::kRequireUpdate);
if (!ok) {
if (!return_null) {
PartitionOutOfMemoryCommitFailure(root, slot_size);
}
{
ScopedSyscallTimer timer{root};
#if !BUILDFLAG(HAS_64_BIT_POINTERS)
AddressPoolManager::GetInstance().MarkUnused(pool, reservation_start,
reservation_size);
#endif
AddressPoolManager::GetInstance().UnreserveAndDecommit(
pool, reservation_start, reservation_size);
}
root->total_size_of_direct_mapped_pages.fetch_sub(
reservation_size, std::memory_order_relaxed);
return nullptr;
}
auto* next_entry = PartitionFreelistEntry::EmplaceAndInitNull(slot_start);
page->slot_span_metadata.SetFreelistHead(next_entry);
map_extent = &metadata->direct_map_extent;
map_extent->reservation_size = reservation_size;
map_extent->padding_for_alignment = padding_for_alignment;
map_extent->bucket = &metadata->bucket;
}
root->lock_.AssertAcquired();
map_extent->next_extent = root->direct_map_list;
if (map_extent->next_extent) {
map_extent->next_extent->prev_extent = map_extent;
}
map_extent->prev_extent = nullptr;
root->direct_map_list = map_extent;
return &page->slot_span_metadata;
}
uint8_t ComputeSystemPagesPerSlotSpanPreferSmall(size_t slot_size) {
if (slot_size > MaxRegularSlotSpanSize()) {
return base::bits::AlignUp(slot_size, SystemPageSize()) / SystemPageSize();
}
for (size_t partition_page_count = 1;
partition_page_count <= kMaxPartitionPagesPerRegularSlotSpan;
partition_page_count++) {
size_t candidate_size = partition_page_count * PartitionPageSize();
size_t waste = candidate_size % slot_size;
if (waste <= .02 * SystemPageSize()) {
return partition_page_count * NumSystemPagesPerPartitionPage();
}
}
size_t best_count = 0;
size_t best_waste = std::numeric_limits<size_t>::max();
for (size_t partition_page_count = 1;
partition_page_count <= kMaxPartitionPagesPerRegularSlotSpan;
partition_page_count++) {
for (size_t slack = 0; slack < partition_page_count; slack++) {
size_t system_page_count =
partition_page_count * NumSystemPagesPerPartitionPage() - slack;
size_t candidate_size = system_page_count * SystemPageSize();
size_t waste = candidate_size % slot_size;
if (waste < best_waste) {
best_waste = waste;
best_count = system_page_count;
}
}
}
return best_count;
}
uint8_t ComputeSystemPagesPerSlotSpanInternal(size_t slot_size) {
double best_waste_ratio = 1.0f;
uint16_t best_pages = 0;
if (slot_size > MaxRegularSlotSpanSize()) {
PA_DCHECK(!(slot_size % SystemPageSize()));
best_pages = static_cast<uint16_t>(slot_size >> SystemPageShift());
PA_CHECK(best_pages <= std::numeric_limits<uint8_t>::max());
return static_cast<uint8_t>(best_pages);
}
PA_DCHECK(slot_size <= MaxRegularSlotSpanSize());
for (uint16_t i = NumSystemPagesPerPartitionPage() - 1;
i <= MaxSystemPagesPerRegularSlotSpan(); ++i) {
size_t page_size = i << SystemPageShift();
size_t num_slots = page_size / slot_size;
size_t waste = page_size - (num_slots * slot_size);
size_t num_remainder_pages = i & (NumSystemPagesPerPartitionPage() - 1);
size_t num_unfaulted_pages =
num_remainder_pages
? (NumSystemPagesPerPartitionPage() - num_remainder_pages)
: 0;
waste += sizeof(void*) * num_unfaulted_pages;
double waste_ratio =
static_cast<double>(waste) / static_cast<double>(page_size);
if (waste_ratio < best_waste_ratio) {
best_waste_ratio = waste_ratio;
best_pages = i;
}
}
PA_DCHECK(best_pages > 0);
PA_CHECK(best_pages <= MaxSystemPagesPerRegularSlotSpan());
return static_cast<uint8_t>(best_pages);
}
}
uint8_t ComputeSystemPagesPerSlotSpan(size_t slot_size,
bool prefer_smaller_slot_spans) {
if (prefer_smaller_slot_spans) {
size_t system_page_count =
ComputeSystemPagesPerSlotSpanPreferSmall(slot_size);
size_t waste = (system_page_count * SystemPageSize()) % slot_size;
if (waste <= .05 * SystemPageSize()) {
return system_page_count;
}
}
return ComputeSystemPagesPerSlotSpanInternal(slot_size);
}
template <bool thread_safe>
void PartitionBucket<thread_safe>::Init(uint32_t new_slot_size) {
slot_size = new_slot_size;
slot_size_reciprocal = kReciprocalMask / new_slot_size + 1;
active_slot_spans_head =
#if defined(OHOS_ENABLE_POINTER_HARDENED)
(SlotSpanMetadata<thread_safe>* )EncodeBucket((void*)SlotSpanMetadata<thread_safe>::get_sentinel_slot_span_non_const());
#else
SlotSpanMetadata<thread_safe>::get_sentinel_slot_span_non_const();
#endif
empty_slot_spans_head = nullptr;
decommitted_slot_spans_head = nullptr;
num_full_slot_spans = 0;
bool prefer_smaller_slot_spans =
#if PA_CONFIG(PREFER_SMALLER_SLOT_SPANS)
true
#else
false
#endif
;
num_system_pages_per_slot_span =
ComputeSystemPagesPerSlotSpan(slot_size, prefer_smaller_slot_spans);
}
template <bool thread_safe>
PA_ALWAYS_INLINE SlotSpanMetadata<thread_safe>*
PartitionBucket<thread_safe>::AllocNewSlotSpan(PartitionRoot<thread_safe>* root,
unsigned int flags,
size_t slot_span_alignment) {
PA_DCHECK(!(root->next_partition_page % PartitionPageSize()));
PA_DCHECK(!(root->next_partition_page_end % PartitionPageSize()));
size_t num_partition_pages = get_pages_per_slot_span();
size_t slot_span_reservation_size = num_partition_pages
<< PartitionPageShift();
size_t slot_span_committed_size = get_bytes_per_span();
PA_DCHECK(num_partition_pages <= NumPartitionPagesPerSuperPage());
PA_DCHECK(slot_span_committed_size % SystemPageSize() == 0);
PA_DCHECK(slot_span_committed_size <= slot_span_reservation_size);
uintptr_t adjusted_next_partition_page =
base::bits::AlignUp(root->next_partition_page, slot_span_alignment);
if (PA_UNLIKELY(adjusted_next_partition_page + slot_span_reservation_size >
root->next_partition_page_end)) {
PA_DEBUG_DATA_ON_STACK("slotsize", slot_size);
PA_DEBUG_DATA_ON_STACK("spansize", slot_span_reservation_size);
if (!AllocNewSuperPage(root, flags)) {
return nullptr;
}
adjusted_next_partition_page =
base::bits::AlignUp(root->next_partition_page, slot_span_alignment);
PA_CHECK(adjusted_next_partition_page + slot_span_reservation_size <=
root->next_partition_page_end);
}
auto* gap_start_page =
PartitionPage<thread_safe>::FromAddr(root->next_partition_page);
auto* gap_end_page =
PartitionPage<thread_safe>::FromAddr(adjusted_next_partition_page);
for (auto* page = gap_start_page; page < gap_end_page; ++page) {
PA_DCHECK(!page->is_valid);
page->has_valid_span_after_this = 1;
}
root->next_partition_page =
adjusted_next_partition_page + slot_span_reservation_size;
uintptr_t slot_span_start = adjusted_next_partition_page;
auto* slot_span = &gap_end_page->slot_span_metadata;
InitializeSlotSpan(slot_span);
PA_DCHECK(slot_span ==
SlotSpanMetadata<thread_safe>::FromSlotStart(slot_span_start));
if (!kUseLazyCommit) {
PA_DEBUG_DATA_ON_STACK("slotsize", slot_size);
PA_DEBUG_DATA_ON_STACK("spansize", slot_span_reservation_size);
PA_DEBUG_DATA_ON_STACK("spancmt", slot_span_committed_size);
root->RecommitSystemPagesForData(
slot_span_start, slot_span_committed_size,
PageAccessibilityDisposition::kRequireUpdate);
}
PA_CHECK(get_slots_per_span() <=
SlotSpanMetadata<ThreadSafe>::kMaxSlotsPerSlotSpan);
PA_DCHECK(root->next_partition_page <= root->next_partition_page_end);
return slot_span;
}
template <bool thread_safe>
uintptr_t PartitionBucket<thread_safe>::AllocNewSuperPageSpan(
PartitionRoot<thread_safe>* root,
size_t super_page_count,
unsigned int flags) {
PA_CHECK(super_page_count > 0);
PA_CHECK(super_page_count <=
std::numeric_limits<size_t>::max() / kSuperPageSize);
uintptr_t requested_address = root->next_super_page;
pool_handle pool = root->ChoosePool();
uintptr_t super_page_span_start = ReserveMemoryFromPool(
pool, requested_address, super_page_count * kSuperPageSize);
if (PA_UNLIKELY(!super_page_span_start)) {
if (flags & AllocFlags::kReturnNull) {
return 0;
}
::partition_alloc::internal::ScopedUnlockGuard unlock{root->lock_};
PartitionOutOfMemoryMappingFailure(root, kSuperPageSize);
}
uintptr_t super_page_span_end =
super_page_span_start + super_page_count * kSuperPageSize;
for (uintptr_t super_page = super_page_span_start;
super_page < super_page_span_end; super_page += kSuperPageSize) {
InitializeSuperPage(root, super_page, 0);
}
return super_page_span_start;
}
template <bool thread_safe>
PA_ALWAYS_INLINE uintptr_t PartitionBucket<thread_safe>::AllocNewSuperPage(
PartitionRoot<thread_safe>* root,
unsigned int flags) {
auto super_page = AllocNewSuperPageSpan(root, 1, flags);
if (PA_UNLIKELY(!super_page)) {
PA_DCHECK(flags & AllocFlags::kReturnNull);
return 0;
}
return SuperPagePayloadBegin(super_page, root->IsQuarantineAllowed());
}
template <bool thread_safe>
PA_ALWAYS_INLINE uintptr_t PartitionBucket<thread_safe>::InitializeSuperPage(
PartitionRoot<thread_safe>* root,
uintptr_t super_page,
uintptr_t requested_address) {
*ReservationOffsetPointer(super_page) = kOffsetTagNormalBuckets;
root->total_size_of_super_pages.fetch_add(kSuperPageSize,
std::memory_order_relaxed);
root->next_super_page = super_page + kSuperPageSize;
uintptr_t state_bitmap =
super_page + PartitionPageSize() +
(is_direct_mapped() ? 0 : ReservedFreeSlotBitmapSize());
#if BUILDFLAG(USE_STARSCAN)
PA_DCHECK(SuperPageStateBitmapAddr(super_page) == state_bitmap);
const size_t state_bitmap_reservation_size =
root->IsQuarantineAllowed() ? ReservedStateBitmapSize() : 0;
const size_t state_bitmap_size_to_commit =
root->IsQuarantineAllowed() ? CommittedStateBitmapSize() : 0;
PA_DCHECK(state_bitmap_reservation_size % PartitionPageSize() == 0);
PA_DCHECK(state_bitmap_size_to_commit % SystemPageSize() == 0);
PA_DCHECK(state_bitmap_size_to_commit <= state_bitmap_reservation_size);
uintptr_t payload = state_bitmap + state_bitmap_reservation_size;
#else
uintptr_t payload = state_bitmap;
#endif
root->next_partition_page = payload;
root->next_partition_page_end = root->next_super_page - PartitionPageSize();
PA_DCHECK(payload ==
SuperPagePayloadBegin(super_page, root->IsQuarantineAllowed()));
PA_DCHECK(root->next_partition_page_end == SuperPagePayloadEnd(super_page));
{
ScopedSyscallTimer timer{root};
RecommitSystemPages(super_page + SystemPageSize(), SystemPageSize(),
#if PA_CONFIG(ENABLE_SHADOW_METADATA)
root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kRead),
#else
root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
#endif
PageAccessibilityDisposition::kRequireUpdate);
}
#if BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)
if (root->ChoosePool() == kBRPPoolHandle) {
ScopedSyscallTimer timer{root};
RecommitSystemPages(super_page + SystemPageSize() * 2, SystemPageSize(),
root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate);
}
#endif
#if PA_CONFIG(ENABLE_SHADOW_METADATA)
{
ScopedSyscallTimer timer{root};
RecommitSystemPages(ShadowMetadataStart(super_page, root->ChoosePool()),
SystemPageSize(),
root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate);
}
#endif
if (requested_address && requested_address != super_page) {
root->next_super_page = 0;
}
auto* latest_extent = PartitionSuperPageToExtent<thread_safe>(super_page);
#if defined(OHOS_ENABLE_POINTER_HARDENED)
latest_extent->root = (PartitionRoot<thread_safe>*)EncodeRoot((void*)root);
#else
latest_extent->root = root;
#endif
latest_extent->number_of_consecutive_super_pages = 0;
latest_extent->next = nullptr;
latest_extent->number_of_nonempty_slot_spans = 0;
PartitionSuperPageExtentEntry<thread_safe>* current_extent =
root->current_extent;
const bool is_new_extent = super_page != requested_address;
if (PA_UNLIKELY(is_new_extent)) {
if (PA_UNLIKELY(!current_extent)) {
PA_DCHECK(!root->first_extent);
root->first_extent = latest_extent;
} else {
PA_DCHECK(current_extent->number_of_consecutive_super_pages);
current_extent->next = latest_extent;
}
root->current_extent = latest_extent;
latest_extent->number_of_consecutive_super_pages = 1;
} else {
PA_DCHECK(current_extent->number_of_consecutive_super_pages);
++current_extent->number_of_consecutive_super_pages;
PA_DCHECK(payload > SuperPagesBeginFromExtent(current_extent) &&
payload < SuperPagesEndFromExtent(current_extent));
}
#if BUILDFLAG(USE_STARSCAN)
if (root->IsQuarantineEnabled()) {
{
ScopedSyscallTimer timer{root};
RecommitSystemPages(state_bitmap, state_bitmap_size_to_commit,
root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate);
}
PCScan::RegisterNewSuperPage(root, super_page);
}
#endif
#if BUILDFLAG(USE_FREESLOT_BITMAP)
if (!is_direct_mapped()) {
uintptr_t freeslot_bitmap_addr = super_page + PartitionPageSize();
PA_DCHECK(SuperPageFreeSlotBitmapAddr(super_page) == freeslot_bitmap_addr);
ScopedSyscallTimer timer{root};
RecommitSystemPages(freeslot_bitmap_addr, CommittedFreeSlotBitmapSize(),
root->PageAccessibilityWithPkeyIfEnabled(
PageAccessibilityConfiguration::kReadWrite),
PageAccessibilityDisposition::kRequireUpdate);
}
#endif
return payload;
}
template <bool thread_safe>
PA_ALWAYS_INLINE void PartitionBucket<thread_safe>::InitializeSlotSpan(
SlotSpanMetadata<thread_safe>* slot_span) {
new (slot_span) SlotSpanMetadata<thread_safe>(this);
slot_span->Reset();
uint16_t num_partition_pages = get_pages_per_slot_span();
auto* page = reinterpret_cast<PartitionPage<thread_safe>*>(slot_span);
for (uint16_t i = 0; i < num_partition_pages; ++i, ++page) {
PA_DCHECK(i <= PartitionPage<thread_safe>::kMaxSlotSpanMetadataOffset);
page->slot_span_metadata_offset = i;
page->is_valid = true;
}
}
template <bool thread_safe>
PA_ALWAYS_INLINE uintptr_t
PartitionBucket<thread_safe>::ProvisionMoreSlotsAndAllocOne(
PartitionRoot<thread_safe>* root,
SlotSpanMetadata<thread_safe>* slot_span) {
PA_DCHECK(slot_span !=
SlotSpanMetadata<thread_safe>::get_sentinel_slot_span());
size_t num_slots = slot_span->num_unprovisioned_slots;
PA_DCHECK(num_slots);
PA_DCHECK(num_slots <= get_slots_per_span());
PA_DCHECK(num_slots + slot_span->num_allocated_slots == get_slots_per_span());
PA_DCHECK(!slot_span->get_freelist_head());
PA_DCHECK(!slot_span->is_full());
uintptr_t slot_span_start =
SlotSpanMetadata<thread_safe>::ToSlotSpanStart(slot_span);
uintptr_t return_slot =
slot_span_start + (slot_size * slot_span->num_allocated_slots);
uintptr_t next_slot = return_slot + slot_size;
uintptr_t commit_start = base::bits::AlignUp(return_slot, SystemPageSize());
PA_DCHECK(next_slot > commit_start);
uintptr_t commit_end = base::bits::AlignUp(next_slot, SystemPageSize());
PA_DCHECK(commit_end > commit_start);
slot_span->num_allocated_slots++;
size_t slots_to_provision = (commit_end - return_slot) / slot_size;
slot_span->num_unprovisioned_slots -= slots_to_provision;
PA_DCHECK(slot_span->num_allocated_slots +
slot_span->num_unprovisioned_slots <=
get_slots_per_span());
if (kUseLazyCommit) {
root->RecommitSystemPagesForData(
commit_start, commit_end - commit_start,
PageAccessibilityDisposition::kRequireUpdate);
}
if (PA_LIKELY(slot_size <= kMaxMemoryTaggingSize &&
root->IsMemoryTaggingEnabled())) {
TagMemoryRangeRandomly(return_slot, slot_size);
}
PartitionFreelistEntry* prev_entry = nullptr;
#if defined(OHOS_ENABLE_RANDOM)
uintptr_t random_slot;
int num = (commit_end - next_slot) / slot_size;
int i;
size_t random[num];
size_t tmp;
uint32_t rand;
uint32_t randseed = RandomValue();
size_t free_list_entries_added = 0;
for (i = 0; i < num; i++) {
random[i] = i;
}
for (i = num - 1; i > 0; i--) {
rand = randseed % i;
tmp = random[i];
random[i] = random[rand];
random[rand] = tmp;
}
for (i = 0; i < num; i++) {
void* next_slot_ptr;
random_slot = next_slot + slot_size * random[i];
if (PA_LIKELY(slot_size <= kMaxMemoryTaggingSize)) {
next_slot_ptr = TagMemoryRangeRandomly(random_slot, slot_size);
} else {
next_slot_ptr = reinterpret_cast<void*>(random_slot);
}
#else
uintptr_t next_slot_end = next_slot + slot_size;
size_t free_list_entries_added = 0;
while (next_slot_end <= commit_end) {
void* next_slot_ptr;
if (PA_LIKELY(slot_size <= kMaxMemoryTaggingSize)) {
next_slot_ptr = TagMemoryRangeRandomly(next_slot, slot_size);
} else {
next_slot_ptr = reinterpret_cast<void*>(next_slot);
}
#endif
auto* entry = PartitionFreelistEntry::EmplaceAndInitNull(next_slot_ptr);
if (!slot_span->get_freelist_head()) {
PA_DCHECK(!prev_entry);
PA_DCHECK(!free_list_entries_added);
slot_span->SetFreelistHead(entry);
} else {
PA_DCHECK(free_list_entries_added);
prev_entry->SetNext(entry);
}
#if BUILDFLAG(USE_FREESLOT_BITMAP)
FreeSlotBitmapMarkSlotAsFree(next_slot);
#endif
#if !defined(OHOS_ENABLE_RANDOM)
next_slot = next_slot_end;
next_slot_end = next_slot + slot_size;
#endif
prev_entry = entry;
#if BUILDFLAG(PA_DCHECK_IS_ON)
free_list_entries_added++;
#endif
}
#if BUILDFLAG(USE_FREESLOT_BITMAP)
FreeSlotBitmapMarkSlotAsFree(return_slot);
#endif
#if BUILDFLAG(PA_DCHECK_IS_ON)
PA_DCHECK(slots_to_provision == free_list_entries_added + 1);
if (slot_span->get_freelist_head()) {
PA_DCHECK(free_list_entries_added);
slot_span->get_freelist_head()->CheckFreeList(slot_size);
}
#endif
slot_span->set_freelist_sorted();
return return_slot;
}
template <bool thread_safe>
bool PartitionBucket<thread_safe>::SetNewActiveSlotSpan() {
#if defined(OHOS_ENABLE_POINTER_HARDENED)
SlotSpanMetadata<thread_safe>* slot_span = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)active_slot_spans_head);
#else
SlotSpanMetadata<thread_safe>* slot_span = active_slot_spans_head;
#endif
if (slot_span == SlotSpanMetadata<thread_safe>::get_sentinel_slot_span()) {
return false;
}
SlotSpanMetadata<thread_safe>* next_slot_span;
SlotSpanMetadata<thread_safe>* to_provision_head = nullptr;
SlotSpanMetadata<thread_safe>* to_provision_tail = nullptr;
for (; slot_span; slot_span = next_slot_span) {
next_slot_span = slot_span->next_slot_span;
PA_DCHECK(slot_span->bucket == this);
#if defined(OHOS_ENABLE_POINTER_HARDENED)
SlotSpanMetadata<thread_safe>* real_empty =
(SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)empty_slot_spans_head);
SlotSpanMetadata<thread_safe>* real_decommitted =
(SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)decommitted_slot_spans_head);
PA_DCHECK(slot_span != real_empty);
PA_DCHECK(slot_span != real_decommitted);
#else
PA_DCHECK(slot_span != empty_slot_spans_head);
PA_DCHECK(slot_span != decommitted_slot_spans_head);
#endif
if (slot_span->is_active()) {
if (slot_span->get_freelist_head()) {
break;
} else {
if (!to_provision_head) {
to_provision_head = slot_span;
}
if (to_provision_tail) {
to_provision_tail->next_slot_span = slot_span;
}
to_provision_tail = slot_span;
slot_span->next_slot_span = nullptr;
}
} else if (slot_span->is_empty()) {
#if defined(OHOS_ENABLE_POINTER_HARDENED)
slot_span->next_slot_span = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)empty_slot_spans_head);
empty_slot_spans_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)slot_span);
#else
slot_span->next_slot_span = empty_slot_spans_head;
empty_slot_spans_head = slot_span;
#endif
} else if (PA_LIKELY(slot_span->is_decommitted())) {
#if defined(OHOS_ENABLE_POINTER_HARDENED)
slot_span->next_slot_span = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)decommitted_slot_spans_head);
decommitted_slot_spans_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)slot_span);
#else
slot_span->next_slot_span = decommitted_slot_spans_head;
decommitted_slot_spans_head = slot_span;
#endif
} else {
PA_DCHECK(slot_span->is_full());
slot_span->marked_full = 1;
++num_full_slot_spans;
PA_CHECK(num_full_slot_spans);
slot_span->next_slot_span = nullptr;
}
}
bool usable_active_list_head = false;
if (slot_span) {
usable_active_list_head = true;
if (to_provision_head) {
auto* next = slot_span->next_slot_span;
slot_span->next_slot_span = to_provision_head;
to_provision_tail->next_slot_span = next;
}
#if defined(OHOS_ENABLE_POINTER_HARDENED)
active_slot_spans_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)slot_span);
#else
active_slot_spans_head = slot_span;
#endif
} else if (to_provision_head) {
usable_active_list_head = true;
#if defined(OHOS_ENABLE_POINTER_HARDENED)
active_slot_spans_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)to_provision_head);
#else
active_slot_spans_head = to_provision_head;
#endif
} else {
active_slot_spans_head =
#if defined(OHOS_ENABLE_POINTER_HARDENED)
(SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)SlotSpanMetadata<thread_safe>::get_sentinel_slot_span_non_const());
#else
SlotSpanMetadata<thread_safe>::get_sentinel_slot_span_non_const();
#endif
}
return usable_active_list_head;
}
template <bool thread_safe>
void PartitionBucket<thread_safe>::MaintainActiveList() {
#if defined(OHOS_ENABLE_POINTER_HARDENED)
SlotSpanMetadata<thread_safe>* slot_span = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)active_slot_spans_head);
#else
SlotSpanMetadata<thread_safe>* slot_span = active_slot_spans_head;
#endif
if (slot_span == SlotSpanMetadata<thread_safe>::get_sentinel_slot_span()) {
return;
}
SlotSpanMetadata<thread_safe>* new_active_slot_spans_head = nullptr;
SlotSpanMetadata<thread_safe>* new_active_slot_spans_tail = nullptr;
SlotSpanMetadata<thread_safe>* next_slot_span;
for (; slot_span; slot_span = next_slot_span) {
next_slot_span = slot_span->next_slot_span;
if (slot_span->is_active()) {
if (!new_active_slot_spans_head) {
new_active_slot_spans_head = slot_span;
}
if (new_active_slot_spans_tail) {
new_active_slot_spans_tail->next_slot_span = slot_span;
}
new_active_slot_spans_tail = slot_span;
slot_span->next_slot_span = nullptr;
} else if (slot_span->is_empty()) {
#if defined(OHOS_ENABLE_POINTER_HARDENED)
slot_span->next_slot_span = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)empty_slot_spans_head);
empty_slot_spans_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)slot_span);
#else
slot_span->next_slot_span = empty_slot_spans_head;
empty_slot_spans_head = slot_span;
#endif
} else if (slot_span->is_decommitted()) {
#if defined(OHOS_ENABLE_POINTER_HARDENED)
slot_span->next_slot_span = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)decommitted_slot_spans_head);
decommitted_slot_spans_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)slot_span);
#else
slot_span->next_slot_span = decommitted_slot_spans_head;
decommitted_slot_spans_head = slot_span;
#endif
} else {
PA_DCHECK(slot_span->is_full());
slot_span->marked_full = 1;
++num_full_slot_spans;
PA_CHECK(num_full_slot_spans);
slot_span->next_slot_span = nullptr;
}
}
if (!new_active_slot_spans_head) {
new_active_slot_spans_head =
SlotSpanMetadata<thread_safe>::get_sentinel_slot_span_non_const();
}
#if defined(OHOS_ENABLE_POINTER_HARDENED)
active_slot_spans_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)new_active_slot_spans_head);
#else
active_slot_spans_head = new_active_slot_spans_head;
#endif
}
template <bool thread_safe>
void PartitionBucket<thread_safe>::SortSlotSpanFreelists() {
#if defined(OHOS_ENABLE_POINTER_HARDENED)
SlotSpanMetadata<thread_safe>* real_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)active_slot_spans_head);
for (auto* slot_span = real_head; slot_span;
#else
for (auto* slot_span = active_slot_spans_head; slot_span;
#endif
slot_span = slot_span->next_slot_span) {
if (slot_span->num_allocated_slots > 0 &&
!slot_span->freelist_is_sorted()) {
slot_span->SortFreelist();
}
}
}
PA_COMPONENT_EXPORT(PARTITION_ALLOC)
bool CompareSlotSpans(SlotSpanMetadata<ThreadSafe>* a,
SlotSpanMetadata<ThreadSafe>* b) {
auto criteria_tuple = [](SlotSpanMetadata<ThreadSafe> const* a) {
size_t freelist_length = a->GetFreelistLength();
return std::tuple<bool, size_t, size_t>{
freelist_length == 0, freelist_length, a->num_unprovisioned_slots};
};
return criteria_tuple(a) < criteria_tuple(b);
}
template <bool thread_safe>
void PartitionBucket<thread_safe>::SortActiveSlotSpans() {
SlotSpanMetadata<thread_safe>* active_spans_array[kMaxSlotSpansToSort];
size_t index = 0;
SlotSpanMetadata<thread_safe>* overflow_spans_start = nullptr;
#if defined(OHOS_ENABLE_POINTER_HARDENED)
SlotSpanMetadata<thread_safe>* real_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)active_slot_spans_head);
for (auto* slot_span = real_head; slot_span;
#else
for (auto* slot_span = active_slot_spans_head; slot_span;
#endif
slot_span = slot_span->next_slot_span) {
if (index < kMaxSlotSpansToSort) {
active_spans_array[index++] = slot_span;
} else {
overflow_spans_start = slot_span;
break;
}
}
std::sort(active_spans_array, active_spans_array + index, CompareSlotSpans);
#if defined(OHOS_ENABLE_POINTER_HARDENED)
active_slot_spans_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)overflow_spans_start);
#else
active_slot_spans_head = overflow_spans_start;
#endif
for (int i = index - 1; i >= 0; i--) {
if (active_spans_array[i] ==
SlotSpanMetadata<thread_safe>::get_sentinel_slot_span()) {
PA_DCHECK(active_slot_spans_head == nullptr);
} else {
#if defined(OHOS_ENABLE_POINTER_HARDENED)
active_spans_array[i]->next_slot_span = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)active_slot_spans_head);
}
active_slot_spans_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)active_spans_array[i]);
#else
active_spans_array[i]->next_slot_span = active_slot_spans_head;
}
active_slot_spans_head = active_spans_array[i];
#endif
}
}
template <bool thread_safe>
uintptr_t PartitionBucket<thread_safe>::SlowPathAlloc(
PartitionRoot<thread_safe>* root,
unsigned int flags,
size_t raw_size,
size_t slot_span_alignment,
bool* is_already_zeroed) {
PA_DCHECK((slot_span_alignment >= PartitionPageSize()) &&
base::bits::IsPowerOfTwo(slot_span_alignment));
bool allocate_aligned_slot_span = slot_span_alignment > PartitionPageSize();
#if defined(OHOS_ENABLE_POINTER_HARDENED)
SlotSpanMetadata<thread_safe>* real_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)active_slot_spans_head);
PA_DCHECK(!real_head->get_freelist_head() ||
#else
PA_DCHECK(!active_slot_spans_head->get_freelist_head() ||
#endif
allocate_aligned_slot_span);
SlotSpanMetadata<thread_safe>* new_slot_span = nullptr;
PartitionBucket* new_bucket = this;
*is_already_zeroed = false;
if (PA_UNLIKELY(is_direct_mapped())) {
PA_DCHECK(raw_size > kMaxBucketed);
PA_DCHECK(this == &root->sentinel_bucket);
#if defined(OHOS_ENABLE_POINTER_HARDENED)
PA_DCHECK(real_head ==
#else
PA_DCHECK(active_slot_spans_head ==
#endif
SlotSpanMetadata<thread_safe>::get_sentinel_slot_span());
if (flags & AllocFlags::kFastPathOrReturnNull) {
return 0;
}
new_slot_span =
PartitionDirectMap(root, flags, raw_size, slot_span_alignment);
if (new_slot_span) {
new_bucket = new_slot_span->bucket;
}
*is_already_zeroed = true;
} else if (PA_LIKELY(!allocate_aligned_slot_span && SetNewActiveSlotSpan())) {
#if defined(OHOS_ENABLE_POINTER_HARDENED)
new_slot_span = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)active_slot_spans_head);
#else
new_slot_span = active_slot_spans_head;
#endif
PA_DCHECK(new_slot_span->is_active());
} else if (PA_LIKELY(!allocate_aligned_slot_span &&
(empty_slot_spans_head != nullptr ||
decommitted_slot_spans_head != nullptr))) {
#if defined(OHOS_ENABLE_POINTER_HARDENED)
SlotSpanMetadata<thread_safe>* real_empty = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)empty_slot_spans_head);
while (PA_LIKELY((new_slot_span = real_empty) != nullptr)) {
#else
while (PA_LIKELY((new_slot_span = empty_slot_spans_head) != nullptr)) {
#endif
PA_DCHECK(new_slot_span->bucket == this);
PA_DCHECK(new_slot_span->is_empty() || new_slot_span->is_decommitted());
#if defined(OHOS_ENABLE_POINTER_HARDENED)
empty_slot_spans_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)(new_slot_span->next_slot_span));
real_empty = new_slot_span->next_slot_span;
#else
empty_slot_spans_head = new_slot_span->next_slot_span;
#endif
if (new_slot_span->get_freelist_head()) {
new_slot_span->next_slot_span = nullptr;
new_slot_span->ToSuperPageExtent()
->IncrementNumberOfNonemptySlotSpans();
size_t dirty_size = base::bits::AlignUp(
new_slot_span->GetProvisionedSize(), SystemPageSize());
PA_DCHECK(root->empty_slot_spans_dirty_bytes >= dirty_size);
root->empty_slot_spans_dirty_bytes -= dirty_size;
break;
}
PA_DCHECK(new_slot_span->is_decommitted());
#if defined(OHOS_ENABLE_POINTER_HARDENED)
new_slot_span->next_slot_span = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)decommitted_slot_spans_head);
decommitted_slot_spans_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)new_slot_span);
#else
new_slot_span->next_slot_span = decommitted_slot_spans_head;
decommitted_slot_spans_head = new_slot_span;
#endif
}
if (PA_UNLIKELY(!new_slot_span) &&
PA_LIKELY(decommitted_slot_spans_head != nullptr)) {
if (flags & AllocFlags::kFastPathOrReturnNull) {
return 0;
}
#if defined(OHOS_ENABLE_POINTER_HARDENED)
new_slot_span = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)decommitted_slot_spans_head);
#else
new_slot_span = decommitted_slot_spans_head;
#endif
PA_DCHECK(new_slot_span->bucket == this);
PA_DCHECK(new_slot_span->is_decommitted());
#if defined(OHOS_ENABLE_POINTER_HARDENED)
decommitted_slot_spans_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)(new_slot_span->next_slot_span));
#else
decommitted_slot_spans_head = new_slot_span->next_slot_span;
#endif
if (!kUseLazyCommit) {
uintptr_t slot_span_start =
SlotSpanMetadata<thread_safe>::ToSlotSpanStart(new_slot_span);
root->RecommitSystemPagesForData(
slot_span_start, new_slot_span->bucket->get_bytes_per_span(),
PageAccessibilityDisposition::kAllowKeepForPerf);
}
new_slot_span->Reset();
*is_already_zeroed = DecommittedMemoryIsAlwaysZeroed();
}
PA_DCHECK(new_slot_span);
} else {
if (flags & AllocFlags::kFastPathOrReturnNull) {
return 0;
}
new_slot_span = AllocNewSlotSpan(root, flags, slot_span_alignment);
*is_already_zeroed = true;
}
if (PA_UNLIKELY(!new_slot_span)) {
#if defined(OHOS_ENABLE_POINTER_HARDENED)
real_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)active_slot_spans_head);
PA_DCHECK(real_head ==
#else
PA_DCHECK(active_slot_spans_head ==
#endif
SlotSpanMetadata<thread_safe>::get_sentinel_slot_span());
if (flags & AllocFlags::kReturnNull) {
return 0;
}
ScopedUnlockGuard unlock{root->lock_};
root->OutOfMemory(raw_size);
PA_IMMEDIATE_CRASH();
}
PA_DCHECK(new_bucket != &root->sentinel_bucket);
#if defined(OHOS_ENABLE_POINTER_HARDENED)
new_bucket->active_slot_spans_head = (SlotSpanMetadata<thread_safe>*)EncodeBucket((void*)new_slot_span);
#else
new_bucket->active_slot_spans_head = new_slot_span;
#endif
if (new_slot_span->CanStoreRawSize()) {
new_slot_span->SetRawSize(raw_size);
}
if (PA_LIKELY(new_slot_span->get_freelist_head() != nullptr)) {
PartitionFreelistEntry* entry =
new_slot_span->PopForAlloc(new_bucket->slot_size);
uintptr_t slot_start = entry->ClearForAllocation();
return slot_start;
}
PA_DCHECK(new_slot_span->num_unprovisioned_slots);
return ProvisionMoreSlotsAndAllocOne(root, new_slot_span);
}
template <bool thread_safe>
uintptr_t PartitionBucket<thread_safe>::AllocNewSuperPageSpanForGwpAsan(
PartitionRoot<thread_safe>* root,
size_t super_page_count,
unsigned int flags) {
return AllocNewSuperPageSpan(root, super_page_count, flags);
}
template <bool thread_safe>
void PartitionBucket<thread_safe>::InitializeSlotSpanForGwpAsan(
SlotSpanMetadata<thread_safe>* slot_span) {
InitializeSlotSpan(slot_span);
}
template struct PartitionBucket<ThreadSafe>;
}