Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(515)

Side by Side Diff: third_party/WebKit/Source/wtf/PageAllocator.cpp

Issue 1881983003: Move PartitionAlloc related things into wtf/allocator. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2013 Google 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 are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "wtf/PageAllocator.h"
32
33 #include "wtf/AddressSpaceRandomization.h"
34 #include "wtf/Assertions.h"
35
36 #include <limits.h>
37
38 #if OS(POSIX)
39
40 #include <errno.h>
41 #include <sys/mman.h>
42
43 #ifndef MADV_FREE
44 #define MADV_FREE MADV_DONTNEED
45 #endif
46
47 #ifndef MAP_ANONYMOUS
48 #define MAP_ANONYMOUS MAP_ANON
49 #endif
50
51 // On POSIX memmap uses a nearby address if the hint address is blocked.
52 static const bool kHintIsAdvisory = true;
53 static uint32_t allocPageErrorCode = 0;
54
55 #elif OS(WIN)
56
57 #include <windows.h>
58
59 // VirtualAlloc will fail if allocation at the hint address is blocked.
60 static const bool kHintIsAdvisory = false;
61 static uint32_t allocPageErrorCode = ERROR_SUCCESS;
62
63 #else
64 #error Unknown OS
65 #endif // OS(POSIX)
66
67 namespace WTF {
68
69 // This internal function wraps the OS-specific page allocation call. The
70 // behavior of the hint address is determined by the kHintIsAdvisory constant.
71 // If true, a non-zero hint is advisory and the returned address may differ from
72 // the hint. If false, the hint is mandatory and a successful allocation will
73 // not differ from the hint.
74 static void* systemAllocPages(void* hint, size_t len, PageAccessibilityConfigura tion pageAccessibility)
75 {
76 ASSERT(!(len & kPageAllocationGranularityOffsetMask));
77 ASSERT(!(reinterpret_cast<uintptr_t>(hint) & kPageAllocationGranularityOffse tMask));
78 void* ret;
79 #if OS(WIN)
80 DWORD accessFlag = pageAccessibility == PageAccessible ? PAGE_READWRITE : PA GE_NOACCESS;
81 ret = VirtualAlloc(hint, len, MEM_RESERVE | MEM_COMMIT, accessFlag);
82 if (!ret)
83 allocPageErrorCode = GetLastError();
84 #else
85 int accessFlag = pageAccessibility == PageAccessible ? (PROT_READ | PROT_WRI TE) : PROT_NONE;
86 ret = mmap(hint, len, accessFlag, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
87 if (ret == MAP_FAILED) {
88 allocPageErrorCode = errno;
89 ret = 0;
90 }
91 #endif
92 return ret;
93 }
94
95 // Trims base to given length and alignment. Windows returns null on failure and frees base.
96 static void* trimMapping(void *base, size_t baseLen, size_t trimLen, uintptr_t a lign, PageAccessibilityConfiguration pageAccessibility)
97 {
98 size_t preSlack = reinterpret_cast<uintptr_t>(base) & (align - 1);
99 if (preSlack)
100 preSlack = align - preSlack;
101 size_t postSlack = baseLen - preSlack - trimLen;
102 ASSERT(baseLen >= trimLen || preSlack || postSlack);
103 ASSERT(preSlack < baseLen);
104 ASSERT(postSlack < baseLen);
105 void* ret = base;
106
107 #if OS(POSIX) // On POSIX we can resize the allocation run.
108 (void) pageAccessibility;
109 if (preSlack) {
110 int res = munmap(base, preSlack);
111 RELEASE_ASSERT(!res);
112 ret = reinterpret_cast<char*>(base) + preSlack;
113 }
114 if (postSlack) {
115 int res = munmap(reinterpret_cast<char*>(ret) + trimLen, postSlack);
116 RELEASE_ASSERT(!res);
117 }
118 #else // On Windows we can't resize the allocation run.
119 if (preSlack || postSlack) {
120 ret = reinterpret_cast<char*>(base) + preSlack;
121 freePages(base, baseLen);
122 ret = systemAllocPages(ret, trimLen, pageAccessibility);
123 }
124 #endif
125
126 return ret;
127 }
128
129 void* allocPages(void* addr, size_t len, size_t align, PageAccessibilityConfigur ation pageAccessibility)
130 {
131 ASSERT(len >= kPageAllocationGranularity);
132 ASSERT(!(len & kPageAllocationGranularityOffsetMask));
133 ASSERT(align >= kPageAllocationGranularity);
134 ASSERT(!(align & kPageAllocationGranularityOffsetMask));
135 ASSERT(!(reinterpret_cast<uintptr_t>(addr) & kPageAllocationGranularityOffse tMask));
136 uintptr_t alignOffsetMask = align - 1;
137 uintptr_t alignBaseMask = ~alignOffsetMask;
138 ASSERT(!(reinterpret_cast<uintptr_t>(addr) & alignOffsetMask));
139
140 // If the client passed null as the address, choose a good one.
141 if (!addr) {
142 addr = getRandomPageBase();
143 addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & align BaseMask);
144 }
145
146 // First try to force an exact-size, aligned allocation from our random base .
147 for (int count = 0; count < 3; ++count) {
148 void* ret = systemAllocPages(addr, len, pageAccessibility);
149 if (kHintIsAdvisory || ret) {
150 // If the alignment is to our liking, we're done.
151 if (!(reinterpret_cast<uintptr_t>(ret)& alignOffsetMask))
152 return ret;
153 freePages(ret, len);
154 #if CPU(32BIT)
155 addr = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(ret)+ali gn) & alignBaseMask);
156 #endif
157 } else if (!addr) { // We know we're OOM when an unhinted allocation fai ls.
158 return nullptr;
159
160 } else {
161 #if CPU(32BIT)
162 addr = reinterpret_cast<char*>(addr) + align;
163 #endif
164 }
165
166 #if !CPU(32BIT) // Keep trying random addresses on systems that have a large add ress space.
167 addr = getRandomPageBase();
168 addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & align BaseMask);
169 #endif
170 }
171
172 // Map a larger allocation so we can force alignment, but continue randomizi ng only on 64-bit POSIX.
173 size_t tryLen = len + (align - kPageAllocationGranularity);
174 RELEASE_ASSERT(tryLen >= len);
175 void* ret;
176
177 do {
178 // Don't continue to burn cycles on mandatory hints (Windows).
179 addr = kHintIsAdvisory ? getRandomPageBase() : nullptr;
180 ret = systemAllocPages(addr, tryLen, pageAccessibility);
181 // The retries are for Windows, where a race can steal our mapping on resize .
182 } while (ret && !(ret = trimMapping(ret, tryLen, len, align, pageAccessibili ty)));
183
184 return ret;
185 }
186
187 void freePages(void* addr, size_t len)
188 {
189 ASSERT(!(reinterpret_cast<uintptr_t>(addr) & kPageAllocationGranularityOffse tMask));
190 ASSERT(!(len & kPageAllocationGranularityOffsetMask));
191 #if OS(POSIX)
192 int ret = munmap(addr, len);
193 RELEASE_ASSERT(!ret);
194 #else
195 BOOL ret = VirtualFree(addr, 0, MEM_RELEASE);
196 RELEASE_ASSERT(ret);
197 #endif
198 }
199
200 void setSystemPagesInaccessible(void* addr, size_t len)
201 {
202 ASSERT(!(len & kSystemPageOffsetMask));
203 #if OS(POSIX)
204 int ret = mprotect(addr, len, PROT_NONE);
205 RELEASE_ASSERT(!ret);
206 #else
207 BOOL ret = VirtualFree(addr, len, MEM_DECOMMIT);
208 RELEASE_ASSERT(ret);
209 #endif
210 }
211
212 bool setSystemPagesAccessible(void* addr, size_t len)
213 {
214 ASSERT(!(len & kSystemPageOffsetMask));
215 #if OS(POSIX)
216 return !mprotect(addr, len, PROT_READ | PROT_WRITE);
217 #else
218 return !!VirtualAlloc(addr, len, MEM_COMMIT, PAGE_READWRITE);
219 #endif
220 }
221
222 void decommitSystemPages(void* addr, size_t len)
223 {
224 ASSERT(!(len & kSystemPageOffsetMask));
225 #if OS(POSIX)
226 int ret = madvise(addr, len, MADV_FREE);
227 RELEASE_ASSERT(!ret);
228 #else
229 setSystemPagesInaccessible(addr, len);
230 #endif
231 }
232
233 void recommitSystemPages(void* addr, size_t len)
234 {
235 ASSERT(!(len & kSystemPageOffsetMask));
236 #if OS(POSIX)
237 (void) addr;
238 #else
239 RELEASE_ASSERT(setSystemPagesAccessible(addr, len));
240 #endif
241 }
242
243 void discardSystemPages(void* addr, size_t len)
244 {
245 ASSERT(!(len & kSystemPageOffsetMask));
246 #if OS(POSIX)
247 // On POSIX, the implementation detail is that discard and decommit are the
248 // same, and lead to pages that are returned to the system immediately and
249 // get replaced with zeroed pages when touched. So we just call
250 // decommitSystemPages() here to avoid code duplication.
251 decommitSystemPages(addr, len);
252 #else
253 // On Windows discarded pages are not returned to the system immediately and
254 // not guaranteed to be zeroed when returned to the application.
255 using DiscardVirtualMemoryFunction = DWORD(WINAPI*)(PVOID virtualAddress, SI ZE_T size);
256 static DiscardVirtualMemoryFunction discardVirtualMemory = reinterpret_cast< DiscardVirtualMemoryFunction>(-1);
257 if (discardVirtualMemory == reinterpret_cast<DiscardVirtualMemoryFunction>(- 1))
258 discardVirtualMemory = reinterpret_cast<DiscardVirtualMemoryFunction>(Ge tProcAddress(GetModuleHandle(L"Kernel32.dll"), "DiscardVirtualMemory"));
259 // Use DiscardVirtualMemory when available because it releases faster than M EM_RESET.
260 DWORD ret = 1;
261 if (discardVirtualMemory)
262 ret = discardVirtualMemory(addr, len);
263 // DiscardVirtualMemory is buggy in Win10 SP0, so fall back to MEM_RESET on failure.
264 if (ret) {
265 void* ret = VirtualAlloc(addr, len, MEM_RESET, PAGE_READWRITE);
266 RELEASE_ASSERT(ret);
267 }
268 #endif
269 }
270
271 uint32_t getAllocPageErrorCode()
272 {
273 return allocPageErrorCode;
274 }
275
276 } // namespace WTF
277
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698