0273a0de603c36411bf45250a532d9c167bdba50
[WebKit-https.git] / Source / bmalloc / bmalloc / VMAllocate.h
1 /*
2  * Copyright (C) 2014 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 "Range.h"
31 #include "Sizes.h"
32 #include "Syscall.h"
33 #include <algorithm>
34 #include <sys/mman.h>
35 #include <unistd.h>
36
37 #if BOS(DARWIN)
38 #include <mach/vm_statistics.h>
39 #endif
40
41 namespace bmalloc {
42
43 #if BOS(DARWIN)
44 #define BMALLOC_VM_TAG VM_MAKE_TAG(VM_MEMORY_TCMALLOC)
45 #else
46 #define BMALLOC_VM_TAG -1
47 #endif
48
49 inline size_t vmSize(size_t size)
50 {
51     return roundUpToMultipleOf<vmPageSize>(size);
52 }
53
54 inline void vmValidate(size_t vmSize)
55 {
56     // We use getpagesize() here instead of vmPageSize because vmPageSize is
57     // allowed to be larger than the OS's true page size.
58
59     UNUSED(vmSize);
60     BASSERT(vmSize);
61     BASSERT(vmSize == roundUpToMultipleOf(static_cast<size_t>(getpagesize()), vmSize));
62 }
63
64 inline void vmValidate(void* p, size_t vmSize)
65 {
66     // We use getpagesize() here instead of vmPageSize because vmPageSize is
67     // allowed to be larger than the OS's true page size.
68
69     vmValidate(vmSize);
70     
71     UNUSED(p);
72     BASSERT(p);
73     BASSERT(p == mask(p, ~(getpagesize() - 1)));
74 }
75
76 inline void* tryVMAllocate(size_t vmSize)
77 {
78     vmValidate(vmSize);
79     void* result = mmap(0, vmSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, BMALLOC_VM_TAG, 0);
80     if (result == MAP_FAILED)
81         return nullptr;
82     return result;
83 }
84
85 inline bool tryVMExtend(void* p, size_t vmOldSize, size_t vmNewSize)
86 {
87     vmValidate(vmOldSize);
88     vmValidate(vmNewSize);
89     
90     BASSERT(vmOldSize < vmNewSize);
91
92     void* nextAddress = static_cast<char*>(p) + vmOldSize;
93     size_t extentionSize = vmNewSize - vmOldSize;
94
95     void* result = mmap(nextAddress, extentionSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, BMALLOC_VM_TAG, 0);
96
97     if (result == MAP_FAILED)
98         return false;
99
100     if (result != nextAddress) {
101         munmap(result, extentionSize);
102         return false;
103     }
104     
105     return true;
106 }
107
108 inline void* vmAllocate(size_t vmSize)
109 {
110     void* result = tryVMAllocate(vmSize);
111     RELEASE_BASSERT(result);
112     return result;
113 }
114
115 inline void vmDeallocate(void* p, size_t vmSize)
116 {
117     vmValidate(p, vmSize);
118     munmap(p, vmSize);
119 }
120
121 // Allocates vmSize bytes at a specified power-of-two alignment.
122 // Use this function to create maskable memory regions.
123
124 inline void* tryVMAllocate(size_t vmAlignment, size_t vmSize)
125 {
126     vmValidate(vmSize);
127     vmValidate(vmAlignment);
128
129     size_t mappedSize = std::max(vmSize, vmAlignment) + vmAlignment;
130     char* mapped = static_cast<char*>(tryVMAllocate(mappedSize));
131     if (!mapped)
132         return nullptr;
133     char* mappedEnd = mapped + mappedSize;
134
135     char* aligned = roundUpToMultipleOf(vmAlignment, mapped);
136     char* alignedEnd = aligned + vmSize;
137     
138     if (size_t leftExtra = aligned - mapped)
139         vmDeallocate(mapped, leftExtra);
140     
141     if (size_t rightExtra = mappedEnd - alignedEnd)
142         vmDeallocate(alignedEnd, rightExtra);
143
144     return aligned;
145 }
146
147 inline void* vmAllocate(size_t vmAlignment, size_t vmSize)
148 {
149     void* result = tryVMAllocate(vmAlignment, vmSize);
150     RELEASE_BASSERT(result);
151     return result;
152 }
153
154 inline void vmDeallocatePhysicalPages(void* p, size_t vmSize)
155 {
156     vmValidate(p, vmSize);
157 #if BOS(DARWIN)
158     SYSCALL(madvise(p, vmSize, MADV_FREE_REUSABLE));
159 #else
160     SYSCALL(madvise(p, vmSize, MADV_DONTNEED));
161 #endif
162 }
163
164 inline void vmAllocatePhysicalPages(void* p, size_t vmSize)
165 {
166     vmValidate(p, vmSize);
167 #if BOS(DARWIN)
168     SYSCALL(madvise(p, vmSize, MADV_FREE_REUSE));
169 #else
170     SYSCALL(madvise(p, vmSize, MADV_NORMAL));
171 #endif
172 }
173
174 // Trims requests that are un-page-aligned.
175 inline void vmDeallocatePhysicalPagesSloppy(void* p, size_t size)
176 {
177     char* begin = roundUpToMultipleOf<vmPageSize>(static_cast<char*>(p));
178     char* end = roundDownToMultipleOf<vmPageSize>(static_cast<char*>(p) + size);
179
180     if (begin >= end)
181         return;
182
183     vmDeallocatePhysicalPages(begin, end - begin);
184 }
185
186 // Expands requests that are un-page-aligned.
187 inline void vmAllocatePhysicalPagesSloppy(void* p, size_t size)
188 {
189     char* begin = roundDownToMultipleOf<vmPageSize>(static_cast<char*>(p));
190     char* end = roundUpToMultipleOf<vmPageSize>(static_cast<char*>(p) + size);
191
192     if (begin >= end)
193         return;
194
195     vmAllocatePhysicalPages(begin, end - begin);
196 }
197
198 } // namespace bmalloc
199
200 #endif // VMAllocate_h