1e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman//==- llvm/Support/Recycler.h - Recycling Allocator --------------*- C++ -*-==//
2e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman//
3e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman//                     The LLVM Compiler Infrastructure
4e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman//
5e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman// This file is distributed under the University of Illinois Open Source
6e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman// License. See LICENSE.TXT for details.
7e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman//
8e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman//===----------------------------------------------------------------------===//
9e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman//
10e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman// This file defines the Recycler class template.  See the doxygen comment for
11e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman// Recycler for more details.
12e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman//
13e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman//===----------------------------------------------------------------------===//
14e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman
15e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman#ifndef LLVM_SUPPORT_RECYCLER_H
16e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman#define LLVM_SUPPORT_RECYCLER_H
17e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman
18fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman#include "llvm/ADT/ilist.h"
19fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman#include "llvm/Support/AlignOf.h"
2036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/Support/Allocator.h"
2150bee42b54cd9aec5f49566307df2b0cf23afcf6Craig Topper#include "llvm/Support/ErrorHandling.h"
22fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman#include <cassert>
23e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman
24e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohmannamespace llvm {
25e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman
26e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman/// PrintRecyclingAllocatorStats - Helper for RecyclingAllocator for
27e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman/// printing statistics.
28e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman///
29fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohmanvoid PrintRecyclerStats(size_t Size, size_t Align, size_t FreeListSize);
30fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman
31fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman/// RecyclerStruct - Implementation detail for Recycler. This is a
32fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman/// class that the recycler imposes on free'd memory to carve out
33fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman/// next/prev pointers.
34fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohmanstruct RecyclerStruct {
35fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  RecyclerStruct *Prev, *Next;
36fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman};
37fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman
38fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohmantemplate<>
3959bf4fcc0680e75b408579064d1205a132361196Duncan Sandsstruct ilist_traits<RecyclerStruct> :
4059bf4fcc0680e75b408579064d1205a132361196Duncan Sands    public ilist_default_traits<RecyclerStruct> {
41fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  static RecyclerStruct *getPrev(const RecyclerStruct *t) { return t->Prev; }
42fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  static RecyclerStruct *getNext(const RecyclerStruct *t) { return t->Next; }
43fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  static void setPrev(RecyclerStruct *t, RecyclerStruct *p) { t->Prev = p; }
44fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  static void setNext(RecyclerStruct *t, RecyclerStruct *n) { t->Next = n; }
45fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman
46fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  mutable RecyclerStruct Sentinel;
47fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  RecyclerStruct *createSentinel() const {
48fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman    return &Sentinel;
49fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  }
50fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  static void destroySentinel(RecyclerStruct *) {}
51fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman
52c23b8719ef9d6b1220e854b37d40e9e1c48a82bcGabor Greif  RecyclerStruct *provideInitialHead() const { return createSentinel(); }
53c23b8719ef9d6b1220e854b37d40e9e1c48a82bcGabor Greif  RecyclerStruct *ensureHead(RecyclerStruct*) const { return createSentinel(); }
54f3841fcbd587c31aa9842b3f33bd57de40c9f443Gabor Greif  static void noteHead(RecyclerStruct*, RecyclerStruct*) {}
55c23b8719ef9d6b1220e854b37d40e9e1c48a82bcGabor Greif
56fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  static void deleteNode(RecyclerStruct *) {
5750bee42b54cd9aec5f49566307df2b0cf23afcf6Craig Topper    llvm_unreachable("Recycler's ilist_traits shouldn't see a deleteNode call!");
58fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  }
59fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman};
60e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman
61e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman/// Recycler - This class manages a linked-list of deallocated nodes
62e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman/// and facilitates reusing deallocated memory in place of allocating
63fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman/// new memory.
64e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman///
65fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohmantemplate<class T, size_t Size = sizeof(T), size_t Align = AlignOf<T>::Alignment>
66e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohmanclass Recycler {
67e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  /// FreeList - Doubly-linked list of nodes that have deleted contents and
68e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  /// are not in active use.
69e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  ///
70fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  iplist<RecyclerStruct> FreeList;
71e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman
72e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohmanpublic:
73fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  ~Recycler() {
74fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman    // If this fails, either the callee has lost track of some allocation,
75fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman    // or the callee isn't tracking allocations and should just call
76fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman    // clear() before deleting the Recycler.
77fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman    assert(FreeList.empty() && "Non-empty recycler deleted!");
78fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  }
79e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman
80fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  /// clear - Release all the tracked allocations to the allocator. The
81fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  /// recycler must be free of any tracked allocations before being
82fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman  /// deleted; calling clear is one way to ensure this.
83e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  template<class AllocatorType>
84e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  void clear(AllocatorType &Allocator) {
85fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman    while (!FreeList.empty()) {
86fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman      T *t = reinterpret_cast<T *>(FreeList.remove(FreeList.begin()));
87fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman      Allocator.Deallocate(t);
88fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman    }
89e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  }
90e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman
91b2e01b3707e23276a087f0f67edfc86082acdaa2Jakob Stoklund Olesen  /// Special case for BumpPtrAllocator which has an empty Deallocate()
92b2e01b3707e23276a087f0f67edfc86082acdaa2Jakob Stoklund Olesen  /// function.
93b2e01b3707e23276a087f0f67edfc86082acdaa2Jakob Stoklund Olesen  ///
94b2e01b3707e23276a087f0f67edfc86082acdaa2Jakob Stoklund Olesen  /// There is no need to traverse the free list, pulling all the objects into
95b2e01b3707e23276a087f0f67edfc86082acdaa2Jakob Stoklund Olesen  /// cache.
96b2e01b3707e23276a087f0f67edfc86082acdaa2Jakob Stoklund Olesen  void clear(BumpPtrAllocator&) {
97b2e01b3707e23276a087f0f67edfc86082acdaa2Jakob Stoklund Olesen    FreeList.clearAndLeakNodesUnsafely();
98b2e01b3707e23276a087f0f67edfc86082acdaa2Jakob Stoklund Olesen  }
99b2e01b3707e23276a087f0f67edfc86082acdaa2Jakob Stoklund Olesen
100e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  template<class SubClass, class AllocatorType>
101e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  SubClass *Allocate(AllocatorType &Allocator) {
10236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    static_assert(AlignOf<SubClass>::Alignment <= Align,
10336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                  "Recycler allocation alignment is less than object align!");
10436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines    static_assert(sizeof(SubClass) <= Size,
10536b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines                  "Recycler allocation size is less than object size!");
106fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman    return !FreeList.empty() ?
107fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman           reinterpret_cast<SubClass *>(FreeList.remove(FreeList.begin())) :
108fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman           static_cast<SubClass *>(Allocator.Allocate(Size, Align));
109e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  }
110e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman
111e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  template<class AllocatorType>
112e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  T *Allocate(AllocatorType &Allocator) {
113e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman    return Allocate<T>(Allocator);
114e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  }
115e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman
116e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  template<class SubClass, class AllocatorType>
11798fd7f6b2f109e16abf3e4279c971f8d3703b8a6Bill Wendling  void Deallocate(AllocatorType & /*Allocator*/, SubClass* Element) {
118fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman    FreeList.push_front(reinterpret_cast<RecyclerStruct *>(Element));
119e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  }
120e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman
121e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  void PrintStats() {
122fed90b6d097d50881afb45e4d79f430db66dd741Dan Gohman    PrintRecyclerStats(Size, Align, FreeList.size());
123e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman  }
124e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman};
125e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman
126e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman}
127e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman
128e14d81deeb6bb3404ffee5e59ecb88304f112f4aDan Gohman#endif
129