819dc95dd5b4bac902a2e9ba466aaafd87ed5d64
[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 #else
48 #define BMALLOC_VM_TAG -1
49 #endif
50
51 inline size_t vmPageSize()
52 {
53     static size_t cached;
54     if (!cached)
55         cached = sysconf(_SC_PAGESIZE);
56     return cached;
57 }
58
59 inline size_t vmPageShift()
60 {
61     static size_t cached;
62     if (!cached)
63         cached = log2(vmPageSize());
64     return cached;
65 }
66
67 inline size_t vmSize(size_t size)
68 {
69     return roundUpToMultipleOf(vmPageSize(), size);
70 }
71
72 inline void vmValidate(size_t vmSize)
73 {
74     UNUSED(vmSize);
75     BASSERT(vmSize);
76     BASSERT(vmSize == roundUpToMultipleOf(vmPageSize(), vmSize));
77 }
78
79 inline void vmValidate(void* p, size_t vmSize)
80 {
81     vmValidate(vmSize);
82     
83     UNUSED(p);
84     BASSERT(p);
85     BASSERT(p == mask(p, ~(vmPageSize() - 1)));
86 }
87
88 inline size_t vmPageSizePhysical()
89 {
90 #if BPLATFORM(IOS)
91     return vm_kernel_page_size;
92 #else
93     static size_t cached;
94     if (!cached)
95         cached = sysconf(_SC_PAGESIZE);
96     return cached;
97 #endif
98 }
99
100 inline void vmValidatePhysical(size_t vmSize)
101 {
102     UNUSED(vmSize);
103     BASSERT(vmSize);
104     BASSERT(vmSize == roundUpToMultipleOf(vmPageSizePhysical(), vmSize));
105 }
106
107 inline void vmValidatePhysical(void* p, size_t vmSize)
108 {
109     vmValidatePhysical(vmSize);
110     
111     UNUSED(p);
112     BASSERT(p);
113     BASSERT(p == mask(p, ~(vmPageSizePhysical() - 1)));
114 }
115
116 inline void* tryVMAllocate(size_t vmSize)
117 {
118     vmValidate(vmSize);
119     void* result = mmap(0, vmSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, BMALLOC_VM_TAG, 0);
120     if (result == MAP_FAILED) {
121         logVMFailure();
122         return nullptr;
123     }
124     return result;
125 }
126
127 inline void* vmAllocate(size_t vmSize)
128 {
129     void* result = tryVMAllocate(vmSize);
130     RELEASE_BASSERT(result);
131     return result;
132 }
133
134 inline void vmDeallocate(void* p, size_t vmSize)
135 {
136     vmValidate(p, vmSize);
137     munmap(p, vmSize);
138 }
139
140 inline void vmRevokePermissions(void* p, size_t vmSize)
141 {
142     vmValidate(p, vmSize);
143     mprotect(p, vmSize, PROT_NONE);
144 }
145
146 // Allocates vmSize bytes at a specified power-of-two alignment.
147 // Use this function to create maskable memory regions.
148
149 inline void* tryVMAllocate(size_t vmAlignment, size_t vmSize)
150 {
151     vmValidate(vmSize);
152     vmValidate(vmAlignment);
153
154     size_t mappedSize = vmAlignment + vmSize;
155     if (mappedSize < vmAlignment || mappedSize < vmSize) // Check for overflow
156         return nullptr;
157
158     char* mapped = static_cast<char*>(tryVMAllocate(mappedSize));
159     if (!mapped)
160         return nullptr;
161     char* mappedEnd = mapped + mappedSize;
162
163     char* aligned = roundUpToMultipleOf(vmAlignment, mapped);
164     char* alignedEnd = aligned + vmSize;
165     
166     RELEASE_BASSERT(alignedEnd <= mappedEnd);
167     
168     if (size_t leftExtra = aligned - mapped)
169         vmDeallocate(mapped, leftExtra);
170     
171     if (size_t rightExtra = mappedEnd - alignedEnd)
172         vmDeallocate(alignedEnd, rightExtra);
173
174     return aligned;
175 }
176
177 inline void* vmAllocate(size_t vmAlignment, size_t vmSize)
178 {
179     void* result = tryVMAllocate(vmAlignment, vmSize);
180     RELEASE_BASSERT(result);
181     return result;
182 }
183
184 inline void vmDeallocatePhysicalPages(void* p, size_t vmSize)
185 {
186     vmValidatePhysical(p, vmSize);
187 #if BOS(DARWIN)
188     SYSCALL(madvise(p, vmSize, MADV_FREE_REUSABLE));
189 #else
190     SYSCALL(madvise(p, vmSize, MADV_DONTNEED));
191 #endif
192 }
193
194 inline void vmAllocatePhysicalPages(void* p, size_t vmSize)
195 {
196     vmValidatePhysical(p, vmSize);
197 #if BOS(DARWIN)
198     SYSCALL(madvise(p, vmSize, MADV_FREE_REUSE));
199 #else
200     SYSCALL(madvise(p, vmSize, MADV_NORMAL));
201 #endif
202 }
203
204 // Trims requests that are un-page-aligned.
205 inline void vmDeallocatePhysicalPagesSloppy(void* p, size_t size)
206 {
207     char* begin = roundUpToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p));
208     char* end = roundDownToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p) + size);
209
210     if (begin >= end)
211         return;
212
213     vmDeallocatePhysicalPages(begin, end - begin);
214 }
215
216 // Expands requests that are un-page-aligned.
217 inline void vmAllocatePhysicalPagesSloppy(void* p, size_t size)
218 {
219     char* begin = roundDownToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p));
220     char* end = roundUpToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p) + size);
221
222     if (begin >= end)
223         return;
224
225     vmAllocatePhysicalPages(begin, end - begin);
226 }
227
228 } // namespace bmalloc
229
230 #endif // VMAllocate_h