Build bmalloc on Mac
[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 <mach/vm_statistics.h>
35 #include <sys/mman.h>
36 #include <unistd.h>
37
38 namespace bmalloc {
39
40 #define BMALLOC_VM_TAG VM_MAKE_TAG(VM_MEMORY_TCMALLOC)
41     
42 static const size_t vmPageSize = 16 * kB; // Least upper bound of the OS's we support.
43 static const size_t vmPageMask = ~(vmPageSize - 1);
44     
45 inline size_t vmSize(size_t size)
46 {
47     return roundUpToMultipleOf<vmPageSize>(size);
48 }
49     
50 inline void vmValidate(size_t vmSize)
51 {
52     UNUSED(vmSize);
53     ASSERT(vmSize);
54     ASSERT(vmSize == bmalloc::vmSize(vmSize));
55 }
56
57 inline void vmValidate(void* p, size_t vmSize)
58 {
59     vmValidate(vmSize);
60     
61     // We use getpagesize() here instead of vmPageSize because vmPageSize is
62     // allowed to be larger than the OS's true page size.
63     UNUSED(p);
64     ASSERT(p);
65     ASSERT(p == mask(p, ~(getpagesize() - 1)));
66 }
67
68 inline void* vmAllocate(size_t vmSize)
69 {
70     vmValidate(vmSize);
71     return mmap(0, vmSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, BMALLOC_VM_TAG, 0);
72 }
73
74 inline void vmDeallocate(void* p, size_t vmSize)
75 {
76     vmValidate(p, vmSize);
77     munmap(p, vmSize);
78 }
79
80 // Allocates vmSize bytes at a specified offset from a power-of-two alignment.
81 // Use this function to create pointer masks that aren't simple powers of two.
82
83 inline std::pair<void*, Range> vmAllocate(size_t vmSize, size_t alignment, size_t offset)
84 {
85     vmValidate(vmSize);
86     ASSERT(isPowerOfTwo(alignment));
87
88     size_t mappedSize = std::max(vmSize, alignment) + alignment;
89     char* mapped = static_cast<char*>(vmAllocate(mappedSize));
90     
91     uintptr_t alignmentMask = alignment - 1;
92     if (!test(mapped, alignmentMask) && offset + vmSize <= alignment) {
93         // We got two perfectly aligned regions. Give one back to avoid wasting
94         // VM unnecessarily. This isn't costly because we aren't making holes.
95         vmDeallocate(mapped + alignment, alignment);
96         return std::make_pair(mapped + offset, Range(mapped, alignment));
97     }
98
99     // We got an unaligned region. Keep the whole thing to avoid creating holes,
100     // and hopefully realign the VM allocator for future allocations. On Darwin,
101     // VM holes trigger O(N^2) behavior in mmap, so we want to minimize them.
102     char* mappedAligned = mask(mapped, ~alignmentMask) + alignment;
103     return std::make_pair(mappedAligned + offset, Range(mapped, mappedSize));
104 }
105
106 inline void vmDeallocatePhysicalPages(void* p, size_t vmSize)
107 {
108     vmValidate(p, vmSize);
109     SYSCALL(madvise(p, vmSize, MADV_FREE_REUSABLE));
110 }
111
112 inline void vmAllocatePhysicalPages(void* p, size_t vmSize)
113 {
114     vmValidate(p, vmSize);
115     SYSCALL(madvise(p, vmSize, MADV_FREE_REUSE));
116 }
117
118 // Trims requests that are un-page-aligned. NOTE: size must be at least a page.
119 inline void vmDeallocatePhysicalPagesSloppy(void* p, size_t size)
120 {
121     ASSERT(size >= vmPageSize);
122
123     char* begin = roundUpToMultipleOf<vmPageSize>(static_cast<char*>(p));
124     char* end = roundDownToMultipleOf<vmPageSize>(static_cast<char*>(p) + size);
125
126     Range range(begin, end - begin);
127     if (!range)
128         return;
129     vmDeallocatePhysicalPages(range.begin(), range.size());
130 }
131
132 // Expands requests that are un-page-aligned. NOTE: Allocation must proceed left-to-right.
133 inline void vmAllocatePhysicalPagesSloppy(void* p, size_t size)
134 {
135     char* begin = roundUpToMultipleOf<vmPageSize>(static_cast<char*>(p));
136     char* end = roundUpToMultipleOf<vmPageSize>(static_cast<char*>(p) + size);
137
138     Range range(begin, end - begin);
139     if (!range)
140         return;
141     vmAllocatePhysicalPages(range.begin(), range.size());
142 }
143
144 } // namespace bmalloc
145
146 #endif // VMAllocate_h