File indexing completed on 2026-05-10 08:44:27
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef LLVM_SUPPORT_ALLOCATOR_H
0018 #define LLVM_SUPPORT_ALLOCATOR_H
0019
0020 #include "llvm/ADT/SmallVector.h"
0021 #include "llvm/Support/Alignment.h"
0022 #include "llvm/Support/AllocatorBase.h"
0023 #include "llvm/Support/Compiler.h"
0024 #include "llvm/Support/MathExtras.h"
0025 #include <algorithm>
0026 #include <cassert>
0027 #include <cstddef>
0028 #include <cstdint>
0029 #include <iterator>
0030 #include <optional>
0031 #include <utility>
0032
0033 namespace llvm {
0034
0035 namespace detail {
0036
0037
0038
0039 void printBumpPtrAllocatorStats(unsigned NumSlabs, size_t BytesAllocated,
0040 size_t TotalMemory);
0041
0042 }
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 template <typename AllocatorT = MallocAllocator, size_t SlabSize = 4096,
0062 size_t SizeThreshold = SlabSize, size_t GrowthDelay = 128>
0063 class BumpPtrAllocatorImpl
0064 : public AllocatorBase<BumpPtrAllocatorImpl<AllocatorT, SlabSize,
0065 SizeThreshold, GrowthDelay>>,
0066 private detail::AllocatorHolder<AllocatorT> {
0067 using AllocTy = detail::AllocatorHolder<AllocatorT>;
0068
0069 public:
0070 static_assert(SizeThreshold <= SlabSize,
0071 "The SizeThreshold must be at most the SlabSize to ensure "
0072 "that objects larger than a slab go into their own memory "
0073 "allocation.");
0074 static_assert(GrowthDelay > 0,
0075 "GrowthDelay must be at least 1 which already increases the"
0076 "slab size after each allocated slab.");
0077
0078 BumpPtrAllocatorImpl() = default;
0079
0080 template <typename T>
0081 BumpPtrAllocatorImpl(T &&Allocator)
0082 : AllocTy(std::forward<T &&>(Allocator)) {}
0083
0084
0085
0086 BumpPtrAllocatorImpl(BumpPtrAllocatorImpl &&Old)
0087 : AllocTy(std::move(Old.getAllocator())), CurPtr(Old.CurPtr),
0088 End(Old.End), Slabs(std::move(Old.Slabs)),
0089 CustomSizedSlabs(std::move(Old.CustomSizedSlabs)),
0090 BytesAllocated(Old.BytesAllocated), RedZoneSize(Old.RedZoneSize) {
0091 Old.CurPtr = Old.End = nullptr;
0092 Old.BytesAllocated = 0;
0093 Old.Slabs.clear();
0094 Old.CustomSizedSlabs.clear();
0095 }
0096
0097 ~BumpPtrAllocatorImpl() {
0098 DeallocateSlabs(Slabs.begin(), Slabs.end());
0099 DeallocateCustomSizedSlabs();
0100 }
0101
0102 BumpPtrAllocatorImpl &operator=(BumpPtrAllocatorImpl &&RHS) {
0103 DeallocateSlabs(Slabs.begin(), Slabs.end());
0104 DeallocateCustomSizedSlabs();
0105
0106 CurPtr = RHS.CurPtr;
0107 End = RHS.End;
0108 BytesAllocated = RHS.BytesAllocated;
0109 RedZoneSize = RHS.RedZoneSize;
0110 Slabs = std::move(RHS.Slabs);
0111 CustomSizedSlabs = std::move(RHS.CustomSizedSlabs);
0112 AllocTy::operator=(std::move(RHS.getAllocator()));
0113
0114 RHS.CurPtr = RHS.End = nullptr;
0115 RHS.BytesAllocated = 0;
0116 RHS.Slabs.clear();
0117 RHS.CustomSizedSlabs.clear();
0118 return *this;
0119 }
0120
0121
0122
0123 void Reset() {
0124
0125 DeallocateCustomSizedSlabs();
0126 CustomSizedSlabs.clear();
0127
0128 if (Slabs.empty())
0129 return;
0130
0131
0132 BytesAllocated = 0;
0133 CurPtr = (char *)Slabs.front();
0134 End = CurPtr + SlabSize;
0135
0136 __asan_poison_memory_region(*Slabs.begin(), computeSlabSize(0));
0137 DeallocateSlabs(std::next(Slabs.begin()), Slabs.end());
0138 Slabs.erase(std::next(Slabs.begin()), Slabs.end());
0139 }
0140
0141
0142
0143
0144
0145
0146
0147
0148 LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, Align Alignment) {
0149
0150 BytesAllocated += Size;
0151
0152 uintptr_t AlignedPtr = alignAddr(CurPtr, Alignment);
0153
0154 size_t SizeToAllocate = Size;
0155 #if LLVM_ADDRESS_SANITIZER_BUILD
0156
0157 SizeToAllocate += RedZoneSize;
0158 #endif
0159
0160 uintptr_t AllocEndPtr = AlignedPtr + SizeToAllocate;
0161 assert(AllocEndPtr >= uintptr_t(CurPtr) &&
0162 "Alignment + Size must not overflow");
0163
0164
0165 if (LLVM_LIKELY(AllocEndPtr <= uintptr_t(End)
0166
0167 && CurPtr != nullptr)) {
0168 CurPtr = reinterpret_cast<char *>(AllocEndPtr);
0169
0170
0171
0172 __msan_allocated_memory(reinterpret_cast<char *>(AlignedPtr), Size);
0173
0174 __asan_unpoison_memory_region(reinterpret_cast<char *>(AlignedPtr), Size);
0175 return reinterpret_cast<char *>(AlignedPtr);
0176 }
0177
0178 return AllocateSlow(Size, SizeToAllocate, Alignment);
0179 }
0180
0181 LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_NOINLINE void *
0182 AllocateSlow(size_t Size, size_t SizeToAllocate, Align Alignment) {
0183
0184 size_t PaddedSize = SizeToAllocate + Alignment.value() - 1;
0185 if (PaddedSize > SizeThreshold) {
0186 void *NewSlab =
0187 this->getAllocator().Allocate(PaddedSize, alignof(std::max_align_t));
0188
0189
0190 __asan_poison_memory_region(NewSlab, PaddedSize);
0191 CustomSizedSlabs.push_back(std::make_pair(NewSlab, PaddedSize));
0192
0193 uintptr_t AlignedAddr = alignAddr(NewSlab, Alignment);
0194 assert(AlignedAddr + Size <= (uintptr_t)NewSlab + PaddedSize);
0195 char *AlignedPtr = (char*)AlignedAddr;
0196 __msan_allocated_memory(AlignedPtr, Size);
0197 __asan_unpoison_memory_region(AlignedPtr, Size);
0198 return AlignedPtr;
0199 }
0200
0201
0202 StartNewSlab();
0203 uintptr_t AlignedAddr = alignAddr(CurPtr, Alignment);
0204 assert(AlignedAddr + SizeToAllocate <= (uintptr_t)End &&
0205 "Unable to allocate memory!");
0206 char *AlignedPtr = (char*)AlignedAddr;
0207 CurPtr = AlignedPtr + SizeToAllocate;
0208 __msan_allocated_memory(AlignedPtr, Size);
0209 __asan_unpoison_memory_region(AlignedPtr, Size);
0210 return AlignedPtr;
0211 }
0212
0213 inline LLVM_ATTRIBUTE_RETURNS_NONNULL void *
0214 Allocate(size_t Size, size_t Alignment) {
0215 assert(Alignment > 0 && "0-byte alignment is not allowed. Use 1 instead.");
0216 return Allocate(Size, Align(Alignment));
0217 }
0218
0219
0220 using AllocatorBase<BumpPtrAllocatorImpl>::Allocate;
0221
0222
0223
0224
0225 void Deallocate(const void *Ptr, size_t Size, size_t ) {
0226 __asan_poison_memory_region(Ptr, Size);
0227 }
0228
0229
0230 using AllocatorBase<BumpPtrAllocatorImpl>::Deallocate;
0231
0232 size_t GetNumSlabs() const { return Slabs.size() + CustomSizedSlabs.size(); }
0233
0234
0235
0236
0237
0238
0239 std::optional<int64_t> identifyObject(const void *Ptr) {
0240 const char *P = static_cast<const char *>(Ptr);
0241 int64_t InSlabIdx = 0;
0242 for (size_t Idx = 0, E = Slabs.size(); Idx < E; Idx++) {
0243 const char *S = static_cast<const char *>(Slabs[Idx]);
0244 if (P >= S && P < S + computeSlabSize(Idx))
0245 return InSlabIdx + static_cast<int64_t>(P - S);
0246 InSlabIdx += static_cast<int64_t>(computeSlabSize(Idx));
0247 }
0248
0249
0250 int64_t InCustomSizedSlabIdx = -1;
0251 for (size_t Idx = 0, E = CustomSizedSlabs.size(); Idx < E; Idx++) {
0252 const char *S = static_cast<const char *>(CustomSizedSlabs[Idx].first);
0253 size_t Size = CustomSizedSlabs[Idx].second;
0254 if (P >= S && P < S + Size)
0255 return InCustomSizedSlabIdx - static_cast<int64_t>(P - S);
0256 InCustomSizedSlabIdx -= static_cast<int64_t>(Size);
0257 }
0258 return std::nullopt;
0259 }
0260
0261
0262
0263
0264
0265 int64_t identifyKnownObject(const void *Ptr) {
0266 std::optional<int64_t> Out = identifyObject(Ptr);
0267 assert(Out && "Wrong allocator used");
0268 return *Out;
0269 }
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281 template <typename T>
0282 int64_t identifyKnownAlignedObject(const void *Ptr) {
0283 int64_t Out = identifyKnownObject(Ptr);
0284 assert(Out % alignof(T) == 0 && "Wrong alignment information");
0285 return Out / alignof(T);
0286 }
0287
0288 size_t getTotalMemory() const {
0289 size_t TotalMemory = 0;
0290 for (auto I = Slabs.begin(), E = Slabs.end(); I != E; ++I)
0291 TotalMemory += computeSlabSize(std::distance(Slabs.begin(), I));
0292 for (const auto &PtrAndSize : CustomSizedSlabs)
0293 TotalMemory += PtrAndSize.second;
0294 return TotalMemory;
0295 }
0296
0297 size_t getBytesAllocated() const { return BytesAllocated; }
0298
0299 void setRedZoneSize(size_t NewSize) {
0300 RedZoneSize = NewSize;
0301 }
0302
0303 void PrintStats() const {
0304 detail::printBumpPtrAllocatorStats(Slabs.size(), BytesAllocated,
0305 getTotalMemory());
0306 }
0307
0308 private:
0309
0310
0311
0312 char *CurPtr = nullptr;
0313
0314
0315 char *End = nullptr;
0316
0317
0318 SmallVector<void *, 4> Slabs;
0319
0320
0321 SmallVector<std::pair<void *, size_t>, 0> CustomSizedSlabs;
0322
0323
0324
0325
0326 size_t BytesAllocated = 0;
0327
0328
0329
0330 size_t RedZoneSize = 1;
0331
0332 static size_t computeSlabSize(unsigned SlabIdx) {
0333
0334
0335
0336
0337 return SlabSize *
0338 ((size_t)1 << std::min<size_t>(30, SlabIdx / GrowthDelay));
0339 }
0340
0341
0342
0343 void StartNewSlab() {
0344 size_t AllocatedSlabSize = computeSlabSize(Slabs.size());
0345
0346 void *NewSlab = this->getAllocator().Allocate(AllocatedSlabSize,
0347 alignof(std::max_align_t));
0348
0349
0350 __asan_poison_memory_region(NewSlab, AllocatedSlabSize);
0351
0352 Slabs.push_back(NewSlab);
0353 CurPtr = (char *)(NewSlab);
0354 End = ((char *)NewSlab) + AllocatedSlabSize;
0355 }
0356
0357
0358 void DeallocateSlabs(SmallVectorImpl<void *>::iterator I,
0359 SmallVectorImpl<void *>::iterator E) {
0360 for (; I != E; ++I) {
0361 size_t AllocatedSlabSize =
0362 computeSlabSize(std::distance(Slabs.begin(), I));
0363 this->getAllocator().Deallocate(*I, AllocatedSlabSize,
0364 alignof(std::max_align_t));
0365 }
0366 }
0367
0368
0369 void DeallocateCustomSizedSlabs() {
0370 for (auto &PtrAndSize : CustomSizedSlabs) {
0371 void *Ptr = PtrAndSize.first;
0372 size_t Size = PtrAndSize.second;
0373 this->getAllocator().Deallocate(Ptr, Size, alignof(std::max_align_t));
0374 }
0375 }
0376
0377 template <typename T> friend class SpecificBumpPtrAllocator;
0378 };
0379
0380
0381
0382 typedef BumpPtrAllocatorImpl<> BumpPtrAllocator;
0383
0384
0385
0386
0387
0388
0389 template <typename T> class SpecificBumpPtrAllocator {
0390 BumpPtrAllocator Allocator;
0391
0392 public:
0393 SpecificBumpPtrAllocator() {
0394
0395
0396 Allocator.setRedZoneSize(0);
0397 }
0398 SpecificBumpPtrAllocator(SpecificBumpPtrAllocator &&Old)
0399 : Allocator(std::move(Old.Allocator)) {}
0400 ~SpecificBumpPtrAllocator() { DestroyAll(); }
0401
0402 SpecificBumpPtrAllocator &operator=(SpecificBumpPtrAllocator &&RHS) {
0403 Allocator = std::move(RHS.Allocator);
0404 return *this;
0405 }
0406
0407
0408
0409
0410 void DestroyAll() {
0411 auto DestroyElements = [](char *Begin, char *End) {
0412 assert(Begin == (char *)alignAddr(Begin, Align::Of<T>()));
0413 for (char *Ptr = Begin; Ptr + sizeof(T) <= End; Ptr += sizeof(T))
0414 reinterpret_cast<T *>(Ptr)->~T();
0415 };
0416
0417 for (auto I = Allocator.Slabs.begin(), E = Allocator.Slabs.end(); I != E;
0418 ++I) {
0419 size_t AllocatedSlabSize = BumpPtrAllocator::computeSlabSize(
0420 std::distance(Allocator.Slabs.begin(), I));
0421 char *Begin = (char *)alignAddr(*I, Align::Of<T>());
0422 char *End = *I == Allocator.Slabs.back() ? Allocator.CurPtr
0423 : (char *)*I + AllocatedSlabSize;
0424
0425 DestroyElements(Begin, End);
0426 }
0427
0428 for (auto &PtrAndSize : Allocator.CustomSizedSlabs) {
0429 void *Ptr = PtrAndSize.first;
0430 size_t Size = PtrAndSize.second;
0431 DestroyElements((char *)alignAddr(Ptr, Align::Of<T>()),
0432 (char *)Ptr + Size);
0433 }
0434
0435 Allocator.Reset();
0436 }
0437
0438
0439 T *Allocate(size_t num = 1) { return Allocator.Allocate<T>(num); }
0440
0441
0442
0443
0444 std::optional<int64_t> identifyObject(const void *Ptr) {
0445 return Allocator.identifyObject(Ptr);
0446 }
0447 };
0448
0449 }
0450
0451 template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold,
0452 size_t GrowthDelay>
0453 void *
0454 operator new(size_t Size,
0455 llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize, SizeThreshold,
0456 GrowthDelay> &Allocator) {
0457 return Allocator.Allocate(Size, std::min((size_t)llvm::NextPowerOf2(Size),
0458 alignof(std::max_align_t)));
0459 }
0460
0461 template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold,
0462 size_t GrowthDelay>
0463 void operator delete(void *,
0464 llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize,
0465 SizeThreshold, GrowthDelay> &) {
0466 }
0467
0468 #endif