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