summaryrefslogtreecommitdiffstats
path: root/lib/Support/Allocator.cpp
blob: db0d8f31e55dc0618b1a316eec960474fa150ad1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//===--- Allocator.cpp - Simple memory allocation abstraction -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the BumpPtrAllocator interface.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/Allocator.h"
#include "llvm/Support/Recycler.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Streams.h"
#include <ostream>
using namespace llvm;

//===----------------------------------------------------------------------===//
// MemRegion class implementation
//===----------------------------------------------------------------------===//

namespace {
/// MemRegion - This is one chunk of the BumpPtrAllocator.
class MemRegion {
  unsigned RegionSize;
  MemRegion *Next;
  char *NextPtr;
public:
  void Init(unsigned size, unsigned Alignment, MemRegion *next) {
    RegionSize = size;
    Next = next;
    NextPtr = (char*)(this+1);
    
    // Align NextPtr.
    NextPtr = (char*)((intptr_t)(NextPtr+Alignment-1) &
                      ~(intptr_t)(Alignment-1));
  }
  
  const MemRegion *getNext() const { return Next; }
  unsigned getNumBytesAllocated() const {
    return NextPtr-(const char*)this;
  }
  
  /// Allocate - Allocate and return at least the specified number of bytes.
  ///
  void *Allocate(size_t AllocSize, size_t Alignment, MemRegion **RegPtr) {
    
    char* Result = (char*) (((uintptr_t) (NextPtr+Alignment-1)) 
                            & ~((uintptr_t) Alignment-1));

    // Speculate the new value of NextPtr.
    char* NextPtrTmp = Result + AllocSize;
    
    // If we are still within the current region, return Result.
    if (unsigned (NextPtrTmp - (char*) this) <= RegionSize) {
      NextPtr = NextPtrTmp;
      return Result;
    }
    
    // Otherwise, we have to allocate a new chunk.  Create one twice as big as
    // this one.
    MemRegion *NewRegion = (MemRegion *)malloc(RegionSize*2);
    NewRegion->Init(RegionSize*2, Alignment, this);

    // Update the current "first region" pointer  to point to the new region.
    *RegPtr = NewRegion;
    
    // Try allocating from it now.
    return NewRegion->Allocate(AllocSize, Alignment, RegPtr);
  }
  
  /// Deallocate - Recursively release all memory for this and its next regions
  /// to the system.
  void Deallocate() {
    MemRegion *next = Next;
    free(this);
    if (next)
      next->Deallocate();
  }

  /// DeallocateAllButLast - Recursively release all memory for this and its
  /// next regions to the system stopping at the last region in the list.
  /// Returns the pointer to the last region.
  MemRegion *DeallocateAllButLast() {
    MemRegion *next = Next;
    if (!next)
      return this;
    free(this);
    return next->DeallocateAllButLast();
  }
};
}

//===----------------------------------------------------------------------===//
// BumpPtrAllocator class implementation
//===----------------------------------------------------------------------===//

BumpPtrAllocator::BumpPtrAllocator() {
  TheMemory = malloc(4096);
  ((MemRegion*)TheMemory)->Init(4096, 1, 0);
}

BumpPtrAllocator::~BumpPtrAllocator() {
  ((MemRegion*)TheMemory)->Deallocate();
}

void BumpPtrAllocator::Reset() {
  MemRegion *MRP = (MemRegion*)TheMemory;
  MRP = MRP->DeallocateAllButLast();
  MRP->Init(4096, 1, 0);
  TheMemory = MRP;
}

void *BumpPtrAllocator::Allocate(size_t Size, size_t Align) {
  MemRegion *MRP = (MemRegion*)TheMemory;
  void *Ptr = MRP->Allocate(Size, Align, &MRP);
  TheMemory = MRP;
  return Ptr;
}

void BumpPtrAllocator::PrintStats() const {
  unsigned BytesUsed = 0;
  unsigned NumRegions = 0;
  const MemRegion *R = (MemRegion*)TheMemory;
  for (; R; R = R->getNext(), ++NumRegions)
    BytesUsed += R->getNumBytesAllocated();

  cerr << "\nNumber of memory regions: " << NumRegions << "\n";
  cerr << "Bytes allocated: " << BytesUsed << "\n";
}

void llvm::PrintRecyclerStats(size_t Size,
                              size_t Align,
                              size_t FreeListSize) {
  cerr << "Recycler element size: " << Size << '\n';
  cerr << "Recycler element alignment: " << Align << '\n';
  cerr << "Number of elements free for recycling: " << FreeListSize << '\n';
}
OpenPOWER on IntegriCloud