blob: d494fa4fafee9b869e774161bc7dbf1d332c8fa9 [file] [log] [blame]
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_TAG_BITMAP_H_
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_TAG_BITMAP_H_
#include "base/allocator/buildflags.h"
#include "base/allocator/partition_allocator/page_allocator_constants.h"
#include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
#include "base/allocator/partition_allocator/partition_alloc_constants.h"
namespace partition_alloc::internal {
#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
namespace tag_bitmap {
// kPartitionTagSize should be equal to sizeof(PartitionTag).
// PartitionTag is defined in partition_tag.h and static_assert there
// checks the condition.
static constexpr size_t kPartitionTagSizeShift = 0;
static constexpr size_t kPartitionTagSize = 1U << kPartitionTagSizeShift;
static constexpr size_t kBytesPerPartitionTagShift = 4;
// One partition tag is assigned per |kBytesPerPartitionTag| bytes in the slot
// spans.
// +-----------+ 0
// | | ====> 1 partition tag
// +-----------+ kBytesPerPartitionTag
// | | ====> 1 partition tag
// +-----------+ 2*kBytesPerPartitionTag
// ...
// +-----------+ slot_size
static constexpr size_t kBytesPerPartitionTag = 1U
<< kBytesPerPartitionTagShift;
static_assert(
kMinBucketedOrder >= kBytesPerPartitionTagShift + 1,
"MTECheckedPtr requires kBytesPerPartitionTagShift-bytes alignment.");
static constexpr size_t kBytesPerPartitionTagRatio =
kBytesPerPartitionTag / kPartitionTagSize;
static_assert(kBytesPerPartitionTag > 0,
"kBytesPerPartitionTag should be larger than 0");
static_assert(
kBytesPerPartitionTag % kPartitionTagSize == 0,
"kBytesPerPartitionTag should be multiples of sizeof(PartitionTag).");
constexpr size_t CeilCountOfUnits(size_t size, size_t unit_size) {
return (size + unit_size - 1) / unit_size;
}
} // namespace tag_bitmap
// kTagBitmapSize is calculated in the following way:
// (1) kSuperPageSize - 2 * PartitionPageSize() = kTagBitmapSize +
// SlotSpanSize()
// (2) kTagBitmapSize >= SlotSpanSize() / kBytesPerPartitionTag *
// sizeof(PartitionTag)
//--
// (1)' SlotSpanSize() = kSuperPageSize - 2 * PartitionPageSize() -
// kTagBitmapSize
// (2)' SlotSpanSize() <= kTagBitmapSize * Y
// (3)' Y = kBytesPerPartitionTag / sizeof(PartitionTag) =
// kBytesPerPartitionTagRatio
//
// kTagBitmapSize * Y >= kSuperPageSize - 2 * PartitionPageSize() -
// kTagBitmapSize (1 + Y) * kTagBimapSize >= kSuperPageSize - 2 *
// PartitionPageSize()
// Finally,
// kTagBitmapSize >= (kSuperPageSize - 2 * PartitionPageSize()) / (1 + Y)
PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
NumPartitionPagesPerTagBitmap() {
return tag_bitmap::CeilCountOfUnits(
kSuperPageSize / PartitionPageSize() - 2,
tag_bitmap::kBytesPerPartitionTagRatio + 1);
}
// To make guard pages between the tag bitmap and the slot span, calculate the
// number of SystemPages of TagBitmap. If kNumSystemPagesPerTagBitmap *
// SystemPageSize() < kTagBitmapSize, guard pages will be created. (c.f. no
// guard pages if sizeof(PartitionTag) == 2.)
PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
NumSystemPagesPerTagBitmap() {
return tag_bitmap::CeilCountOfUnits(
kSuperPageSize / SystemPageSize() -
2 * PartitionPageSize() / SystemPageSize(),
tag_bitmap::kBytesPerPartitionTagRatio + 1);
}
PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
ActualTagBitmapSize() {
return NumSystemPagesPerTagBitmap() * SystemPageSize();
}
// PartitionPageSize-aligned tag bitmap size.
PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
ReservedTagBitmapSize() {
return PartitionPageSize() * NumPartitionPagesPerTagBitmap();
}
#if PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR
static_assert(ActualTagBitmapSize() <= ReservedTagBitmapSize(),
"kActualTagBitmapSize should be smaller than or equal to "
"kReservedTagBitmapSize.");
static_assert(ReservedTagBitmapSize() - ActualTagBitmapSize() <
PartitionPageSize(),
"Unused space in the tag bitmap should be smaller than "
"PartitionPageSize()");
// The region available for slot spans is the reminder of the super page, after
// taking away the first and last partition page (for metadata and guard pages)
// and partition pages reserved for the tag bitmap.
PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
SlotSpansSize() {
return kSuperPageSize - 2 * PartitionPageSize() - ReservedTagBitmapSize();
}
static_assert(ActualTagBitmapSize() * tag_bitmap::kBytesPerPartitionTagRatio >=
SlotSpansSize(),
"bitmap is large enough to cover slot spans");
static_assert((ActualTagBitmapSize() - PartitionPageSize()) *
tag_bitmap::kBytesPerPartitionTagRatio <
SlotSpansSize(),
"any smaller bitmap wouldn't suffice to cover slots spans");
#endif // PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR
#else
constexpr PA_ALWAYS_INLINE size_t NumPartitionPagesPerTagBitmap() {
return 0;
}
constexpr PA_ALWAYS_INLINE size_t ActualTagBitmapSize() {
return 0;
}
constexpr PA_ALWAYS_INLINE size_t ReservedTagBitmapSize() {
return 0;
}
#endif // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
} // namespace partition_alloc::internal
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_TAG_BITMAP_H_