bmalloc: Miscellaneous cleanup
[WebKit-https.git] / Source / bmalloc / bmalloc / LargeObject.h
1 /*
2  * Copyright (C) 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 LargeObject_h
27 #define LargeObject_h
28
29 #include "BeginTag.h"
30 #include "EndTag.h"
31 #include "LargeChunk.h"
32 #include "Range.h"
33
34 namespace bmalloc {
35
36 class LargeObject {
37 public:
38     static Range init(LargeChunk*);
39
40     LargeObject();
41     LargeObject(void*);
42
43     enum DoNotValidateTag { DoNotValidate };
44     LargeObject(DoNotValidateTag, void*);
45     
46     operator bool() { return !!*this; }
47     bool operator!() { return !m_object; }
48
49     char* begin() const { return static_cast<char*>(m_object); }
50     char* end() const { return begin() + size(); }
51     size_t size() const { return m_beginTag->size(); }
52     Range range() const { return Range(m_object, size()); }
53
54     void setFree(bool) const;
55     bool isFree() const;
56     
57     Owner owner() const;
58     void setOwner(Owner) const;
59     
60     bool isMarked() const;
61     void setMarked(bool) const;
62     
63     bool isValidAndFree(Owner, size_t) const;
64
65     LargeObject merge() const;
66     std::pair<LargeObject, LargeObject> split(size_t) const;
67
68 private:
69     LargeObject(BeginTag*, EndTag*, void*);
70
71     void validate() const;
72     void validateSelf() const;
73
74     BeginTag* m_beginTag;
75     EndTag* m_endTag;
76     void* m_object;
77 };
78
79 inline LargeObject::LargeObject()
80     : m_beginTag(nullptr)
81     , m_endTag(nullptr)
82     , m_object(nullptr)
83 {
84 }
85
86 inline LargeObject::LargeObject(void* object)
87     : m_beginTag(LargeChunk::beginTag(object))
88     , m_endTag(LargeChunk::endTag(object, m_beginTag->size()))
89     , m_object(object)
90 {
91     validate();
92 }
93
94 inline LargeObject::LargeObject(DoNotValidateTag, void* object)
95     : m_beginTag(LargeChunk::beginTag(object))
96     , m_endTag(LargeChunk::endTag(object, m_beginTag->size()))
97     , m_object(object)
98 {
99 }
100
101 inline LargeObject::LargeObject(BeginTag* beginTag, EndTag* endTag, void* object)
102     : m_beginTag(beginTag)
103     , m_endTag(endTag)
104     , m_object(object)
105 {
106 }
107
108 inline void LargeObject::setFree(bool isFree) const
109 {
110     validate();
111     m_beginTag->setFree(isFree);
112     m_endTag->setFree(isFree);
113 }
114
115 inline bool LargeObject::isFree() const
116 {
117     validate();
118     return m_beginTag->isFree();
119 }
120
121 inline Owner LargeObject::owner() const
122 {
123     validate();
124     return m_beginTag->owner();
125 }
126
127 inline void LargeObject::setOwner(Owner owner) const
128 {
129     validate();
130     m_beginTag->setOwner(owner);
131     m_endTag->setOwner(owner);
132 }
133
134 inline bool LargeObject::isMarked() const
135 {
136     validate();
137     return m_beginTag->isMarked();
138 }
139
140 inline void LargeObject::setMarked(bool isMarked) const
141 {
142     validate();
143     m_beginTag->setMarked(isMarked);
144     m_endTag->setMarked(isMarked);
145 }
146
147 inline bool LargeObject::isValidAndFree(Owner expectedOwner, size_t expectedSize) const
148 {
149     if (!m_beginTag->isFree())
150         return false;
151     
152     if (m_beginTag->isEnd())
153         return false;
154
155     if (m_beginTag->size() != expectedSize)
156         return false;
157     
158     if (m_beginTag->compactBegin() != BoundaryTag::compactBegin(m_object))
159         return false;
160
161     if (m_beginTag->owner() != expectedOwner)
162         return false;
163     
164     return true;
165 }
166
167 inline LargeObject LargeObject::merge() const
168 {
169     validate();
170     BASSERT(isFree());
171
172     BeginTag* beginTag = m_beginTag;
173     EndTag* endTag = m_endTag;
174     Range range = this->range();
175     Owner owner = this->owner();
176     
177     EndTag* prev = beginTag->prev();
178     if (prev->isFree() && prev->owner() == owner) {
179         Range left(range.begin() - prev->size(), prev->size());
180         range = Range(left.begin(), left.size() + range.size());
181
182         prev->clear();
183         beginTag->clear();
184
185         beginTag = LargeChunk::beginTag(range.begin());
186     }
187
188     BeginTag* next = endTag->next();
189     if (next->isFree() && next->owner() == owner) {
190         Range right(range.end(), next->size());
191         range = Range(range.begin(), range.size() + right.size());
192
193         endTag->clear();
194         next->clear();
195
196         endTag = LargeChunk::endTag(range.begin(), range.size());
197     }
198
199     beginTag->setRange(range);
200     beginTag->setFree(true);
201     beginTag->setOwner(owner);
202     endTag->init(beginTag);
203
204     return LargeObject(beginTag, endTag, range.begin());
205 }
206
207 inline std::pair<LargeObject, LargeObject> LargeObject::split(size_t size) const
208 {
209     BASSERT(isFree());
210
211     Range split(begin(), size);
212     Range leftover = Range(split.end(), this->size() - size);
213     BASSERT(leftover.size() >= largeMin);
214
215     BeginTag* splitBeginTag = m_beginTag;
216     EndTag* splitEndTag = LargeChunk::endTag(split.begin(), size);
217
218     BeginTag* leftoverBeginTag = LargeChunk::beginTag(leftover.begin());
219     EndTag* leftoverEndTag = m_endTag;
220
221     splitBeginTag->setRange(split);
222     splitEndTag->init(splitBeginTag);
223
224     *leftoverBeginTag = *splitBeginTag;
225     leftoverBeginTag->setRange(leftover);
226     leftoverEndTag->init(leftoverBeginTag);
227
228     return std::make_pair(
229         LargeObject(splitBeginTag, splitEndTag, split.begin()),
230         LargeObject(leftoverBeginTag, leftoverEndTag, leftover.begin()));
231 }
232
233 inline void LargeObject::validateSelf() const
234 {
235     BASSERT(!m_beginTag->isEnd());
236     BASSERT(m_endTag->isEnd() || static_cast<BoundaryTag*>(m_endTag) == static_cast<BoundaryTag*>(m_beginTag));
237
238     BASSERT(size() >= largeMin);
239
240     BASSERT(m_beginTag->size() == m_endTag->size());
241     BASSERT(m_beginTag->isFree() == m_endTag->isFree());
242     BASSERT(m_beginTag->owner() == m_endTag->owner());
243     BASSERT(m_beginTag->isMarked() == m_endTag->isMarked());
244 }
245
246 inline void LargeObject::validate() const
247 {
248     if (!m_beginTag->prev()->isSentinel()) {
249         LargeObject prev(DoNotValidate, begin() - m_beginTag->prev()->size());
250         prev.validateSelf();
251     }
252
253     validateSelf();
254
255     if (!m_endTag->next()->isSentinel()) {
256         LargeObject next(DoNotValidate, begin() + size());
257         next.validateSelf();
258     }
259 }
260
261 inline Range LargeObject::init(LargeChunk* chunk)
262 {
263     Range range(chunk->begin(), chunk->end() - chunk->begin());
264
265     BeginTag* beginTag = LargeChunk::beginTag(range.begin());
266     beginTag->setRange(range);
267     beginTag->setFree(true);
268     beginTag->setOwner(Owner::VMHeap);
269
270     EndTag* endTag = LargeChunk::endTag(range.begin(), range.size());
271     endTag->init(beginTag);
272
273     // Mark the left and right edges of our chunk as allocated. This naturally
274     // prevents merging logic from overflowing beyond our chunk, without requiring
275     // special-case checks.
276     
277     EndTag* leftSentinel = beginTag->prev();
278     BASSERT(leftSentinel >= static_cast<void*>(chunk));
279     leftSentinel->initSentinel();
280
281     BeginTag* rightSentinel = endTag->next();
282     BASSERT(rightSentinel < static_cast<void*>(range.begin()));
283     rightSentinel->initSentinel();
284     
285     return range;
286 }
287
288 } // namespace bmalloc
289
290 #endif // LargeObject_h