1 /* Vector API for GNU compiler.
2 Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2012
3 Free Software Foundation, Inc.
4 Contributed by Nathan Sidwell <nathan@codesourcery.com>
5 Re-implemented in C++ by Diego Novillo <dnovillo@google.com>
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 3, or (at your option) any later
14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING3. If not see
21 <http://www.gnu.org/licenses/>. */
23 /* This file is compiled twice: once for the generator programs
24 once for the compiler. */
32 #include "coretypes.h"
35 #include "diagnostic-core.h"
38 /* vNULL is an empty type with a template cast operation that returns
39 a zero-initialized vec<T, A, L> instance. Use this when you want
40 to assign nil values to new vec instances or pass a nil vector as
41 a function call argument.
43 We use this technique because vec<T, A, L> must be PODs (they are
44 stored in unions and passed in vararg functions), this means that
45 they cannot have ctors/dtors. */
49 /* Store information about each particular vector. */
61 /* Hashtable mapping vec addresses to descriptors. */
62 static htab_t vec_desc_hash
;
64 /* Hashtable helpers. */
66 hash_descriptor (const void *p
)
68 const struct vec_descriptor
*const d
=
69 (const struct vec_descriptor
*) p
;
70 return htab_hash_pointer (d
->file
) + d
->line
;
73 eq_descriptor (const void *p1
, const void *p2
)
75 const struct vec_descriptor
*const d
= (const struct vec_descriptor
*) p1
;
76 const struct vec_descriptor
*const l
= (const struct vec_descriptor
*) p2
;
77 return d
->file
== l
->file
&& d
->function
== l
->function
&& d
->line
== l
->line
;
80 /* Hashtable converting address of allocated field to loc descriptor. */
81 static htab_t ptr_hash
;
85 struct vec_descriptor
*loc
;
89 /* Hash table helpers functions. */
91 hash_ptr (const void *p
)
93 const struct ptr_hash_entry
*const d
= (const struct ptr_hash_entry
*) p
;
95 return htab_hash_pointer (d
->ptr
);
99 eq_ptr (const void *p1
, const void *p2
)
101 const struct ptr_hash_entry
*const p
= (const struct ptr_hash_entry
*) p1
;
103 return (p
->ptr
== p2
);
106 /* Return descriptor for given call site, create new one if needed. */
107 static struct vec_descriptor
*
108 vec_descriptor (const char *name
, int line
, const char *function
)
110 struct vec_descriptor loc
;
111 struct vec_descriptor
**slot
;
115 loc
.function
= function
;
117 vec_desc_hash
= htab_create (10, hash_descriptor
, eq_descriptor
, NULL
);
119 slot
= (struct vec_descriptor
**) htab_find_slot (vec_desc_hash
, &loc
,
123 *slot
= XCNEW (struct vec_descriptor
);
124 (*slot
)->file
= name
;
125 (*slot
)->line
= line
;
126 (*slot
)->function
= function
;
127 (*slot
)->allocated
= 0;
132 /* Account the overhead. */
135 vec_prefix::register_overhead (size_t size
, const char *name
, int line
,
136 const char *function
)
138 struct vec_descriptor
*loc
= vec_descriptor (name
, line
, function
);
139 struct ptr_hash_entry
*p
= XNEW (struct ptr_hash_entry
);
146 ptr_hash
= htab_create (10, hash_ptr
, eq_ptr
, NULL
);
147 slot
= htab_find_slot_with_hash (ptr_hash
, this, htab_hash_pointer (this),
152 loc
->allocated
+= size
;
153 if (loc
->peak
< loc
->allocated
)
154 loc
->peak
+= loc
->allocated
;
159 /* Notice that the memory allocated for the vector has been freed. */
162 vec_prefix::release_overhead (void)
164 PTR
*slot
= htab_find_slot_with_hash (ptr_hash
, this,
165 htab_hash_pointer (this),
167 struct ptr_hash_entry
*p
= (struct ptr_hash_entry
*) *slot
;
168 p
->loc
->allocated
-= p
->allocated
;
169 htab_clear_slot (ptr_hash
, slot
);
174 /* Calculate the number of slots to reserve a vector, making sure that
175 RESERVE slots are free. If EXACT grow exactly, otherwise grow
176 exponentially. PFX is the control data for the vector. */
179 vec_prefix::calculate_allocation (vec_prefix
*pfx
, unsigned reserve
,
191 /* If there's no vector, and we've not requested anything, then we
192 will create a NULL vector. */
195 /* We must have run out of room. */
196 gcc_assert (alloc
- num
< reserve
);
200 alloc
= num
+ reserve
;
203 /* Exponential growth. */
207 /* Double when small. */
210 /* Grow slower when large. */
211 alloc
= (alloc
* 3 / 2);
213 /* If this is still too small, set it to the right size. */
214 if (alloc
< num
+ reserve
)
215 alloc
= num
+ reserve
;
221 /* Stack vectors are a little different. VEC_alloc turns into a call
222 to vec<T, A>::stack_reserve and passes in space allocated via a
223 call to alloca. We record that pointer so that we know that we
224 shouldn't free it. If the vector is resized, we resize it on the
225 heap. We record the pointers in a vector and search it in LIFO
226 order--i.e., we look for the newest stack vectors first. We don't
227 expect too many stack vectors at any one level, and searching from
228 the end should normally be efficient even if they are used in a
229 recursive function. */
231 static vec
<void *> stack_vecs
;
233 /* Add a stack vector to STACK_VECS. */
236 register_stack_vec (void *vec
)
238 stack_vecs
.safe_push (vec
);
242 /* If VEC is registered in STACK_VECS, return its index.
243 Otherwise, return -1. */
246 stack_vec_register_index (void *vec
)
248 for (unsigned ix
= stack_vecs
.length (); ix
> 0; --ix
)
249 if (stack_vecs
[ix
- 1] == vec
)
250 return static_cast<int> (ix
- 1);
255 /* Remove vector at slot IX from the list of registered stack vectors. */
258 unregister_stack_vec (unsigned ix
)
260 stack_vecs
.unordered_remove (ix
);
264 /* Helper for qsort; sort descriptors by amount of memory consumed. */
267 cmp_statistic (const void *loc1
, const void *loc2
)
269 const struct vec_descriptor
*const l1
=
270 *(const struct vec_descriptor
*const *) loc1
;
271 const struct vec_descriptor
*const l2
=
272 *(const struct vec_descriptor
*const *) loc2
;
274 diff
= l1
->allocated
- l2
->allocated
;
276 diff
= l1
->peak
- l2
->peak
;
278 diff
= l1
->times
- l2
->times
;
279 return diff
> 0 ? 1 : diff
< 0 ? -1 : 0;
283 /* Collect array of the descriptors from hashtable. */
285 static struct vec_descriptor
**loc_array
;
287 add_statistics (void **slot
, void *b
)
290 loc_array
[*n
] = (struct vec_descriptor
*) *slot
;
295 /* Dump per-site memory statistics. */
298 dump_vec_loc_statistics (void)
302 size_t allocated
= 0;
306 if (! GATHER_STATISTICS
)
309 loc_array
= XCNEWVEC (struct vec_descriptor
*, vec_desc_hash
->n_elements
);
310 fprintf (stderr
, "Heap vectors:\n");
311 fprintf (stderr
, "\n%-48s %10s %10s %10s\n",
312 "source location", "Leak", "Peak", "Times");
313 fprintf (stderr
, "-------------------------------------------------------\n");
314 htab_traverse (vec_desc_hash
, add_statistics
, &nentries
);
315 qsort (loc_array
, nentries
, sizeof (*loc_array
), cmp_statistic
);
316 for (i
= 0; i
< nentries
; i
++)
318 struct vec_descriptor
*d
= loc_array
[i
];
319 allocated
+= d
->allocated
;
322 for (i
= 0; i
< nentries
; i
++)
324 struct vec_descriptor
*d
= loc_array
[i
];
325 const char *s1
= d
->file
;
327 while ((s2
= strstr (s1
, "gcc/")))
329 sprintf (s
, "%s:%i (%s)", s1
, d
->line
, d
->function
);
331 fprintf (stderr
, "%-48s %10li:%4.1f%% %10li %10li:%4.1f%% \n", s
,
333 (d
->allocated
) * 100.0 / allocated
,
336 (d
->times
) * 100.0 / times
);
338 fprintf (stderr
, "%-48s %10ld %10ld\n",
339 "Total", (long)allocated
, (long)times
);
340 fprintf (stderr
, "\n%-48s %10s %10s %10s\n",
341 "source location", "Leak", "Peak", "Times");
342 fprintf (stderr
, "-------------------------------------------------------\n");