1*e4b17023SJohn Marino /* Vector API for GNU compiler.
2*e4b17023SJohn Marino Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010
3*e4b17023SJohn Marino Free Software Foundation, Inc.
4*e4b17023SJohn Marino Contributed by Nathan Sidwell <nathan@codesourcery.com>
5*e4b17023SJohn Marino
6*e4b17023SJohn Marino This file is part of GCC.
7*e4b17023SJohn Marino
8*e4b17023SJohn Marino GCC is free software; you can redistribute it and/or modify it under
9*e4b17023SJohn Marino the terms of the GNU General Public License as published by the Free
10*e4b17023SJohn Marino Software Foundation; either version 3, or (at your option) any later
11*e4b17023SJohn Marino version.
12*e4b17023SJohn Marino
13*e4b17023SJohn Marino GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14*e4b17023SJohn Marino WARRANTY; without even the implied warranty of MERCHANTABILITY or
15*e4b17023SJohn Marino FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16*e4b17023SJohn Marino for more details.
17*e4b17023SJohn Marino
18*e4b17023SJohn Marino You should have received a copy of the GNU General Public License
19*e4b17023SJohn Marino along with GCC; see the file COPYING3. If not see
20*e4b17023SJohn Marino <http://www.gnu.org/licenses/>. */
21*e4b17023SJohn Marino
22*e4b17023SJohn Marino /* This file is compiled twice: once for the generator programs
23*e4b17023SJohn Marino once for the compiler. */
24*e4b17023SJohn Marino #ifdef GENERATOR_FILE
25*e4b17023SJohn Marino #include "bconfig.h"
26*e4b17023SJohn Marino #else
27*e4b17023SJohn Marino #include "config.h"
28*e4b17023SJohn Marino #endif
29*e4b17023SJohn Marino
30*e4b17023SJohn Marino #include "system.h"
31*e4b17023SJohn Marino #include "coretypes.h"
32*e4b17023SJohn Marino #include "ggc.h"
33*e4b17023SJohn Marino #include "vec.h"
34*e4b17023SJohn Marino #include "diagnostic-core.h"
35*e4b17023SJohn Marino #include "hashtab.h"
36*e4b17023SJohn Marino
37*e4b17023SJohn Marino #ifdef GATHER_STATISTICS
38*e4b17023SJohn Marino
39*e4b17023SJohn Marino /* Store information about each particular vector. */
40*e4b17023SJohn Marino struct vec_descriptor
41*e4b17023SJohn Marino {
42*e4b17023SJohn Marino const char *function;
43*e4b17023SJohn Marino const char *file;
44*e4b17023SJohn Marino int line;
45*e4b17023SJohn Marino size_t allocated;
46*e4b17023SJohn Marino size_t times;
47*e4b17023SJohn Marino size_t peak;
48*e4b17023SJohn Marino };
49*e4b17023SJohn Marino
50*e4b17023SJohn Marino
51*e4b17023SJohn Marino /* Hashtable mapping vec addresses to descriptors. */
52*e4b17023SJohn Marino static htab_t vec_desc_hash;
53*e4b17023SJohn Marino
54*e4b17023SJohn Marino /* Hashtable helpers. */
55*e4b17023SJohn Marino static hashval_t
hash_descriptor(const void * p)56*e4b17023SJohn Marino hash_descriptor (const void *p)
57*e4b17023SJohn Marino {
58*e4b17023SJohn Marino const struct vec_descriptor *const d =
59*e4b17023SJohn Marino (const struct vec_descriptor *) p;
60*e4b17023SJohn Marino return htab_hash_pointer (d->file) + d->line;
61*e4b17023SJohn Marino }
62*e4b17023SJohn Marino static int
eq_descriptor(const void * p1,const void * p2)63*e4b17023SJohn Marino eq_descriptor (const void *p1, const void *p2)
64*e4b17023SJohn Marino {
65*e4b17023SJohn Marino const struct vec_descriptor *const d = (const struct vec_descriptor *) p1;
66*e4b17023SJohn Marino const struct vec_descriptor *const l = (const struct vec_descriptor *) p2;
67*e4b17023SJohn Marino return d->file == l->file && d->function == l->function && d->line == l->line;
68*e4b17023SJohn Marino }
69*e4b17023SJohn Marino
70*e4b17023SJohn Marino /* Hashtable converting address of allocated field to loc descriptor. */
71*e4b17023SJohn Marino static htab_t ptr_hash;
72*e4b17023SJohn Marino struct ptr_hash_entry
73*e4b17023SJohn Marino {
74*e4b17023SJohn Marino void *ptr;
75*e4b17023SJohn Marino struct vec_descriptor *loc;
76*e4b17023SJohn Marino size_t allocated;
77*e4b17023SJohn Marino };
78*e4b17023SJohn Marino
79*e4b17023SJohn Marino /* Hash table helpers functions. */
80*e4b17023SJohn Marino static hashval_t
hash_ptr(const void * p)81*e4b17023SJohn Marino hash_ptr (const void *p)
82*e4b17023SJohn Marino {
83*e4b17023SJohn Marino const struct ptr_hash_entry *const d = (const struct ptr_hash_entry *) p;
84*e4b17023SJohn Marino
85*e4b17023SJohn Marino return htab_hash_pointer (d->ptr);
86*e4b17023SJohn Marino }
87*e4b17023SJohn Marino
88*e4b17023SJohn Marino static int
eq_ptr(const void * p1,const void * p2)89*e4b17023SJohn Marino eq_ptr (const void *p1, const void *p2)
90*e4b17023SJohn Marino {
91*e4b17023SJohn Marino const struct ptr_hash_entry *const p = (const struct ptr_hash_entry *) p1;
92*e4b17023SJohn Marino
93*e4b17023SJohn Marino return (p->ptr == p2);
94*e4b17023SJohn Marino }
95*e4b17023SJohn Marino
96*e4b17023SJohn Marino /* Return descriptor for given call site, create new one if needed. */
97*e4b17023SJohn Marino static struct vec_descriptor *
vec_descriptor(const char * name,int line,const char * function)98*e4b17023SJohn Marino vec_descriptor (const char *name, int line, const char *function)
99*e4b17023SJohn Marino {
100*e4b17023SJohn Marino struct vec_descriptor loc;
101*e4b17023SJohn Marino struct vec_descriptor **slot;
102*e4b17023SJohn Marino
103*e4b17023SJohn Marino loc.file = name;
104*e4b17023SJohn Marino loc.line = line;
105*e4b17023SJohn Marino loc.function = function;
106*e4b17023SJohn Marino if (!vec_desc_hash)
107*e4b17023SJohn Marino vec_desc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL);
108*e4b17023SJohn Marino
109*e4b17023SJohn Marino slot = (struct vec_descriptor **) htab_find_slot (vec_desc_hash, &loc,
110*e4b17023SJohn Marino INSERT);
111*e4b17023SJohn Marino if (*slot)
112*e4b17023SJohn Marino return *slot;
113*e4b17023SJohn Marino *slot = XCNEW (struct vec_descriptor);
114*e4b17023SJohn Marino (*slot)->file = name;
115*e4b17023SJohn Marino (*slot)->line = line;
116*e4b17023SJohn Marino (*slot)->function = function;
117*e4b17023SJohn Marino (*slot)->allocated = 0;
118*e4b17023SJohn Marino (*slot)->peak = 0;
119*e4b17023SJohn Marino return *slot;
120*e4b17023SJohn Marino }
121*e4b17023SJohn Marino
122*e4b17023SJohn Marino /* Account the overhead. */
123*e4b17023SJohn Marino static void
register_overhead(struct vec_prefix * ptr,size_t size,const char * name,int line,const char * function)124*e4b17023SJohn Marino register_overhead (struct vec_prefix *ptr, size_t size,
125*e4b17023SJohn Marino const char *name, int line, const char *function)
126*e4b17023SJohn Marino {
127*e4b17023SJohn Marino struct vec_descriptor *loc = vec_descriptor (name, line, function);
128*e4b17023SJohn Marino struct ptr_hash_entry *p = XNEW (struct ptr_hash_entry);
129*e4b17023SJohn Marino PTR *slot;
130*e4b17023SJohn Marino
131*e4b17023SJohn Marino p->ptr = ptr;
132*e4b17023SJohn Marino p->loc = loc;
133*e4b17023SJohn Marino p->allocated = size;
134*e4b17023SJohn Marino if (!ptr_hash)
135*e4b17023SJohn Marino ptr_hash = htab_create (10, hash_ptr, eq_ptr, NULL);
136*e4b17023SJohn Marino slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr), INSERT);
137*e4b17023SJohn Marino gcc_assert (!*slot);
138*e4b17023SJohn Marino *slot = p;
139*e4b17023SJohn Marino
140*e4b17023SJohn Marino loc->allocated += size;
141*e4b17023SJohn Marino if (loc->peak < loc->allocated)
142*e4b17023SJohn Marino loc->peak += loc->allocated;
143*e4b17023SJohn Marino loc->times++;
144*e4b17023SJohn Marino }
145*e4b17023SJohn Marino
146*e4b17023SJohn Marino /* Notice that the pointer has been freed. */
147*e4b17023SJohn Marino static void
free_overhead(struct vec_prefix * ptr)148*e4b17023SJohn Marino free_overhead (struct vec_prefix *ptr)
149*e4b17023SJohn Marino {
150*e4b17023SJohn Marino PTR *slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr),
151*e4b17023SJohn Marino NO_INSERT);
152*e4b17023SJohn Marino struct ptr_hash_entry *p = (struct ptr_hash_entry *) *slot;
153*e4b17023SJohn Marino p->loc->allocated -= p->allocated;
154*e4b17023SJohn Marino htab_clear_slot (ptr_hash, slot);
155*e4b17023SJohn Marino free (p);
156*e4b17023SJohn Marino }
157*e4b17023SJohn Marino
158*e4b17023SJohn Marino void
vec_heap_free(void * ptr)159*e4b17023SJohn Marino vec_heap_free (void *ptr)
160*e4b17023SJohn Marino {
161*e4b17023SJohn Marino free_overhead ((struct vec_prefix *)ptr);
162*e4b17023SJohn Marino free (ptr);
163*e4b17023SJohn Marino }
164*e4b17023SJohn Marino #endif
165*e4b17023SJohn Marino
166*e4b17023SJohn Marino /* Calculate the new ALLOC value, making sure that RESERVE slots are
167*e4b17023SJohn Marino free. If EXACT grow exactly, otherwise grow exponentially. */
168*e4b17023SJohn Marino
169*e4b17023SJohn Marino static inline unsigned
calculate_allocation(const struct vec_prefix * pfx,int reserve,bool exact)170*e4b17023SJohn Marino calculate_allocation (const struct vec_prefix *pfx, int reserve, bool exact)
171*e4b17023SJohn Marino {
172*e4b17023SJohn Marino unsigned alloc = 0;
173*e4b17023SJohn Marino unsigned num = 0;
174*e4b17023SJohn Marino
175*e4b17023SJohn Marino gcc_assert (reserve >= 0);
176*e4b17023SJohn Marino
177*e4b17023SJohn Marino if (pfx)
178*e4b17023SJohn Marino {
179*e4b17023SJohn Marino alloc = pfx->alloc;
180*e4b17023SJohn Marino num = pfx->num;
181*e4b17023SJohn Marino }
182*e4b17023SJohn Marino else if (!reserve)
183*e4b17023SJohn Marino /* If there's no prefix, and we've not requested anything, then we
184*e4b17023SJohn Marino will create a NULL vector. */
185*e4b17023SJohn Marino return 0;
186*e4b17023SJohn Marino
187*e4b17023SJohn Marino /* We must have run out of room. */
188*e4b17023SJohn Marino gcc_assert (alloc - num < (unsigned) reserve);
189*e4b17023SJohn Marino
190*e4b17023SJohn Marino if (exact)
191*e4b17023SJohn Marino /* Exact size. */
192*e4b17023SJohn Marino alloc = num + reserve;
193*e4b17023SJohn Marino else
194*e4b17023SJohn Marino {
195*e4b17023SJohn Marino /* Exponential growth. */
196*e4b17023SJohn Marino if (!alloc)
197*e4b17023SJohn Marino alloc = 4;
198*e4b17023SJohn Marino else if (alloc < 16)
199*e4b17023SJohn Marino /* Double when small. */
200*e4b17023SJohn Marino alloc = alloc * 2;
201*e4b17023SJohn Marino else
202*e4b17023SJohn Marino /* Grow slower when large. */
203*e4b17023SJohn Marino alloc = (alloc * 3 / 2);
204*e4b17023SJohn Marino
205*e4b17023SJohn Marino /* If this is still too small, set it to the right size. */
206*e4b17023SJohn Marino if (alloc < num + reserve)
207*e4b17023SJohn Marino alloc = num + reserve;
208*e4b17023SJohn Marino }
209*e4b17023SJohn Marino return alloc;
210*e4b17023SJohn Marino }
211*e4b17023SJohn Marino
212*e4b17023SJohn Marino /* Ensure there are at least RESERVE free slots in VEC. If EXACT grow
213*e4b17023SJohn Marino exactly, else grow exponentially. As a special case, if VEC is
214*e4b17023SJohn Marino NULL and RESERVE is 0, no vector will be created. The vector's
215*e4b17023SJohn Marino trailing array is at VEC_OFFSET offset and consists of ELT_SIZE
216*e4b17023SJohn Marino sized elements. */
217*e4b17023SJohn Marino
218*e4b17023SJohn Marino static void *
vec_gc_o_reserve_1(void * vec,int reserve,size_t vec_offset,size_t elt_size,bool exact MEM_STAT_DECL)219*e4b17023SJohn Marino vec_gc_o_reserve_1 (void *vec, int reserve, size_t vec_offset, size_t elt_size,
220*e4b17023SJohn Marino bool exact MEM_STAT_DECL)
221*e4b17023SJohn Marino {
222*e4b17023SJohn Marino struct vec_prefix *pfx = (struct vec_prefix *) vec;
223*e4b17023SJohn Marino unsigned alloc = calculate_allocation (pfx, reserve, exact);
224*e4b17023SJohn Marino size_t size;
225*e4b17023SJohn Marino
226*e4b17023SJohn Marino if (!alloc)
227*e4b17023SJohn Marino {
228*e4b17023SJohn Marino if (pfx)
229*e4b17023SJohn Marino ggc_free (pfx);
230*e4b17023SJohn Marino return NULL;
231*e4b17023SJohn Marino }
232*e4b17023SJohn Marino
233*e4b17023SJohn Marino /* Calculate the amount of space we want. */
234*e4b17023SJohn Marino size = vec_offset + alloc * elt_size;
235*e4b17023SJohn Marino /* Ask the allocator how much space it will really give us. */
236*e4b17023SJohn Marino size = ggc_round_alloc_size (size);
237*e4b17023SJohn Marino /* Adjust the number of slots accordingly. */
238*e4b17023SJohn Marino alloc = (size - vec_offset) / elt_size;
239*e4b17023SJohn Marino /* And finally, recalculate the amount of space we ask for. */
240*e4b17023SJohn Marino size = vec_offset + alloc * elt_size;
241*e4b17023SJohn Marino
242*e4b17023SJohn Marino vec = ggc_realloc_stat (vec, size PASS_MEM_STAT);
243*e4b17023SJohn Marino
244*e4b17023SJohn Marino ((struct vec_prefix *)vec)->alloc = alloc;
245*e4b17023SJohn Marino if (!pfx)
246*e4b17023SJohn Marino ((struct vec_prefix *)vec)->num = 0;
247*e4b17023SJohn Marino
248*e4b17023SJohn Marino return vec;
249*e4b17023SJohn Marino }
250*e4b17023SJohn Marino
251*e4b17023SJohn Marino /* Ensure there are at least RESERVE free slots in VEC, growing
252*e4b17023SJohn Marino exponentially. If RESERVE < 0 grow exactly, else grow
253*e4b17023SJohn Marino exponentially. As a special case, if VEC is NULL, and RESERVE is
254*e4b17023SJohn Marino 0, no vector will be created. */
255*e4b17023SJohn Marino
256*e4b17023SJohn Marino void *
vec_gc_p_reserve(void * vec,int reserve MEM_STAT_DECL)257*e4b17023SJohn Marino vec_gc_p_reserve (void *vec, int reserve MEM_STAT_DECL)
258*e4b17023SJohn Marino {
259*e4b17023SJohn Marino return vec_gc_o_reserve_1 (vec, reserve,
260*e4b17023SJohn Marino sizeof (struct vec_prefix),
261*e4b17023SJohn Marino sizeof (void *), false
262*e4b17023SJohn Marino PASS_MEM_STAT);
263*e4b17023SJohn Marino }
264*e4b17023SJohn Marino
265*e4b17023SJohn Marino /* Ensure there are at least RESERVE free slots in VEC, growing
266*e4b17023SJohn Marino exactly. If RESERVE < 0 grow exactly, else grow exponentially. As
267*e4b17023SJohn Marino a special case, if VEC is NULL, and RESERVE is 0, no vector will be
268*e4b17023SJohn Marino created. */
269*e4b17023SJohn Marino
270*e4b17023SJohn Marino void *
vec_gc_p_reserve_exact(void * vec,int reserve MEM_STAT_DECL)271*e4b17023SJohn Marino vec_gc_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
272*e4b17023SJohn Marino {
273*e4b17023SJohn Marino return vec_gc_o_reserve_1 (vec, reserve,
274*e4b17023SJohn Marino sizeof (struct vec_prefix),
275*e4b17023SJohn Marino sizeof (void *), true
276*e4b17023SJohn Marino PASS_MEM_STAT);
277*e4b17023SJohn Marino }
278*e4b17023SJohn Marino
279*e4b17023SJohn Marino /* As for vec_gc_p_reserve, but for object vectors. The vector's
280*e4b17023SJohn Marino trailing array is at VEC_OFFSET offset and consists of ELT_SIZE
281*e4b17023SJohn Marino sized elements. */
282*e4b17023SJohn Marino
283*e4b17023SJohn Marino void *
vec_gc_o_reserve(void * vec,int reserve,size_t vec_offset,size_t elt_size MEM_STAT_DECL)284*e4b17023SJohn Marino vec_gc_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size
285*e4b17023SJohn Marino MEM_STAT_DECL)
286*e4b17023SJohn Marino {
287*e4b17023SJohn Marino return vec_gc_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
288*e4b17023SJohn Marino PASS_MEM_STAT);
289*e4b17023SJohn Marino }
290*e4b17023SJohn Marino
291*e4b17023SJohn Marino /* As for vec_gc_p_reserve_exact, but for object vectors. The
292*e4b17023SJohn Marino vector's trailing array is at VEC_OFFSET offset and consists of
293*e4b17023SJohn Marino ELT_SIZE sized elements. */
294*e4b17023SJohn Marino
295*e4b17023SJohn Marino void *
vec_gc_o_reserve_exact(void * vec,int reserve,size_t vec_offset,size_t elt_size MEM_STAT_DECL)296*e4b17023SJohn Marino vec_gc_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
297*e4b17023SJohn Marino size_t elt_size MEM_STAT_DECL)
298*e4b17023SJohn Marino {
299*e4b17023SJohn Marino return vec_gc_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
300*e4b17023SJohn Marino PASS_MEM_STAT);
301*e4b17023SJohn Marino }
302*e4b17023SJohn Marino
303*e4b17023SJohn Marino /* As for vec_gc_o_reserve_1, but for heap allocated vectors. */
304*e4b17023SJohn Marino
305*e4b17023SJohn Marino static void *
vec_heap_o_reserve_1(void * vec,int reserve,size_t vec_offset,size_t elt_size,bool exact MEM_STAT_DECL)306*e4b17023SJohn Marino vec_heap_o_reserve_1 (void *vec, int reserve, size_t vec_offset,
307*e4b17023SJohn Marino size_t elt_size, bool exact MEM_STAT_DECL)
308*e4b17023SJohn Marino {
309*e4b17023SJohn Marino struct vec_prefix *pfx = (struct vec_prefix *) vec;
310*e4b17023SJohn Marino unsigned alloc = calculate_allocation (pfx, reserve, exact);
311*e4b17023SJohn Marino
312*e4b17023SJohn Marino if (!alloc)
313*e4b17023SJohn Marino {
314*e4b17023SJohn Marino if (pfx)
315*e4b17023SJohn Marino vec_heap_free (pfx);
316*e4b17023SJohn Marino return NULL;
317*e4b17023SJohn Marino }
318*e4b17023SJohn Marino
319*e4b17023SJohn Marino #ifdef GATHER_STATISTICS
320*e4b17023SJohn Marino if (vec)
321*e4b17023SJohn Marino free_overhead (pfx);
322*e4b17023SJohn Marino #endif
323*e4b17023SJohn Marino
324*e4b17023SJohn Marino vec = xrealloc (vec, vec_offset + alloc * elt_size);
325*e4b17023SJohn Marino ((struct vec_prefix *)vec)->alloc = alloc;
326*e4b17023SJohn Marino if (!pfx)
327*e4b17023SJohn Marino ((struct vec_prefix *)vec)->num = 0;
328*e4b17023SJohn Marino #ifdef GATHER_STATISTICS
329*e4b17023SJohn Marino if (vec)
330*e4b17023SJohn Marino register_overhead ((struct vec_prefix *)vec,
331*e4b17023SJohn Marino vec_offset + alloc * elt_size PASS_MEM_STAT);
332*e4b17023SJohn Marino #endif
333*e4b17023SJohn Marino
334*e4b17023SJohn Marino return vec;
335*e4b17023SJohn Marino }
336*e4b17023SJohn Marino
337*e4b17023SJohn Marino /* As for vec_gc_p_reserve, but for heap allocated vectors. */
338*e4b17023SJohn Marino
339*e4b17023SJohn Marino void *
vec_heap_p_reserve(void * vec,int reserve MEM_STAT_DECL)340*e4b17023SJohn Marino vec_heap_p_reserve (void *vec, int reserve MEM_STAT_DECL)
341*e4b17023SJohn Marino {
342*e4b17023SJohn Marino return vec_heap_o_reserve_1 (vec, reserve,
343*e4b17023SJohn Marino sizeof (struct vec_prefix),
344*e4b17023SJohn Marino sizeof (void *), false
345*e4b17023SJohn Marino PASS_MEM_STAT);
346*e4b17023SJohn Marino }
347*e4b17023SJohn Marino
348*e4b17023SJohn Marino /* As for vec_gc_p_reserve_exact, but for heap allocated vectors. */
349*e4b17023SJohn Marino
350*e4b17023SJohn Marino void *
vec_heap_p_reserve_exact(void * vec,int reserve MEM_STAT_DECL)351*e4b17023SJohn Marino vec_heap_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
352*e4b17023SJohn Marino {
353*e4b17023SJohn Marino return vec_heap_o_reserve_1 (vec, reserve,
354*e4b17023SJohn Marino sizeof (struct vec_prefix),
355*e4b17023SJohn Marino sizeof (void *), true
356*e4b17023SJohn Marino PASS_MEM_STAT);
357*e4b17023SJohn Marino }
358*e4b17023SJohn Marino
359*e4b17023SJohn Marino /* As for vec_gc_o_reserve, but for heap allocated vectors. */
360*e4b17023SJohn Marino
361*e4b17023SJohn Marino void *
vec_heap_o_reserve(void * vec,int reserve,size_t vec_offset,size_t elt_size MEM_STAT_DECL)362*e4b17023SJohn Marino vec_heap_o_reserve (void *vec, int reserve, size_t vec_offset, size_t elt_size
363*e4b17023SJohn Marino MEM_STAT_DECL)
364*e4b17023SJohn Marino {
365*e4b17023SJohn Marino return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
366*e4b17023SJohn Marino PASS_MEM_STAT);
367*e4b17023SJohn Marino }
368*e4b17023SJohn Marino
369*e4b17023SJohn Marino /* As for vec_gc_o_reserve_exact, but for heap allocated vectors. */
370*e4b17023SJohn Marino
371*e4b17023SJohn Marino void *
vec_heap_o_reserve_exact(void * vec,int reserve,size_t vec_offset,size_t elt_size MEM_STAT_DECL)372*e4b17023SJohn Marino vec_heap_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
373*e4b17023SJohn Marino size_t elt_size MEM_STAT_DECL)
374*e4b17023SJohn Marino {
375*e4b17023SJohn Marino return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
376*e4b17023SJohn Marino PASS_MEM_STAT);
377*e4b17023SJohn Marino }
378*e4b17023SJohn Marino
379*e4b17023SJohn Marino /* Stack vectors are a little different. VEC_alloc turns into a call
380*e4b17023SJohn Marino to vec_stack_p_reserve_exact1 and passes in space allocated via a
381*e4b17023SJohn Marino call to alloca. We record that pointer so that we know that we
382*e4b17023SJohn Marino shouldn't free it. If the vector is resized, we resize it on the
383*e4b17023SJohn Marino heap. We record the pointers in a vector and search it in LIFO
384*e4b17023SJohn Marino order--i.e., we look for the newest stack vectors first. We don't
385*e4b17023SJohn Marino expect too many stack vectors at any one level, and searching from
386*e4b17023SJohn Marino the end should normally be efficient even if they are used in a
387*e4b17023SJohn Marino recursive function. */
388*e4b17023SJohn Marino
389*e4b17023SJohn Marino typedef void *void_p;
390*e4b17023SJohn Marino DEF_VEC_P(void_p);
391*e4b17023SJohn Marino DEF_VEC_ALLOC_P(void_p,heap);
392*e4b17023SJohn Marino
VEC(void_p,heap)393*e4b17023SJohn Marino static VEC(void_p,heap) *stack_vecs;
394*e4b17023SJohn Marino
395*e4b17023SJohn Marino /* Allocate a vector which uses alloca for the initial allocation.
396*e4b17023SJohn Marino SPACE is space allocated using alloca, ALLOC is the number of
397*e4b17023SJohn Marino entries allocated. */
398*e4b17023SJohn Marino
399*e4b17023SJohn Marino void *
400*e4b17023SJohn Marino vec_stack_p_reserve_exact_1 (int alloc, void *space)
401*e4b17023SJohn Marino {
402*e4b17023SJohn Marino struct vec_prefix *pfx = (struct vec_prefix *) space;
403*e4b17023SJohn Marino
404*e4b17023SJohn Marino VEC_safe_push (void_p, heap, stack_vecs, space);
405*e4b17023SJohn Marino
406*e4b17023SJohn Marino pfx->num = 0;
407*e4b17023SJohn Marino pfx->alloc = alloc;
408*e4b17023SJohn Marino
409*e4b17023SJohn Marino return space;
410*e4b17023SJohn Marino }
411*e4b17023SJohn Marino
412*e4b17023SJohn Marino /* Grow a vector allocated using alloca. When this happens, we switch
413*e4b17023SJohn Marino back to heap allocation. We remove the vector from stack_vecs, if
414*e4b17023SJohn Marino it is there, since we no longer need to avoid freeing it. */
415*e4b17023SJohn Marino
416*e4b17023SJohn Marino static void *
vec_stack_o_reserve_1(void * vec,int reserve,size_t vec_offset,size_t elt_size,bool exact MEM_STAT_DECL)417*e4b17023SJohn Marino vec_stack_o_reserve_1 (void *vec, int reserve, size_t vec_offset,
418*e4b17023SJohn Marino size_t elt_size, bool exact MEM_STAT_DECL)
419*e4b17023SJohn Marino {
420*e4b17023SJohn Marino bool found;
421*e4b17023SJohn Marino unsigned int ix;
422*e4b17023SJohn Marino void *newvec;
423*e4b17023SJohn Marino
424*e4b17023SJohn Marino found = false;
425*e4b17023SJohn Marino for (ix = VEC_length (void_p, stack_vecs); ix > 0; --ix)
426*e4b17023SJohn Marino {
427*e4b17023SJohn Marino if (VEC_index (void_p, stack_vecs, ix - 1) == vec)
428*e4b17023SJohn Marino {
429*e4b17023SJohn Marino VEC_unordered_remove (void_p, stack_vecs, ix - 1);
430*e4b17023SJohn Marino found = true;
431*e4b17023SJohn Marino break;
432*e4b17023SJohn Marino }
433*e4b17023SJohn Marino }
434*e4b17023SJohn Marino
435*e4b17023SJohn Marino if (!found)
436*e4b17023SJohn Marino {
437*e4b17023SJohn Marino /* VEC is already on the heap. */
438*e4b17023SJohn Marino return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size,
439*e4b17023SJohn Marino exact PASS_MEM_STAT);
440*e4b17023SJohn Marino }
441*e4b17023SJohn Marino
442*e4b17023SJohn Marino /* Move VEC to the heap. */
443*e4b17023SJohn Marino reserve += ((struct vec_prefix *) vec)->num;
444*e4b17023SJohn Marino newvec = vec_heap_o_reserve_1 (NULL, reserve, vec_offset, elt_size,
445*e4b17023SJohn Marino exact PASS_MEM_STAT);
446*e4b17023SJohn Marino if (newvec && vec)
447*e4b17023SJohn Marino {
448*e4b17023SJohn Marino ((struct vec_prefix *) newvec)->num = ((struct vec_prefix *) vec)->num;
449*e4b17023SJohn Marino memcpy (((struct vec_prefix *) newvec)+1,
450*e4b17023SJohn Marino ((struct vec_prefix *) vec)+1,
451*e4b17023SJohn Marino ((struct vec_prefix *) vec)->num * elt_size);
452*e4b17023SJohn Marino }
453*e4b17023SJohn Marino return newvec;
454*e4b17023SJohn Marino }
455*e4b17023SJohn Marino
456*e4b17023SJohn Marino /* Grow a vector allocated on the stack. */
457*e4b17023SJohn Marino
458*e4b17023SJohn Marino void *
vec_stack_p_reserve(void * vec,int reserve MEM_STAT_DECL)459*e4b17023SJohn Marino vec_stack_p_reserve (void *vec, int reserve MEM_STAT_DECL)
460*e4b17023SJohn Marino {
461*e4b17023SJohn Marino return vec_stack_o_reserve_1 (vec, reserve,
462*e4b17023SJohn Marino sizeof (struct vec_prefix),
463*e4b17023SJohn Marino sizeof (void *), false
464*e4b17023SJohn Marino PASS_MEM_STAT);
465*e4b17023SJohn Marino }
466*e4b17023SJohn Marino
467*e4b17023SJohn Marino /* Exact version of vec_stack_p_reserve. */
468*e4b17023SJohn Marino
469*e4b17023SJohn Marino void *
vec_stack_p_reserve_exact(void * vec,int reserve MEM_STAT_DECL)470*e4b17023SJohn Marino vec_stack_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL)
471*e4b17023SJohn Marino {
472*e4b17023SJohn Marino return vec_stack_o_reserve_1 (vec, reserve,
473*e4b17023SJohn Marino sizeof (struct vec_prefix),
474*e4b17023SJohn Marino sizeof (void *), true
475*e4b17023SJohn Marino PASS_MEM_STAT);
476*e4b17023SJohn Marino }
477*e4b17023SJohn Marino
478*e4b17023SJohn Marino /* Like vec_stack_p_reserve, but for objects. */
479*e4b17023SJohn Marino
480*e4b17023SJohn Marino void *
vec_stack_o_reserve(void * vec,int reserve,size_t vec_offset,size_t elt_size MEM_STAT_DECL)481*e4b17023SJohn Marino vec_stack_o_reserve (void *vec, int reserve, size_t vec_offset,
482*e4b17023SJohn Marino size_t elt_size MEM_STAT_DECL)
483*e4b17023SJohn Marino {
484*e4b17023SJohn Marino return vec_stack_o_reserve_1 (vec, reserve, vec_offset, elt_size, false
485*e4b17023SJohn Marino PASS_MEM_STAT);
486*e4b17023SJohn Marino }
487*e4b17023SJohn Marino
488*e4b17023SJohn Marino /* Like vec_stack_p_reserve_exact, but for objects. */
489*e4b17023SJohn Marino
490*e4b17023SJohn Marino void *
vec_stack_o_reserve_exact(void * vec,int reserve,size_t vec_offset,size_t elt_size MEM_STAT_DECL)491*e4b17023SJohn Marino vec_stack_o_reserve_exact (void *vec, int reserve, size_t vec_offset,
492*e4b17023SJohn Marino size_t elt_size MEM_STAT_DECL)
493*e4b17023SJohn Marino {
494*e4b17023SJohn Marino return vec_stack_o_reserve_1 (vec, reserve, vec_offset, elt_size, true
495*e4b17023SJohn Marino PASS_MEM_STAT);
496*e4b17023SJohn Marino }
497*e4b17023SJohn Marino
498*e4b17023SJohn Marino /* Free a vector allocated on the stack. Don't actually free it if we
499*e4b17023SJohn Marino find it in the hash table. */
500*e4b17023SJohn Marino
501*e4b17023SJohn Marino void
vec_stack_free(void * vec)502*e4b17023SJohn Marino vec_stack_free (void *vec)
503*e4b17023SJohn Marino {
504*e4b17023SJohn Marino unsigned int ix;
505*e4b17023SJohn Marino
506*e4b17023SJohn Marino for (ix = VEC_length (void_p, stack_vecs); ix > 0; --ix)
507*e4b17023SJohn Marino {
508*e4b17023SJohn Marino if (VEC_index (void_p, stack_vecs, ix - 1) == vec)
509*e4b17023SJohn Marino {
510*e4b17023SJohn Marino VEC_unordered_remove (void_p, stack_vecs, ix - 1);
511*e4b17023SJohn Marino return;
512*e4b17023SJohn Marino }
513*e4b17023SJohn Marino }
514*e4b17023SJohn Marino
515*e4b17023SJohn Marino /* VEC was not on the list of vecs allocated on the stack, so it
516*e4b17023SJohn Marino must be allocated on the heap. */
517*e4b17023SJohn Marino vec_heap_free (vec);
518*e4b17023SJohn Marino }
519*e4b17023SJohn Marino
520*e4b17023SJohn Marino #if ENABLE_CHECKING
521*e4b17023SJohn Marino /* Issue a vector domain error, and then fall over. */
522*e4b17023SJohn Marino
523*e4b17023SJohn Marino void
vec_assert_fail(const char * op,const char * struct_name,const char * file,unsigned int line,const char * function)524*e4b17023SJohn Marino vec_assert_fail (const char *op, const char *struct_name,
525*e4b17023SJohn Marino const char *file, unsigned int line, const char *function)
526*e4b17023SJohn Marino {
527*e4b17023SJohn Marino internal_error ("vector %s %s domain error, in %s at %s:%u",
528*e4b17023SJohn Marino struct_name, op, function, trim_filename (file), line);
529*e4b17023SJohn Marino }
530*e4b17023SJohn Marino #endif
531*e4b17023SJohn Marino
532*e4b17023SJohn Marino #ifdef GATHER_STATISTICS
533*e4b17023SJohn Marino /* Helper for qsort; sort descriptors by amount of memory consumed. */
534*e4b17023SJohn Marino static int
cmp_statistic(const void * loc1,const void * loc2)535*e4b17023SJohn Marino cmp_statistic (const void *loc1, const void *loc2)
536*e4b17023SJohn Marino {
537*e4b17023SJohn Marino const struct vec_descriptor *const l1 =
538*e4b17023SJohn Marino *(const struct vec_descriptor *const *) loc1;
539*e4b17023SJohn Marino const struct vec_descriptor *const l2 =
540*e4b17023SJohn Marino *(const struct vec_descriptor *const *) loc2;
541*e4b17023SJohn Marino long diff;
542*e4b17023SJohn Marino diff = l1->allocated - l2->allocated;
543*e4b17023SJohn Marino if (!diff)
544*e4b17023SJohn Marino diff = l1->peak - l2->peak;
545*e4b17023SJohn Marino if (!diff)
546*e4b17023SJohn Marino diff = l1->times - l2->times;
547*e4b17023SJohn Marino return diff > 0 ? 1 : diff < 0 ? -1 : 0;
548*e4b17023SJohn Marino }
549*e4b17023SJohn Marino /* Collect array of the descriptors from hashtable. */
550*e4b17023SJohn Marino static struct vec_descriptor **loc_array;
551*e4b17023SJohn Marino static int
add_statistics(void ** slot,void * b)552*e4b17023SJohn Marino add_statistics (void **slot, void *b)
553*e4b17023SJohn Marino {
554*e4b17023SJohn Marino int *n = (int *)b;
555*e4b17023SJohn Marino loc_array[*n] = (struct vec_descriptor *) *slot;
556*e4b17023SJohn Marino (*n)++;
557*e4b17023SJohn Marino return 1;
558*e4b17023SJohn Marino }
559*e4b17023SJohn Marino
560*e4b17023SJohn Marino /* Dump per-site memory statistics. */
561*e4b17023SJohn Marino #endif
562*e4b17023SJohn Marino void
dump_vec_loc_statistics(void)563*e4b17023SJohn Marino dump_vec_loc_statistics (void)
564*e4b17023SJohn Marino {
565*e4b17023SJohn Marino #ifdef GATHER_STATISTICS
566*e4b17023SJohn Marino int nentries = 0;
567*e4b17023SJohn Marino char s[4096];
568*e4b17023SJohn Marino size_t allocated = 0;
569*e4b17023SJohn Marino size_t times = 0;
570*e4b17023SJohn Marino int i;
571*e4b17023SJohn Marino
572*e4b17023SJohn Marino loc_array = XCNEWVEC (struct vec_descriptor *, vec_desc_hash->n_elements);
573*e4b17023SJohn Marino fprintf (stderr, "Heap vectors:\n");
574*e4b17023SJohn Marino fprintf (stderr, "\n%-48s %10s %10s %10s\n",
575*e4b17023SJohn Marino "source location", "Leak", "Peak", "Times");
576*e4b17023SJohn Marino fprintf (stderr, "-------------------------------------------------------\n");
577*e4b17023SJohn Marino htab_traverse (vec_desc_hash, add_statistics, &nentries);
578*e4b17023SJohn Marino qsort (loc_array, nentries, sizeof (*loc_array), cmp_statistic);
579*e4b17023SJohn Marino for (i = 0; i < nentries; i++)
580*e4b17023SJohn Marino {
581*e4b17023SJohn Marino struct vec_descriptor *d = loc_array[i];
582*e4b17023SJohn Marino allocated += d->allocated;
583*e4b17023SJohn Marino times += d->times;
584*e4b17023SJohn Marino }
585*e4b17023SJohn Marino for (i = 0; i < nentries; i++)
586*e4b17023SJohn Marino {
587*e4b17023SJohn Marino struct vec_descriptor *d = loc_array[i];
588*e4b17023SJohn Marino const char *s1 = d->file;
589*e4b17023SJohn Marino const char *s2;
590*e4b17023SJohn Marino while ((s2 = strstr (s1, "gcc/")))
591*e4b17023SJohn Marino s1 = s2 + 4;
592*e4b17023SJohn Marino sprintf (s, "%s:%i (%s)", s1, d->line, d->function);
593*e4b17023SJohn Marino s[48] = 0;
594*e4b17023SJohn Marino fprintf (stderr, "%-48s %10li:%4.1f%% %10li %10li:%4.1f%% \n", s,
595*e4b17023SJohn Marino (long)d->allocated,
596*e4b17023SJohn Marino (d->allocated) * 100.0 / allocated,
597*e4b17023SJohn Marino (long)d->peak,
598*e4b17023SJohn Marino (long)d->times,
599*e4b17023SJohn Marino (d->times) * 100.0 / times);
600*e4b17023SJohn Marino }
601*e4b17023SJohn Marino fprintf (stderr, "%-48s %10ld %10ld\n",
602*e4b17023SJohn Marino "Total", (long)allocated, (long)times);
603*e4b17023SJohn Marino fprintf (stderr, "\n%-48s %10s %10s %10s\n",
604*e4b17023SJohn Marino "source location", "Leak", "Peak", "Times");
605*e4b17023SJohn Marino fprintf (stderr, "-------------------------------------------------------\n");
606*e4b17023SJohn Marino #endif
607*e4b17023SJohn Marino }
608