]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/alloc-pool.c
* bitmap.c (bitmap_and, bitmap_and_into, bitmap_and_compl,
[thirdparty/gcc.git] / gcc / alloc-pool.c
CommitLineData
263e39ce 1/* Functions to support a pool of allocatable objects.
cfaf579d 2 Copyright (C) 1987, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
3 2007, 2008 Free Software Foundation, Inc.
263e39ce 4 Contributed by Daniel Berlin <dan@cgsoftware.com>
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
8c4c00c1 10Software Foundation; either version 3, or (at your option) any later
263e39ce 11version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
8c4c00c1 19along with GCC; see the file COPYING3. If not see
20<http://www.gnu.org/licenses/>. */
263e39ce 21
263e39ce 22#include "config.h"
23#include "system.h"
24#include "alloc-pool.h"
7fec61de 25#include "hashtab.h"
263e39ce 26
263e39ce 27#define align_eight(x) (((x+7) >> 3) << 3)
28
a5f52a45 29/* The internal allocation object. */
30typedef struct allocation_object_def
31{
32#ifdef ENABLE_CHECKING
33 /* The ID of alloc pool which the object was allocated from. */
34 ALLOC_POOL_ID_TYPE id;
35#endif
36
37 union
38 {
39 /* The data of the object. */
40 char data[1];
41
42 /* Because we want any type of data to be well aligned after the ID,
43 the following elements are here. They are never accessed so
3089b75c 44 the allocated object may be even smaller than this structure.
45 We do not care about alignment for floating-point types. */
a5f52a45 46 char *align_p;
a5f52a45 47 HOST_WIDEST_INT align_i;
a5f52a45 48 } u;
49} allocation_object;
50
51/* Convert a pointer to allocation_object from a pointer to user data. */
52#define ALLOCATION_OBJECT_PTR_FROM_USER_PTR(X) \
53 ((allocation_object *) (((char *) (X)) \
54 - offsetof (allocation_object, u.data)))
55
56/* Convert a pointer to user data from a pointer to allocation_object. */
57#define USER_PTR_FROM_ALLOCATION_OBJECT_PTR(X) \
58 ((void *) (((allocation_object *) (X))->u.data))
59
3573ec04 60#ifdef ENABLE_CHECKING
a5f52a45 61/* Last used ID. */
62static ALLOC_POOL_ID_TYPE last_id;
3573ec04 63#endif
a5f52a45 64
7fec61de 65#ifdef GATHER_STATISTICS
66
918c094d 67/* Store information about each particular alloc_pool. Note that this
68 will underestimate the amount the amount of storage used by a small amount:
69 1) The overhead in a pool is not accounted for.
70 2) The unallocated elements in a block are not accounted for. Note
71 that this can at worst case be one element smaller that the block
72 size for that pool. */
7fec61de 73struct alloc_pool_descriptor
74{
75 const char *name;
918c094d 76 /* Number of pools allocated. */
77 unsigned long created;
78 /* Gross allocated storage. */
79 unsigned long allocated;
80 /* Amount of currently active storage. */
81 unsigned long current;
82 /* Peak amount of storage used. */
83 unsigned long peak;
84 /* Size of element in the pool. */
85 int elt_size;
7fec61de 86};
87
88/* Hashtable mapping alloc_pool names to descriptors. */
89static htab_t alloc_pool_hash;
90
91/* Hashtable helpers. */
92static hashval_t
93hash_descriptor (const void *p)
94{
b8ede6a9 95 const struct alloc_pool_descriptor *const d =
96 (const struct alloc_pool_descriptor * )p;
7fec61de 97 return htab_hash_pointer (d->name);
98}
99static int
100eq_descriptor (const void *p1, const void *p2)
101{
b8ede6a9 102 const struct alloc_pool_descriptor *const d =
103 (const struct alloc_pool_descriptor *) p1;
7fec61de 104 return d->name == p2;
105}
106
107/* For given name, return descriptor, create new if needed. */
108static struct alloc_pool_descriptor *
109alloc_pool_descriptor (const char *name)
110{
111 struct alloc_pool_descriptor **slot;
112
113 if (!alloc_pool_hash)
114 alloc_pool_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL);
115
116 slot = (struct alloc_pool_descriptor **)
117 htab_find_slot_with_hash (alloc_pool_hash, name,
a0c938f0 118 htab_hash_pointer (name),
29d35324 119 INSERT);
7fec61de 120 if (*slot)
121 return *slot;
b8ede6a9 122 *slot = XCNEW (struct alloc_pool_descriptor);
7fec61de 123 (*slot)->name = name;
124 return *slot;
125}
126#endif
127
263e39ce 128/* Create a pool of things of size SIZE, with NUM in each block we
129 allocate. */
130
131alloc_pool
aecda0d6 132create_alloc_pool (const char *name, size_t size, size_t num)
263e39ce 133{
134 alloc_pool pool;
c768b48b 135 size_t header_size;
7fec61de 136#ifdef GATHER_STATISTICS
137 struct alloc_pool_descriptor *desc;
138#endif
263e39ce 139
0ea2d350 140 gcc_checking_assert (name);
263e39ce 141
142 /* Make size large enough to store the list header. */
143 if (size < sizeof (alloc_pool_list))
144 size = sizeof (alloc_pool_list);
145
146 /* Now align the size to a multiple of 4. */
992f5b1b 147 size = align_eight (size);
263e39ce 148
a5f52a45 149#ifdef ENABLE_CHECKING
150 /* Add the aligned size of ID. */
151 size += offsetof (allocation_object, u.data);
152#endif
153
263e39ce 154 /* Um, we can't really allocate 0 elements per block. */
0ea2d350 155 gcc_checking_assert (num);
263e39ce 156
c768b48b 157 /* Allocate memory for the pool structure. */
158 pool = XNEW (struct alloc_pool_def);
263e39ce 159
160 /* Now init the various pieces of our pool structure. */
7fec61de 161 pool->name = /*xstrdup (name)*/name;
162#ifdef GATHER_STATISTICS
163 desc = alloc_pool_descriptor (name);
918c094d 164 desc->elt_size = size;
7fec61de 165 desc->created++;
166#endif
263e39ce 167 pool->elt_size = size;
168 pool->elts_per_block = num;
169
8b332087 170 /* List header size should be a multiple of 8. */
263e39ce 171 header_size = align_eight (sizeof (struct alloc_pool_list_def));
172
173 pool->block_size = (size * num) + header_size;
3072d30e 174 pool->returned_free_list = NULL;
175 pool->virgin_free_list = NULL;
176 pool->virgin_elts_remaining = 0;
263e39ce 177 pool->elts_allocated = 0;
178 pool->elts_free = 0;
179 pool->blocks_allocated = 0;
180 pool->block_list = NULL;
181
a5f52a45 182#ifdef ENABLE_CHECKING
183 /* Increase the last used ID and use it for this pool.
184 ID == 0 is used for free elements of pool so skip it. */
185 last_id++;
186 if (last_id == 0)
187 last_id++;
188
189 pool->id = last_id;
190#endif
191
263e39ce 192 return (pool);
193}
194
195/* Free all memory allocated for the given memory pool. */
196void
48694fc0 197empty_alloc_pool (alloc_pool pool)
263e39ce 198{
199 alloc_pool_list block, next_block;
7fec61de 200#ifdef GATHER_STATISTICS
201 struct alloc_pool_descriptor *desc = alloc_pool_descriptor (pool->name);
202#endif
263e39ce 203
0ea2d350 204 gcc_checking_assert (pool);
263e39ce 205
206 /* Free each block allocated to the pool. */
207 for (block = pool->block_list; block != NULL; block = next_block)
208 {
209 next_block = block->next;
210 free (block);
211 }
48694fc0 212
918c094d 213#ifdef GATHER_STATISTICS
214 desc->current -= (pool->elts_allocated - pool->elts_free) * pool->elt_size;
215#endif
48694fc0 216 pool->returned_free_list = NULL;
217 pool->virgin_free_list = NULL;
218 pool->virgin_elts_remaining = 0;
219 pool->elts_allocated = 0;
220 pool->elts_free = 0;
221 pool->blocks_allocated = 0;
222 pool->block_list = NULL;
223}
224
225/* Free all memory allocated for the given memory pool and the pool itself. */
226void
227free_alloc_pool (alloc_pool pool)
228{
229 /* First empty the pool. */
230 empty_alloc_pool (pool);
992f5b1b 231#ifdef ENABLE_CHECKING
232 memset (pool, 0xaf, sizeof (*pool));
233#endif
7fec61de 234 /* Lastly, free the pool. */
263e39ce 235 free (pool);
236}
237
0a06d4f0 238/* Frees the alloc_pool, if it is empty and zero *POOL in this case. */
239void
240free_alloc_pool_if_empty (alloc_pool *pool)
241{
242 if ((*pool)->elts_free == (*pool)->elts_allocated)
243 {
244 free_alloc_pool (*pool);
245 *pool = NULL;
246 }
247}
248
263e39ce 249/* Allocates one element from the pool specified. */
250void *
aecda0d6 251pool_alloc (alloc_pool pool)
263e39ce 252{
253 alloc_pool_list header;
7fec61de 254#ifdef GATHER_STATISTICS
255 struct alloc_pool_descriptor *desc = alloc_pool_descriptor (pool->name);
256
918c094d 257 desc->allocated += pool->elt_size;
258 desc->current += pool->elt_size;
259 if (desc->peak < desc->current)
260 desc->peak = desc->current;
7fec61de 261#endif
263e39ce 262
0ea2d350 263 gcc_checking_assert (pool);
263e39ce 264
265 /* If there are no more free elements, make some more!. */
3072d30e 266 if (!pool->returned_free_list)
263e39ce 267 {
3072d30e 268 char *block;
269 if (!pool->virgin_elts_remaining)
270 {
271 alloc_pool_list block_header;
272
273 /* Make the block. */
274 block = XNEWVEC (char, pool->block_size);
275 block_header = (alloc_pool_list) block;
276 block += align_eight (sizeof (struct alloc_pool_list_def));
48e1416a 277
3072d30e 278 /* Throw it on the block list. */
279 block_header->next = pool->block_list;
280 pool->block_list = block_header;
281
282 /* Make the block available for allocation. */
283 pool->virgin_free_list = block;
284 pool->virgin_elts_remaining = pool->elts_per_block;
285
286 /* Also update the number of elements we have free/allocated, and
287 increment the allocated block count. */
288 pool->elts_allocated += pool->elts_per_block;
289 pool->elts_free += pool->elts_per_block;
290 pool->blocks_allocated += 1;
291 }
292
48e1416a 293
3072d30e 294 /* We now know that we can take the first elt off the virgin list and
295 put it on the returned list. */
296 block = pool->virgin_free_list;
297 header = (alloc_pool_list) USER_PTR_FROM_ALLOCATION_OBJECT_PTR (block);
298 header->next = NULL;
a5f52a45 299#ifdef ENABLE_CHECKING
3072d30e 300 /* Mark the element to be free. */
301 ((allocation_object *) block)->id = 0;
a5f52a45 302#endif
3072d30e 303 pool->returned_free_list = header;
304 pool->virgin_free_list += pool->elt_size;
305 pool->virgin_elts_remaining--;
306
263e39ce 307 }
308
309 /* Pull the first free element from the free list, and return it. */
3072d30e 310 header = pool->returned_free_list;
311 pool->returned_free_list = header->next;
263e39ce 312 pool->elts_free--;
a5f52a45 313
314#ifdef ENABLE_CHECKING
315 /* Set the ID for element. */
316 ALLOCATION_OBJECT_PTR_FROM_USER_PTR (header)->id = pool->id;
317#endif
318
263e39ce 319 return ((void *) header);
320}
321
322/* Puts PTR back on POOL's free list. */
323void
aecda0d6 324pool_free (alloc_pool pool, void *ptr)
263e39ce 325{
326 alloc_pool_list header;
918c094d 327#ifdef GATHER_STATISTICS
328 struct alloc_pool_descriptor *desc = alloc_pool_descriptor (pool->name);
329#endif
263e39ce 330
263e39ce 331
64db345d 332#ifdef ENABLE_CHECKING
0ea2d350 333 gcc_assert (ptr
334 /* Check if we free more than we allocated, which is Bad (TM). */
335 && pool->elts_free < pool->elts_allocated
336 /* Check whether the PTR was allocated from POOL. */
337 && pool->id == ALLOCATION_OBJECT_PTR_FROM_USER_PTR (ptr)->id);
a5f52a45 338
3471582e 339 memset (ptr, 0xaf, pool->elt_size - offsetof (allocation_object, u.data));
340
a5f52a45 341 /* Mark the element to be free. */
342 ALLOCATION_OBJECT_PTR_FROM_USER_PTR (ptr)->id = 0;
343#else
a5f52a45 344#endif
345
263e39ce 346 header = (alloc_pool_list) ptr;
3072d30e 347 header->next = pool->returned_free_list;
348 pool->returned_free_list = header;
263e39ce 349 pool->elts_free++;
918c094d 350
351#ifdef GATHER_STATISTICS
352 desc->current -= pool->elt_size;
353#endif
354
263e39ce 355}
7fec61de 356/* Output per-alloc_pool statistics. */
357#ifdef GATHER_STATISTICS
358
359/* Used to accumulate statistics about alloc_pool sizes. */
360struct output_info
361{
918c094d 362 unsigned long total_created;
363 unsigned long total_allocated;
7fec61de 364};
365
366/* Called via htab_traverse. Output alloc_pool descriptor pointed out by SLOT
367 and update statistics. */
368static int
369print_statistics (void **slot, void *b)
370{
371 struct alloc_pool_descriptor *d = (struct alloc_pool_descriptor *) *slot;
372 struct output_info *i = (struct output_info *) b;
373
374 if (d->allocated)
375 {
918c094d 376 fprintf (stderr, "%-22s %6d %10lu %10lu(%10lu) %10lu(%10lu) %10lu(%10lu)\n", d->name,
48e1416a 377 d->elt_size, d->created, d->allocated, d->allocated / d->elt_size,
378 d->peak, d->peak / d->elt_size,
918c094d 379 d->current, d->current / d->elt_size);
380 i->total_allocated += d->allocated;
381 i->total_created += d->created;
7fec61de 382 }
383 return 1;
384}
385#endif
386
387/* Output per-alloc_pool memory usage statistics. */
2e2fd8fe 388void
389dump_alloc_pool_statistics (void)
7fec61de 390{
391#ifdef GATHER_STATISTICS
392 struct output_info info;
393
1bb42c87 394 if (!alloc_pool_hash)
395 return;
396
918c094d 397 fprintf (stderr, "\nAlloc-pool Kind Elt size Pools Allocated (elts) Peak (elts) Leak (elts)\n");
398 fprintf (stderr, "--------------------------------------------------------------------------------------------------------------\n");
399 info.total_created = 0;
400 info.total_allocated = 0;
7fec61de 401 htab_traverse (alloc_pool_hash, print_statistics, &info);
918c094d 402 fprintf (stderr, "--------------------------------------------------------------------------------------------------------------\n");
403 fprintf (stderr, "%-22s %7lu %10lu\n",
404 "Total", info.total_created, info.total_allocated);
405 fprintf (stderr, "--------------------------------------------------------------------------------------------------------------\n");
7fec61de 406#endif
407}