llvm.org GIT mirror llvm / 8f51a62
Re-committing changes from r76825 to BumpPtrAllocator with a fix and tests for an off-by-one error. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@76891 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 10 years ago
3 changed file(s) with 325 addition(s) and 115 deletion(s). Raw diff Collapse all Expand all
1414 #define LLVM_SUPPORT_ALLOCATOR_H
1515
1616 #include "llvm/Support/AlignOf.h"
17 #include "llvm/Support/DataTypes.h"
18 #include
1719 #include
1820
1921 namespace llvm {
4042 void PrintStats() const {}
4143 };
4244
43 /// BumpPtrAllocator - This allocator is useful for containers that need very
44 /// simple memory allocation strategies. In particular, this just keeps
45 /// MemSlab - This structure lives at the beginning of every slab allocated by
46 /// the bump allocator.
47 class MemSlab {
48 public:
49 size_t Size;
50 MemSlab *NextPtr;
51 };
52
53 /// SlabAllocator - This class can be used to parameterize the underlying
54 /// allocation strategy for the bump allocator. In particular, this is used
55 /// by the JIT to allocate contiguous swathes of executable memory. The
56 /// interface uses MemSlab's instead of void *'s so that the allocator
57 /// doesn't have to remember the size of the pointer it allocated.
58 class SlabAllocator {
59 public:
60 virtual ~SlabAllocator();
61 virtual MemSlab *Allocate(size_t Size) = 0;
62 virtual void Deallocate(MemSlab *Slab) = 0;
63 };
64
65 /// MallocSlabAllocator - The default slab allocator for the bump allocator
66 /// is an adapter class for MallocAllocator that just forwards the method
67 /// calls and translates the arguments.
68 class MallocSlabAllocator : public SlabAllocator {
69 /// Allocator - The underlying allocator that we forward to.
70 ///
71 MallocAllocator Allocator;
72
73 public:
74 MallocSlabAllocator() : Allocator() { }
75 virtual ~MallocSlabAllocator();
76 virtual MemSlab *Allocate(size_t Size);
77 virtual void Deallocate(MemSlab *Slab);
78 };
79
80 /// BumpPtrAllocator - This allocator is useful for containers that need
81 /// very simple memory allocation strategies. In particular, this just keeps
4582 /// allocating memory, and never deletes it until the entire block is dead. This
4683 /// makes allocation speedy, but must only be used when the trade-off is ok.
4784 class BumpPtrAllocator {
4885 BumpPtrAllocator(const BumpPtrAllocator &); // do not implement
4986 void operator=(const BumpPtrAllocator &); // do not implement
5087
51 void *TheMemory;
88 /// SlabSize - Allocate data into slabs of this size unless we get an
89 /// allocation above SizeThreshold.
90 size_t SlabSize;
91
92 /// SizeThreshold - For any allocation larger than this threshold, we should
93 /// allocate a separate slab.
94 size_t SizeThreshold;
95
96 /// Allocator - The underlying allocator we use to get slabs of memory. This
97 /// defaults to MallocSlabAllocator, which wraps malloc, but it could be
98 /// changed to use a custom allocator.
99 SlabAllocator &Allocator;
100
101 /// CurSlab - The slab that we are currently allocating into.
102 ///
103 MemSlab *CurSlab;
104
105 /// CurPtr - The current pointer into the current slab. This points to the
106 /// next free byte in the slab.
107 char *CurPtr;
108
109 /// End - The end of the current slab.
110 ///
111 char *End;
112
113 /// BytesAllocated - This field tracks how many bytes we've allocated, so
114 /// that we can compute how much space was wasted.
115 size_t BytesAllocated;
116
117 /// AlignPtr - Align Ptr to Alignment bytes, rounding up. Alignment should
118 /// be a power of two. This method rounds up, so AlignPtr(7, 4) == 8 and
119 /// AlignPtr(8, 4) == 8.
120 static char *AlignPtr(char *Ptr, size_t Alignment);
121
122 /// StartNewSlab - Allocate a new slab and move the bump pointers over into
123 /// the new slab. Modifies CurPtr and End.
124 void StartNewSlab();
125
126 /// DeallocateSlabs - Deallocate all memory slabs after and including this
127 /// one.
128 void DeallocateSlabs(MemSlab *Slab);
129
130 static MallocSlabAllocator DefaultSlabAllocator;
131
52132 public:
53 BumpPtrAllocator();
133 BumpPtrAllocator(size_t size = 4096, size_t threshold = 4096,
134 SlabAllocator &allocator = DefaultSlabAllocator);
54135 ~BumpPtrAllocator();
55136
137 /// Reset - Deallocate all but the current slab and reset the current pointer
138 /// to the beginning of it, freeing all memory allocated so far.
56139 void Reset();
57140
141 /// Allocate - Allocate space at the specified alignment.
142 ///
58143 void *Allocate(size_t Size, size_t Alignment);
59144
60145 /// Allocate space, but do not construct, one object.
82167
83168 void Deallocate(const void * /*Ptr*/) {}
84169
170 unsigned GetNumSlabs() const;
171
85172 void PrintStats() const;
86173 };
87174
88175 } // end namespace llvm
89176
90 #endif
177 #endif // LLVM_SUPPORT_ALLOCATOR_H
1111 //===----------------------------------------------------------------------===//
1212
1313 #include "llvm/Support/Allocator.h"
14 #include "llvm/Support/DataTypes.h"
1415 #include "llvm/Support/Recycler.h"
15 #include "llvm/Support/DataTypes.h"
1616 #include "llvm/Support/Streams.h"
17 #include
18 using namespace llvm;
17 #include
1918
20 //===----------------------------------------------------------------------===//
21 // MemRegion class implementation
22 //===----------------------------------------------------------------------===//
19 namespace llvm {
2320
24 namespace {
25 /// MemRegion - This is one chunk of the BumpPtrAllocator.
26 class MemRegion {
27 unsigned RegionSize;
28 MemRegion *Next;
29 char *NextPtr;
30 public:
31 void Init(unsigned size, unsigned Alignment, MemRegion *next) {
32 RegionSize = size;
33 Next = next;
34 NextPtr = (char*)(this+1);
35
36 // Align NextPtr.
37 NextPtr = (char*)((intptr_t)(NextPtr+Alignment-1) &
38 ~(intptr_t)(Alignment-1));
39 }
40
41 const MemRegion *getNext() const { return Next; }
42 unsigned getNumBytesAllocated() const {
43 return NextPtr-(const char*)this;
44 }
45
46 /// Allocate - Allocate and return at least the specified number of bytes.
47 ///
48 void *Allocate(size_t AllocSize, size_t Alignment, MemRegion **RegPtr) {
49
50 char* Result = (char*) (((uintptr_t) (NextPtr+Alignment-1))
51 & ~((uintptr_t) Alignment-1));
52
53 // Speculate the new value of NextPtr.
54 char* NextPtrTmp = Result + AllocSize;
55
56 // If we are still within the current region, return Result.
57 if (unsigned (NextPtrTmp - (char*) this) <= RegionSize) {
58 NextPtr = NextPtrTmp;
59 return Result;
60 }
61
62 // Otherwise, we have to allocate a new chunk. Create one twice as big as
63 // this one.
64 MemRegion *NewRegion = (MemRegion *)malloc(RegionSize*2);
65 NewRegion->Init(RegionSize*2, Alignment, this);
66
67 // Update the current "first region" pointer to point to the new region.
68 *RegPtr = NewRegion;
69
70 // Try allocating from it now.
71 return NewRegion->Allocate(AllocSize, Alignment, RegPtr);
72 }
73
74 /// Deallocate - Recursively release all memory for this and its next regions
75 /// to the system.
76 void Deallocate() {
77 MemRegion *next = Next;
78 free(this);
79 if (next)
80 next->Deallocate();
81 }
82
83 /// DeallocateAllButLast - Recursively release all memory for this and its
84 /// next regions to the system stopping at the last region in the list.
85 /// Returns the pointer to the last region.
86 MemRegion *DeallocateAllButLast() {
87 MemRegion *next = Next;
88 if (!next)
89 return this;
90 free(this);
91 return next->DeallocateAllButLast();
92 }
93 };
94 }
95
96 //===----------------------------------------------------------------------===//
97 // BumpPtrAllocator class implementation
98 //===----------------------------------------------------------------------===//
99
100 BumpPtrAllocator::BumpPtrAllocator() {
101 TheMemory = malloc(4096);
102 ((MemRegion*)TheMemory)->Init(4096, 1, 0);
21 BumpPtrAllocator::BumpPtrAllocator(size_t size, size_t threshold,
22 SlabAllocator &allocator)
23 : SlabSize(size), SizeThreshold(threshold), Allocator(allocator),
24 CurSlab(0), BytesAllocated(0) {
25 StartNewSlab();
10326 }
10427
10528 BumpPtrAllocator::~BumpPtrAllocator() {
106 ((MemRegion*)TheMemory)->Deallocate();
29 DeallocateSlabs(CurSlab);
10730 }
10831
109 void BumpPtrAllocator::Reset() {
110 MemRegion *MRP = (MemRegion*)TheMemory;
111 MRP = MRP->DeallocateAllButLast();
112 MRP->Init(4096, 1, 0);
113 TheMemory = MRP;
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!");
38
39 // Do the alignment.
40 return (char*)(((uintptr_t)Ptr + Alignment - 1) &
41 ~(uintptr_t)(Alignment - 1));
11442 }
11543
116 void *BumpPtrAllocator::Allocate(size_t Size, size_t Align) {
117 MemRegion *MRP = (MemRegion*)TheMemory;
118 void *Ptr = MRP->Allocate(Size, Align, &MRP);
119 TheMemory = MRP;
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 MemSlab *NewSlab = Allocator.Allocate(SlabSize);
48 NewSlab->NextPtr = CurSlab;
49 CurSlab = NewSlab;
50 CurPtr = (char*)(CurSlab + 1);
51 End = ((char*)CurSlab) + CurSlab->Size;
52 }
53
54 /// DeallocateSlabs - Deallocate all memory slabs after and including this
55 /// one.
56 void BumpPtrAllocator::DeallocateSlabs(MemSlab *Slab) {
57 while (Slab) {
58 MemSlab *NextSlab = Slab->NextPtr;
59 #ifndef NDEBUG
60 // Poison the memory so stale pointers crash sooner. Note we must
61 // preserve the Size and NextPtr fields at the beginning.
62 memset(Slab + 1, 0xCD, Slab->Size - sizeof(MemSlab));
63 #endif
64 Allocator.Deallocate(Slab);
65 Slab = NextSlab;
66 }
67 }
68
69 /// Reset - Deallocate all but the current slab and reset the current pointer
70 /// to the beginning of it, freeing all memory allocated so far.
71 void BumpPtrAllocator::Reset() {
72 DeallocateSlabs(CurSlab->NextPtr);
73 CurSlab->NextPtr = 0;
74 CurPtr = (char*)(CurSlab + 1);
75 End = ((char*)CurSlab) + CurSlab->Size;
76 }
77
78 /// Allocate - Allocate space at the specified alignment.
79 ///
80 void *BumpPtrAllocator::Allocate(size_t Size, size_t Alignment) {
81 // Keep track of how many bytes we've allocated.
82 BytesAllocated += Size;
83
84 // 0-byte alignment means 1-byte alignment.
85 if (Alignment == 0) Alignment = 1;
86
87 // Allocate the aligned space, going forwards from CurPtr.
88 char *Ptr = AlignPtr(CurPtr, Alignment);
89
90 // Check if we can hold it.
91 if (Ptr + Size <= End) {
92 CurPtr = Ptr + Size;
93 return Ptr;
94 }
95
96 // If Size is really big, allocate a separate slab for it.
97 if (Size > SizeThreshold) {
98 size_t PaddedSize = Size + sizeof(MemSlab) + Alignment - 1;
99 MemSlab *NewSlab = Allocator.Allocate(PaddedSize);
100
101 // Put the new slab after the current slab, since we are not allocating
102 // into it.
103 NewSlab->NextPtr = CurSlab->NextPtr;
104 CurSlab->NextPtr = NewSlab;
105
106 Ptr = AlignPtr((char*)(NewSlab + 1), Alignment);
107 assert((uintptr_t)Ptr + Size <= (uintptr_t)NewSlab + NewSlab->Size);
108 return Ptr;
109 }
110
111 // Otherwise, start a new slab and try again.
112 StartNewSlab();
113 Ptr = AlignPtr(CurPtr, Alignment);
114 CurPtr = Ptr + Size;
115 assert(CurPtr <= End && "Unable to allocate memory!");
120116 return Ptr;
121117 }
122118
123 void BumpPtrAllocator::PrintStats() const {
124 unsigned BytesUsed = 0;
125 unsigned NumRegions = 0;
126 const MemRegion *R = (MemRegion*)TheMemory;
127 for (; R; R = R->getNext(), ++NumRegions)
128 BytesUsed += R->getNumBytesAllocated();
129
130 cerr << "\nNumber of memory regions: " << NumRegions << "\n";
131 cerr << "Bytes allocated: " << BytesUsed << "\n";
119 unsigned BumpPtrAllocator::GetNumSlabs() const {
120 unsigned NumSlabs = 0;
121 for (MemSlab *Slab = CurSlab; Slab != 0; Slab = Slab->NextPtr) {
122 ++NumSlabs;
123 }
124 return NumSlabs;
132125 }
133126
134 void llvm::PrintRecyclerStats(size_t Size,
135 size_t Align,
136 size_t FreeListSize) {
137 cerr << "Recycler element size: " << Size << '\n';
138 cerr << "Recycler element alignment: " << Align << '\n';
139 cerr << "Number of elements free for recycling: " << FreeListSize << '\n';
127 void BumpPtrAllocator::PrintStats() const {
128 unsigned NumSlabs = 0;
129 size_t TotalMemory = 0;
130 for (MemSlab *Slab = CurSlab; Slab != 0; Slab = Slab->NextPtr) {
131 TotalMemory += Slab->Size;
132 ++NumSlabs;
133 }
134
135 cerr << "\nNumber of memory regions: " << NumSlabs << '\n'
136 << "Bytes used: " << BytesAllocated << '\n'
137 << "Bytes allocated: " << TotalMemory << '\n'
138 << "Bytes wasted: " << (TotalMemory - BytesAllocated)
139 << " (includes alignment, etc)\n";
140140 }
141
142 MallocSlabAllocator BumpPtrAllocator::DefaultSlabAllocator =
143 MallocSlabAllocator();
144
145 SlabAllocator::~SlabAllocator() { }
146
147 MallocSlabAllocator::~MallocSlabAllocator() { }
148
149 MemSlab *MallocSlabAllocator::Allocate(size_t Size) {
150 MemSlab *Slab = (MemSlab*)Allocator.Allocate(Size, 0);
151 Slab->Size = Size;
152 Slab->NextPtr = 0;
153 return Slab;
154 }
155
156 void MallocSlabAllocator::Deallocate(MemSlab *Slab) {
157 Allocator.Deallocate(Slab);
158 }
159
160 void PrintRecyclerStats(size_t Size,
161 size_t Align,
162 size_t FreeListSize) {
163 cerr << "Recycler element size: " << Size << '\n'
164 << "Recycler element alignment: " << Align << '\n'
165 << "Number of elements free for recycling: " << FreeListSize << '\n';
166 }
167
168 }
0 //===- llvm/unittest/Support/AllocatorTest.cpp - BumpPtrAllocator tests ---===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/Support/Allocator.h"
10
11 #include "gtest/gtest.h"
12
13 using namespace llvm;
14
15 namespace {
16
17 TEST(AllocatorTest, Basics) {
18 BumpPtrAllocator Alloc;
19 int *a = (int*)Alloc.Allocate(sizeof(int), 0);
20 int *b = (int*)Alloc.Allocate(sizeof(int) * 10, 0);
21 int *c = (int*)Alloc.Allocate(sizeof(int), 0);
22 *a = 1;
23 b[0] = 2;
24 b[9] = 2;
25 *c = 3;
26 EXPECT_EQ(1, *a);
27 EXPECT_EQ(2, b[0]);
28 EXPECT_EQ(2, b[9]);
29 EXPECT_EQ(3, *c);
30 EXPECT_EQ(1U, Alloc.GetNumSlabs());
31 }
32
33 // Allocate enough bytes to create three slabs.
34 TEST(AllocatorTest, ThreeSlabs) {
35 BumpPtrAllocator Alloc(4096, 4096);
36 Alloc.Allocate(3000, 0);
37 EXPECT_EQ(1U, Alloc.GetNumSlabs());
38 Alloc.Allocate(3000, 0);
39 EXPECT_EQ(2U, Alloc.GetNumSlabs());
40 Alloc.Allocate(3000, 0);
41 EXPECT_EQ(3U, Alloc.GetNumSlabs());
42 }
43
44 // Allocate enough bytes to create two slabs, reset the allocator, and do it
45 // again.
46 TEST(AllocatorTest, TestReset) {
47 BumpPtrAllocator Alloc(4096, 4096);
48 Alloc.Allocate(3000, 0);
49 EXPECT_EQ(1U, Alloc.GetNumSlabs());
50 Alloc.Allocate(3000, 0);
51 EXPECT_EQ(2U, Alloc.GetNumSlabs());
52 Alloc.Reset();
53 EXPECT_EQ(1U, Alloc.GetNumSlabs());
54 Alloc.Allocate(3000, 0);
55 EXPECT_EQ(1U, Alloc.GetNumSlabs());
56 Alloc.Allocate(3000, 0);
57 EXPECT_EQ(2U, Alloc.GetNumSlabs());
58 }
59
60 // Test some allocations at varying alignments.
61 TEST(AllocatorTest, TestAlignment) {
62 BumpPtrAllocator Alloc;
63 uintptr_t a;
64 a = (uintptr_t)Alloc.Allocate(1, 2);
65 EXPECT_EQ(0U, a & 1);
66 a = (uintptr_t)Alloc.Allocate(1, 4);
67 EXPECT_EQ(0U, a & 3);
68 a = (uintptr_t)Alloc.Allocate(1, 8);
69 EXPECT_EQ(0U, a & 7);
70 a = (uintptr_t)Alloc.Allocate(1, 16);
71 EXPECT_EQ(0U, a & 15);
72 a = (uintptr_t)Alloc.Allocate(1, 32);
73 EXPECT_EQ(0U, a & 31);
74 a = (uintptr_t)Alloc.Allocate(1, 64);
75 EXPECT_EQ(0U, a & 63);
76 a = (uintptr_t)Alloc.Allocate(1, 128);
77 EXPECT_EQ(0U, a & 127);
78 }
79
80 // Test allocating just over the slab size. This tests a bug where before the
81 // allocator incorrectly calculated the buffer end pointer.
82 TEST(AllocatorTest, TestOverflow) {
83 BumpPtrAllocator Alloc(4096, 4096);
84
85 // Fill the slab right up until the end pointer.
86 Alloc.Allocate(4096 - sizeof(MemSlab), 0);
87 EXPECT_EQ(1U, Alloc.GetNumSlabs());
88
89 // If we dont't allocate a new slab, then we will have overflowed.
90 Alloc.Allocate(1, 0);
91 EXPECT_EQ(2U, Alloc.GetNumSlabs());
92 }
93
94 } // anonymous namespace