]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===- llvm/unittest/Support/AllocatorTest.cpp - BumpPtrAllocator tests ---===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | ||
10 | #include "llvm/Support/Allocator.h" | |
223e47cc LB |
11 | #include "gtest/gtest.h" |
12 | #include <cstdlib> | |
13 | ||
14 | using namespace llvm; | |
15 | ||
16 | namespace { | |
17 | ||
18 | TEST(AllocatorTest, Basics) { | |
19 | BumpPtrAllocator Alloc; | |
1a4d82fc JJ |
20 | int *a = (int*)Alloc.Allocate(sizeof(int), 1); |
21 | int *b = (int*)Alloc.Allocate(sizeof(int) * 10, 1); | |
22 | int *c = (int*)Alloc.Allocate(sizeof(int), 1); | |
223e47cc LB |
23 | *a = 1; |
24 | b[0] = 2; | |
25 | b[9] = 2; | |
26 | *c = 3; | |
27 | EXPECT_EQ(1, *a); | |
28 | EXPECT_EQ(2, b[0]); | |
29 | EXPECT_EQ(2, b[9]); | |
30 | EXPECT_EQ(3, *c); | |
31 | EXPECT_EQ(1U, Alloc.GetNumSlabs()); | |
1a4d82fc JJ |
32 | |
33 | BumpPtrAllocator Alloc2 = std::move(Alloc); | |
34 | EXPECT_EQ(0U, Alloc.GetNumSlabs()); | |
35 | EXPECT_EQ(1U, Alloc2.GetNumSlabs()); | |
36 | ||
37 | // Make sure the old pointers still work. These are especially interesting | |
38 | // under ASan or Valgrind. | |
39 | EXPECT_EQ(1, *a); | |
40 | EXPECT_EQ(2, b[0]); | |
41 | EXPECT_EQ(2, b[9]); | |
42 | EXPECT_EQ(3, *c); | |
43 | ||
44 | Alloc = std::move(Alloc2); | |
45 | EXPECT_EQ(0U, Alloc2.GetNumSlabs()); | |
46 | EXPECT_EQ(1U, Alloc.GetNumSlabs()); | |
223e47cc LB |
47 | } |
48 | ||
49 | // Allocate enough bytes to create three slabs. | |
50 | TEST(AllocatorTest, ThreeSlabs) { | |
1a4d82fc JJ |
51 | BumpPtrAllocator Alloc; |
52 | Alloc.Allocate(3000, 1); | |
223e47cc | 53 | EXPECT_EQ(1U, Alloc.GetNumSlabs()); |
1a4d82fc | 54 | Alloc.Allocate(3000, 1); |
223e47cc | 55 | EXPECT_EQ(2U, Alloc.GetNumSlabs()); |
1a4d82fc | 56 | Alloc.Allocate(3000, 1); |
223e47cc LB |
57 | EXPECT_EQ(3U, Alloc.GetNumSlabs()); |
58 | } | |
59 | ||
60 | // Allocate enough bytes to create two slabs, reset the allocator, and do it | |
61 | // again. | |
62 | TEST(AllocatorTest, TestReset) { | |
1a4d82fc JJ |
63 | BumpPtrAllocator Alloc; |
64 | Alloc.Allocate(3000, 1); | |
223e47cc | 65 | EXPECT_EQ(1U, Alloc.GetNumSlabs()); |
1a4d82fc | 66 | Alloc.Allocate(3000, 1); |
223e47cc LB |
67 | EXPECT_EQ(2U, Alloc.GetNumSlabs()); |
68 | Alloc.Reset(); | |
69 | EXPECT_EQ(1U, Alloc.GetNumSlabs()); | |
1a4d82fc | 70 | Alloc.Allocate(3000, 1); |
223e47cc | 71 | EXPECT_EQ(1U, Alloc.GetNumSlabs()); |
1a4d82fc | 72 | Alloc.Allocate(3000, 1); |
223e47cc LB |
73 | EXPECT_EQ(2U, Alloc.GetNumSlabs()); |
74 | } | |
75 | ||
76 | // Test some allocations at varying alignments. | |
77 | TEST(AllocatorTest, TestAlignment) { | |
78 | BumpPtrAllocator Alloc; | |
79 | uintptr_t a; | |
80 | a = (uintptr_t)Alloc.Allocate(1, 2); | |
81 | EXPECT_EQ(0U, a & 1); | |
82 | a = (uintptr_t)Alloc.Allocate(1, 4); | |
83 | EXPECT_EQ(0U, a & 3); | |
84 | a = (uintptr_t)Alloc.Allocate(1, 8); | |
85 | EXPECT_EQ(0U, a & 7); | |
86 | a = (uintptr_t)Alloc.Allocate(1, 16); | |
87 | EXPECT_EQ(0U, a & 15); | |
88 | a = (uintptr_t)Alloc.Allocate(1, 32); | |
89 | EXPECT_EQ(0U, a & 31); | |
90 | a = (uintptr_t)Alloc.Allocate(1, 64); | |
91 | EXPECT_EQ(0U, a & 63); | |
92 | a = (uintptr_t)Alloc.Allocate(1, 128); | |
93 | EXPECT_EQ(0U, a & 127); | |
94 | } | |
95 | ||
96 | // Test allocating just over the slab size. This tests a bug where before the | |
97 | // allocator incorrectly calculated the buffer end pointer. | |
98 | TEST(AllocatorTest, TestOverflow) { | |
1a4d82fc | 99 | BumpPtrAllocator Alloc; |
223e47cc LB |
100 | |
101 | // Fill the slab right up until the end pointer. | |
1a4d82fc | 102 | Alloc.Allocate(4096, 1); |
223e47cc LB |
103 | EXPECT_EQ(1U, Alloc.GetNumSlabs()); |
104 | ||
105 | // If we don't allocate a new slab, then we will have overflowed. | |
1a4d82fc | 106 | Alloc.Allocate(1, 1); |
223e47cc LB |
107 | EXPECT_EQ(2U, Alloc.GetNumSlabs()); |
108 | } | |
109 | ||
110 | // Test allocating with a size larger than the initial slab size. | |
111 | TEST(AllocatorTest, TestSmallSlabSize) { | |
1a4d82fc JJ |
112 | BumpPtrAllocator Alloc; |
113 | ||
114 | Alloc.Allocate(8000, 1); | |
115 | EXPECT_EQ(1U, Alloc.GetNumSlabs()); | |
116 | } | |
117 | ||
118 | // Test requesting alignment that goes past the end of the current slab. | |
119 | TEST(AllocatorTest, TestAlignmentPastSlab) { | |
120 | BumpPtrAllocator Alloc; | |
121 | Alloc.Allocate(4095, 1); | |
122 | ||
123 | // Aligning the current slab pointer is likely to move it past the end of the | |
124 | // slab, which would confuse any unsigned comparisons with the difference of | |
125 | // the the end pointer and the aligned pointer. | |
126 | Alloc.Allocate(1024, 8192); | |
223e47cc | 127 | |
223e47cc LB |
128 | EXPECT_EQ(2U, Alloc.GetNumSlabs()); |
129 | } | |
130 | ||
131 | // Mock slab allocator that returns slabs aligned on 4096 bytes. There is no | |
132 | // easy portable way to do this, so this is kind of a hack. | |
1a4d82fc JJ |
133 | class MockSlabAllocator { |
134 | static size_t LastSlabSize; | |
223e47cc LB |
135 | |
136 | public: | |
1a4d82fc | 137 | ~MockSlabAllocator() { } |
223e47cc | 138 | |
1a4d82fc | 139 | void *Allocate(size_t Size, size_t /*Alignment*/) { |
223e47cc LB |
140 | // Allocate space for the alignment, the slab, and a void* that goes right |
141 | // before the slab. | |
142 | size_t Alignment = 4096; | |
143 | void *MemBase = malloc(Size + Alignment - 1 + sizeof(void*)); | |
144 | ||
1a4d82fc JJ |
145 | // Find the slab start. |
146 | void *Slab = (void *)alignAddr((char*)MemBase + sizeof(void *), Alignment); | |
223e47cc LB |
147 | |
148 | // Hold a pointer to the base so we can free the whole malloced block. | |
149 | ((void**)Slab)[-1] = MemBase; | |
150 | ||
1a4d82fc | 151 | LastSlabSize = Size; |
223e47cc LB |
152 | return Slab; |
153 | } | |
154 | ||
1a4d82fc | 155 | void Deallocate(void *Slab, size_t Size) { |
223e47cc LB |
156 | free(((void**)Slab)[-1]); |
157 | } | |
158 | ||
1a4d82fc | 159 | static size_t GetLastSlabSize() { return LastSlabSize; } |
223e47cc LB |
160 | }; |
161 | ||
1a4d82fc JJ |
162 | size_t MockSlabAllocator::LastSlabSize = 0; |
163 | ||
223e47cc LB |
164 | // Allocate a large-ish block with a really large alignment so that the |
165 | // allocator will think that it has space, but after it does the alignment it | |
166 | // will not. | |
167 | TEST(AllocatorTest, TestBigAlignment) { | |
1a4d82fc JJ |
168 | BumpPtrAllocatorImpl<MockSlabAllocator> Alloc; |
169 | ||
170 | // First allocate a tiny bit to ensure we have to re-align things. | |
171 | (void)Alloc.Allocate(1, 1); | |
172 | ||
173 | // Now the big chunk with a big alignment. | |
174 | (void)Alloc.Allocate(3000, 2048); | |
175 | ||
176 | // We test that the last slab size is not the default 4096 byte slab, but | |
177 | // rather a custom sized slab that is larger. | |
178 | EXPECT_GT(MockSlabAllocator::GetLastSlabSize(), 4096u); | |
223e47cc LB |
179 | } |
180 | ||
181 | } // anonymous namespace |