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