Line data Source code
1 : //==- llvm/Support/Recycler.h - Recycling Allocator --------------*- C++ -*-==//
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 : // This file defines the Recycler class template. See the doxygen comment for
11 : // Recycler for more details.
12 : //
13 : //===----------------------------------------------------------------------===//
14 :
15 : #ifndef LLVM_SUPPORT_RECYCLER_H
16 : #define LLVM_SUPPORT_RECYCLER_H
17 :
18 : #include "llvm/ADT/ilist.h"
19 : #include "llvm/Support/Allocator.h"
20 : #include "llvm/Support/ErrorHandling.h"
21 : #include <cassert>
22 :
23 : namespace llvm {
24 :
25 : /// PrintRecyclingAllocatorStats - Helper for RecyclingAllocator for
26 : /// printing statistics.
27 : ///
28 : void PrintRecyclerStats(size_t Size, size_t Align, size_t FreeListSize);
29 :
30 : /// Recycler - This class manages a linked-list of deallocated nodes
31 : /// and facilitates reusing deallocated memory in place of allocating
32 : /// new memory.
33 : ///
34 : template <class T, size_t Size = sizeof(T), size_t Align = alignof(T)>
35 1253281 : class Recycler {
36 : struct FreeNode {
37 : FreeNode *Next;
38 : };
39 :
40 : /// List of nodes that have deleted contents and are not in active use.
41 : FreeNode *FreeList = nullptr;
42 :
43 0 : FreeNode *pop_val() {
44 0 : auto *Val = FreeList;
45 : __asan_unpoison_memory_region(Val, Size);
46 39361940 : FreeList = FreeList->Next;
47 : __msan_allocated_memory(Val, Size);
48 0 : return Val;
49 : }
50 0 :
51 0 : void push(FreeNode *N) {
52 58644730 : N->Next = FreeList;
53 58644730 : FreeList = N;
54 : __asan_poison_memory_region(N, Size);
55 0 : }
56 :
57 0 : public:
58 0 : ~Recycler() {
59 : // If this fails, either the callee has lost track of some allocation,
60 0 : // or the callee isn't tracking allocations and should just call
61 : // clear() before deleting the Recycler.
62 0 : assert(!FreeList && "Non-empty recycler deleted!");
63 : }
64 0 :
65 0 : /// clear - Release all the tracked allocations to the allocator. The
66 21403966 : /// recycler must be free of any tracked allocations before being
67 21403966 : /// deleted; calling clear is one way to ensure this.
68 : template<class AllocatorType>
69 0 : void clear(AllocatorType &Allocator) {
70 0 : while (FreeList) {
71 0 : T *t = reinterpret_cast<T *>(pop_val());
72 0 : Allocator.Deallocate(t);
73 3202792 : }
74 3202792 : }
75 0 :
76 0 : /// Special case for BumpPtrAllocator which has an empty Deallocate()
77 0 : /// function.
78 0 : ///
79 0 : /// There is no need to traverse the free list, pulling all the objects into
80 : /// cache.
81 51102 : void clear(BumpPtrAllocator &) { FreeList = nullptr; }
82 0 :
83 0 : template<class SubClass, class AllocatorType>
84 0 : SubClass *Allocate(AllocatorType &Allocator) {
85 : static_assert(alignof(SubClass) <= Align,
86 0 : "Recycler allocation alignment is less than object align!");
87 410945 : static_assert(sizeof(SubClass) <= Size,
88 0 : "Recycler allocation size is less than object size!");
89 31335630 : return FreeList ? reinterpret_cast<SubClass *>(pop_val())
90 1346113 : : static_cast<SubClass *>(Allocator.Allocate(Size, Align));
91 0 : }
92 :
93 : template<class AllocatorType>
94 : T *Allocate(AllocatorType &Allocator) {
95 : return Allocate<T>(Allocator);
96 : }
97 :
98 : template<class SubClass, class AllocatorType>
99 0 : void Deallocate(AllocatorType & /*Allocator*/, SubClass* Element) {
100 : push(reinterpret_cast<FreeNode *>(Element));
101 0 : }
102 0 :
103 : void PrintStats();
104 0 : };
105 822130 :
106 : template <class T, size_t Size, size_t Align>
107 0 : void Recycler<T, Size, Align>::PrintStats() {
108 0 : size_t S = 0;
109 : for (auto *I = FreeList; I; I = I->Next)
110 0 : ++S;
111 0 : PrintRecyclerStats(Size, Align, S);
112 : }
113 55890161 :
114 47180718 : }
115 :
116 : #endif
|