CUBRID Engine  latest
obstackheap.h
Go to the documentation of this file.
1 /* -*- C++ -*- */
2 
3 /*
4 
5  Heap Layers: An Extensible Memory Allocation Infrastructure
6 
7  Copyright (C) 2000-2020 by Emery Berger
8  http://www.emeryberger.com
9  emery@cs.umass.edu
10 
11  Heap Layers is distributed under the terms of the Apache 2.0 license.
12 
13  You may obtain a copy of the License at
14  http://www.apache.org/licenses/LICENSE-2.0
15 
16 */
17 
18 // An "Obstack".
19 
20 #ifndef HL_OBSTACKHEAP_H
21 #define HL_OBSTACKHEAP_H
22 
23 #include <assert.h>
24 #include <new>
25 
26 #include "utility/align.h"
27 
28 namespace HL {
29 
30  template <int ChunkSize, class SuperHeap>
31  class ObstackHeap : public SuperHeap {
32 
33  private:
34  int m_chkSize;
35 
36  public:
37 
38  enum { Alignment = sizeof(double) };
39 
41  {
43  m_chkSize = ChunkSize;
44 
45  if (m_chkSize > 0)
46  {
47  // Get one chunk and set the current position marker.
48  currentChunk = makeChunk (NULL, m_chkSize);
49  currentBase = nextPos = (char *) (currentChunk + 1);
50  assert (isValid ());
51  }
52  }
53 
55  // Free every chunk.
56  assert (isValid());
57  ChunkHeader * ch = currentChunk;
58  while (ch != NULL) {
59  ChunkHeader * pch = ch->getPrevChunk();
60  // cout << "Freeing chunk " << ch << endl;
61  SuperHeap::free (ch);
62  ch = pch;
63  }
64  }
65 
66  inline void reset (const int chkSize)
67  {
68  m_chkSize = chkSize;
69  if (m_chkSize > 0 && currentChunk == NULL)
70  {
71  // Get one chunk and set the current position marker.
72  currentChunk = makeChunk (NULL, m_chkSize);
73  currentBase = nextPos = (char *) (currentChunk + 1);
74  assert (isValid ());
75  }
76  }
77 
78  // "Grow" the current object.
79  // Returns a point in the object just before the current "grow".
80  inline void * grow (size_t sz) {
81  // If we've grown beyond the confines of this chunk,
82  // get a new one.
83  assert (isValid());
84  if ((int) ((char *) currentChunk->getLimit() - (char *) nextPos) < sz) {
85  ChunkHeader * newCurrent = copyToNew(sz);
86  if (newCurrent == NULL)
87  return NULL;
88 #if 0
89  // Now delete the previous chunk if this was the only object in it.
90  if (deleteChunk != NULL) {
91  SuperHeap::free (deleteChunk);
92  }
93 #endif
94  assert (isValid());
95  }
96  assert (((int) ((char *) currentChunk->getLimit() - (char *) nextPos) >= sz));
97  assert ((char *) (sz + nextPos) <= currentChunk->getLimit());
98  // Bump the pointer for the next object.
99  void * prevNextPos = nextPos;
100  nextPos += sz;
101  assert (isValid());
102  return prevNextPos;
103  }
104 
105 
106  inline void * malloc (size_t sz) {
107  assert (isValid());
108  if (currentChunk == NULL) {
109  return NULL;
110  }
111  //sz = align(sz > 0 ? sz : 1);
112  // If this object can't fit in the current chunk,
113  // get another one.
114  if ((ptrdiff_t) ((char *) currentChunk->getLimit() - (char *) nextPos) < (ptrdiff_t) sz) {
115  // Allocate a chunk that's large enough to hold the requested size.
117  if (currentChunk == NULL) {
118  return NULL;
119  }
120  currentBase = nextPos = (char *) (currentChunk + 1);
121  assert (isValid());
122  }
123  assert (((ptrdiff_t) ((char *) currentChunk->getLimit() - (char *) nextPos) >= (ptrdiff_t) sz));
124  assert ((char *) (sz + nextPos) <= currentChunk->getLimit());
125  // Bump the pointers forward.
127  nextPos += sz;
128  void * ptr = currentBase;
129  finalize();
130  assert (isValid());
131  return (void *) ptr;
132  }
133 
134  // Free everything allocated "after" ptr.
135  // NB: Freeing NULL safely empties the entire obstack.
136  inline void free (void * ptr) {
137  assert (isValid());
138  // Free every chunk until we find the one that this pointer is in.
139  // Then reset the current position to ptr.
140  while (currentChunk != NULL &&
141  (((char *) currentChunk > (char *) ptr) ||
142  ((char *) currentChunk->getLimit() < (char *) ptr))) {
143  ChunkHeader * pch = currentChunk;
145  SuperHeap::free (pch);
146  }
147  if (currentChunk != NULL) {
148  currentBase = nextPos = (char *) ptr;
149  assert (isValid());
150  } else {
151  if (ptr != NULL) {
152  // Something bad has happened -- we tried to free an item that
153  // wasn't in any chunk.
154  abort();
155  } else {
156  // Get one chunk.
157  currentChunk = makeChunk (NULL, m_chkSize);
158  currentBase = nextPos = (char *) (currentChunk + 1);
159  assert (isValid());
160  }
161  }
162  }
163 
164 
165  inline void * getObjectBase() {
166  assert (isValid());
167  return currentBase;
168  }
169 
170 
171  inline void finalize() {
172  assert (isValid());
173  nextPos = (char *) HL::align<Alignment> ((size_t) nextPos);
175  assert (isValid());
176  }
177 
178 
179  private:
180 
181 
182  inline int objectSize() {
183  int diff = (int) (nextPos - currentBase);
184  assert (diff >= 0);
185  return diff;
186  }
187 
188 
189  int isValid() {
190  // Verify class invariants.
191 #ifndef NDEBUG
192  bool c1 = (currentBase <= nextPos);
193  assert (c1);
194  bool c2 = (nextPos <= currentChunk->getLimit());
195  assert (c2);
196  bool c3 = ((char *) currentChunk <= currentChunk->getLimit());
197  assert (c3);
198  bool c4 = ((char *) currentChunk <= currentBase);
199  assert (c4);
200  bool c5 = (currentChunk != currentChunk->getPrevChunk());
201  assert (c5);
202  bool c6 = (objectSize() >= 0);
203  assert (c6);
204  return (c1 && c2 && c3 && c4 && c5 && c6);
205 #else
206  return 1;
207 #endif
208  }
209 
210  // The header for every chunk.
211  class ChunkHeader {
212  public:
213  inline ChunkHeader (ChunkHeader * prev, size_t sz)
214  : _pastEnd ((char *) (this + 1) + sz),
215  _prevChunk (prev)
216  {}
217 
218  // Return the end of the current chunk.
219  inline char * getLimit() { return _pastEnd; }
220 
221  // Return the previous chunk.
222  inline ChunkHeader * getPrevChunk() { return _prevChunk; }
223 
224  private:
225  // Just past the end of this chunk.
226  char * _pastEnd;
227 
228  // Address of prior chunk.
230  };
231 
232  // Make a new chunk of at least sz bytes.
233  inline ChunkHeader * makeChunk (ChunkHeader * ch, size_t sz) {
234  // Round up the allocation size to at least one chunk.
235  size_t allocSize
236  = HL::align<Alignment>((sz > m_chkSize - sizeof(ChunkHeader)) ? sz : m_chkSize - sizeof(ChunkHeader));
237  // Make a new chunk.
238  void * ptr = SuperHeap::malloc (sizeof(ChunkHeader) + allocSize);
239  if (ptr == NULL) {
240  return NULL;
241  }
242  ChunkHeader * newChunk
243  = new (ptr) ChunkHeader (ch, allocSize);
244  return newChunk;
245  }
246 
247 
248  // Copy the current object to a new chunk.
249  // sz = the minimum amount of extra space we need.
250  inline ChunkHeader * copyToNew (size_t sz) {
251  size_t obj_size = objectSize();
252  size_t new_size = obj_size + sz + (obj_size >> 3) + 100;
253  //size_t new_size = 2 * (obj_size + sz);
254  ChunkHeader * newChunk;
255 #if 0
256  // This variable will hold the chunk to be deleted (if any).
257  ChunkHeader * deleteChunk = NULL;
258  // If this object was the only one in the chunk,
259  // link back past this chunk.
260  if (currentBase == (char *) (currentChunk + 1)) {
261  newChunk = makeChunk (currentChunk->getPrevChunk(), new_size);
262  deleteChunk = currentChunk;
263  } else {
264  newChunk = makeChunk (currentChunk, new_size);
265  }
266 #else
267  newChunk = makeChunk (currentChunk, new_size);
268 #endif
269  if (newChunk == NULL) {
270  currentChunk = NULL;
271  return NULL;
272  }
273  // Copy the current object to the new chunk.
274  memcpy ((char *) (newChunk + 1), currentBase, obj_size);
275  currentChunk = newChunk;
276  currentBase = (char *) (currentChunk + 1);
277  nextPos = currentBase + obj_size;
278 #if 0
279  if (deleteChunk != NULL) {
280  SuperHeap::free (deleteChunk);
281  }
282 #endif
283  return currentChunk;
284  }
285 
286 
287  // Current position in the current chunk.
288  char * currentBase;
289 
290  // Where to add the next character to the current object.
291  char * nextPos;
292 
293  // My current chunk.
295 
296  };
297 
298 }
299 
300 #endif
ChunkHeader * getPrevChunk()
Definition: obstackheap.h:222
void * grow(size_t sz)
Definition: obstackheap.h:80
char * currentBase
Definition: obstackheap.h:288
ChunkHeader * currentChunk
Definition: obstackheap.h:294
void * malloc(size_t sz)
Definition: obstackheap.h:106
#define diff
Definition: mprec.h:352
void reset(const int chkSize)
Definition: obstackheap.h:66
Definition: heaplayers.h:34
#define assert(x)
void free(void *ptr)
Definition: obstackheap.h:136
#define NULL
Definition: freelistheap.h:34
ChunkHeader * copyToNew(size_t sz)
Definition: obstackheap.h:250
void * getObjectBase()
Definition: obstackheap.h:165
ChunkHeader(ChunkHeader *prev, size_t sz)
Definition: obstackheap.h:213
ChunkHeader * makeChunk(ChunkHeader *ch, size_t sz)
Definition: obstackheap.h:233