757d5cd1989037261e77341dfeea079cef3645e5
[WebKit-https.git] / Source / bmalloc / bmalloc / VMAllocate.h
1 /*
2  * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef VMAllocate_h
27 #define VMAllocate_h
28
29 #include "BAssert.h"
30 #include "Logging.h"
31 #include "Range.h"
32 #include "Sizes.h"
33 #include "Syscall.h"
34 #include <algorithm>
35 #include <sys/mman.h>
36 #include <unistd.h>
37
38 #if BOS(DARWIN)
39 #include <mach/vm_page_size.h>
40 #include <mach/vm_statistics.h>
41 #endif
42
43 namespace bmalloc {
44
45 #if BOS(DARWIN)
46 #define BMALLOC_VM_TAG VM_MAKE_TAG(VM_MEMORY_TCMALLOC)
47 #define BMALLOC_NORESERVE 0
48 #elif BOS(LINUX)
49 #define BMALLOC_VM_TAG -1
50 #define BMALLOC_NORESERVE MAP_NORESERVE
51 #else
52 #define BMALLOC_VM_TAG -1
53 #define BMALLOC_NORESERVE 0
54 #endif
55
56 inline size_t vmPageSize()
57 {
58     static size_t cached;
59     if (!cached) {
60         long pageSize = sysconf(_SC_PAGESIZE);
61         if (pageSize < 0)
62             BCRASH();
63         cached = pageSize;
64     }
65     return cached;
66 }
67
68 inline size_t vmPageShift()
69 {
70     static size_t cached;
71     if (!cached)
72         cached = log2(vmPageSize());
73     return cached;
74 }
75
76 inline size_t vmSize(size_t size)
77 {
78     return roundUpToMultipleOf(vmPageSize(), size);
79 }
80
81 inline void vmValidate(size_t vmSize)
82 {
83     BUNUSED(vmSize);
84     BASSERT(vmSize);
85     BASSERT(vmSize == roundUpToMultipleOf(vmPageSize(), vmSize));
86 }
87
88 inline void vmValidate(void* p, size_t vmSize)
89 {
90     vmValidate(vmSize);
91     
92     BUNUSED(p);
93     BASSERT(p);
94     BASSERT(p == mask(p, ~(vmPageSize() - 1)));
95 }
96
97 inline size_t vmPageSizePhysical()
98 {
99 #if BPLATFORM(IOS_FAMILY)
100     return vm_kernel_page_size;
101 #else
102     static size_t cached;
103     if (!cached)
104         cached = sysconf(_SC_PAGESIZE);
105     return cached;
106 #endif
107 }
108
109 inline void vmValidatePhysical(size_t vmSize)
110 {
111     BUNUSED(vmSize);
112     BASSERT(vmSize);
113     BASSERT(vmSize == roundUpToMultipleOf(vmPageSizePhysical(), vmSize));
114 }
115
116 inline void vmValidatePhysical(void* p, size_t vmSize)
117 {
118     vmValidatePhysical(vmSize);
119     
120     BUNUSED(p);
121     BASSERT(p);
122     BASSERT(p == mask(p, ~(vmPageSizePhysical() - 1)));
123 }
124
125 inline void* tryVMAllocate(size_t vmSize)
126 {
127     vmValidate(vmSize);
128     void* result = mmap(0, vmSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | BMALLOC_NORESERVE, BMALLOC_VM_TAG, 0);
129     if (result == MAP_FAILED)
130         return nullptr;
131     return result;
132 }
133
134 inline void* vmAllocate(size_t vmSize)
135 {
136     void* result = tryVMAllocate(vmSize);
137     RELEASE_BASSERT(result);
138     return result;
139 }
140
141 inline void vmDeallocate(void* p, size_t vmSize)
142 {
143     vmValidate(p, vmSize);
144     munmap(p, vmSize);
145 }
146
147 inline void vmRevokePermissions(void* p, size_t vmSize)
148 {
149     vmValidate(p, vmSize);
150     mprotect(p, vmSize, PROT_NONE);
151 }
152
153 inline void vmZeroAndPurge(void* p, size_t vmSize)
154 {
155     vmValidate(p, vmSize);
156     // MAP_ANON guarantees the memory is zeroed. This will also cause
157     // page faults on accesses to this range following this call.
158     void* result = mmap(p, vmSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED | BMALLOC_NORESERVE, BMALLOC_VM_TAG, 0);
159     RELEASE_BASSERT(result == p);
160 }
161
162 // Allocates vmSize bytes at a specified power-of-two alignment.
163 // Use this function to create maskable memory regions.
164
165 inline void* tryVMAllocate(size_t vmAlignment, size_t vmSize)
166 {
167     vmValidate(vmSize);
168     vmValidate(vmAlignment);
169
170     size_t mappedSize = vmAlignment + vmSize;
171     if (mappedSize < vmAlignment || mappedSize < vmSize) // Check for overflow
172         return nullptr;
173
174     char* mapped = static_cast<char*>(tryVMAllocate(mappedSize));
175     if (!mapped)
176         return nullptr;
177     char* mappedEnd = mapped + mappedSize;
178
179     char* aligned = roundUpToMultipleOf(vmAlignment, mapped);
180     char* alignedEnd = aligned + vmSize;
181     
182     RELEASE_BASSERT(alignedEnd <= mappedEnd);
183     
184     if (size_t leftExtra = aligned - mapped)
185         vmDeallocate(mapped, leftExtra);
186     
187     if (size_t rightExtra = mappedEnd - alignedEnd)
188         vmDeallocate(alignedEnd, rightExtra);
189
190     return aligned;
191 }
192
193 inline void* vmAllocate(size_t vmAlignment, size_t vmSize)
194 {
195     void* result = tryVMAllocate(vmAlignment, vmSize);
196     RELEASE_BASSERT(result);
197     return result;
198 }
199
200 inline void vmDeallocatePhysicalPages(void* p, size_t vmSize)
201 {
202     vmValidatePhysical(p, vmSize);
203 #if BOS(DARWIN)
204     SYSCALL(madvise(p, vmSize, MADV_FREE_REUSABLE));
205 #else
206     SYSCALL(madvise(p, vmSize, MADV_DONTNEED));
207 #if BOS(LINUX)
208     SYSCALL(madvise(p, vmSize, MADV_DONTDUMP));
209 #endif
210 #endif
211 }
212
213 inline void vmAllocatePhysicalPages(void* p, size_t vmSize)
214 {
215     vmValidatePhysical(p, vmSize);
216 #if BOS(DARWIN)
217     SYSCALL(madvise(p, vmSize, MADV_FREE_REUSE));
218 #else
219     SYSCALL(madvise(p, vmSize, MADV_NORMAL));
220 #if BOS(LINUX)
221     SYSCALL(madvise(p, vmSize, MADV_DODUMP));
222 #endif
223 #endif
224 }
225
226 // Returns how much memory you would commit/decommit had you called
227 // vmDeallocate/AllocatePhysicalPagesSloppy with p and size.
228 inline size_t physicalPageSizeSloppy(void* p, size_t size)
229 {
230     char* begin = roundUpToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p));
231     char* end = roundDownToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p) + size);
232
233     if (begin >= end)
234         return 0;
235     return end - begin;
236 }
237
238 // Trims requests that are un-page-aligned.
239 inline void vmDeallocatePhysicalPagesSloppy(void* p, size_t size)
240 {
241     char* begin = roundUpToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p));
242     char* end = roundDownToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p) + size);
243
244     if (begin >= end)
245         return;
246
247     vmDeallocatePhysicalPages(begin, end - begin);
248 }
249
250 // Expands requests that are un-page-aligned.
251 inline void vmAllocatePhysicalPagesSloppy(void* p, size_t size)
252 {
253     char* begin = roundDownToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p));
254     char* end = roundUpToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p) + size);
255
256     if (begin >= end)
257         return;
258
259     vmAllocatePhysicalPages(begin, end - begin);
260 }
261
262 } // namespace bmalloc
263
264 #endif // VMAllocate_h