GCC Middle and Back End API Reference
alloc-pool.h
Go to the documentation of this file.
1/* Functions to support a pool of allocatable objects
2 Copyright (C) 1997-2026 Free Software Foundation, Inc.
3 Contributed by Daniel Berlin <dan@cgsoftware.com>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20#ifndef ALLOC_POOL_H
21#define ALLOC_POOL_H
22
23#include "memory-block.h"
24#include "options.h" // for flag_checking
25
26extern void dump_alloc_pool_statistics (void);
27
28/* Flag indicates whether memory statistics are gathered any longer. */
29extern bool after_memory_report;
30
31typedef unsigned long ALLOC_POOL_ID_TYPE;
32
33/* Last used ID. */
35
36/* Pool allocator memory usage. */
37class pool_usage: public mem_usage
38{
39public:
40 /* Default constructor. */
42 /* Constructor. */
43 pool_usage (size_t allocated, size_t times, size_t peak,
44 size_t instances, size_t element_size,
45 const char *pool_name)
46 : mem_usage (allocated, times, peak, instances),
47 m_element_size (element_size),
48 m_pool_name (pool_name) {}
49
50 /* Sum the usage with SECOND usage. */
52 operator+ (const pool_usage &second)
53 {
54 return pool_usage (m_allocated + second.m_allocated,
55 m_times + second.m_times,
56 m_peak + second.m_peak,
57 m_instances + second.m_instances,
59 }
60
61 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
62 inline void
63 dump (mem_location *loc, const mem_usage &total) const
64 {
65 char *location_string = loc->to_string ();
66
67 fprintf (stderr, "%-32s%-48s " PRsa(5) PRsa(9) ":%5.1f%%"
68 PRsa(9) PRsa(9) ":%5.1f%%%12" PRIu64 "\n",
69 m_pool_name, location_string,
76 (uint64_t)m_element_size);
77
78 free (location_string);
79 }
80
81 /* Dump header with NAME. */
82 static inline void
83 dump_header (const char *name)
84 {
85 fprintf (stderr, "%-32s%-48s %6s%11s%16s%17s%12s\n", "Pool name", name,
86 "Pools", "Leak", "Peak", "Times", "Elt size");
87 }
88
89 /* Dump footer. */
90 inline void
92 {
93 fprintf (stderr, "%s" PRsa(82) PRsa(10) "\n", "Total",
95 }
96
97 /* Element size. */
99 /* Pool name. */
100 const char *m_pool_name;
101};
102
103inline auto &
108
109#if 0
110/* If a pool with custom block size is needed, one might use the following
111 template. An instance of this template can be used as a parameter for
112 instantiating base_pool_allocator template:
113
114 typedef custom_block_allocator <128*1024> huge_block_allocator;
115 ...
116 static base_pool_allocator <huge_block_allocator>
117 value_pool ("value", 16384);
118
119 Right now it's not used anywhere in the code, and is given here as an
120 example). */
121
122template <size_t BlockSize>
123class custom_block_allocator
124{
125public:
126 static const size_t block_size = BlockSize;
127
128 static inline void *
129 allocate () ATTRIBUTE_MALLOC
130 {
131 return XNEWVEC (char, BlockSize);
132 }
133
134 static inline void
135 release (void *block)
136 {
137 XDELETEVEC (block);
138 }
139};
140#endif
141
142/* Generic pool allocator. */
143
144template <typename TBlockAllocator>
146{
147public:
148 /* Default constructor for pool allocator called NAME. */
149 base_pool_allocator (const char *name, size_t size CXX_MEM_STAT_INFO);
151 void release ();
153 void *allocate () ATTRIBUTE_MALLOC;
154 void remove (void *object);
156
157private:
162
163 /* Initialize a pool allocator. */
164 void initialize ();
165
167 {
168#if CHECKING_P
169 /* The ID of alloc pool which the object was allocated from. */
171#endif
172
173 union
174 {
175 /* The data of the object. */
176 char data[1];
177
178 /* Because we want any type of data to be well aligned after the ID,
179 the following elements are here. They are never accessed so
180 the allocated object may be even smaller than this structure.
181 We do not care about alignment for floating-point types. */
182 char *align_p;
183 int64_t align_i;
184 } u;
185
186#if CHECKING_P
187 static inline allocation_object*
188 get_instance (void *data_ptr)
189 {
190 return (allocation_object *)(((char *)(data_ptr))
192 u.data));
193 }
194#endif
195
196 static inline void*
197 get_data (void *instance_ptr)
198 {
199 return (void*)(((allocation_object *) instance_ptr)->u.data);
200 }
201 };
202
203 /* Align X to 8. */
204 static inline size_t
205 align_eight (size_t x)
206 {
207 return (((x+7) >> 3) << 3);
208 }
209
210 const char *m_name;
213
214 /* These are the elements that have been allocated at least once
215 and freed. */
216 allocation_pool_list *m_returned_free_list;
217
218 /* These are the elements that have not yet been allocated out of
219 the last block obtained from XNEWVEC. */
221
222 /* The number of elements in the virgin_free_list that can be
223 allocated before needing another block. */
225 /* The number of elements that are allocated. */
227 /* The number of elements that are released. */
229 /* The number of allocated blocks. */
231 /* List of blocks that are used to allocate new objects. */
232 allocation_pool_list *m_block_list;
233 /* Size of a pool elements in bytes. */
235 /* Size in bytes that should be allocated for each element. */
236 size_t m_size;
237 /* Flag if a pool allocator is initialized. */
239 /* Memory allocation location. */
241};
242
243template <typename TBlockAllocator>
244inline
252
253/* Initialize a pool allocator. */
254
255template <typename TBlockAllocator>
256inline void
258{
260 m_initialized = true;
261
262 size_t size = m_size;
263
266
267 /* Make size large enough to store the list header. */
268 if (size < sizeof (allocation_pool_list*))
269 size = sizeof (allocation_pool_list*);
270
271 /* Now align the size to a multiple of 8. */
272 size = align_eight (size);
273
274 /* Add the aligned size of ID. */
275 size += offsetof (allocation_object, u.data);
276
277 m_elt_size = size;
278
279 if (GATHER_STATISTICS)
280 {
281 pool_usage *u = pool_allocator_usage ().register_descriptor
282 (this, new mem_location (m_location));
283
285 u->m_pool_name = m_name;
286 }
287
288 /* List header size should be a multiple of 8. */
289 size_t header_size = align_eight (sizeof (allocation_pool_list));
290
291 m_elts_per_block = (TBlockAllocator::block_size - header_size) / size;
293
294 /* Increase the last used ID and use it for this pool.
295 ID == 0 is used for free elements of pool so skip it. */
296 last_id++;
297 if (last_id == 0)
298 last_id++;
299
300 m_id = last_id;
301}
302
303/* Free all memory allocated for the given memory pool. */
304template <typename TBlockAllocator>
305inline void
307{
308 if (!m_initialized)
309 return;
310
311 allocation_pool_list *block, *next_block;
312
313 /* Free each block allocated to the pool. */
314 for (block = m_block_list; block != NULL; block = next_block)
315 {
316 next_block = block->next;
317 TBlockAllocator::release (block);
318 }
319
320 if (GATHER_STATISTICS && !after_memory_report)
321 {
322 pool_allocator_usage ().release_instance_overhead
324 }
325
330 m_elts_free = 0;
333}
334
335template <typename TBlockAllocator>
336inline void
342
343template <typename TBlockAllocator>
344inline base_pool_allocator <TBlockAllocator>::~base_pool_allocator ()
345{
346 release ();
347}
348
349/* Allocates one element from the pool specified. */
350template <typename TBlockAllocator>
351inline void*
353{
354 if (!m_initialized)
355 initialize ();
356
358#ifdef ENABLE_VALGRIND_ANNOTATIONS
359 int size;
360#endif
361
362 if (GATHER_STATISTICS)
363 {
364 pool_allocator_usage ().register_instance_overhead (m_elt_size, this);
365 }
366
367#ifdef ENABLE_VALGRIND_ANNOTATIONS
369#endif
370
371 /* If there are no more free elements, make some more!. */
373 {
374 char *block;
376 {
377 allocation_pool_list *block_header;
378
379 /* Make the block. */
380 block = reinterpret_cast<char *> (TBlockAllocator::allocate ());
381 block_header = new (block) allocation_pool_list;
382 block += align_eight (sizeof (allocation_pool_list));
383
384 /* Throw it on the block list. */
385 block_header->next = m_block_list;
386 m_block_list = block_header;
387
388 /* Make the block available for allocation. */
389 m_virgin_free_list = block;
391
392 /* Also update the number of elements we have free/allocated, and
393 increment the allocated block count. */
397 }
398
399 /* We now know that we can take the first elt off the virgin list and
400 put it on the returned list. */
401 block = m_virgin_free_list;
403 header->next = NULL;
404
405 /* Mark the element to be free. */
406#if CHECKING_P
407 ((allocation_object*) block)->id = 0;
408#endif
409 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_NOACCESS (header,size));
413
414 }
415
416 /* Pull the first free element from the free list, and return it. */
418 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_DEFINED (header, sizeof (*header)));
420 m_elts_free--;
421
422 /* Set the ID for element. */
423#if CHECKING_P
424 allocation_object::get_instance (header)->id = m_id;
425#endif
426 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_UNDEFINED (header, size));
427
428 return (void *)(header);
429}
430
431/* Puts PTR back on POOL's free list. */
432template <typename TBlockAllocator>
433inline void
435{
436 int size = m_elt_size - offsetof (allocation_object, u.data);
437
438 if (flag_checking)
439 {
441 gcc_assert (object
442 /* Check if we free more than we allocated. */
444#if CHECKING_P
445 /* Check whether the PTR was allocated from POOL. */
446 gcc_assert (m_id == allocation_object::get_instance (object)->id);
447#endif
448
449 memset (object, 0xaf, size);
450 }
451
452#if CHECKING_P
453 /* Mark the element to be free. */
454 allocation_object::get_instance (object)->id = 0;
455#endif
456
460 VALGRIND_DISCARD (VALGRIND_MAKE_MEM_NOACCESS (object, size));
461 m_elts_free++;
462
463 if (GATHER_STATISTICS)
464 {
465 pool_allocator_usage ().release_instance_overhead (this, m_elt_size);
466 }
467}
468
469/* Number of elements currently active (not returned to pool). Used for cheap
470 consistency checks. */
471template <typename TBlockAllocator>
472inline size_t
477
478/* Specialization of base_pool_allocator which should be used in most cases.
479 Another specialization may be needed, if object size is greater than
480 memory_block_pool::block_size (64 KB). */
481typedef base_pool_allocator <memory_block_pool> pool_allocator;
482
483/* Type based memory pool allocator. */
484template <typename T>
486{
487public:
488 /* Default constructor for pool allocator called NAME. */
490 m_allocator (name, sizeof (T) PASS_MEM_STAT) {}
491
492 inline void
494 {
495 m_allocator.release ();
496 }
497
498 inline void release_if_empty ()
499 {
500 m_allocator.release_if_empty ();
501 }
502
503
504 /* Allocate memory for instance of type T and call a default constructor. */
505
506 template<typename... Ts>
507 inline ATTRIBUTE_MALLOC T *
508 allocate (Ts... args)
509 {
510 return ::new (m_allocator.allocate ()) T (std::forward<Ts> (args)...);
511 }
512
513 /* Allocate memory for instance of type T and return void * that
514 could be used in situations where a default constructor is not provided
515 by the class T. */
516
517 inline void *
518 allocate_raw () ATTRIBUTE_MALLOC
519 {
520 return m_allocator.allocate ();
521 }
522
523 inline void
524 remove (T *object)
525 {
526 /* Call destructor. */
527 object->~T ();
528
529 m_allocator.remove (object);
530 }
531
532 inline void
533 remove_raw (void *object)
534 {
535 m_allocator.remove (object);
536 }
537
538 inline size_t
540 {
541 return m_allocator.num_elts_current ();
542 }
543
544private:
546};
547
548/* Store information about each particular alloc_pool. Note that this
549 will underestimate the amount the amount of storage used by a small amount:
550 1) The overhead in a pool is not accounted for.
551 2) The unallocated elements in a block are not accounted for. Note
552 that this can at worst case be one element smaller that the block
553 size for that pool. */
555{
556 /* Number of pools allocated. */
557 unsigned long created;
558 /* Gross allocated storage. */
559 unsigned long allocated;
560 /* Amount of currently active storage. */
561 unsigned long current;
562 /* Peak amount of storage used. */
563 unsigned long peak;
564 /* Size of element in the pool. */
566};
567
568/* Helper for classes that do not provide default ctor. */
569
570template <typename T>
571inline void *
572operator new (size_t, object_allocator<T> &a)
573{
574 return a.allocate_raw ();
575}
576
577/* Hashtable mapping alloc_pool names to descriptors. */
579
580
581#endif
ALLOC_POOL_ID_TYPE last_id
Definition alloc-pool.cc:26
bool after_memory_report
Definition alloc-pool.cc:27
ALLOC_POOL_ID_TYPE last_id
Definition alloc-pool.cc:26
base_pool_allocator< memory_block_pool > pool_allocator
Definition alloc-pool.h:481
hash_map< const char *, alloc_pool_descriptor > * alloc_pool_hash
void dump_alloc_pool_statistics(void)
Definition alloc-pool.cc:31
auto & pool_allocator_usage()
Definition alloc-pool.h:104
bool after_memory_report
Definition alloc-pool.cc:27
unsigned long ALLOC_POOL_ID_TYPE
Definition alloc-pool.h:31
size_t m_elts_free
Definition alloc-pool.h:228
const char * m_name
Definition alloc-pool.h:210
~base_pool_allocator()
Definition alloc-pool.h:344
char * m_virgin_free_list
Definition alloc-pool.h:220
void release_if_empty()
Definition alloc-pool.h:337
size_t m_virgin_elts_remaining
Definition alloc-pool.h:224
ALLOC_POOL_ID_TYPE m_id
Definition alloc-pool.h:211
allocation_pool_list * m_block_list
Definition alloc-pool.h:232
allocation_pool_list * m_returned_free_list
Definition alloc-pool.h:216
void initialize()
Definition alloc-pool.h:257
size_t m_size
Definition alloc-pool.h:236
base_pool_allocator(const char *name, size_t size CXX_MEM_STAT_INFO)
Definition alloc-pool.h:245
size_t m_elts_per_block
Definition alloc-pool.h:212
size_t m_blocks_allocated
Definition alloc-pool.h:230
static size_t align_eight(size_t x)
Definition alloc-pool.h:205
size_t m_elt_size
Definition alloc-pool.h:234
size_t m_elts_allocated
Definition alloc-pool.h:226
void release()
Definition alloc-pool.h:306
mem_location m_location
Definition alloc-pool.h:240
void * allocate() ATTRIBUTE_MALLOC
Definition alloc-pool.h:352
bool m_initialized
Definition alloc-pool.h:238
Definition hash-map.h:40
static auto & instance()
Definition mem-stats.h:290
Definition mem-stats.h:35
char * to_string()
Definition mem-stats.h:93
mem_usage()
Definition mem-stats.h:131
size_t m_allocated
Definition mem-stats.h:253
size_t m_peak
Definition mem-stats.h:257
size_t m_instances
Definition mem-stats.h:259
size_t m_times
Definition mem-stats.h:255
static float get_percent(size_t nominator, size_t denominator)
Definition mem-stats.h:230
Definition alloc-pool.h:486
ATTRIBUTE_MALLOC T * allocate(Ts... args)
Definition alloc-pool.h:508
pool_allocator m_allocator
Definition alloc-pool.h:545
void * allocate_raw() ATTRIBUTE_MALLOC
Definition alloc-pool.h:518
void remove_raw(void *object)
Definition alloc-pool.h:533
void remove(T *object)
Definition alloc-pool.h:524
object_allocator(const char *name CXX_MEM_STAT_INFO)
Definition alloc-pool.h:489
void release()
Definition alloc-pool.h:493
void release_if_empty()
Definition alloc-pool.h:498
size_t num_elts_current()
Definition alloc-pool.h:539
Definition alloc-pool.h:38
const char * m_pool_name
Definition alloc-pool.h:100
pool_usage()
Definition alloc-pool.h:41
pool_usage operator+(const pool_usage &second)
Definition alloc-pool.h:52
void dump(mem_location *loc, const mem_usage &total) const
Definition alloc-pool.h:63
pool_usage(size_t allocated, size_t times, size_t peak, size_t instances, size_t element_size, const char *pool_name)
Definition alloc-pool.h:43
size_t m_element_size
Definition alloc-pool.h:98
static void dump_header(const char *name)
Definition alloc-pool.h:83
void dump_footer()
Definition alloc-pool.h:91
static struct token T
Definition gengtype-parse.cc:45
free(str)
FILE * header
Definition genrecog.cc:5393
#define PRIu64
Definition hwint.h:93
@ ALLOC_POOL_ORIGIN
Definition mem-stats-traits.h:33
Ca & a
Definition poly-int.h:770
#define PASS_MEM_STAT
Definition statistics.h:54
#define MEM_STAT_DECL
Definition statistics.h:52
#define CXX_MEM_STAT_INFO
Definition statistics.h:58
Definition alloc-pool.h:555
unsigned long current
Definition alloc-pool.h:561
unsigned long allocated
Definition alloc-pool.h:559
int elt_size
Definition alloc-pool.h:565
unsigned long created
Definition alloc-pool.h:557
unsigned long peak
Definition alloc-pool.h:563
Definition alloc-pool.h:167
static void * get_data(void *instance_ptr)
Definition alloc-pool.h:197
int64_t align_i
Definition alloc-pool.h:183
union base_pool_allocator::allocation_object::@267103222306076073205270232113306207323151343062 u
char data[1]
Definition alloc-pool.h:176
char * align_p
Definition alloc-pool.h:182
allocation_pool_list * next
Definition alloc-pool.h:160
Definition collect2.cc:168
#define NULL
Definition system.h:58
#define gcc_assert(EXPR)
Definition system.h:828
#define offsetof(TYPE, MEMBER)
Definition system.h:759
#define false
Definition system.h:902
#define VALGRIND_DISCARD(x)
Definition system.h:1179
#define SIZE_AMOUNT(size)
Definition system.h:1247
#define PRsa(n)
Definition system.h:1251
#define gcc_checking_assert(EXPR)
Definition system.h:835