xref: /dragonfly/contrib/gcc-8.0/gcc/alloc-pool.h (revision 38fd1498)
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