20
20
#define HEADER_SIZE sizeof (BlockHeader)
21
21
#define FOOTER_SIZE sizeof (BlockFooter)
22
22
#define FREE_BLOCK_SIZE sizeof (FreeBlockNode)
23
- #define PAD_SIZE (size ) size + HEADER_SIZE + FOOTER_SIZE
23
+ #define METADATA_OVERHEAD HEADER_SIZE + FOOTER_SIZE
24
+ #define PAD_SIZE (size ) size + METADATA_OVERHEAD
24
25
25
26
#define FL_MIN_INDEX 4
26
27
#define MAX_SL_BUCKETS 16
@@ -36,64 +37,66 @@ namespace Siege
36
37
TlsfAllocator::TlsfAllocator () {}
37
38
38
39
TlsfAllocator::TlsfAllocator (const uint64_t size)
39
- : capacity {size}, bytesRemaining {size}
40
40
{
41
- if (size == 0 || size < MIN_ALLOCATION || size >= UINT64_MAX)
42
- {
43
- capacity = 0 ;
44
- bytesRemaining = 0 ;
41
+ uint64_t paddedSize = PAD_SIZE (size);
42
+ if (size == 0 || size < MIN_ALLOCATION || size > (UINT64_MAX - METADATA_OVERHEAD) || paddedSize < size)
45
43
return ;
46
- }
47
44
48
45
uint64_t maxBuckets = (FL (size) - FL_MIN_INDEX) + 1 ;
49
46
50
- uint64_t totalSize = PAD_SIZE (size);
51
47
uint64_t slBucketSize = sizeof (uint16_t ) * maxBuckets;
52
48
uint64_t freeListSize = maxBuckets * MAX_SL_BUCKETS * sizeof (FreeBlockNode*);
53
49
54
- uint64_t allocSize = totalSize + slBucketSize + freeListSize;
50
+ uint64_t allocSize = paddedSize + slBucketSize + freeListSize;
51
+
52
+ totalSize = paddedSize;
53
+ totalBytesRemaining = paddedSize;
54
+
55
+ capacity = size;
56
+ bytesRemaining = size;
55
57
56
58
data = TO_BYTES (calloc (1 , allocSize));
57
59
58
60
CC_ASSERT (data, " Allocation returned null. This should not happen and implies an implementation failure." )
59
61
60
- freeList = (FreeBlockNode**)(data + totalSize );
61
- slBitmasks = (uint16_t *)(data + totalSize + freeListSize);
62
+ freeList = (FreeBlockNode**)(data + paddedSize );
63
+ slBitmasks = (uint16_t *)(data + paddedSize + freeListSize);
62
64
63
- BlockHeader* firstHeader = CreateHeader (data, totalSize , FREE);
65
+ CreateHeader (data, paddedSize , FREE);
64
66
65
- AddNewBlock (totalSize, firstHeader );
67
+ AddNewBlock (paddedSize, TO_HEADER (data) );
66
68
}
67
69
68
- TlsfAllocator::BlockHeader* TlsfAllocator::CreateHeader (uint8_t * ptr, const uint64_t size,
70
+ void TlsfAllocator::CreateHeader (uint8_t * ptr, const uint64_t size,
69
71
HeaderFlags flags)
70
72
{
71
- if (!ptr) return nullptr ;
73
+ if (!ptr) return ;
72
74
BlockHeader* header = TO_HEADER (ptr);
73
75
header->sizeAndFlags = (size << FLAG_OFFSET) | flags;
74
- return header;
75
76
}
76
77
77
78
void * TlsfAllocator::Allocate (const uint64_t & size)
78
79
{
79
- size_t requiredSize = sizeof (BlockHeader) + size + sizeof (BlockFooter);
80
- if (!data || capacity == 0 ||size == 0 || requiredSize < size || requiredSize > bytesRemaining
81
- || requiredSize < MIN_ALLOCATION) return nullptr ;
80
+ uint64_t requiredSize = sizeof (BlockHeader) + size + sizeof (BlockFooter);
81
+ if (!data || capacity == 0 ||size == 0 || requiredSize < size || requiredSize > totalBytesRemaining
82
+ || size < MIN_ALLOCATION) return nullptr ;
82
83
83
84
FreeBlockNode* block = FindFreeBlock (requiredSize);
84
85
85
86
if (!block) return nullptr ;
86
87
87
88
BlockHeader* header = TrySplitBlock (block, requiredSize);
88
- header = CreateHeader (TO_BYTES (header), requiredSize, FULL);
89
- BlockFooter* footer = CreateFooter (TO_BYTES (GetFooter (header)) , requiredSize);
89
+
90
+ header->sizeAndFlags = (requiredSize << FLAG_OFFSET) | FULL;
91
+ CreateFooter (TO_BYTES (GetFooter (header)), requiredSize);
90
92
91
93
uint8_t * ptr = GetBlockData (header);
92
- bytesRemaining -= requiredSize;
94
+ bytesRemaining -= size;
95
+ totalBytesRemaining -= requiredSize;
93
96
return ptr;
94
97
}
95
98
96
- TlsfAllocator::BlockHeader* TlsfAllocator::TrySplitBlock (TlsfAllocator::FreeBlockNode* node, uint64_t allocatedSize)
99
+ TlsfAllocator::BlockHeader* TlsfAllocator::TrySplitBlock (TlsfAllocator::FreeBlockNode* node, uint64_t & allocatedSize)
97
100
{
98
101
if (!node) return nullptr ;
99
102
@@ -104,9 +107,15 @@ TlsfAllocator::BlockHeader* TlsfAllocator::TrySplitBlock(TlsfAllocator::FreeBloc
104
107
if (!RemoveFreeBlock (node)) return nullptr ;
105
108
106
109
if (oldSize <= allocatedSize || ((oldSize - allocatedSize) <
107
- (HEADER_SIZE + FREE_BLOCK_SIZE + FOOTER_SIZE))) return header;
110
+ (HEADER_SIZE + FREE_BLOCK_SIZE + FOOTER_SIZE)))
111
+ {
112
+ allocatedSize = oldSize;
113
+ return header;
114
+ }
115
+
116
+ BlockHeader* newFreeBlock = TO_HEADER (TO_BYTES (header) + allocatedSize);
108
117
109
- AddNewBlock (oldSize - allocatedSize, TO_HEADER ( TO_BYTES (header) + allocatedSize) );
118
+ AddNewBlock (oldSize - allocatedSize, newFreeBlock );
110
119
111
120
return header;
112
121
}
@@ -116,17 +125,39 @@ void TlsfAllocator::AddNewBlock(const uint64_t size, BlockHeader* header)
116
125
uint64_t fl = 0 ,sl = 0 , index;
117
126
index = CalculateFreeBlockIndices (size, fl, sl);
118
127
119
- BlockHeader* newHeader = CreateHeader (TO_BYTES (header), size, FREE);
120
- FreeBlockNode* node = CreateFreeBlock (TO_BYTES (GetFreeBlock (newHeader )), nullptr , freeList[index]);
121
- BlockFooter* footer = CreateFooter (TO_BYTES (GetFooter (newHeader )), size);
128
+ CreateHeader (TO_BYTES (header), size, FREE);
129
+ FreeBlockNode* node = CreateFreeBlock (TO_BYTES (GetFreeBlock (header )), nullptr , freeList[index]);
130
+ CreateFooter (TO_BYTES (GetFooter (header )), size);
122
131
123
- if (node->next ) node->next ->prev = node;
132
+ if (node && node ->next ) node->next ->prev = node;
124
133
125
134
freeList[index] = node;
126
135
flBitmask |= (1ULL << fl);
127
136
slBitmasks[fl] |= (1 << sl);
128
137
}
129
138
139
+ TlsfAllocator::BlockHeader* TlsfAllocator::TryCoalesce (BlockHeader* header, OUT uint64_t & size)
140
+ {
141
+ BlockHeader* start = header;
142
+ BlockHeader* prev = GetPrevHeader (start);
143
+ BlockHeader* next = GetNextHeader (header);
144
+
145
+ if (prev && IsFree (prev))
146
+ {
147
+ start = prev;
148
+ size += GetHeaderSize (prev);
149
+ RemoveFreeBlock (GetFreeBlock (prev));
150
+ }
151
+
152
+ if (next && IsFree (next))
153
+ {
154
+ size += GetHeaderSize (next);
155
+ RemoveFreeBlock (GetFreeBlock (next));
156
+ }
157
+
158
+ return start;
159
+ }
160
+
130
161
bool TlsfAllocator::RemoveFreeBlock (TlsfAllocator::FreeBlockNode* node)
131
162
{
132
163
BlockHeader* header = GetHeader (node);
@@ -156,6 +187,7 @@ bool TlsfAllocator::RemoveFreeBlock(TlsfAllocator::FreeBlockNode* node)
156
187
TlsfAllocator::FreeBlockNode* TlsfAllocator::FindFreeBlock (const uint64_t & size)
157
188
{
158
189
uint64_t fl, sl, index;
190
+ // 1000 0000 0000 1000
159
191
index = CalculateFreeBlockIndices (size, fl, sl);
160
192
161
193
if (!IsFree (fl, sl)) index = GetNextFreeSlotIndex (fl, sl);
@@ -171,7 +203,7 @@ const uint64_t TlsfAllocator::GetNextFreeSlotIndex(uint64_t& fl, uint64_t& sl)
171
203
if (sl == 32 ) sl = 0 ;
172
204
if (sl) return fl * MAX_SL_BUCKETS + sl;
173
205
174
- fl = flBitmask & ~(((1ULL << (sl + 1 )) - 1 ));
206
+ fl = flBitmask & ~(((1ULL << (fl + 1 )) - 1 ));
175
207
176
208
if (!fl) return INVALID_INDEX;
177
209
@@ -192,37 +224,54 @@ uint64_t TlsfAllocator::CalculateFreeBlockIndices(uint64_t size, OUT uint64_t &
192
224
return fl * MAX_SL_BUCKETS + sl;
193
225
}
194
226
195
- TlsfAllocator::BlockFooter* TlsfAllocator::CreateFooter (uint8_t * ptr, const uint64_t size)
227
+ void TlsfAllocator::CreateFooter (uint8_t * ptr, const uint64_t size)
196
228
{
197
- if (!ptr) return nullptr ;
229
+ if (!ptr) return ;
198
230
BlockFooter* footer = TO_FOOTER (ptr);
199
231
footer->totalBlockSize = size;
200
- return footer;
201
232
}
202
233
203
234
TlsfAllocator::BlockHeader* TlsfAllocator::GetHeader (TlsfAllocator::FreeBlockNode* node)
204
235
{
205
236
if (!node) return nullptr ;
206
- return TO_HEADER (TO_BYTES (node) - HEADER_SIZE);
237
+ uint8_t * rawHeader = TO_BYTES (node) - HEADER_SIZE;
238
+ if (!IsValid (rawHeader)) return nullptr ;
239
+ return TO_HEADER (rawHeader);
240
+ }
241
+
242
+ TlsfAllocator::BlockHeader* TlsfAllocator::GetHeader (uint8_t * ptr)
243
+ {
244
+ if (!ptr) return nullptr ;
245
+ uint8_t * rawHeader = ptr - HEADER_SIZE;
246
+ if (!IsValid (rawHeader)) return nullptr ;
247
+ return TO_HEADER (rawHeader);
207
248
}
208
249
209
250
TlsfAllocator::BlockHeader* TlsfAllocator::GetPrevHeader (TlsfAllocator::BlockHeader* header)
210
251
{
211
- if (!header || TO_BYTES (header) == data) return nullptr ;
212
- return TO_HEADER (TO_BYTES (header) - GetPrevFooter (header)->totalBlockSize );
252
+ if (!header) return nullptr ;
253
+ uint8_t * rawPrevFooter = TO_BYTES (GetPrevFooter (header));
254
+ if (!IsValid (rawPrevFooter)) return nullptr ;
255
+ uint8_t * prevHeader = (rawPrevFooter - TO_FOOTER (rawPrevFooter)->totalBlockSize ) + FOOTER_SIZE;
256
+ if (!IsValid (prevHeader)) return nullptr ;
257
+ return TO_HEADER (prevHeader);
213
258
}
214
259
215
260
TlsfAllocator::BlockHeader* TlsfAllocator::GetNextHeader (TlsfAllocator::BlockHeader* header)
216
261
{
217
262
if (!header) return nullptr ;
218
- return TO_HEADER (TO_BYTES (header) + GetHeaderSize (header));
263
+ uint8_t * rawHeader = TO_BYTES (header);
264
+ uint8_t * next = rawHeader + GetHeaderSize (header);
265
+ if (!IsValid (next)) return nullptr ;
266
+ return TO_HEADER (next);
219
267
}
220
268
221
269
TlsfAllocator::FreeBlockNode* TlsfAllocator::CreateFreeBlock (uint8_t * ptr,
222
270
TlsfAllocator::FreeBlockNode* prev,
223
271
TlsfAllocator::FreeBlockNode* next)
224
272
{
225
- if (!ptr) return nullptr ;
273
+ if (!IsValid (ptr)) return nullptr ;
274
+
226
275
FreeBlockNode* node = TO_FREE_BLOCK (ptr);
227
276
node->prev = prev;
228
277
node->next = next;
@@ -231,8 +280,10 @@ TlsfAllocator::FreeBlockNode* TlsfAllocator::CreateFreeBlock(uint8_t* ptr,
231
280
232
281
TlsfAllocator::FreeBlockNode* TlsfAllocator::GetFreeBlock (BlockHeader* header)
233
282
{
234
- if (!IsFree (header)) return nullptr ;
235
- return TO_FREE_BLOCK (TO_BYTES (header) + HEADER_SIZE);
283
+ if (!header || !IsFree (header)) return nullptr ;
284
+ uint8_t * rawBlock = TO_BYTES (header) + HEADER_SIZE;
285
+ if (!IsValid (rawBlock)) return nullptr ;
286
+ return TO_FREE_BLOCK (rawBlock);
236
287
}
237
288
238
289
TlsfAllocator::FreeBlockNode* TlsfAllocator::GetFreeBlock (const uint64_t fl, const uint64_t sl)
@@ -242,15 +293,19 @@ TlsfAllocator::FreeBlockNode* TlsfAllocator::GetFreeBlock(const uint64_t fl, con
242
293
243
294
TlsfAllocator::BlockFooter* TlsfAllocator::GetFooter (TlsfAllocator::BlockHeader* header)
244
295
{
296
+ if (!header) return nullptr ;
245
297
uint64_t size = GetHeaderSize (header);
246
- return TO_FOOTER (TO_BYTES (header) + (size - FOOTER_SIZE));
298
+ uint8_t * rawFooter = TO_BYTES (header) + (size - FOOTER_SIZE);
299
+ if (!rawFooter || !IsValid (rawFooter)) return nullptr ;
300
+ return TO_FOOTER (rawFooter);
247
301
}
248
302
249
303
TlsfAllocator::BlockFooter* TlsfAllocator::GetPrevFooter (TlsfAllocator::BlockHeader* header)
250
304
{
251
- uint8_t * raw = TO_BYTES (header);
252
- if (raw == data) return nullptr ;
253
- return TO_FOOTER (raw - FOOTER_SIZE);
305
+ if (!header) return nullptr ;
306
+ uint8_t * rawFooter = TO_BYTES (header) - FOOTER_SIZE;
307
+ if (!IsValid (rawFooter)) return nullptr ;
308
+ return TO_FOOTER (rawFooter);
254
309
}
255
310
256
311
uint8_t * TlsfAllocator::GetBlockData (TlsfAllocator::BlockHeader* header)
@@ -277,7 +332,23 @@ bool TlsfAllocator::PrevBlockIsFree(BlockHeader* header)
277
332
{
278
333
uint8_t * raw = TO_BYTES (header);
279
334
if (raw == data) return false ;
280
- return header && IsFree (TO_HEADER (raw - GetPrevFooter (header)->totalBlockSize ));
335
+
336
+ BlockFooter* prevFooter = GetPrevFooter (header);
337
+ if (!prevFooter) return false ;
338
+
339
+ uint8_t * rawPrevHeader = raw - (prevFooter->totalBlockSize - FOOTER_SIZE);
340
+ if (!rawPrevHeader || !IsValid (rawPrevHeader)) return false ;
341
+
342
+ return IsFree (TO_HEADER (rawPrevHeader));
281
343
}
282
344
345
+ bool TlsfAllocator::IsValid (uint8_t * ptr)
346
+ {
347
+ return ptr && ptr >= data && ptr < (data + (capacity + HEADER_SIZE + FOOTER_SIZE));
348
+ }
349
+
350
+ const uint64_t TlsfAllocator::Capacity () { return capacity; }
351
+
352
+ const uint64_t TlsfAllocator::BytesRemaining () { return bytesRemaining; }
353
+
283
354
} // namespace Siege
0 commit comments