Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
headerless.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2010 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * (header-less) pool-based heap allocator
25  */
26 
27 #include "precompiled.h"
29 
30 #include "lib/bits.h"
31 #include "lib/allocators/pool.h"
32 
33 
34 static const bool performSanityChecks = true;
35 
36 // shared by Impl::Allocate and FreedBlock::Validate
37 static bool IsValidSize(size_t size);
38 
39 
40 //-----------------------------------------------------------------------------
41 
42 // this combines the boundary tags and link fields into one structure,
43 // which is safer than direct pointer arithmetic.
44 //
45 // it is written to freed memory, which is fine because IsValidSize ensures
46 // the allocations are large enough.
48 {
49  friend class RangeList; // manipulates link fields directly
50 
51 public:
52  // (required for RangeList::m_sentinel)
54  {
55  }
56 
57  FreedBlock(uintptr_t id, size_t size)
58  : m_magic(s_magic), m_size(size), m_id(id)
59  {
60  }
61 
63  {
64  // clear all fields to prevent accidental reuse
65  prev = next = 0;
66  m_id = 0;
67  m_size = ~size_t(0);
68  m_magic = 0;
69  }
70 
71  size_t Size() const
72  {
73  return m_size;
74  }
75 
76  /**
77  * @return whether this appears to be a FreedBlock instance with the
78  * desired ID. for additional safety, also call Validate().
79  **/
80  bool IsFreedBlock(uintptr_t id) const
81  {
82  if(m_id != id)
83  return false;
84  if(m_magic != s_magic)
85  return false;
86  return true;
87  }
88 
89  /**
90  * warn if any invariant doesn't hold.
91  **/
92  void Validate(uintptr_t id) const
93  {
94  if(!performSanityChecks) return;
95 
96  // note: RangeList::Validate implicitly checks the prev and next
97  // fields by iterating over the list.
98 
99  // note: we can't check for prev != next because we're called for
100  // footers as well, and they don't have valid pointers.
101 
103  ENSURE(IsFreedBlock(id));
104  }
105 
106 private:
107  // note: the magic and ID fields are stored at both ends of this
108  // class to increase the chance of detecting memory corruption.
109  static const u64 s_magic = 0xFF55AA00BBCCDDEEull;
111 
114 
115  // size [bytes] of the entire memory block, including header and footer
116  size_t m_size;
117 
118  // this differentiates between headers and footers.
119  uintptr_t m_id;
120 };
121 
122 
123 static bool IsValidSize(size_t size)
124 {
125  // note: we disallow the questionable practice of zero-byte allocations
126  // because they may be indicative of bugs.
128  return false;
129 
131  return false;
132 
133  return true;
134 }
135 
136 
137 //-----------------------------------------------------------------------------
138 // freelists
139 //-----------------------------------------------------------------------------
140 
141 // policy: address-ordered good fit
142 // mechanism: segregated range lists of power-of-two size classes
143 
145 {
146  static bool ShouldInsertBefore(FreedBlock* current, FreedBlock* successor)
147  {
148  return current < successor;
149  }
150 };
151 
152 // "range list" is a freelist of similarly-sized blocks.
154 {
155 public:
157  {
158  Reset();
159  }
160 
161  void Reset()
162  {
165  m_freeBlocks = 0;
166  m_freeBytes = 0;
167  }
168 
169  template<class InsertPolicy>
170  void Insert(FreedBlock* freedBlock)
171  {
172  // find freedBlock before which to insert
173  FreedBlock* successor;
174  for(successor = m_sentinel.next; successor != &m_sentinel; successor = successor->next)
175  {
176  if(InsertPolicy::ShouldInsertBefore(freedBlock, successor))
177  break;
178  }
179 
180  freedBlock->prev = successor->prev;
181  freedBlock->next = successor;
182  successor->prev->next = freedBlock;
183  successor->prev = freedBlock;
184 
185  m_freeBlocks++;
186  m_freeBytes += freedBlock->Size();
187  }
188 
189  /**
190  * @return the first freed block of size >= minSize or 0 if none exists.
191  **/
192  FreedBlock* Find(size_t minSize)
193  {
194  for(FreedBlock* freedBlock = m_sentinel.next; freedBlock != &m_sentinel; freedBlock = freedBlock->next)
195  {
196  if(freedBlock->Size() >= minSize)
197  return freedBlock;
198  }
199 
200  // none found, so average block size is less than the desired size
201  ENSURE(m_freeBytes/m_freeBlocks < minSize);
202  return 0;
203  }
204 
205  void Remove(FreedBlock* freedBlock)
206  {
207  freedBlock->next->prev = freedBlock->prev;
208  freedBlock->prev->next = freedBlock->next;
209 
210  ENSURE(m_freeBlocks != 0);
211  ENSURE(m_freeBytes >= freedBlock->Size());
212  m_freeBlocks--;
213  m_freeBytes -= freedBlock->Size();
214  }
215 
216  void Validate(uintptr_t id) const
217  {
218  if(!performSanityChecks) return;
219 
220  size_t freeBlocks = 0, freeBytes = 0;
221 
222  for(FreedBlock* freedBlock = m_sentinel.next; freedBlock != &m_sentinel; freedBlock = freedBlock->next)
223  {
224  freedBlock->Validate(id);
225  freeBlocks++;
226  freeBytes += freedBlock->Size();
227  }
228 
229  for(FreedBlock* freedBlock = m_sentinel.prev; freedBlock != &m_sentinel; freedBlock = freedBlock->prev)
230  {
231  freedBlock->Validate(id);
232  freeBlocks++;
233  freeBytes += freedBlock->Size();
234  }
235 
236  // our idea of the number and size of free blocks is correct
237  ENSURE(freeBlocks == m_freeBlocks*2 && freeBytes == m_freeBytes*2);
238  // if empty, state must be as established by Reset
240  }
241 
242  bool IsEmpty() const
243  {
244  return (m_freeBlocks == 0);
245  }
246 
247  size_t FreeBlocks() const
248  {
249  return m_freeBlocks;
250  }
251 
252  size_t FreeBytes() const
253  {
254  return m_freeBytes;
255  }
256 
257 private:
258  // a sentinel simplifies Insert and Remove. we store it here instead of
259  // in a separate array to improve locality (it is actually accessed).
261 
262  size_t m_freeBlocks;
263  size_t m_freeBytes;
264 };
265 
266 
267 //-----------------------------------------------------------------------------
268 
270 {
271 public:
273  {
274  Reset();
275  }
276 
277  void Reset()
278  {
279  m_bitmap = 0;
280  for(size_t i = 0; i < numRangeLists; i++)
281  m_rangeLists[i].Reset();
282  }
283 
284  void Insert(FreedBlock* freedBlock)
285  {
286  const size_t sizeClass = SizeClass(freedBlock->Size());
287  m_rangeLists[sizeClass].Insert<AddressOrder>(freedBlock);
288 
289  m_bitmap |= Bit<uintptr_t>(sizeClass);
290  }
291 
292  /**
293  * @return the first freed block of size >= minSize or 0 if none exists.
294  **/
295  FreedBlock* Find(size_t minSize)
296  {
297  // iterate over all large enough, non-empty size classes
298  // (zero overhead for empty size classes)
299  const size_t minSizeClass = SizeClass(minSize);
300  size_t sizeClassBits = m_bitmap & ((~size_t(0)) << minSizeClass);
301  while(sizeClassBits)
302  {
303  const size_t size = ValueOfLeastSignificantOneBit(sizeClassBits);
304  sizeClassBits &= ~size; // remove from sizeClassBits
305  const size_t sizeClass = SizeClass(size);
306 
307  FreedBlock* freedBlock = m_rangeLists[sizeClass].Find(minSize);
308  if(freedBlock)
309  return freedBlock;
310  }
311 
312  // apparently all classes above minSizeClass are empty,
313  // or the above would have succeeded.
314  ENSURE(m_bitmap < Bit<uintptr_t>(minSizeClass+1));
315  return 0;
316  }
317 
318  void Remove(FreedBlock* freedBlock)
319  {
320  const size_t sizeClass = SizeClass(freedBlock->Size());
321  m_rangeLists[sizeClass].Remove(freedBlock);
322 
323  // (masking with !IsEmpty() << sizeClass would probably be faster)
324  if(m_rangeLists[sizeClass].IsEmpty())
325  m_bitmap &= ~Bit<uintptr_t>(sizeClass);
326  }
327 
328  void Validate(uintptr_t id) const
329  {
330  for(size_t i = 0; i < numRangeLists; i++)
331  {
332  m_rangeLists[i].Validate(id);
333 
334  // both bitmap and list must agree on whether they are empty
335  ENSURE(((m_bitmap & Bit<uintptr_t>(i)) == 0) == m_rangeLists[i].IsEmpty());
336  }
337  }
338 
339  size_t FreeBlocks() const
340  {
341  size_t freeBlocks = 0;
342  for(size_t i = 0; i < numRangeLists; i++)
343  freeBlocks += m_rangeLists[i].FreeBlocks();
344  return freeBlocks;
345  }
346 
347  size_t FreeBytes() const
348  {
349  size_t freeBytes = 0;
350  for(size_t i = 0; i < numRangeLists; i++)
351  freeBytes += m_rangeLists[i].FreeBytes();
352  return freeBytes;
353  }
354 
355 private:
356  /**
357  * @return "size class" of a given size.
358  * class i > 0 contains blocks of size (2**(i-1), 2**i].
359  **/
360  static size_t SizeClass(size_t size)
361  {
362  return ceil_log2(size);
363  }
364 
365  static uintptr_t ValueOfLeastSignificantOneBit(uintptr_t x)
366  {
367  return (x & -(intptr_t)x);
368  }
369 
370  // segregated, i.e. one list per size class.
371  static const size_t numRangeLists = sizeof(uintptr_t)*CHAR_BIT;
373 
374  // bit i set <==> size class i's freelist is not empty.
375  // this allows finding a non-empty list in O(1).
376  uintptr_t m_bitmap;
377 };
378 
379 
380 //-----------------------------------------------------------------------------
381 // coalescing
382 //-----------------------------------------------------------------------------
383 
384 // policy: immediately coalesce
385 // mechanism: boundary tags
386 
387 // note: the id and magic values are all that differentiates tags from
388 // user data. this isn't 100% reliable, but as with headers, we don't want
389 // to insert extra boundary tags into the allocated memory.
390 
391 // note: footers consist of Tag{magic, ID, size}, while headers also
392 // need prev/next pointers. this could comfortably fit in 64 bytes,
393 // but we don't want to inherit headers from a base class because its
394 // prev/next pointers should reside between the magic and ID fields.
395 // maintaining separate FreedBlock and Footer classes is also undesirable;
396 // we prefer to use FreedBlock for both, which increases the minimum
397 // allocation size to 64 + allocationAlignment, e.g. 128.
398 // that's not a problem because the allocator is designed for
399 // returning pages or IO buffers (4..256 KB).
401 
402 
404 {
405 public:
407  : m_freeBlocks(0), m_freeBytes(0)
408  {
409  }
410 
411  FreedBlock* WriteTags(u8* p, size_t size)
412  {
413  FreedBlock* freedBlock = new(p) FreedBlock(s_headerId, size);
414  (void)new(Footer(freedBlock)) FreedBlock(s_footerId, size);
415 
416  m_freeBlocks++;
417  m_freeBytes += size;
418 
419  Validate(freedBlock);
420  return freedBlock;
421  }
422 
423  void RemoveTags(FreedBlock* freedBlock)
424  {
425  Validate(freedBlock);
426 
427  ENSURE(m_freeBlocks != 0);
428  ENSURE(m_freeBytes >= freedBlock->Size());
429  m_freeBlocks--;
430  m_freeBytes -= freedBlock->Size();
431 
432  FreedBlock* footer = Footer(freedBlock);
433  freedBlock->~FreedBlock();
434  footer->~FreedBlock();
435  }
436 
437  FreedBlock* PrecedingBlock(u8* p, u8* beginningOfPool) const
438  {
439  if(p == beginningOfPool) // avoid accessing invalid memory
440  return 0;
441 
442  FreedBlock* precedingBlock;
443  {
444  FreedBlock* const footer = (FreedBlock*)(p - sizeof(FreedBlock));
445  if(!footer->IsFreedBlock(s_footerId))
446  return 0;
447  footer->Validate(s_footerId);
448  precedingBlock = (FreedBlock*)(p - footer->Size());
449  }
450 
451  Validate(precedingBlock);
452  return precedingBlock;
453  }
454 
455  FreedBlock* FollowingBlock(u8* p, size_t size, u8* endOfPool) const
456  {
457  if(p+size == endOfPool) // avoid accessing invalid memory
458  return 0;
459 
460  FreedBlock* const followingBlock = (FreedBlock*)(p + size);
461  if(!followingBlock->IsFreedBlock(s_headerId))
462  return 0;
463 
464  Validate(followingBlock);
465  return followingBlock;
466  }
467 
468  size_t FreeBlocks() const
469  {
470  return m_freeBlocks;
471  }
472 
473  size_t FreeBytes() const
474  {
475  return m_freeBytes;
476  }
477 
478  // (generated via GUID)
479  static const uintptr_t s_headerId = 0x111E8E6Fu;
480  static const uintptr_t s_footerId = 0x4D745342u;
481 
482 private:
483  void Validate(FreedBlock* freedBlock) const
484  {
485  if(!performSanityChecks) return;
486 
487  // the existence of freedBlock means our bookkeeping better have
488  // records of at least that much memory.
489  ENSURE(m_freeBlocks != 0);
490  ENSURE(m_freeBytes >= freedBlock->Size());
491 
492  freedBlock->Validate(s_headerId);
493  Footer(freedBlock)->Validate(s_footerId);
494  }
495 
496  static FreedBlock* Footer(FreedBlock* freedBlock)
497  {
498  u8* const p = (u8*)freedBlock;
499  return (FreedBlock*)(p + freedBlock->Size() - sizeof(FreedBlock));
500  }
501 
502  size_t m_freeBlocks;
503  size_t m_freeBytes;
504 };
505 
506 
507 //-----------------------------------------------------------------------------
508 // stats
509 //-----------------------------------------------------------------------------
510 
511 class Stats
512 {
513 public:
514  void OnReset()
515  {
516  if(!performSanityChecks) return;
517 
522  }
523 
524  void OnAllocate(size_t size)
525  {
526  if(!performSanityChecks) return;
527 
529  m_totalAllocatedBytes += size;
530 
532  m_currentExtantBytes += size;
533  }
534 
535  void OnDeallocate(size_t size)
536  {
537  if(!performSanityChecks) return;
538 
540  m_totalDeallocatedBytes += size;
543 
545  ENSURE(m_currentExtantBytes >= size);
547  m_currentExtantBytes -= size;
548  }
549 
550  void OnAddToFreelist(size_t size)
551  {
553  m_currentFreeBytes += size;
554  }
555 
556  void OnRemoveFromFreelist(size_t size)
557  {
558  if(!performSanityChecks) return;
559 
561  ENSURE(m_currentFreeBytes >= size);
563  m_currentFreeBytes -= size;
564  }
565 
566  void Validate() const
567  {
568  if(!performSanityChecks) return;
569 
572 
575  }
576 
577  size_t FreeBlocks() const
578  {
579  return m_currentFreeBlocks;
580  }
581 
582  size_t FreeBytes() const
583  {
584  return m_currentFreeBytes;
585  }
586 
587 private:
592 };
593 
594 
595 //-----------------------------------------------------------------------------
596 // HeaderlessAllocator::Impl
597 //-----------------------------------------------------------------------------
598 
599 static void AssertEqual(size_t x1, size_t x2, size_t x3)
600 {
601  ENSURE(x1 == x2 && x2 == x3);
602 }
603 
605 {
606 public:
607  Impl(size_t poolSize)
608  {
609  (void)pool_create(&m_pool, poolSize, 0);
610 
611  Reset();
612  }
613 
615  {
616  Validate();
617 
618  (void)pool_destroy(&m_pool);
619  }
620 
621  void Reset()
622  {
625  m_stats.OnReset();
626 
627  Validate();
628  }
629 
630  NOTHROW_DEFINE void* Allocate(size_t size)
631  {
632  ENSURE(IsValidSize(size));
633  Validate();
634 
635  void* p = TakeAndSplitFreeBlock(size);
636  if(!p)
637  {
638  p = pool_alloc(&m_pool, size);
639  if(!p) // both failed; don't throw bad_alloc because
640  return 0; // this often happens with the file cache.
641  }
642 
643  // (NB: we must not update the statistics if allocation failed)
644  m_stats.OnAllocate(size);
645 
646  Validate();
647  ENSURE((uintptr_t)p % allocationAlignment == 0);
648  return p;
649  }
650 
651  void Deallocate(u8* p, size_t size)
652  {
653  ENSURE((uintptr_t)p % allocationAlignment == 0);
654  ENSURE(IsValidSize(size));
656  ENSURE(pool_contains(&m_pool, p+size-1));
657 
658  Validate();
659 
660  m_stats.OnDeallocate(size);
661  Coalesce(p, size);
662  AddToFreelist(p, size);
663 
664  Validate();
665  }
666 
667  void Validate() const
668  {
669  if(!performSanityChecks) return;
670 
672  m_stats.Validate();
673 
676  }
677 
678 private:
679  void AddToFreelist(u8* p, size_t size)
680  {
681  FreedBlock* freedBlock = m_boundaryTagManager.WriteTags(p, size);
682  m_segregatedRangeLists.Insert(freedBlock);
683  m_stats.OnAddToFreelist(size);
684  }
685 
686  void RemoveFromFreelist(FreedBlock* freedBlock)
687  {
688  m_stats.OnRemoveFromFreelist(freedBlock->Size());
689  m_segregatedRangeLists.Remove(freedBlock);
690  m_boundaryTagManager.RemoveTags(freedBlock);
691  }
692 
693  /**
694  * expand a block by coalescing it with its free neighbor(s).
695  **/
696  void Coalesce(u8*& p, size_t& size)
697  {
698  {
700  if(precedingBlock)
701  {
702  p -= precedingBlock->Size();
703  size += precedingBlock->Size();
704  RemoveFromFreelist(precedingBlock);
705  }
706  }
707 
708  {
710  if(followingBlock)
711  {
712  size += followingBlock->Size();
713  RemoveFromFreelist(followingBlock);
714  }
715  }
716  }
717 
718  void* TakeAndSplitFreeBlock(size_t size)
719  {
720  u8* p;
721  size_t leftoverSize = 0;
722  {
723  FreedBlock* freedBlock = m_segregatedRangeLists.Find(size);
724  if(!freedBlock)
725  return 0;
726 
727  p = (u8*)freedBlock;
728  leftoverSize = freedBlock->Size() - size;
729  RemoveFromFreelist(freedBlock);
730  }
731 
732  if(IsValidSize(leftoverSize))
733  AddToFreelist(p+size, leftoverSize);
734 
735  return p;
736  }
737 
742 };
743 
744 
745 //-----------------------------------------------------------------------------
746 
748  : impl(new Impl(poolSize))
749 {
750 }
751 
753 {
754  return impl->Reset();
755 }
756 
758 {
759  return impl->Allocate(size);
760 }
761 
762 void HeaderlessAllocator::Deallocate(void* p, size_t size)
763 {
764  return impl->Deallocate((u8*)p, size);
765 }
766 
768 {
769  return impl->Validate();
770 }
#define u8
Definition: types.h:39
uintptr_t m_id
Definition: headerless.cpp:119
void OnAddToFreelist(size_t size)
Definition: headerless.cpp:550
size_t FreeBytes() const
Definition: headerless.cpp:252
size_t m_freeBlocks
Definition: headerless.cpp:262
FreedBlock * next
Definition: headerless.cpp:113
shared_ptr< Impl > impl
Definition: headerless.h:95
size_t FreeBlocks() const
Definition: headerless.cpp:339
void Validate(uintptr_t id) const
Definition: headerless.cpp:216
void RemoveFromFreelist(FreedBlock *freedBlock)
Definition: headerless.cpp:686
SegregatedRangeLists m_segregatedRangeLists
Definition: headerless.cpp:739
void RemoveTags(FreedBlock *freedBlock)
Definition: headerless.cpp:423
#define NOTHROW_DEFINE
void * pool_alloc(Pool *p, size_t size)
Dole out memory from the pool.
Definition: pool.cpp:120
FreedBlock * PrecedingBlock(u8 *p, u8 *beginningOfPool) const
Definition: headerless.cpp:437
void Deallocate(u8 *p, size_t size)
Definition: headerless.cpp:651
void OnDeallocate(size_t size)
Definition: headerless.cpp:535
static const u64 s_magic
Definition: headerless.cpp:109
static const size_t allocationAlignment
Definition: headerless.h:56
void * TakeAndSplitFreeBlock(size_t size)
Definition: headerless.cpp:718
size_t m_freeBytes
Definition: headerless.cpp:263
u64 m_totalAllocatedBlocks
Definition: headerless.cpp:588
RangeList m_rangeLists[numRangeLists]
Definition: headerless.cpp:372
size_t FreeBlocks() const
Definition: headerless.cpp:247
static FreedBlock * Footer(FreedBlock *freedBlock)
Definition: headerless.cpp:496
void Insert(FreedBlock *freedBlock)
Definition: headerless.cpp:284
static bool IsValidSize(size_t size)
Definition: headerless.cpp:123
Status pool_create(Pool *p, size_t max_size, size_t el_size)
Ready Pool for use.
Definition: pool.cpp:86
size_t FreeBlocks() const
Definition: headerless.cpp:468
NOTHROW_DEFINE void * Allocate(size_t size)
Definition: headerless.cpp:630
static const uintptr_t s_footerId
Definition: headerless.cpp:480
void Reset()
restore the original state (as if newly constructed).
Definition: headerless.cpp:752
void AddToFreelist(u8 *p, size_t size)
Definition: headerless.cpp:679
void OnRemoveFromFreelist(size_t size)
Definition: headerless.cpp:556
void Reset()
Definition: headerless.cpp:161
void OnAllocate(size_t size)
Definition: headerless.cpp:524
void Remove(FreedBlock *freedBlock)
Definition: headerless.cpp:205
static bool ShouldInsertBefore(FreedBlock *current, FreedBlock *successor)
Definition: headerless.cpp:146
u64 m_currentExtantBytes
Definition: headerless.cpp:590
NOTHROW_DECLARE void * Allocate(size_t size)
Definition: headerless.cpp:757
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
FreedBlock m_sentinel
Definition: headerless.cpp:260
u64 m_totalAllocatedBytes
Definition: headerless.cpp:588
void Validate(uintptr_t id) const
warn if any invariant doesn&#39;t hold.
Definition: headerless.cpp:92
u8 * base
Definition: dynarray.h:41
void Validate(FreedBlock *freedBlock) const
Definition: headerless.cpp:483
static const size_t minAllocationSize
Definition: headerless.h:60
size_t FreeBlocks() const
Definition: headerless.cpp:577
size_t Size() const
Definition: headerless.cpp:71
void Validate() const
perform sanity checks; ensure allocator state is consistent.
Definition: headerless.cpp:767
bool IsFreedBlock(uintptr_t id) const
Definition: headerless.cpp:80
void Validate() const
Definition: headerless.cpp:566
size_t FreeBytes() const
Definition: headerless.cpp:473
static const size_t numRangeLists
Definition: headerless.cpp:371
allocator design parameters:
Definition: pool.h:114
void Insert(FreedBlock *freedBlock)
Definition: headerless.cpp:170
size_t pos
Definition: dynarray.h:46
Impl(size_t poolSize)
Definition: headerless.cpp:607
void Validate(uintptr_t id) const
Definition: headerless.cpp:328
FreedBlock * Find(size_t minSize)
Definition: headerless.cpp:295
void Coalesce(u8 *&p, size_t &size)
expand a block by coalescing it with its free neighbor(s).
Definition: headerless.cpp:696
DynArray da
Definition: pool.h:116
size_t FreeBytes() const
Definition: headerless.cpp:582
FreedBlock * Find(size_t minSize)
Definition: headerless.cpp:192
static size_t SizeClass(size_t size)
Definition: headerless.cpp:360
void OnReset()
Definition: headerless.cpp:514
#define u64
Definition: types.h:42
static const uintptr_t s_headerId
Definition: headerless.cpp:479
u64 m_currentExtantBlocks
Definition: headerless.cpp:590
void pool_free_all(Pool *p)
&quot;free&quot; all user allocations that ensued from the given Pool.
Definition: pool.cpp:164
size_t ceil_log2(T x)
ceil(log2(x))
Definition: bits.h:197
size_t FreeBytes() const
Definition: headerless.cpp:347
void Deallocate(void *p, size_t size)
deallocate memory.
Definition: headerless.cpp:762
static uintptr_t ValueOfLeastSignificantOneBit(uintptr_t x)
Definition: headerless.cpp:365
size_t m_size
Definition: headerless.cpp:116
FreedBlock(uintptr_t id, size_t size)
Definition: headerless.cpp:57
Status pool_destroy(Pool *p)
free all memory (address space + physical) that constitutes the given Pool.
Definition: pool.cpp:98
FreedBlock * prev
Definition: headerless.cpp:112
void Remove(FreedBlock *freedBlock)
Definition: headerless.cpp:318
u64 m_currentFreeBlocks
Definition: headerless.cpp:591
#define cassert(expr)
Compile-time assertion.
bool IsEmpty() const
Definition: headerless.cpp:242
static const bool performSanityChecks
Definition: headerless.cpp:34
static void AssertEqual(size_t x1, size_t x2, size_t x3)
Definition: headerless.cpp:599
u64 m_totalDeallocatedBytes
Definition: headerless.cpp:589
FreedBlock * WriteTags(u8 *p, size_t size)
Definition: headerless.cpp:411
FreedBlock * FollowingBlock(u8 *p, size_t size, u8 *endOfPool) const
Definition: headerless.cpp:455
u64 m_totalDeallocatedBlocks
Definition: headerless.cpp:589
HeaderlessAllocator(size_t poolSize)
Definition: headerless.cpp:747
bool pool_contains(const Pool *p, void *el)
indicate whether a pointer was allocated from the given pool.
Definition: pool.cpp:108
BoundaryTagManager m_boundaryTagManager
Definition: headerless.cpp:740
u64 m_currentFreeBytes
Definition: headerless.cpp:591