]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/alloc-pool.c
re PR testsuite/27476 (ACATS: Ada testsuite Bourne shell compatibility problem on...
[thirdparty/gcc.git] / gcc / alloc-pool.c
CommitLineData
7f22efe1 1/* Functions to support a pool of allocatable objects.
a2130901 2 Copyright (C) 1987, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005
76abd4c6 3 Free Software Foundation, Inc.
7f22efe1
DB
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
366ccddb
KC
20Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2102110-1301, USA. */
7f22efe1 22
7f22efe1
DB
23#include "config.h"
24#include "system.h"
25#include "alloc-pool.h"
1e0f41c9 26#include "hashtab.h"
7f22efe1 27
7f22efe1
DB
28#define align_eight(x) (((x+7) >> 3) << 3)
29
76abd4c6
JZ
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;
76abd4c6 47 HOST_WIDEST_INT align_i;
76abd4c6 48 long double align_ld;
76abd4c6
JZ
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
517958ba 61#ifdef ENABLE_CHECKING
76abd4c6
JZ
62/* Last used ID. */
63static ALLOC_POOL_ID_TYPE last_id;
517958ba 64#endif
76abd4c6 65
1e0f41c9
JH
66#ifdef GATHER_STATISTICS
67
a457ee07 68/* Store information about each particular alloc_pool. */
1e0f41c9
JH
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,
106 htab_hash_pointer (name),
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
7f22efe1
DB
116/* Create a pool of things of size SIZE, with NUM in each block we
117 allocate. */
118
119alloc_pool
4682ae04 120create_alloc_pool (const char *name, size_t size, size_t num)
7f22efe1
DB
121{
122 alloc_pool pool;
123 size_t pool_size, header_size;
1e0f41c9
JH
124#ifdef GATHER_STATISTICS
125 struct alloc_pool_descriptor *desc;
126#endif
7f22efe1 127
298e6adc 128 gcc_assert (name);
7f22efe1
DB
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. */
8b07361e 135 size = align_eight (size);
7f22efe1 136
76abd4c6
JZ
137#ifdef ENABLE_CHECKING
138 /* Add the aligned size of ID. */
139 size += offsetof (allocation_object, u.data);
140#endif
141
7f22efe1 142 /* Um, we can't really allocate 0 elements per block. */
298e6adc 143 gcc_assert (num);
7f22efe1
DB
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. */
703ad42b 149 pool = xmalloc (pool_size);
7f22efe1
DB
150
151 /* Now init the various pieces of our pool structure. */
1e0f41c9
JH
152 pool->name = /*xstrdup (name)*/name;
153#ifdef GATHER_STATISTICS
154 desc = alloc_pool_descriptor (name);
155 desc->created++;
156#endif
7f22efe1
DB
157 pool->elt_size = size;
158 pool->elts_per_block = num;
159
6614fd40 160 /* List header size should be a multiple of 8. */
7f22efe1
DB
161 header_size = align_eight (sizeof (struct alloc_pool_list_def));
162
163 pool->block_size = (size * num) + header_size;
164 pool->free_list = NULL;
165 pool->elts_allocated = 0;
166 pool->elts_free = 0;
167 pool->blocks_allocated = 0;
168 pool->block_list = NULL;
169
76abd4c6
JZ
170#ifdef ENABLE_CHECKING
171 /* Increase the last used ID and use it for this pool.
172 ID == 0 is used for free elements of pool so skip it. */
173 last_id++;
174 if (last_id == 0)
175 last_id++;
176
177 pool->id = last_id;
178#endif
179
7f22efe1
DB
180 return (pool);
181}
182
183/* Free all memory allocated for the given memory pool. */
184void
4682ae04 185free_alloc_pool (alloc_pool pool)
7f22efe1
DB
186{
187 alloc_pool_list block, next_block;
1e0f41c9
JH
188#ifdef GATHER_STATISTICS
189 struct alloc_pool_descriptor *desc = alloc_pool_descriptor (pool->name);
190#endif
7f22efe1 191
298e6adc 192 gcc_assert (pool);
7f22efe1
DB
193
194 /* Free each block allocated to the pool. */
195 for (block = pool->block_list; block != NULL; block = next_block)
196 {
197 next_block = block->next;
198 free (block);
1e0f41c9
JH
199#ifdef GATHER_STATISTICS
200 desc->current -= pool->block_size;
201#endif
7f22efe1 202 }
8b07361e
JH
203#ifdef ENABLE_CHECKING
204 memset (pool, 0xaf, sizeof (*pool));
205#endif
1e0f41c9 206 /* Lastly, free the pool. */
7f22efe1
DB
207 free (pool);
208}
209
210/* Allocates one element from the pool specified. */
211void *
4682ae04 212pool_alloc (alloc_pool pool)
7f22efe1
DB
213{
214 alloc_pool_list header;
215 char *block;
1e0f41c9
JH
216#ifdef GATHER_STATISTICS
217 struct alloc_pool_descriptor *desc = alloc_pool_descriptor (pool->name);
218
219 desc->allocated+=pool->elt_size;
220#endif
7f22efe1 221
298e6adc 222 gcc_assert (pool);
7f22efe1
DB
223
224 /* If there are no more free elements, make some more!. */
225 if (!pool->free_list)
226 {
227 size_t i;
228 alloc_pool_list block_header;
229
f9da5064 230 /* Make the block. */
5ed6ace5 231 block = XNEWVEC (char, pool->block_size);
7f22efe1
DB
232 block_header = (alloc_pool_list) block;
233 block += align_eight (sizeof (struct alloc_pool_list_def));
1e0f41c9
JH
234#ifdef GATHER_STATISTICS
235 desc->current += pool->block_size;
236 if (desc->peak < desc->current)
237 desc->peak = desc->current;
238#endif
7f22efe1 239
f9da5064 240 /* Throw it on the block list. */
7f22efe1
DB
241 block_header->next = pool->block_list;
242 pool->block_list = block_header;
243
244 /* Now put the actual block pieces onto the free list. */
245 for (i = 0; i < pool->elts_per_block; i++, block += pool->elt_size)
246 {
76abd4c6
JZ
247#ifdef ENABLE_CHECKING
248 /* Mark the element to be free. */
249 ((allocation_object *) block)->id = 0;
250#endif
251 header = (alloc_pool_list) USER_PTR_FROM_ALLOCATION_OBJECT_PTR (block);
7f22efe1
DB
252 header->next = pool->free_list;
253 pool->free_list = header;
254 }
255 /* Also update the number of elements we have free/allocated, and
256 increment the allocated block count. */
257 pool->elts_allocated += pool->elts_per_block;
258 pool->elts_free += pool->elts_per_block;
259 pool->blocks_allocated += 1;
260 }
261
262 /* Pull the first free element from the free list, and return it. */
263 header = pool->free_list;
264 pool->free_list = header->next;
265 pool->elts_free--;
76abd4c6
JZ
266
267#ifdef ENABLE_CHECKING
268 /* Set the ID for element. */
269 ALLOCATION_OBJECT_PTR_FROM_USER_PTR (header)->id = pool->id;
270#endif
271
7f22efe1
DB
272 return ((void *) header);
273}
274
275/* Puts PTR back on POOL's free list. */
276void
4682ae04 277pool_free (alloc_pool pool, void *ptr)
7f22efe1
DB
278{
279 alloc_pool_list header;
280
298e6adc 281 gcc_assert (ptr);
7f22efe1 282
298e6adc 283#ifdef ENABLE_CHECKING
8b07361e
JH
284 memset (ptr, 0xaf, pool->elt_size - offsetof (allocation_object, u.data));
285
76abd4c6 286 /* Check whether the PTR was allocated from POOL. */
298e6adc 287 gcc_assert (pool->id == ALLOCATION_OBJECT_PTR_FROM_USER_PTR (ptr)->id);
76abd4c6
JZ
288
289 /* Mark the element to be free. */
290 ALLOCATION_OBJECT_PTR_FROM_USER_PTR (ptr)->id = 0;
291#else
7f22efe1 292 /* Check if we free more than we allocated, which is Bad (TM). */
298e6adc 293 gcc_assert (pool->elts_free < pool->elts_allocated);
76abd4c6
JZ
294#endif
295
7f22efe1
DB
296 header = (alloc_pool_list) ptr;
297 header->next = pool->free_list;
298 pool->free_list = header;
299 pool->elts_free++;
300}
1e0f41c9
JH
301/* Output per-alloc_pool statistics. */
302#ifdef GATHER_STATISTICS
303
304/* Used to accumulate statistics about alloc_pool sizes. */
305struct output_info
306{
307 int count;
308 int size;
309};
310
311/* Called via htab_traverse. Output alloc_pool descriptor pointed out by SLOT
312 and update statistics. */
313static int
314print_statistics (void **slot, void *b)
315{
316 struct alloc_pool_descriptor *d = (struct alloc_pool_descriptor *) *slot;
317 struct output_info *i = (struct output_info *) b;
318
319 if (d->allocated)
320 {
321 fprintf (stderr, "%-21s %6d %10d %10d %10d\n", d->name,
322 d->created, d->allocated, d->peak, d->current);
323 i->size += d->allocated;
324 i->count += d->created;
325 }
326 return 1;
327}
328#endif
329
330/* Output per-alloc_pool memory usage statistics. */
331void dump_alloc_pool_statistics (void)
332{
333#ifdef GATHER_STATISTICS
334 struct output_info info;
335
08cee789
DJ
336 if (!alloc_pool_hash)
337 return;
338
1e0f41c9
JH
339 fprintf (stderr, "\nAlloc-pool Kind Pools Allocated Peak Leak\n");
340 fprintf (stderr, "-------------------------------------------------------------\n");
341 info.count = 0;
342 info.size = 0;
343 htab_traverse (alloc_pool_hash, print_statistics, &info);
344 fprintf (stderr, "-------------------------------------------------------------\n");
345 fprintf (stderr, "%-20s %7d %10d\n",
346 "Total", info.count, info.size);
347 fprintf (stderr, "-------------------------------------------------------------\n");
348#endif
349}