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