page_allocator_constants.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Copyright (c) 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_CONSTANTS_H_
  5. #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_CONSTANTS_H_
  6. #include <stddef.h>
  7. #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
  8. #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
  9. #include "build/build_config.h"
  10. #if BUILDFLAG(IS_APPLE) && defined(ARCH_CPU_64_BITS)
  11. #include <mach/vm_page_size.h>
  12. // Although page allocator constants are not constexpr, they are run-time
  13. // constant. Because the underlying variables they access, such as vm_page_size,
  14. // are not marked const, the compiler normally has no way to know that they
  15. // don’t change and must obtain their values whenever it can't prove that they
  16. // haven't been modified, even if they had already been obtained previously.
  17. // Attaching __attribute__((const)) to these declarations allows these redundant
  18. // accesses to be omitted under optimization such as common subexpression
  19. // elimination.
  20. #define PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR __attribute__((const))
  21. #elif BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64)
  22. // This should work for all POSIX (if needed), but currently all other
  23. // supported OS/architecture combinations use either hard-coded values
  24. // (such as x86) or have means to determine these values without needing
  25. // atomics (such as macOS on arm64).
  26. // Page allocator constants are run-time constant
  27. #define PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR __attribute__((const))
  28. #include <unistd.h>
  29. #include <atomic>
  30. namespace partition_alloc::internal {
  31. // Holds the current page size and shift, where size = 1 << shift
  32. // Use PageAllocationGranularity(), PageAllocationGranularityShift()
  33. // to initialize and retrieve these values safely.
  34. struct PageCharacteristics {
  35. std::atomic<size_t> size;
  36. std::atomic<size_t> shift;
  37. };
  38. PA_COMPONENT_EXPORT(PARTITION_ALLOC)
  39. extern PageCharacteristics page_characteristics;
  40. } // namespace partition_alloc::internal
  41. #else
  42. // When defined, page size constants are fixed at compile time. When not
  43. // defined, they may vary at run time.
  44. #define PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR 1
  45. // Use this macro to declare a function as constexpr or not based on whether
  46. // PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR is defined.
  47. #define PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR constexpr
  48. #endif
  49. namespace partition_alloc::internal {
  50. // Forward declaration, implementation below
  51. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
  52. PageAllocationGranularity();
  53. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
  54. PageAllocationGranularityShift() {
  55. #if BUILDFLAG(IS_WIN) || defined(ARCH_CPU_PPC64)
  56. // Modern ppc64 systems support 4kB (shift = 12) and 64kB (shift = 16) page
  57. // sizes. Since 64kB is the de facto standard on the platform and binaries
  58. // compiled for 64kB are likely to work on 4kB systems, 64kB is a good choice
  59. // here.
  60. return 16; // 64kB
  61. #elif defined(_MIPS_ARCH_LOONGSON)
  62. return 14; // 16kB
  63. #elif BUILDFLAG(IS_APPLE) && defined(ARCH_CPU_64_BITS)
  64. return static_cast<size_t>(vm_page_shift);
  65. #elif BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64)
  66. // arm64 supports 4kb (shift = 12), 16kb (shift = 14), and 64kb (shift = 16)
  67. // page sizes. Retrieve from or initialize cache.
  68. size_t shift = page_characteristics.shift.load(std::memory_order_relaxed);
  69. if (PA_UNLIKELY(shift == 0)) {
  70. shift = static_cast<size_t>(
  71. __builtin_ctz((unsigned int)PageAllocationGranularity()));
  72. page_characteristics.shift.store(shift, std::memory_order_relaxed);
  73. }
  74. return shift;
  75. #else
  76. return 12; // 4kB
  77. #endif
  78. }
  79. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
  80. PageAllocationGranularity() {
  81. #if BUILDFLAG(IS_APPLE) && defined(ARCH_CPU_64_BITS)
  82. // This is literally equivalent to |1 << PageAllocationGranularityShift()|
  83. // below, but was separated out for IS_APPLE to avoid << on a non-constexpr.
  84. return vm_page_size;
  85. #elif BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64)
  86. // arm64 supports 4kb, 16kb, and 64kb page sizes. Retrieve from or
  87. // initialize cache.
  88. size_t size = page_characteristics.size.load(std::memory_order_relaxed);
  89. if (PA_UNLIKELY(size == 0)) {
  90. size = static_cast<size_t>(getpagesize());
  91. page_characteristics.size.store(size, std::memory_order_relaxed);
  92. }
  93. return size;
  94. #else
  95. return 1 << PageAllocationGranularityShift();
  96. #endif
  97. }
  98. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
  99. PageAllocationGranularityOffsetMask() {
  100. return PageAllocationGranularity() - 1;
  101. }
  102. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
  103. PageAllocationGranularityBaseMask() {
  104. return ~PageAllocationGranularityOffsetMask();
  105. }
  106. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
  107. SystemPageShift() {
  108. // On Windows allocation granularity is higher than the page size. This comes
  109. // into play when reserving address space range (allocation granularity),
  110. // compared to committing pages into memory (system page granularity).
  111. #if BUILDFLAG(IS_WIN)
  112. return 12; // 4096=1<<12
  113. #else
  114. return PageAllocationGranularityShift();
  115. #endif
  116. }
  117. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
  118. SystemPageSize() {
  119. #if (BUILDFLAG(IS_APPLE) && defined(ARCH_CPU_64_BITS)) || \
  120. (BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64))
  121. // This is literally equivalent to |1 << SystemPageShift()| below, but was
  122. // separated out for 64-bit IS_APPLE and arm64 on Linux to avoid << on a
  123. // non-constexpr.
  124. return PageAllocationGranularity();
  125. #else
  126. return 1 << SystemPageShift();
  127. #endif
  128. }
  129. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
  130. SystemPageOffsetMask() {
  131. return SystemPageSize() - 1;
  132. }
  133. PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR PA_ALWAYS_INLINE size_t
  134. SystemPageBaseMask() {
  135. return ~SystemPageOffsetMask();
  136. }
  137. constexpr size_t kPageMetadataShift = 5; // 32 bytes per partition page.
  138. constexpr size_t kPageMetadataSize = 1 << kPageMetadataShift;
  139. } // namespace partition_alloc::internal
  140. #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_CONSTANTS_H_