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 /* Store information about each particular vector. */
50 /* Hashtable mapping vec addresses to descriptors. */
51 static htab_t vec_desc_hash
;
53 /* Hashtable helpers. */
55 hash_descriptor (const void *p
)
57 const struct vec_descriptor
*const d
=
58 (const struct vec_descriptor
*) p
;
59 return htab_hash_pointer (d
->file
) + d
->line
;
62 eq_descriptor (const void *p1
, const void *p2
)
64 const struct vec_descriptor
*const d
= (const struct vec_descriptor
*) p1
;
65 const struct vec_descriptor
*const l
= (const struct vec_descriptor
*) p2
;
66 return d
->file
== l
->file
&& d
->function
== l
->function
&& d
->line
== l
->line
;
69 /* Hashtable converting address of allocated field to loc descriptor. */
70 static htab_t ptr_hash
;
74 struct vec_descriptor
*loc
;
78 /* Hash table helpers functions. */
80 hash_ptr (const void *p
)
82 const struct ptr_hash_entry
*const d
= (const struct ptr_hash_entry
*) p
;
84 return htab_hash_pointer (d
->ptr
);
88 eq_ptr (const void *p1
, const void *p2
)
90 const struct ptr_hash_entry
*const p
= (const struct ptr_hash_entry
*) p1
;
92 return (p
->ptr
== p2
);
95 /* Return descriptor for given call site, create new one if needed. */
96 static struct vec_descriptor
*
97 vec_descriptor (const char *name
, int line
, const char *function
)
99 struct vec_descriptor loc
;
100 struct vec_descriptor
**slot
;
104 loc
.function
= function
;
106 vec_desc_hash
= htab_create (10, hash_descriptor
, eq_descriptor
, NULL
);
108 slot
= (struct vec_descriptor
**) htab_find_slot (vec_desc_hash
, &loc
,
112 *slot
= XCNEW (struct vec_descriptor
);
113 (*slot
)->file
= name
;
114 (*slot
)->line
= line
;
115 (*slot
)->function
= function
;
116 (*slot
)->allocated
= 0;
121 /* Account the overhead. */
123 register_overhead (struct vec_prefix
*ptr
, size_t size
,
124 const char *name
, int line
, const char *function
)
126 struct vec_descriptor
*loc
= vec_descriptor (name
, line
, function
);
127 struct ptr_hash_entry
*p
= XNEW (struct ptr_hash_entry
);
134 ptr_hash
= htab_create (10, hash_ptr
, eq_ptr
, NULL
);
135 slot
= htab_find_slot_with_hash (ptr_hash
, ptr
, htab_hash_pointer (ptr
), INSERT
);
139 loc
->allocated
+= size
;
140 if (loc
->peak
< loc
->allocated
)
141 loc
->peak
+= loc
->allocated
;
145 /* Notice that the pointer has been freed. */
147 free_overhead (struct vec_prefix
*ptr
)
149 PTR
*slot
= htab_find_slot_with_hash (ptr_hash
, ptr
, htab_hash_pointer (ptr
),
151 struct ptr_hash_entry
*p
= (struct ptr_hash_entry
*) *slot
;
152 p
->loc
->allocated
-= p
->allocated
;
153 htab_clear_slot (ptr_hash
, slot
);
158 vec_heap_free (void *ptr
)
160 if (GATHER_STATISTICS
)
161 free_overhead ((struct vec_prefix
*)ptr
);
165 /* Calculate the new ALLOC value, making sure that RESERVE slots are
166 free. If EXACT grow exactly, otherwise grow exponentially. */
168 static inline unsigned
169 calculate_allocation (const struct vec_prefix
*pfx
, int reserve
, bool exact
)
174 gcc_assert (reserve
>= 0);
182 /* If there's no prefix, and we've not requested anything, then we
183 will create a NULL vector. */
186 /* We must have run out of room. */
187 gcc_assert (alloc
- num
< (unsigned) reserve
);
191 alloc
= num
+ reserve
;
194 /* Exponential growth. */
198 /* Double when small. */
201 /* Grow slower when large. */
202 alloc
= (alloc
* 3 / 2);
204 /* If this is still too small, set it to the right size. */
205 if (alloc
< num
+ reserve
)
206 alloc
= num
+ reserve
;
211 /* Ensure there are at least RESERVE free slots in VEC. If EXACT grow
212 exactly, else grow exponentially. As a special case, if VEC is
213 NULL and RESERVE is 0, no vector will be created. The vector's
214 trailing array is at VEC_OFFSET offset and consists of ELT_SIZE
218 vec_gc_o_reserve_1 (void *vec
, int reserve
, size_t vec_offset
, size_t elt_size
,
219 bool exact MEM_STAT_DECL
)
221 struct vec_prefix
*pfx
= (struct vec_prefix
*) vec
;
222 unsigned alloc
= calculate_allocation (pfx
, reserve
, exact
);
232 /* Calculate the amount of space we want. */
233 size
= vec_offset
+ alloc
* elt_size
;
234 /* Ask the allocator how much space it will really give us. */
235 size
= ggc_round_alloc_size (size
);
236 /* Adjust the number of slots accordingly. */
237 alloc
= (size
- vec_offset
) / elt_size
;
238 /* And finally, recalculate the amount of space we ask for. */
239 size
= vec_offset
+ alloc
* elt_size
;
241 vec
= ggc_realloc_stat (vec
, size PASS_MEM_STAT
);
243 ((struct vec_prefix
*)vec
)->alloc_
= alloc
;
245 ((struct vec_prefix
*)vec
)->num_
= 0;
251 /* As for vec_gc_o_reserve_1, but for heap allocated vectors. */
254 vec_heap_o_reserve_1 (void *vec
, int reserve
, size_t vec_offset
,
255 size_t elt_size
, bool exact MEM_STAT_DECL
)
257 struct vec_prefix
*pfx
= (struct vec_prefix
*) vec
;
258 unsigned alloc
= calculate_allocation (pfx
, reserve
, exact
);
267 if (GATHER_STATISTICS
&& vec
)
270 vec
= xrealloc (vec
, vec_offset
+ alloc
* elt_size
);
271 ((struct vec_prefix
*)vec
)->alloc_
= alloc
;
273 ((struct vec_prefix
*)vec
)->num_
= 0;
274 if (GATHER_STATISTICS
&& vec
)
275 register_overhead ((struct vec_prefix
*)vec
,
276 vec_offset
+ alloc
* elt_size FINAL_PASS_MEM_STAT
);
282 /* Stack vectors are a little different. VEC_alloc turns into a call
283 to vec_stack_p_reserve_exact1 and passes in space allocated via a
284 call to alloca. We record that pointer so that we know that we
285 shouldn't free it. If the vector is resized, we resize it on the
286 heap. We record the pointers in a vector and search it in LIFO
287 order--i.e., we look for the newest stack vectors first. We don't
288 expect too many stack vectors at any one level, and searching from
289 the end should normally be efficient even if they are used in a
290 recursive function. */
292 typedef void *void_p
;
294 DEF_VEC_ALLOC_P(void_p
,heap
);
296 static VEC(void_p
,heap
) *stack_vecs
;
298 /* Allocate a vector which uses alloca for the initial allocation.
299 SPACE is space allocated using alloca, ALLOC is the number of
300 entries allocated. */
303 vec_stack_p_reserve_exact_1 (int alloc
, void *space
)
305 struct vec_prefix
*pfx
= (struct vec_prefix
*) space
;
307 VEC_safe_push (void_p
, heap
, stack_vecs
, space
);
315 /* Grow a vector allocated using alloca. When this happens, we switch
316 back to heap allocation. We remove the vector from stack_vecs, if
317 it is there, since we no longer need to avoid freeing it. */
320 vec_stack_o_reserve_1 (void *vec
, int reserve
, size_t vec_offset
,
321 size_t elt_size
, bool exact MEM_STAT_DECL
)
328 for (ix
= VEC_length (void_p
, stack_vecs
); ix
> 0; --ix
)
330 if (VEC_index (void_p
, stack_vecs
, ix
- 1) == vec
)
332 VEC_unordered_remove (void_p
, stack_vecs
, ix
- 1);
340 /* VEC is already on the heap. */
341 return vec_heap_o_reserve_1 (vec
, reserve
, vec_offset
, elt_size
,
342 exact PASS_MEM_STAT
);
345 /* Move VEC to the heap. */
346 reserve
+= ((struct vec_prefix
*) vec
)->num_
;
347 newvec
= vec_heap_o_reserve_1 (NULL
, reserve
, vec_offset
, elt_size
,
348 exact PASS_MEM_STAT
);
351 ((struct vec_prefix
*) newvec
)->num_
= ((struct vec_prefix
*) vec
)->num_
;
352 memcpy (((struct vec_prefix
*) newvec
)+1,
353 ((struct vec_prefix
*) vec
)+1,
354 ((struct vec_prefix
*) vec
)->num_
* elt_size
);
359 /* Grow a vector allocated on the stack. */
362 vec_stack_o_reserve (void *vec
, int reserve
, size_t vec_offset
,
363 size_t elt_size MEM_STAT_DECL
)
365 return vec_stack_o_reserve_1 (vec
, reserve
, vec_offset
, elt_size
, false
369 /* Exact version of vec_stack_o_reserve. */
372 vec_stack_o_reserve_exact (void *vec
, int reserve
, size_t vec_offset
,
373 size_t elt_size MEM_STAT_DECL
)
375 return vec_stack_o_reserve_1 (vec
, reserve
, vec_offset
, elt_size
, true
379 /* Free a vector allocated on the stack. Don't actually free it if we
380 find it in the hash table. */
383 vec_stack_free (void *vec
)
387 for (ix
= VEC_length (void_p
, stack_vecs
); ix
> 0; --ix
)
389 if (VEC_index (void_p
, stack_vecs
, ix
- 1) == vec
)
391 VEC_unordered_remove (void_p
, stack_vecs
, ix
- 1);
396 /* VEC was not on the list of vecs allocated on the stack, so it
397 must be allocated on the heap. */
402 /* Issue a vector domain error, and then fall over. */
405 vec_assert_fail (const char *op
, const char *struct_name
,
406 const char *file
, unsigned int line
, const char *function
)
408 internal_error ("vector %s %s domain error, in %s at %s:%u",
409 struct_name
, op
, function
, trim_filename (file
), line
);
413 /* Helper for qsort; sort descriptors by amount of memory consumed. */
415 cmp_statistic (const void *loc1
, const void *loc2
)
417 const struct vec_descriptor
*const l1
=
418 *(const struct vec_descriptor
*const *) loc1
;
419 const struct vec_descriptor
*const l2
=
420 *(const struct vec_descriptor
*const *) loc2
;
422 diff
= l1
->allocated
- l2
->allocated
;
424 diff
= l1
->peak
- l2
->peak
;
426 diff
= l1
->times
- l2
->times
;
427 return diff
> 0 ? 1 : diff
< 0 ? -1 : 0;
429 /* Collect array of the descriptors from hashtable. */
430 static struct vec_descriptor
**loc_array
;
432 add_statistics (void **slot
, void *b
)
435 loc_array
[*n
] = (struct vec_descriptor
*) *slot
;
440 /* Dump per-site memory statistics. */
443 dump_vec_loc_statistics (void)
447 size_t allocated
= 0;
451 if (! GATHER_STATISTICS
)
454 loc_array
= XCNEWVEC (struct vec_descriptor
*, vec_desc_hash
->n_elements
);
455 fprintf (stderr
, "Heap vectors:\n");
456 fprintf (stderr
, "\n%-48s %10s %10s %10s\n",
457 "source location", "Leak", "Peak", "Times");
458 fprintf (stderr
, "-------------------------------------------------------\n");
459 htab_traverse (vec_desc_hash
, add_statistics
, &nentries
);
460 qsort (loc_array
, nentries
, sizeof (*loc_array
), cmp_statistic
);
461 for (i
= 0; i
< nentries
; i
++)
463 struct vec_descriptor
*d
= loc_array
[i
];
464 allocated
+= d
->allocated
;
467 for (i
= 0; i
< nentries
; i
++)
469 struct vec_descriptor
*d
= loc_array
[i
];
470 const char *s1
= d
->file
;
472 while ((s2
= strstr (s1
, "gcc/")))
474 sprintf (s
, "%s:%i (%s)", s1
, d
->line
, d
->function
);
476 fprintf (stderr
, "%-48s %10li:%4.1f%% %10li %10li:%4.1f%% \n", s
,
478 (d
->allocated
) * 100.0 / allocated
,
481 (d
->times
) * 100.0 / times
);
483 fprintf (stderr
, "%-48s %10ld %10ld\n",
484 "Total", (long)allocated
, (long)times
);
485 fprintf (stderr
, "\n%-48s %10s %10s %10s\n",
486 "source location", "Leak", "Peak", "Times");
487 fprintf (stderr
, "-------------------------------------------------------\n");