Skip to content

Commit d03108a

Browse files
committed
Fixed broken unit tests
1 parent 7ade793 commit d03108a

File tree

3 files changed

+509
-55
lines changed

3 files changed

+509
-55
lines changed

engine/utils/TlsfAllocator.cpp

Lines changed: 116 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
#define HEADER_SIZE sizeof(BlockHeader)
2121
#define FOOTER_SIZE sizeof(BlockFooter)
2222
#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
2425

2526
#define FL_MIN_INDEX 4
2627
#define MAX_SL_BUCKETS 16
@@ -36,64 +37,66 @@ namespace Siege
3637
TlsfAllocator::TlsfAllocator() {}
3738

3839
TlsfAllocator::TlsfAllocator(const uint64_t size)
39-
: capacity {size}, bytesRemaining {size}
4040
{
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)
4543
return;
46-
}
4744

4845
uint64_t maxBuckets = (FL(size) - FL_MIN_INDEX) + 1;
4946

50-
uint64_t totalSize = PAD_SIZE(size);
5147
uint64_t slBucketSize = sizeof(uint16_t) * maxBuckets;
5248
uint64_t freeListSize = maxBuckets * MAX_SL_BUCKETS * sizeof(FreeBlockNode*);
5349

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;
5557

5658
data = TO_BYTES(calloc(1, allocSize));
5759

5860
CC_ASSERT(data, "Allocation returned null. This should not happen and implies an implementation failure.")
5961

60-
freeList = (FreeBlockNode**)(data + totalSize);
61-
slBitmasks = (uint16_t*)(data + totalSize + freeListSize);
62+
freeList = (FreeBlockNode**)(data + paddedSize);
63+
slBitmasks = (uint16_t*)(data + paddedSize + freeListSize);
6264

63-
BlockHeader* firstHeader = CreateHeader(data, totalSize, FREE);
65+
CreateHeader(data, paddedSize, FREE);
6466

65-
AddNewBlock(totalSize, firstHeader);
67+
AddNewBlock(paddedSize, TO_HEADER(data));
6668
}
6769

68-
TlsfAllocator::BlockHeader* TlsfAllocator::CreateHeader(uint8_t* ptr, const uint64_t size,
70+
void TlsfAllocator::CreateHeader(uint8_t* ptr, const uint64_t size,
6971
HeaderFlags flags)
7072
{
71-
if (!ptr) return nullptr;
73+
if (!ptr) return;
7274
BlockHeader* header = TO_HEADER(ptr);
7375
header->sizeAndFlags = (size << FLAG_OFFSET) | flags;
74-
return header;
7576
}
7677

7778
void* TlsfAllocator::Allocate(const uint64_t& size)
7879
{
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;
8283

8384
FreeBlockNode* block = FindFreeBlock(requiredSize);
8485

8586
if (!block) return nullptr;
8687

8788
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);
9092

9193
uint8_t* ptr = GetBlockData(header);
92-
bytesRemaining -= requiredSize;
94+
bytesRemaining -= size;
95+
totalBytesRemaining -= requiredSize;
9396
return ptr;
9497
}
9598

96-
TlsfAllocator::BlockHeader* TlsfAllocator::TrySplitBlock(TlsfAllocator::FreeBlockNode* node, uint64_t allocatedSize)
99+
TlsfAllocator::BlockHeader* TlsfAllocator::TrySplitBlock(TlsfAllocator::FreeBlockNode* node, uint64_t& allocatedSize)
97100
{
98101
if (!node) return nullptr;
99102

@@ -104,9 +107,15 @@ TlsfAllocator::BlockHeader* TlsfAllocator::TrySplitBlock(TlsfAllocator::FreeBloc
104107
if (!RemoveFreeBlock(node)) return nullptr;
105108

106109
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);
108117

109-
AddNewBlock(oldSize - allocatedSize, TO_HEADER(TO_BYTES(header) + allocatedSize));
118+
AddNewBlock(oldSize - allocatedSize, newFreeBlock);
110119

111120
return header;
112121
}
@@ -116,17 +125,39 @@ void TlsfAllocator::AddNewBlock(const uint64_t size, BlockHeader* header)
116125
uint64_t fl = 0,sl = 0, index;
117126
index = CalculateFreeBlockIndices(size, fl, sl);
118127

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);
122131

123-
if (node->next) node->next->prev = node;
132+
if (node && node->next) node->next->prev = node;
124133

125134
freeList[index] = node;
126135
flBitmask |= (1ULL << fl);
127136
slBitmasks[fl] |= (1 << sl);
128137
}
129138

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+
130161
bool TlsfAllocator::RemoveFreeBlock(TlsfAllocator::FreeBlockNode* node)
131162
{
132163
BlockHeader* header = GetHeader(node);
@@ -156,6 +187,7 @@ bool TlsfAllocator::RemoveFreeBlock(TlsfAllocator::FreeBlockNode* node)
156187
TlsfAllocator::FreeBlockNode* TlsfAllocator::FindFreeBlock(const uint64_t& size)
157188
{
158189
uint64_t fl, sl, index;
190+
// 1000 0000 0000 1000
159191
index = CalculateFreeBlockIndices(size, fl, sl);
160192

161193
if (!IsFree(fl, sl)) index = GetNextFreeSlotIndex(fl, sl);
@@ -171,7 +203,7 @@ const uint64_t TlsfAllocator::GetNextFreeSlotIndex(uint64_t& fl, uint64_t& sl)
171203
if (sl == 32) sl = 0;
172204
if (sl) return fl * MAX_SL_BUCKETS + sl;
173205

174-
fl = flBitmask & ~(((1ULL << (sl + 1)) - 1));
206+
fl = flBitmask & ~(((1ULL << (fl + 1)) - 1));
175207

176208
if (!fl) return INVALID_INDEX;
177209

@@ -192,37 +224,54 @@ uint64_t TlsfAllocator::CalculateFreeBlockIndices(uint64_t size, OUT uint64_t &
192224
return fl * MAX_SL_BUCKETS + sl;
193225
}
194226

195-
TlsfAllocator::BlockFooter* TlsfAllocator::CreateFooter(uint8_t* ptr, const uint64_t size)
227+
void TlsfAllocator::CreateFooter(uint8_t* ptr, const uint64_t size)
196228
{
197-
if (!ptr) return nullptr;
229+
if (!ptr) return;
198230
BlockFooter* footer = TO_FOOTER(ptr);
199231
footer->totalBlockSize = size;
200-
return footer;
201232
}
202233

203234
TlsfAllocator::BlockHeader* TlsfAllocator::GetHeader(TlsfAllocator::FreeBlockNode* node)
204235
{
205236
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);
207248
}
208249

209250
TlsfAllocator::BlockHeader* TlsfAllocator::GetPrevHeader(TlsfAllocator::BlockHeader* header)
210251
{
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);
213258
}
214259

215260
TlsfAllocator::BlockHeader* TlsfAllocator::GetNextHeader(TlsfAllocator::BlockHeader* header)
216261
{
217262
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);
219267
}
220268

221269
TlsfAllocator::FreeBlockNode* TlsfAllocator::CreateFreeBlock(uint8_t* ptr,
222270
TlsfAllocator::FreeBlockNode* prev,
223271
TlsfAllocator::FreeBlockNode* next)
224272
{
225-
if (!ptr) return nullptr;
273+
if (!IsValid(ptr)) return nullptr;
274+
226275
FreeBlockNode* node = TO_FREE_BLOCK(ptr);
227276
node->prev = prev;
228277
node->next = next;
@@ -231,8 +280,10 @@ TlsfAllocator::FreeBlockNode* TlsfAllocator::CreateFreeBlock(uint8_t* ptr,
231280

232281
TlsfAllocator::FreeBlockNode* TlsfAllocator::GetFreeBlock(BlockHeader* header)
233282
{
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);
236287
}
237288

238289
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
242293

243294
TlsfAllocator::BlockFooter* TlsfAllocator::GetFooter(TlsfAllocator::BlockHeader* header)
244295
{
296+
if (!header) return nullptr;
245297
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);
247301
}
248302

249303
TlsfAllocator::BlockFooter* TlsfAllocator::GetPrevFooter(TlsfAllocator::BlockHeader* header)
250304
{
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);
254309
}
255310

256311
uint8_t* TlsfAllocator::GetBlockData(TlsfAllocator::BlockHeader* header)
@@ -277,7 +332,23 @@ bool TlsfAllocator::PrevBlockIsFree(BlockHeader* header)
277332
{
278333
uint8_t* raw = TO_BYTES(header);
279334
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));
281343
}
282344

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+
283354
} // namespace Siege

engine/utils/TlsfAllocator.h

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ class TlsfAllocator
5353

5454
// Other functions
5555

56-
BlockHeader* CreateHeader(uint8_t* ptr, const uint64_t size, HeaderFlags flags);
57-
BlockFooter* CreateFooter(uint8_t* ptr, const uint64_t size);
56+
void CreateHeader(uint8_t* ptr, const uint64_t size, HeaderFlags flags);
57+
void CreateFooter(uint8_t* ptr, const uint64_t size);
5858
FreeBlockNode* CreateFreeBlock(uint8_t* ptr, FreeBlockNode* prev, FreeBlockNode* next);
5959
FreeBlockNode* FindFreeBlock(const uint64_t& size);
6060

@@ -72,25 +72,68 @@ class TlsfAllocator
7272
BlockFooter* GetFooter(BlockHeader* header);
7373
BlockFooter* GetPrevFooter(BlockHeader* header);
7474
BlockHeader* GetHeader(FreeBlockNode* node);
75+
BlockHeader* GetHeader(uint8_t* ptr);
7576
BlockHeader* GetPrevHeader(BlockHeader* header);
7677
BlockHeader* GetNextHeader(BlockHeader* header);
7778

7879
// Allocate/Deallocate
7980

8081
void* Allocate(const uint64_t& size);
81-
BlockHeader* TrySplitBlock(FreeBlockNode* node, uint64_t allocatedSize);
82+
83+
template<typename T>
84+
void Deallocate(T*& ptr)
85+
{
86+
uint8_t* raw = (uint8_t*)ptr;
87+
if (!raw) return;
88+
if (raw < data || raw >= (data + capacity)) return;
89+
90+
BlockHeader* header = GetHeader(raw);
91+
92+
if (IsFree(header)) return;
93+
94+
uint64_t blockSize = GetHeaderSize(header);
95+
96+
uint64_t totalBlockSize = blockSize;
97+
header = TryCoalesce(header, totalBlockSize);
98+
BlockFooter* footer = GetFooter(header);
99+
100+
header->sizeAndFlags = (totalBlockSize << 3) | (header->sizeAndFlags & PREV_IS_FREE) | FREE;
101+
footer->totalBlockSize = totalBlockSize;
102+
103+
BlockHeader* nextHeader = GetNextHeader(header);
104+
105+
if (nextHeader && ((uint8_t*)nextHeader < (data + capacity)))
106+
{
107+
nextHeader->sizeAndFlags |= PREV_IS_FREE;
108+
}
109+
110+
AddNewBlock(totalBlockSize, header);
111+
112+
bytesRemaining += blockSize - sizeof(BlockHeader) - sizeof(BlockFooter);
113+
totalBytesRemaining += blockSize;
114+
115+
ptr = nullptr;
116+
}
117+
BlockHeader* TrySplitBlock(FreeBlockNode* node, uint64_t& allocatedSize);
82118
bool RemoveFreeBlock(FreeBlockNode* node);
83119
void AddNewBlock(const uint64_t size, BlockHeader* currentNode);
120+
BlockHeader* TryCoalesce(BlockHeader* header, OUT uint64_t& size);
84121

85122
// Getters
86123

124+
bool IsValid(uint8_t* ptr);
87125
const uint64_t GetHeaderSize(BlockHeader* header);
88-
const uint64_t Capacity() { return capacity; }
89-
const uint64_t BytesRemaining() { return bytesRemaining; }
126+
const uint64_t Capacity();
127+
const uint64_t BytesRemaining();
128+
const uint64_t TotalBytesRemaining() { return totalBytesRemaining; }
129+
const uint64_t TotalSize() { return totalSize; }
90130
const uint8_t* Data() { return data; }
91131
const uint64_t FlBitmask() { return flBitmask; }
92132
const uint16_t& SlBitmask(const uint64_t fl) { return slBitmasks[fl]; }
93133
private:
134+
uint64_t totalSize {0};
135+
uint64_t totalBytesRemaining {0};
136+
94137
uint64_t capacity {0};
95138
uint64_t bytesRemaining {0};
96139

0 commit comments

Comments
 (0)