1 /* Vector API for GNU compiler.
2 Copyright (C) 2004-2013 Free Software Foundation, Inc.
3 Contributed by Nathan Sidwell <nathan@codesourcery.com>
4 Re-implemented in C++ by Diego Novillo <dnovillo@google.com>
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 /* This file is compiled twice: once for the generator programs
23 once for the compiler. */
31 #include "coretypes.h"
34 #include "diagnostic-core.h"
37 /* vNULL is an empty type with a template cast operation that returns
38 a zero-initialized vec<T, A, L> instance. Use this when you want
39 to assign nil values to new vec instances or pass a nil vector as
40 a function call argument.
42 We use this technique because vec<T, A, L> must be PODs (they are
43 stored in unions and passed in vararg functions), this means that
44 they cannot have ctors/dtors. */
48 /* Store information about each particular vector. */
60 /* Hashtable mapping vec addresses to descriptors. */
61 static htab_t vec_desc_hash
;
63 /* Hashtable helpers. */
65 hash_descriptor (const void *p
)
67 const struct vec_descriptor
*const d
=
68 (const struct vec_descriptor
*) p
;
69 return htab_hash_pointer (d
->file
) + d
->line
;
72 eq_descriptor (const void *p1
, const void *p2
)
74 const struct vec_descriptor
*const d
= (const struct vec_descriptor
*) p1
;
75 const struct vec_descriptor
*const l
= (const struct vec_descriptor
*) p2
;
76 return d
->file
== l
->file
&& d
->function
== l
->function
&& d
->line
== l
->line
;
79 /* Hashtable converting address of allocated field to loc descriptor. */
80 static htab_t ptr_hash
;
84 struct vec_descriptor
*loc
;
88 /* Hash table helpers functions. */
90 hash_ptr (const void *p
)
92 const struct ptr_hash_entry
*const d
= (const struct ptr_hash_entry
*) p
;
94 return htab_hash_pointer (d
->ptr
);
98 eq_ptr (const void *p1
, const void *p2
)
100 const struct ptr_hash_entry
*const p
= (const struct ptr_hash_entry
*) p1
;
102 return (p
->ptr
== p2
);
105 /* Return descriptor for given call site, create new one if needed. */
106 static struct vec_descriptor
*
107 vec_descriptor (const char *name
, int line
, const char *function
)
109 struct vec_descriptor loc
;
110 struct vec_descriptor
**slot
;
114 loc
.function
= function
;
116 vec_desc_hash
= htab_create (10, hash_descriptor
, eq_descriptor
, NULL
);
118 slot
= (struct vec_descriptor
**) htab_find_slot (vec_desc_hash
, &loc
,
122 *slot
= XCNEW (struct vec_descriptor
);
123 (*slot
)->file
= name
;
124 (*slot
)->line
= line
;
125 (*slot
)->function
= function
;
126 (*slot
)->allocated
= 0;
131 /* Account the overhead. */
134 vec_prefix::register_overhead (size_t size
, const char *name
, int line
,
135 const char *function
)
137 struct vec_descriptor
*loc
= vec_descriptor (name
, line
, function
);
138 struct ptr_hash_entry
*p
= XNEW (struct ptr_hash_entry
);
145 ptr_hash
= htab_create (10, hash_ptr
, eq_ptr
, NULL
);
146 slot
= htab_find_slot_with_hash (ptr_hash
, this, htab_hash_pointer (this),
151 loc
->allocated
+= size
;
152 if (loc
->peak
< loc
->allocated
)
153 loc
->peak
+= loc
->allocated
;
158 /* Notice that the memory allocated for the vector has been freed. */
161 vec_prefix::release_overhead (void)
163 PTR
*slot
= htab_find_slot_with_hash (ptr_hash
, this,
164 htab_hash_pointer (this),
166 struct ptr_hash_entry
*p
= (struct ptr_hash_entry
*) *slot
;
167 p
->loc
->allocated
-= p
->allocated
;
168 htab_clear_slot (ptr_hash
, slot
);
173 /* Calculate the number of slots to reserve a vector, making sure that
174 RESERVE slots are free. If EXACT grow exactly, otherwise grow
175 exponentially. PFX is the control data for the vector. */
178 vec_prefix::calculate_allocation (vec_prefix
*pfx
, unsigned reserve
,
186 alloc
= pfx
->m_alloc
;
190 /* If there's no vector, and we've not requested anything, then we
191 will create a NULL vector. */
194 /* We must have run out of room. */
195 gcc_assert (alloc
- num
< reserve
);
199 alloc
= num
+ reserve
;
202 /* Exponential growth. */
206 /* Double when small. */
209 /* Grow slower when large. */
210 alloc
= (alloc
* 3 / 2);
212 /* If this is still too small, set it to the right size. */
213 if (alloc
< num
+ reserve
)
214 alloc
= num
+ reserve
;
220 /* Stack vectors are a little different. VEC_alloc turns into a call
221 to vec<T, A>::stack_reserve and passes in space allocated via a
222 call to alloca. We record that pointer so that we know that we
223 shouldn't free it. If the vector is resized, we resize it on the
224 heap. We record the pointers in a vector and search it in LIFO
225 order--i.e., we look for the newest stack vectors first. We don't
226 expect too many stack vectors at any one level, and searching from
227 the end should normally be efficient even if they are used in a
228 recursive function. */
230 static vec
<void *> stack_vecs
;
232 /* Add a stack vector to STACK_VECS. */
235 register_stack_vec (void *vec
)
237 stack_vecs
.safe_push (vec
);
241 /* If VEC is registered in STACK_VECS, return its index.
242 Otherwise, return -1. */
245 stack_vec_register_index (void *vec
)
247 for (unsigned ix
= stack_vecs
.length (); ix
> 0; --ix
)
248 if (stack_vecs
[ix
- 1] == vec
)
249 return static_cast<int> (ix
- 1);
254 /* Remove vector at slot IX from the list of registered stack vectors. */
257 unregister_stack_vec (unsigned ix
)
259 stack_vecs
.unordered_remove (ix
);
263 /* Helper for qsort; sort descriptors by amount of memory consumed. */
266 cmp_statistic (const void *loc1
, const void *loc2
)
268 const struct vec_descriptor
*const l1
=
269 *(const struct vec_descriptor
*const *) loc1
;
270 const struct vec_descriptor
*const l2
=
271 *(const struct vec_descriptor
*const *) loc2
;
273 diff
= l1
->allocated
- l2
->allocated
;
275 diff
= l1
->peak
- l2
->peak
;
277 diff
= l1
->times
- l2
->times
;
278 return diff
> 0 ? 1 : diff
< 0 ? -1 : 0;
282 /* Collect array of the descriptors from hashtable. */
284 static struct vec_descriptor
**loc_array
;
286 add_statistics (void **slot
, void *b
)
289 loc_array
[*n
] = (struct vec_descriptor
*) *slot
;
294 /* Dump per-site memory statistics. */
297 dump_vec_loc_statistics (void)
301 size_t allocated
= 0;
305 if (! GATHER_STATISTICS
)
308 loc_array
= XCNEWVEC (struct vec_descriptor
*, vec_desc_hash
->n_elements
);
309 fprintf (stderr
, "Heap vectors:\n");
310 fprintf (stderr
, "\n%-48s %10s %10s %10s\n",
311 "source location", "Leak", "Peak", "Times");
312 fprintf (stderr
, "-------------------------------------------------------\n");
313 htab_traverse (vec_desc_hash
, add_statistics
, &nentries
);
314 qsort (loc_array
, nentries
, sizeof (*loc_array
), cmp_statistic
);
315 for (i
= 0; i
< nentries
; i
++)
317 struct vec_descriptor
*d
= loc_array
[i
];
318 allocated
+= d
->allocated
;
321 for (i
= 0; i
< nentries
; i
++)
323 struct vec_descriptor
*d
= loc_array
[i
];
324 const char *s1
= d
->file
;
326 while ((s2
= strstr (s1
, "gcc/")))
328 sprintf (s
, "%s:%i (%s)", s1
, d
->line
, d
->function
);
330 fprintf (stderr
, "%-48s %10li:%4.1f%% %10li %10li:%4.1f%% \n", s
,
332 (d
->allocated
) * 100.0 / allocated
,
335 (d
->times
) * 100.0 / times
);
337 fprintf (stderr
, "%-48s %10ld %10ld\n",
338 "Total", (long)allocated
, (long)times
);
339 fprintf (stderr
, "\n%-48s %10s %10s %10s\n",
340 "source location", "Leak", "Peak", "Times");
341 fprintf (stderr
, "-------------------------------------------------------\n");