AllocatorTest.cpp 5.4 KB

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