bmalloc
[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_mediumAllocator()
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     for (auto& allocator : m_smallAllocators)
55         log(allocator);
56     processSmallAllocatorLog();
57
58     log(m_mediumAllocator);
59     processMediumAllocatorLog();
60 }
61
62 void Allocator::log(SmallAllocator& allocator)
63 {
64     if (m_smallAllocatorLog.size() == m_smallAllocatorLog.capacity())
65         processSmallAllocatorLog();
66     
67     if (allocator.isNull())
68         return;
69
70     m_smallAllocatorLog.push(std::make_pair(allocator.line(), allocator.derefCount()));
71 }
72
73 void Allocator::processSmallAllocatorLog()
74 {
75     std::lock_guard<Mutex> lock(PerProcess<Heap>::mutex());
76
77     for (auto& logEntry : m_smallAllocatorLog) {
78         if (!logEntry.first->deref(logEntry.second))
79             continue;
80         m_deallocator.deallocateSmallLine(logEntry.first);
81     }
82     m_smallAllocatorLog.clear();
83 }
84
85 void Allocator::log(MediumAllocator& allocator)
86 {
87     if (m_mediumAllocatorLog.size() == m_mediumAllocatorLog.capacity())
88         processMediumAllocatorLog();
89
90     if (allocator.isNull())
91         return;
92
93     m_mediumAllocatorLog.push(std::make_pair(allocator.line(), allocator.derefCount()));
94 }
95
96 void Allocator::processMediumAllocatorLog()
97 {
98     std::lock_guard<Mutex> lock(PerProcess<Heap>::mutex());
99
100     for (auto& logEntry : m_mediumAllocatorLog) {
101         if (!logEntry.first->deref(logEntry.second))
102             continue;
103         m_deallocator.deallocateMediumLine(logEntry.first);
104     }
105     m_mediumAllocatorLog.clear();
106 }
107
108 void* Allocator::allocateLarge(size_t size)
109 {
110     size = roundUpToMultipleOf<largeAlignment>(size);
111     std::lock_guard<Mutex> lock(PerProcess<Heap>::mutex());
112     return PerProcess<Heap>::getFastCase()->allocateLarge(lock, size);
113 }
114
115 void* Allocator::allocateXLarge(size_t size)
116 {
117     size = roundUpToMultipleOf<largeAlignment>(size);
118     std::lock_guard<Mutex> lock(PerProcess<Heap>::mutex());
119     return PerProcess<Heap>::getFastCase()->allocateXLarge(lock, size);
120 }
121
122 void* Allocator::allocateMedium(size_t size)
123 {
124     MediumAllocator& allocator = m_mediumAllocator;
125     size = roundUpToMultipleOf<alignment>(size);
126
127     void* object;
128     if (allocator.allocate(size, object))
129         return object;
130
131     log(allocator);
132     allocator.refill(m_deallocator.allocateMediumLine());
133     return allocator.allocate(size);
134 }
135
136 void* Allocator::allocateSlowCase(size_t size)
137 {
138 IF_DEBUG(
139     void* dummy;
140     ASSERT(!allocateFastCase(size, dummy));
141 )
142     if (size <= smallMax) {
143         SmallAllocator& allocator = smallAllocatorFor(size);
144         log(allocator);
145         allocator.refill(m_deallocator.allocateSmallLine());
146         return allocator.allocate();
147     }
148
149     if (size <= mediumMax)
150         return allocateMedium(size);
151     
152     if (size <= largeMax)
153         return allocateLarge(size);
154
155     return allocateXLarge(size);
156 }
157
158 } // namespace bmalloc