diff --git a/llvm/include/llvm/ADT/ScopedHashTable.h b/llvm/include/llvm/ADT/ScopedHashTable.h --- a/llvm/include/llvm/ADT/ScopedHashTable.h +++ b/llvm/include/llvm/ADT/ScopedHashTable.h @@ -147,7 +147,9 @@ }; template -class ScopedHashTable { +class ScopedHashTable : UnderlyingAllocTy { + using AllocTy = UnderlyingAllocTy; + public: /// ScopeTy - This is a helpful typedef that allows clients to get easy access /// to the name of the scope for this hash table. @@ -162,11 +164,9 @@ DenseMap TopLevelMap; ScopeTy *CurScope = nullptr; - AllocatorTy Allocator; - public: ScopedHashTable() = default; - ScopedHashTable(AllocatorTy A) : Allocator(A) {} + ScopedHashTable(AllocatorTy A) : AllocTy(A) {} ScopedHashTable(const ScopedHashTable &) = delete; ScopedHashTable &operator=(const ScopedHashTable &) = delete; @@ -175,8 +175,10 @@ } /// Access to the allocator. - AllocatorTy &getAllocator() { return Allocator; } - const AllocatorTy &getAllocator() const { return Allocator; } + AllocatorTy &getAllocator() { return static_cast(*this); } + const AllocatorTy &getAllocator() const { + return static_cast(*this); + } /// Return 1 if the specified key is in the table, 0 otherwise. size_type count(const K &Key) const { @@ -217,7 +219,7 @@ assert(S && "No scope active!"); ScopedHashTableVal *&KeyEntry = TopLevelMap[Key]; KeyEntry = ValTy::Create(S->getLastValInScope(), KeyEntry, Key, Val, - Allocator); + getAllocator()); S->setLastValInScope(KeyEntry); } }; diff --git a/llvm/include/llvm/ADT/StringMap.h b/llvm/include/llvm/ADT/StringMap.h --- a/llvm/include/llvm/ADT/StringMap.h +++ b/llvm/include/llvm/ADT/StringMap.h @@ -107,8 +107,8 @@ /// funky memory allocation and hashing things to make it extremely efficient, /// storing the string data *after* the value in the map. template -class StringMap : public StringMapImpl { - AllocatorTy Allocator; +class StringMap : public StringMapImpl, private UnderlyingAllocTy { + using AllocTy = UnderlyingAllocTy; public: using MapEntryTy = StringMapEntry; @@ -119,12 +119,11 @@ : StringMapImpl(InitialSize, static_cast(sizeof(MapEntryTy))) {} explicit StringMap(AllocatorTy A) - : StringMapImpl(static_cast(sizeof(MapEntryTy))), Allocator(A) { - } + : StringMapImpl(static_cast(sizeof(MapEntryTy))), AllocTy(A) {} StringMap(unsigned InitialSize, AllocatorTy A) : StringMapImpl(InitialSize, static_cast(sizeof(MapEntryTy))), - Allocator(A) {} + AllocTy(A) {} StringMap(std::initializer_list> List) : StringMapImpl(List.size(), static_cast(sizeof(MapEntryTy))) { @@ -132,11 +131,11 @@ } StringMap(StringMap &&RHS) - : StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {} + : StringMapImpl(std::move(RHS)), AllocTy(static_cast(RHS)) {} StringMap(const StringMap &RHS) : StringMapImpl(static_cast(sizeof(MapEntryTy))), - Allocator(RHS.Allocator) { + AllocTy(static_cast(RHS)) { if (RHS.empty()) return; @@ -156,7 +155,7 @@ } TheTable[I] = MapEntryTy::Create( - static_cast(Bucket)->getKey(), Allocator, + static_cast(Bucket)->getKey(), getAllocator(), static_cast(Bucket)->getValue()); HashTable[I] = RHSHashTable[I]; } @@ -171,7 +170,7 @@ StringMap &operator=(StringMap RHS) { StringMapImpl::swap(RHS); - std::swap(Allocator, RHS.Allocator); + std::swap(getAllocator(), RHS.getAllocator()); return *this; } @@ -183,15 +182,17 @@ for (unsigned I = 0, E = NumBuckets; I != E; ++I) { StringMapEntryBase *Bucket = TheTable[I]; if (Bucket && Bucket != getTombstoneVal()) { - static_cast(Bucket)->Destroy(Allocator); + static_cast(Bucket)->Destroy(getAllocator()); } } } free(TheTable); } - AllocatorTy &getAllocator() { return Allocator; } - const AllocatorTy &getAllocator() const { return Allocator; } + AllocatorTy &getAllocator() { return static_cast(*this); } + const AllocatorTy &getAllocator() const { + return static_cast(*this); + } using key_type = const char *; using mapped_type = ValueTy; @@ -336,7 +337,8 @@ if (Bucket == getTombstoneVal()) --NumTombstones; - Bucket = MapEntryTy::Create(Key, Allocator, std::forward(Args)...); + Bucket = + MapEntryTy::Create(Key, getAllocator(), std::forward(Args)...); ++NumItems; assert(NumItems + NumTombstones <= NumBuckets); @@ -354,7 +356,7 @@ for (unsigned I = 0, E = NumBuckets; I != E; ++I) { StringMapEntryBase *&Bucket = TheTable[I]; if (Bucket && Bucket != getTombstoneVal()) { - static_cast(Bucket)->Destroy(Allocator); + static_cast(Bucket)->Destroy(getAllocator()); } Bucket = nullptr; } @@ -370,7 +372,7 @@ void erase(iterator I) { MapEntryTy &V = *I; remove(&V); - V.Destroy(Allocator); + V.Destroy(getAllocator()); } bool erase(StringRef Key) { diff --git a/llvm/include/llvm/Support/Allocator.h b/llvm/include/llvm/Support/Allocator.h --- a/llvm/include/llvm/Support/Allocator.h +++ b/llvm/include/llvm/Support/Allocator.h @@ -63,7 +63,9 @@ class BumpPtrAllocatorImpl : public AllocatorBase>, - private AllocatorT { + private UnderlyingAllocTy { + using AllocTy = UnderlyingAllocTy; + public: static_assert(SizeThreshold <= SlabSize, "The SizeThreshold must be at most the SlabSize to ensure " @@ -77,13 +79,13 @@ template BumpPtrAllocatorImpl(T &&Allocator) - : AllocatorT(std::forward(Allocator)) {} + : AllocTy(std::forward(Allocator)) {} // Manually implement a move constructor as we must clear the old allocator's // slabs as a matter of correctness. BumpPtrAllocatorImpl(BumpPtrAllocatorImpl &&Old) - : AllocatorT(static_cast(Old)), CurPtr(Old.CurPtr), - End(Old.End), Slabs(std::move(Old.Slabs)), + : AllocTy(static_cast(Old)), CurPtr(Old.CurPtr), End(Old.End), + Slabs(std::move(Old.Slabs)), CustomSizedSlabs(std::move(Old.CustomSizedSlabs)), BytesAllocated(Old.BytesAllocated), RedZoneSize(Old.RedZoneSize) { Old.CurPtr = Old.End = nullptr; @@ -107,7 +109,7 @@ RedZoneSize = RHS.RedZoneSize; Slabs = std::move(RHS.Slabs); CustomSizedSlabs = std::move(RHS.CustomSizedSlabs); - AllocatorT::operator=(static_cast(RHS)); + AllocTy::operator=(static_cast(RHS)); RHS.CurPtr = RHS.End = nullptr; RHS.BytesAllocated = 0; @@ -174,8 +176,7 @@ // If Size is really big, allocate a separate slab for it. size_t PaddedSize = SizeToAllocate + Alignment.value() - 1; if (PaddedSize > SizeThreshold) { - void *NewSlab = - AllocatorT::Allocate(PaddedSize, alignof(std::max_align_t)); + void *NewSlab = AllocTy::Allocate(PaddedSize, alignof(std::max_align_t)); // We own the new slab and don't want anyone reading anyting other than // pieces returned from this method. So poison the whole slab. __asan_poison_memory_region(NewSlab, PaddedSize); @@ -335,7 +336,7 @@ size_t AllocatedSlabSize = computeSlabSize(Slabs.size()); void *NewSlab = - AllocatorT::Allocate(AllocatedSlabSize, alignof(std::max_align_t)); + AllocTy::Allocate(AllocatedSlabSize, alignof(std::max_align_t)); // We own the new slab and don't want anyone reading anything other than // pieces returned from this method. So poison the whole slab. __asan_poison_memory_region(NewSlab, AllocatedSlabSize); @@ -351,7 +352,7 @@ for (; I != E; ++I) { size_t AllocatedSlabSize = computeSlabSize(std::distance(Slabs.begin(), I)); - AllocatorT::Deallocate(*I, AllocatedSlabSize, alignof(std::max_align_t)); + AllocTy::Deallocate(*I, AllocatedSlabSize, alignof(std::max_align_t)); } } @@ -360,7 +361,7 @@ for (auto &PtrAndSize : CustomSizedSlabs) { void *Ptr = PtrAndSize.first; size_t Size = PtrAndSize.second; - AllocatorT::Deallocate(Ptr, Size, alignof(std::max_align_t)); + AllocTy::Deallocate(Ptr, Size, alignof(std::max_align_t)); } } diff --git a/llvm/include/llvm/Support/AllocatorBase.h b/llvm/include/llvm/Support/AllocatorBase.h --- a/llvm/include/llvm/Support/AllocatorBase.h +++ b/llvm/include/llvm/Support/AllocatorBase.h @@ -99,6 +99,42 @@ void PrintStats() const {} }; +namespace detail { + +template +class ReferenceAllocator : public AllocatorBase> { + static_assert(!std::is_const::value, "Cannot have a const type here"); + T &Underlying; + +public: + ReferenceAllocator(T &Underlying) : Underlying(Underlying) {} + + LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, size_t Alignment) { + return Underlying.Allocate(Size, Alignment); + } + + void Deallocate(const void *Ptr, size_t Size, size_t Alignment) { + Underlying.Deallocate(Ptr, Size, Alignment); + } + + using AllocatorBase>::Allocate; + using AllocatorBase>::Deallocate; + + operator T &() { return Underlying; } + operator const T &() const { return Underlying; } +}; +template struct MaybeReferenceAllocType { + using type = T; +}; + +template struct MaybeReferenceAllocType { + using type = ReferenceAllocator; +}; +} // namespace detail + +template +using UnderlyingAllocTy = typename detail::MaybeReferenceAllocType::type; + } // namespace llvm #endif // LLVM_SUPPORT_ALLOCATORBASE_H