78a29324695bcdaa44c499c2426fd257a2e2e7b2
[WebKit-https.git] / Source / bmalloc / bmalloc / Allocator.cpp
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 #include "Allocator.h"
27 #include "BAssert.h"
28 #include "Deallocator.h"
29 #include "Heap.h"
30 #include "PerProcess.h"
31 #include "Sizes.h"
32 #include <algorithm>
33
34 using namespace std;
35
36 namespace bmalloc {
37
38 Allocator::Allocator(Deallocator& deallocator)
39     : m_deallocator(deallocator)
40     , m_smallAllocators()
41     , m_mediumAllocators()
42     , m_smallAllocatorLog()
43     , m_mediumAllocatorLog()
44 {
45     unsigned short size = alignment;
46     for (auto& allocator : m_smallAllocators) {
47         allocator = SmallAllocator(size);
48         size += alignment;
49     }
50 }
51
52 Allocator::~Allocator()
53 {
54     scavenge();
55 }
56
57 void Allocator::scavenge()
58 {
59     for (auto& allocator : m_smallAllocators) {
60         retire(allocator);
61         allocator.clear();
62     }
63     processSmallAllocatorLog();
64
65     for (auto& allocator : m_mediumAllocators) {
66         retire(allocator);
67         allocator.clear();
68     }
69     processMediumAllocatorLog();
70 }
71
72 void Allocator::retire(SmallAllocator& allocator)
73 {
74     if (m_smallAllocatorLog.size() == m_smallAllocatorLog.capacity())
75         processSmallAllocatorLog();
76     
77     if (allocator.isNull())
78         return;
79
80     m_smallAllocatorLog.push(std::make_pair(allocator.line(), allocator.derefCount()));
81 }
82
83 void Allocator::processSmallAllocatorLog()
84 {
85     std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex());
86
87     for (auto& logEntry : m_smallAllocatorLog) {
88         if (!logEntry.first->deref(lock, logEntry.second))
89             continue;
90         m_deallocator.deallocateSmallLine(lock, logEntry.first);
91     }
92     m_smallAllocatorLog.clear();
93 }
94
95 void Allocator::retire(MediumAllocator& allocator)
96 {
97     if (m_mediumAllocatorLog.size() == m_mediumAllocatorLog.capacity())
98         processMediumAllocatorLog();
99
100     if (allocator.isNull())
101         return;
102
103     m_mediumAllocatorLog.push(std::make_pair(allocator.line(), allocator.derefCount()));
104 }
105
106 void Allocator::processMediumAllocatorLog()
107 {
108     std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex());
109
110     for (auto& logEntry : m_mediumAllocatorLog) {
111         if (!logEntry.first->deref(lock, logEntry.second))
112             continue;
113         m_deallocator.deallocateMediumLine(lock, logEntry.first);
114     }
115     m_mediumAllocatorLog.clear();
116 }
117
118 void* Allocator::allocateLarge(size_t size)
119 {
120     size = roundUpToMultipleOf<largeAlignment>(size);
121     std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex());
122     return PerProcess<Heap>::getFastCase()->allocateLarge(lock, size);
123 }
124
125 void* Allocator::allocateXLarge(size_t size)
126 {
127     size = roundUpToMultipleOf<largeAlignment>(size);
128     std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex());
129     return PerProcess<Heap>::getFastCase()->allocateXLarge(lock, size);
130 }
131
132 void* Allocator::allocateMedium(size_t size)
133 {
134     MediumAllocator& allocator = m_mediumAllocators[mediumSizeClassFor(size)];
135     size = roundUpToMultipleOf<alignment>(size);
136
137     void* object;
138     if (allocator.allocate(size, object))
139         return object;
140
141     retire(allocator);
142     allocator.refill(m_deallocator.allocateMediumLine());
143     return allocator.allocate(size);
144 }
145
146 void* Allocator::allocateSlowCase(size_t size)
147 {
148 IF_DEBUG(
149     void* dummy;
150     BASSERT(!allocateFastCase(size, dummy));
151 )
152     if (size <= smallMax) {
153         size_t smallSizeClass = smallSizeClassFor(size);
154         SmallAllocator& allocator = m_smallAllocators[smallSizeClass];
155         retire(allocator);
156         allocator.refill(m_deallocator.allocateSmallLine(smallSizeClass));
157         return allocator.allocate();
158     }
159
160     if (size <= mediumMax)
161         return allocateMedium(size);
162     
163     if (size <= largeMax)
164         return allocateLarge(size);
165
166     return allocateXLarge(size);
167 }
168
169 } // namespace bmalloc