1 //===--- Allocator.cpp - Simple memory allocation abstraction -------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the BumpPtrAllocator interface.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Support/Allocator.h"
15 #include "llvm/Support/DataTypes.h"
16 #include "llvm/Support/Recycler.h"
17 #include "llvm/Support/raw_ostream.h"
18 #include "llvm/Support/Memory.h"
23 BumpPtrAllocator::BumpPtrAllocator(size_t size
, size_t threshold
,
24 SlabAllocator
&allocator
)
25 : SlabSize(size
), SizeThreshold(threshold
), Allocator(allocator
),
26 CurSlab(0), BytesAllocated(0) { }
28 BumpPtrAllocator::~BumpPtrAllocator() {
29 DeallocateSlabs(CurSlab
);
32 /// AlignPtr - Align Ptr to Alignment bytes, rounding up. Alignment should
33 /// be a power of two. This method rounds up, so AlignPtr(7, 4) == 8 and
34 /// AlignPtr(8, 4) == 8.
35 char *BumpPtrAllocator::AlignPtr(char *Ptr
, size_t Alignment
) {
36 assert(Alignment
&& (Alignment
& (Alignment
- 1)) == 0 &&
37 "Alignment is not a power of two!");
40 return (char*)(((uintptr_t)Ptr
+ Alignment
- 1) &
41 ~(uintptr_t)(Alignment
- 1));
44 /// StartNewSlab - Allocate a new slab and move the bump pointers over into
45 /// the new slab. Modifies CurPtr and End.
46 void BumpPtrAllocator::StartNewSlab() {
47 // If we allocated a big number of slabs already it's likely that we're going
48 // to allocate more. Increase slab size to reduce mallocs and possibly memory
49 // overhead. The factors are chosen conservatively to avoid overallocation.
50 if (BytesAllocated
>= SlabSize
* 128)
53 MemSlab
*NewSlab
= Allocator
.Allocate(SlabSize
);
54 NewSlab
->NextPtr
= CurSlab
;
56 CurPtr
= (char*)(CurSlab
+ 1);
57 End
= ((char*)CurSlab
) + CurSlab
->Size
;
60 /// DeallocateSlabs - Deallocate all memory slabs after and including this
62 void BumpPtrAllocator::DeallocateSlabs(MemSlab
*Slab
) {
64 MemSlab
*NextSlab
= Slab
->NextPtr
;
66 // Poison the memory so stale pointers crash sooner. Note we must
67 // preserve the Size and NextPtr fields at the beginning.
68 sys::Memory::setRangeWritable(Slab
+ 1, Slab
->Size
- sizeof(MemSlab
));
69 memset(Slab
+ 1, 0xCD, Slab
->Size
- sizeof(MemSlab
));
71 Allocator
.Deallocate(Slab
);
76 /// Reset - Deallocate all but the current slab and reset the current pointer
77 /// to the beginning of it, freeing all memory allocated so far.
78 void BumpPtrAllocator::Reset() {
81 DeallocateSlabs(CurSlab
->NextPtr
);
83 CurPtr
= (char*)(CurSlab
+ 1);
84 End
= ((char*)CurSlab
) + CurSlab
->Size
;
87 /// Allocate - Allocate space at the specified alignment.
89 void *BumpPtrAllocator::Allocate(size_t Size
, size_t Alignment
) {
90 if (!CurSlab
) // Start a new slab if we haven't allocated one already.
93 // Keep track of how many bytes we've allocated.
94 BytesAllocated
+= Size
;
96 // 0-byte alignment means 1-byte alignment.
97 if (Alignment
== 0) Alignment
= 1;
99 // Allocate the aligned space, going forwards from CurPtr.
100 char *Ptr
= AlignPtr(CurPtr
, Alignment
);
102 // Check if we can hold it.
103 if (Ptr
+ Size
<= End
) {
108 // If Size is really big, allocate a separate slab for it.
109 size_t PaddedSize
= Size
+ sizeof(MemSlab
) + Alignment
- 1;
110 if (PaddedSize
> SizeThreshold
) {
111 MemSlab
*NewSlab
= Allocator
.Allocate(PaddedSize
);
113 // Put the new slab after the current slab, since we are not allocating
115 NewSlab
->NextPtr
= CurSlab
->NextPtr
;
116 CurSlab
->NextPtr
= NewSlab
;
118 Ptr
= AlignPtr((char*)(NewSlab
+ 1), Alignment
);
119 assert((uintptr_t)Ptr
+ Size
<= (uintptr_t)NewSlab
+ NewSlab
->Size
);
123 // Otherwise, start a new slab and try again.
125 Ptr
= AlignPtr(CurPtr
, Alignment
);
127 assert(CurPtr
<= End
&& "Unable to allocate memory!");
131 unsigned BumpPtrAllocator::GetNumSlabs() const {
132 unsigned NumSlabs
= 0;
133 for (MemSlab
*Slab
= CurSlab
; Slab
!= 0; Slab
= Slab
->NextPtr
) {
139 size_t BumpPtrAllocator::getTotalMemory() const {
140 size_t TotalMemory
= 0;
141 for (MemSlab
*Slab
= CurSlab
; Slab
!= 0; Slab
= Slab
->NextPtr
) {
142 TotalMemory
+= Slab
->Size
;
147 void BumpPtrAllocator::PrintStats() const {
148 unsigned NumSlabs
= 0;
149 size_t TotalMemory
= 0;
150 for (MemSlab
*Slab
= CurSlab
; Slab
!= 0; Slab
= Slab
->NextPtr
) {
151 TotalMemory
+= Slab
->Size
;
155 errs() << "\nNumber of memory regions: " << NumSlabs
<< '\n'
156 << "Bytes used: " << BytesAllocated
<< '\n'
157 << "Bytes allocated: " << TotalMemory
<< '\n'
158 << "Bytes wasted: " << (TotalMemory
- BytesAllocated
)
159 << " (includes alignment, etc)\n";
162 MallocSlabAllocator
BumpPtrAllocator::DefaultSlabAllocator
=
163 MallocSlabAllocator();
165 SlabAllocator::~SlabAllocator() { }
167 MallocSlabAllocator::~MallocSlabAllocator() { }
169 MemSlab
*MallocSlabAllocator::Allocate(size_t Size
) {
170 MemSlab
*Slab
= (MemSlab
*)Allocator
.Allocate(Size
, 0);
176 void MallocSlabAllocator::Deallocate(MemSlab
*Slab
) {
177 Allocator
.Deallocate(Slab
);
180 void PrintRecyclerStats(size_t Size
,
182 size_t FreeListSize
) {
183 errs() << "Recycler element size: " << Size
<< '\n'
184 << "Recycler element alignment: " << Align
<< '\n'
185 << "Number of elements free for recycling: " << FreeListSize
<< '\n';