bmalloc: Pathological madvise churn on the free(malloc(x)) benchmark
[WebKit-https.git] / Source / bmalloc / bmalloc / VMHeap.h
1 /*
2  * Copyright (C) 2014, 2015 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 VMHeap_h
27 #define VMHeap_h
28
29 #include "AsyncTask.h"
30 #include "FixedVector.h"
31 #include "LargeChunk.h"
32 #include "LargeObject.h"
33 #include "MediumChunk.h"
34 #include "Range.h"
35 #include "SegregatedFreeList.h"
36 #include "SmallChunk.h"
37 #include "Vector.h"
38 #if BPLATFORM(DARWIN)
39 #include "Zone.h"
40 #endif
41
42 namespace bmalloc {
43
44 class BeginTag;
45 class EndTag;
46 class Heap;
47 class SuperChunk;
48
49 class VMHeap {
50 public:
51     VMHeap();
52
53     SmallPage* allocateSmallPage();
54     MediumPage* allocateMediumPage();
55     LargeObject allocateLargeObject(size_t);
56     LargeObject allocateLargeObject(size_t alignment, size_t, size_t unalignedSize);
57
58     void deallocateSmallPage(std::unique_lock<StaticMutex>&, SmallPage*);
59     void deallocateMediumPage(std::unique_lock<StaticMutex>&, MediumPage*);
60     void deallocateLargeObject(std::unique_lock<StaticMutex>&, LargeObject&);
61
62 private:
63     LargeObject allocateLargeObject(LargeObject&, size_t);
64     void grow();
65
66     Vector<SmallPage*> m_smallPages;
67     Vector<MediumPage*> m_mediumPages;
68     SegregatedFreeList m_largeObjects;
69 #if BPLATFORM(DARWIN)
70     Zone m_zone;
71 #endif
72 };
73
74 inline SmallPage* VMHeap::allocateSmallPage()
75 {
76     if (!m_smallPages.size())
77         grow();
78
79     SmallPage* page = m_smallPages.pop();
80     vmAllocatePhysicalPages(page->begin()->begin(), vmPageSize);
81     return page;
82 }
83
84 inline MediumPage* VMHeap::allocateMediumPage()
85 {
86     if (!m_mediumPages.size())
87         grow();
88
89     MediumPage* page = m_mediumPages.pop();
90     vmAllocatePhysicalPages(page->begin()->begin(), vmPageSize);
91     return page;
92 }
93
94 inline LargeObject VMHeap::allocateLargeObject(LargeObject& largeObject, size_t size)
95 {
96     BASSERT(largeObject.isFree());
97
98     if (largeObject.size() - size > largeMin) {
99         std::pair<LargeObject, LargeObject> split = largeObject.split(size);
100         largeObject = split.first;
101         m_largeObjects.insert(split.second);
102     }
103
104     vmAllocatePhysicalPagesSloppy(largeObject.begin(), largeObject.size());
105     largeObject.setOwner(Owner::Heap);
106     return largeObject.begin();
107 }
108
109 inline LargeObject VMHeap::allocateLargeObject(size_t size)
110 {
111     LargeObject largeObject = m_largeObjects.take(size);
112     if (!largeObject) {
113         grow();
114         largeObject = m_largeObjects.take(size);
115         BASSERT(largeObject);
116     }
117
118     return allocateLargeObject(largeObject, size);
119 }
120
121 inline LargeObject VMHeap::allocateLargeObject(size_t alignment, size_t size, size_t unalignedSize)
122 {
123     LargeObject largeObject = m_largeObjects.take(alignment, size, unalignedSize);
124     if (!largeObject) {
125         grow();
126         largeObject = m_largeObjects.take(alignment, size, unalignedSize);
127         BASSERT(largeObject);
128     }
129
130     size_t alignmentMask = alignment - 1;
131     if (test(largeObject.begin(), alignmentMask))
132         return allocateLargeObject(largeObject, unalignedSize);
133     return allocateLargeObject(largeObject, size);
134 }
135
136 inline void VMHeap::deallocateSmallPage(std::unique_lock<StaticMutex>& lock, SmallPage* page)
137 {
138     lock.unlock();
139     vmDeallocatePhysicalPages(page->begin()->begin(), vmPageSize);
140     lock.lock();
141     
142     m_smallPages.push(page);
143 }
144
145 inline void VMHeap::deallocateMediumPage(std::unique_lock<StaticMutex>& lock, MediumPage* page)
146 {
147     lock.unlock();
148     vmDeallocatePhysicalPages(page->begin()->begin(), vmPageSize);
149     lock.lock();
150     
151     m_mediumPages.push(page);
152 }
153
154 inline void VMHeap::deallocateLargeObject(std::unique_lock<StaticMutex>& lock, LargeObject& largeObject)
155 {
156     largeObject.setOwner(Owner::VMHeap);
157     
158     // If we couldn't merge with our neighbors before because they were in the
159     // VM heap, we can merge with them now.
160     LargeObject merged = largeObject.merge();
161
162     // Temporarily mark this object as allocated to prevent clients from merging
163     // with it or allocating it while we're messing with its physical pages.
164     merged.setFree(false);
165
166     lock.unlock();
167     vmDeallocatePhysicalPagesSloppy(merged.begin(), merged.size());
168     lock.lock();
169
170     merged.setFree(true);
171
172     m_largeObjects.insert(merged);
173 }
174
175 } // namespace bmalloc
176
177 #endif // VMHeap_h