summaryrefslogtreecommitdiff
path: root/third_party/base/allocator/partition_allocator/page_allocator.h
blob: 64be33c3c2b74ed8786f26402e045d3ac098807c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Copyright (c) 2013 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 THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_H_
#define THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_H_

#include <stdint.h>

#include <cstddef>

#include "build/build_config.h"
#include "third_party/base/allocator/partition_allocator/page_allocator_constants.h"
#include "third_party/base/base_export.h"
#include "third_party/base/compiler_specific.h"

namespace pdfium {
namespace base {

enum PageAccessibilityConfiguration {
  PageInaccessible,
  PageRead,
  PageReadWrite,
  PageReadExecute,
  // This flag is deprecated and will go away soon.
  // TODO(bbudge) Remove this as soon as V8 doesn't need RWX pages.
  PageReadWriteExecute,
};

// Mac OSX supports tagged memory regions, to help in debugging.
enum class PageTag {
  kFirst = 240,     // Minimum tag value.
  kChromium = 254,  // Chromium page, including off-heap V8 ArrayBuffers.
  kV8 = 255,        // V8 heap pages.
  kLast = kV8       // Maximum tag value.
};

// Allocate one or more pages.
//
// The requested |address| is just a hint; the actual address returned may
// differ. The returned address will be aligned at least to |align| bytes.
// |length| is in bytes, and must be a multiple of |kPageAllocationGranularity|.
// |align| is in bytes, and must be a power-of-two multiple of
// |kPageAllocationGranularity|.
//
// If |address| is null, then a suitable and randomized address will be chosen
// automatically.
//
// |page_accessibility| controls the permission of the allocated pages.
//
// This call will return null if the allocation cannot be satisfied.
BASE_EXPORT void* AllocPages(void* address,
                             size_t length,
                             size_t align,
                             PageAccessibilityConfiguration page_accessibility,
                             PageTag tag = PageTag::kChromium,
                             bool commit = true);

// Free one or more pages starting at |address| and continuing for |length|
// bytes.
//
// |address| and |length| must match a previous call to |AllocPages|. Therefore,
// |address| must be aligned to |kPageAllocationGranularity| bytes, and |length|
// must be a multiple of |kPageAllocationGranularity|.
BASE_EXPORT void FreePages(void* address, size_t length);

// Mark one or more system pages, starting at |address| with the given
// |page_accessibility|. |length| must be a multiple of |kSystemPageSize| bytes.
//
// Returns true if the permission change succeeded. In most cases you must
// |CHECK| the result.
BASE_EXPORT WARN_UNUSED_RESULT bool SetSystemPagesAccess(
    void* address,
    size_t length,
    PageAccessibilityConfiguration page_accessibility);

// Decommit one or more system pages starting at |address| and continuing for
// |length| bytes. |length| must be a multiple of |kSystemPageSize|.
//
// Decommitted means that physical resources (RAM or swap) backing the allocated
// virtual address range are released back to the system, but the address space
// is still allocated to the process (possibly using up page table entries or
// other accounting resources). Any access to a decommitted region of memory
// is an error and will generate a fault.
//
// This operation is not atomic on all platforms.
//
// Note: "Committed memory" is a Windows Memory Subsystem concept that ensures
// processes will not fault when touching a committed memory region. There is
// no analogue in the POSIX memory API where virtual memory pages are
// best-effort allocated resources on the first touch. To create a
// platform-agnostic abstraction, this API simulates the Windows "decommit"
// state by both discarding the region (allowing the OS to avoid swap
// operations) and changing the page protections so accesses fault.
//
// TODO(ajwong): This currently does not change page protections on POSIX
// systems due to a perf regression. Tracked at http://crbug.com/766882.
BASE_EXPORT void DecommitSystemPages(void* address, size_t length);

// Recommit one or more system pages, starting at |address| and continuing for
// |length| bytes with the given |page_accessibility|. |length| must be a
// multiple of |kSystemPageSize|.
//
// Decommitted system pages must be recommitted with their original permissions
// before they are used again.
//
// Returns true if the recommit change succeeded. In most cases you must |CHECK|
// the result.
BASE_EXPORT WARN_UNUSED_RESULT bool RecommitSystemPages(
    void* address,
    size_t length,
    PageAccessibilityConfiguration page_accessibility);

// Discard one or more system pages starting at |address| and continuing for
// |length| bytes. |length| must be a multiple of |kSystemPageSize|.
//
// Discarding is a hint to the system that the page is no longer required. The
// hint may:
//   - Do nothing.
//   - Discard the page immediately, freeing up physical pages.
//   - Discard the page at some time in the future in response to memory
//   pressure.
//
// Only committed pages should be discarded. Discarding a page does not decommit
// it, and it is valid to discard an already-discarded page. A read or write to
// a discarded page will not fault.
//
// Reading from a discarded page may return the original page content, or a page
// full of zeroes.
//
// Writing to a discarded page is the only guaranteed way to tell the system
// that the page is required again. Once written to, the content of the page is
// guaranteed stable once more. After being written to, the page content may be
// based on the original page content, or a page of zeroes.
BASE_EXPORT void DiscardSystemPages(void* address, size_t length);

// Rounds up |address| to the next multiple of |kSystemPageSize|. Returns
// 0 for an |address| of 0.
constexpr ALWAYS_INLINE uintptr_t RoundUpToSystemPage(uintptr_t address) {
  return (address + kSystemPageOffsetMask) & kSystemPageBaseMask;
}

// Rounds down |address| to the previous multiple of |kSystemPageSize|. Returns
// 0 for an |address| of 0.
constexpr ALWAYS_INLINE uintptr_t RoundDownToSystemPage(uintptr_t address) {
  return address & kSystemPageBaseMask;
}

// Rounds up |address| to the next multiple of |kPageAllocationGranularity|.
// Returns 0 for an |address| of 0.
constexpr ALWAYS_INLINE uintptr_t
RoundUpToPageAllocationGranularity(uintptr_t address) {
  return (address + kPageAllocationGranularityOffsetMask) &
         kPageAllocationGranularityBaseMask;
}

// Rounds down |address| to the previous multiple of
// |kPageAllocationGranularity|. Returns 0 for an |address| of 0.
constexpr ALWAYS_INLINE uintptr_t
RoundDownToPageAllocationGranularity(uintptr_t address) {
  return address & kPageAllocationGranularityBaseMask;
}

// Reserves (at least) |size| bytes of address space, aligned to
// |kPageAllocationGranularity|. This can be called early on to make it more
// likely that large allocations will succeed. Returns true if the reservation
// succeeded, false if the reservation failed or a reservation was already made.
BASE_EXPORT bool ReserveAddressSpace(size_t size);

// Releases any reserved address space. |AllocPages| calls this automatically on
// an allocation failure. External allocators may also call this on failure.
BASE_EXPORT void ReleaseReservation();

// Returns |errno| (POSIX) or the result of |GetLastError| (Windows) when |mmap|
// (POSIX) or |VirtualAlloc| (Windows) fails.
BASE_EXPORT uint32_t GetAllocPageErrorCode();

}  // namespace base
}  // namespace pdfium

#endif  // THIRD_PARTY_BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_H_