source: proiecte/swift/trunk/lib/hoard-371/src/heaplayers/obstackheap.h @ 176

Last change on this file since 176 was 176, checked in by (none), 14 years ago
  • imported repo from "guagal"
File size: 7.8 KB
Line 
1/* -*- C++ -*- */
2
3/*
4
5  Heap Layers: An Extensible Memory Allocation Infrastructure
6 
7  Copyright (C) 2000-2003 by Emery Berger
8  http://www.cs.umass.edu/~emery
9  emery@cs.umass.edu
10 
11  This program is free software; you can redistribute it and/or modify
12  it under the terms of the GNU General Public License as published by
13  the Free Software Foundation; either version 2 of the License, or
14  (at your option) any later version.
15 
16  This program is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  GNU General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with this program; if not, write to the Free Software
23  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24
25*/
26
27// An "Obstack".
28
29#ifndef _HLOBSTACK_H_
30#define _HLOBSTACK_H_
31
32#ifdef __cplusplus
33
34#include <assert.h>
35#include <new>
36
37namespace HL {
38
39template <int ChunkSize, class SuperHeap>
40class ObstackHeap : public SuperHeap {
41public:
42
43  ObstackHeap (void)
44  {
45    // Get one chunk and set the current position marker.
46    currentChunk = makeChunk (NULL, ChunkSize);
47    currentBase = nextPos = (char *) (currentChunk + 1);
48    assert (isValid());
49  }
50
51  ~ObstackHeap (void) {
52    // Free every chunk.
53    assert (isValid());
54    ChunkHeader * ch = currentChunk;
55    while (ch != NULL) {
56      ChunkHeader * pch = ch->getPrevChunk();
57      // cout << "Freeing chunk " << ch << endl;
58      SuperHeap::free (ch);
59      ch = pch;
60    }
61  }
62
63  // "Grow" the current object.
64  // Returns a point in the object just before the current "grow".
65  inline void * grow (size_t sz) {
66    // If we've grown beyond the confines of this chunk,
67    // get a new one.
68    assert (isValid());
69    if ((int) ((char *) currentChunk->getLimit() - (char *) nextPos) < sz) {
70      ChunkHeader * newCurrent = copyToNew(sz);
71      if (newCurrent == NULL)
72        return NULL;
73#if 0
74      // Now delete the previous chunk if this was the only object in it.
75      if (deleteChunk != NULL) {
76        SuperHeap::free (deleteChunk);
77      }
78#endif
79      assert (isValid());
80    }
81    assert (((int) ((char *) currentChunk->getLimit() - (char *) nextPos) >= sz));
82    assert ((char *) (sz + nextPos) <= currentChunk->getLimit());
83    // Bump the pointer for the next object.
84    void * prevNextPos = nextPos;
85    nextPos += sz;
86    assert (isValid());
87    return prevNextPos;
88  }
89
90
91  inline void * malloc (size_t sz) {
92    assert (isValid());
93    if (currentChunk == NULL) {
94      return NULL;
95    }
96    //sz = align(sz > 0 ? sz : 1);
97    // If this object can't fit in the current chunk,
98    // get another one.
99    if ((int) ((char *) currentChunk->getLimit() - (char *) nextPos) < sz) {
100      // Allocate a chunk that's large enough to hold the requested size.
101      currentChunk = makeChunk (currentChunk, sz);
102      if (currentChunk == NULL) {
103        return NULL;
104      }
105      currentBase = nextPos = (char *) (currentChunk + 1);
106      assert (isValid());
107    }
108    assert (((int) ((char *) currentChunk->getLimit() - (char *) nextPos) >= sz));
109    assert ((char *) (sz + nextPos) <= currentChunk->getLimit());
110    // Bump the pointers forward.
111    currentBase = nextPos;
112    nextPos += sz;
113    void * ptr = currentBase;
114    finalize();
115    assert (isValid());
116    return (void *) ptr;
117  }
118
119  // Free everything allocated "after" ptr.
120  // NB: Freeing NULL safely empties the entire obstack.
121  inline void free (void * ptr) {
122    assert (isValid());
123    // Free every chunk until we find the one that this pointer is in.
124    // Then reset the current position to ptr.
125    while (currentChunk != NULL &&
126           (((char *) currentChunk > (char *) ptr) ||
127            ((char *) currentChunk->getLimit() < (char *) ptr))) {
128      ChunkHeader * pch = currentChunk;
129      currentChunk = currentChunk->getPrevChunk();
130      SuperHeap::free (pch);
131    }
132    if (currentChunk != NULL) {
133      currentBase = nextPos = (char *) ptr;
134      assert (isValid());
135    } else {
136      if (ptr != NULL) {
137        // Something bad has happened -- we tried to free an item that
138        // wasn't in any chunk.
139        abort();
140      } else {
141        // Get one chunk.
142        currentChunk = makeChunk (NULL, ChunkSize);
143        currentBase = nextPos = (char *) (currentChunk + 1);
144        assert (isValid());
145      }
146    }
147  }
148
149
150  inline void * getObjectBase (void) {
151    assert (isValid());
152    return currentBase;
153  }
154
155
156  inline void finalize (void) {
157    assert (isValid());
158    nextPos = (char *) align((int) nextPos);
159    currentBase = nextPos;
160    assert (isValid());
161  }
162
163
164private:
165
166
167  inline int objectSize (void) {
168    int diff = (int) (nextPos - currentBase);
169    assert (diff >= 0);
170    return diff;
171  }
172
173
174  int isValid (void) {
175    // Verify class invariants.
176#ifndef NDEBUG
177    bool c1 = (currentBase <= nextPos);
178    assert (c1);
179    bool c2 = (nextPos <= currentChunk->getLimit());
180    assert (c2);
181    bool c3 = ((char *) currentChunk <= currentChunk->getLimit());
182    assert (c3);
183    bool c4 = ((char *) currentChunk <= currentBase);
184    assert (c4);
185    bool c5 = (currentChunk != currentChunk->getPrevChunk());
186    assert (c5);
187    bool c6 = (objectSize() >= 0);
188    assert (c6);
189    return (c1 && c2 && c3 && c4 && c5 && c6);
190#else
191    return 1;
192#endif
193  }
194
195  // The header for every chunk.
196  class ChunkHeader {
197  public:
198    inline ChunkHeader (ChunkHeader * prev, size_t sz)
199      : _pastEnd ((char *) (this + 1) + sz),
200        _prevChunk (prev)
201    {}
202
203    // Return the end of the current chunk.
204    inline char * getLimit (void) { return _pastEnd; }
205
206    // Return the previous chunk.
207    inline ChunkHeader * getPrevChunk (void) { return _prevChunk; }
208
209  private:
210    // Just past the end of this chunk.
211    char * _pastEnd;
212
213    // Address of prior chunk.
214    ChunkHeader * _prevChunk;
215  };
216
217
218  inline static size_t align (int sz) {
219    return (sz + (sizeof(double) - 1)) & ~(sizeof(double) - 1);
220  }
221
222  // Make a new chunk of at least sz bytes.
223  inline ChunkHeader * makeChunk (ChunkHeader * ch, size_t sz) {
224    // Round up the allocation size to at least one chunk.
225    size_t allocSize
226      = align((sz > ChunkSize - sizeof(ChunkHeader)) ? sz : ChunkSize - sizeof(ChunkHeader));
227    // Make a new chunk.
228    void * ptr = SuperHeap::malloc (sizeof(ChunkHeader) + allocSize);
229    if (ptr == NULL) {
230      return NULL;
231    }
232    ChunkHeader * newChunk
233      = new (ptr) ChunkHeader (ch, allocSize);
234    return newChunk;
235  }
236
237
238  // Copy the current object to a new chunk.
239  // sz = the minimum amount of extra space we need.
240  inline ChunkHeader * copyToNew (size_t sz) {
241    size_t obj_size = objectSize();
242    size_t new_size = obj_size + sz + (obj_size >> 3) + 100;
243    //size_t new_size = 2 * (obj_size + sz);
244    ChunkHeader * newChunk;
245#if 0
246    // This variable will hold the chunk to be deleted (if any).
247    ChunkHeader * deleteChunk = NULL;
248    // If this object was the only one in the chunk,
249    // link back past this chunk.
250    if (currentBase == (char *) (currentChunk + 1)) {
251      newChunk = makeChunk (currentChunk->getPrevChunk(), new_size);
252      deleteChunk = currentChunk;
253    } else {
254      newChunk = makeChunk (currentChunk, new_size);
255    }
256#else
257    newChunk = makeChunk (currentChunk, new_size);
258#endif
259    if (newChunk == NULL) {
260      currentChunk = NULL;
261      return NULL;
262    }
263    // Copy the current object to the new chunk.
264    memcpy ((char *) (newChunk + 1), currentBase, obj_size);
265    currentChunk = newChunk;
266    currentBase = (char *) (currentChunk + 1);
267    nextPos = currentBase + obj_size;
268#if 0
269    if (deleteChunk != NULL) {
270      SuperHeap::free (deleteChunk);
271    }
272#endif
273    return currentChunk;
274  }
275
276
277  // Current position in the current chunk.
278  char * currentBase;
279
280  // Where to add the next character to the current object.
281  char * nextPos;
282
283  // My current chunk.
284  ChunkHeader * currentChunk;
285
286};
287
288};
289
290#endif // __cplusplus
291
292#endif // _HLOBSTACK_H_
Note: See TracBrowser for help on using the repository browser.